@@ -209,6 +209,9 @@ pub fn run_simulation(
209209 ) ;
210210 let dither_mode = args. dither_mode ( ) . unwrap_or ( DitherMode :: None ) ;
211211 renderer. set_dither_mode ( dither_mode) ;
212+ // Dither is dev-only for v0.1.0: runtime keys work only when it was
213+ // explicitly enabled at startup via the (hidden) CLI flags.
214+ let dither_unlocked = !matches ! ( dither_mode, DitherMode :: None ) ;
212215 renderer. set_ascii_contrast ( args. ascii_contrast ) ;
213216 renderer. set_window_frame ( config. window_frame ) ;
214217 let mut timer = FrameTimer :: with_time_scale ( args. fps , args. frame_delay , args. time_scale ) ;
@@ -330,7 +333,7 @@ pub fn run_simulation(
330333 }
331334
332335 // let config = args.to_sim_config().unwrap(); // Already parsed above
333- if args. species_colors {
336+ if args. species_colors_enabled ( ) {
334337 let species_rgb_colors = extract_species_rgb_colors ( & config) ;
335338 renderer. set_species_colors ( true , species_rgb_colors) ;
336339 }
@@ -411,13 +414,6 @@ pub fn run_simulation(
411414 } else {
412415 None
413416 } ;
414- #[ cfg( not( feature = "audio" ) ) ]
415- {
416- if args. choir {
417- eprintln ! ( "--choir requires building with --features audio" ) ;
418- }
419- }
420-
421417 loop {
422418 if is_shutdown_requested ( ) {
423419 break ;
@@ -1113,7 +1109,7 @@ pub fn run_simulation(
11131109 } ) ;
11141110 }
11151111
1116- if args. species_colors && sim. config ( ) . separate_species_trails {
1112+ if args. species_colors_enabled ( ) && sim. config ( ) . separate_species_trails {
11171113 let species_trail_maps = sim. trail_maps_for_species_colors ( ) ;
11181114 let species_rgb_colors = extract_species_rgb_colors ( & current_config) ;
11191115 let combined: Vec < _ > = species_trail_maps
@@ -1582,16 +1578,37 @@ pub fn run_simulation(
15821578 ) ) ;
15831579 }
15841580 ControlAction :: ToggleDither => {
1585- runtime_state. toggle_dither ( ) ;
1586- renderer. set_dither_mode ( runtime_state. dither_mode ) ;
1581+ if dither_unlocked {
1582+ runtime_state. toggle_dither ( ) ;
1583+ renderer. set_dither_mode ( runtime_state. dither_mode ) ;
1584+ } else {
1585+ runtime_state. show_notification (
1586+ "Dither is dev-only - see help-wanted issues on GitHub"
1587+ . to_string ( ) ,
1588+ ) ;
1589+ }
15871590 }
15881591 ControlAction :: CycleDitherMode => {
1589- runtime_state. cycle_dither_mode ( ) ;
1590- renderer. set_dither_mode ( runtime_state. dither_mode ) ;
1592+ if dither_unlocked {
1593+ runtime_state. cycle_dither_mode ( ) ;
1594+ renderer. set_dither_mode ( runtime_state. dither_mode ) ;
1595+ } else {
1596+ runtime_state. show_notification (
1597+ "Dither is dev-only - see help-wanted issues on GitHub"
1598+ . to_string ( ) ,
1599+ ) ;
1600+ }
15911601 }
15921602 ControlAction :: AdjustDitherIntensity ( delta) => {
1593- runtime_state. adjust_dither_intensity ( delta) ;
1594- renderer. set_dither_mode ( runtime_state. dither_mode ) ;
1603+ if dither_unlocked {
1604+ runtime_state. adjust_dither_intensity ( delta) ;
1605+ renderer. set_dither_mode ( runtime_state. dither_mode ) ;
1606+ } else {
1607+ runtime_state. show_notification (
1608+ "Dither is dev-only - see help-wanted issues on GitHub"
1609+ . to_string ( ) ,
1610+ ) ;
1611+ }
15951612 }
15961613 ControlAction :: ToggleKeyboardHints => {
15971614 runtime_state. toggle_keyboard_hints ( ) ;
@@ -2074,35 +2091,26 @@ pub fn run_simulation(
20742091 renderer. set_window_layout ( None ) ;
20752092 }
20762093 }
2094+ #[ cfg( feature = "audio" ) ]
20772095 ControlAction :: ToggleChoir => {
2078- #[ cfg( feature = "audio" ) ]
2079- {
2080- if choir. is_some ( ) {
2081- choir = None ;
2082- runtime_state. show_notification ( "Choir mode: off" . to_string ( ) ) ;
2083- } else {
2084- match crate :: audio:: Choir :: try_new (
2085- args. choir_volume . clamp ( 0.0 , 1.0 ) ,
2086- ) {
2087- Ok ( c) => {
2088- choir = Some ( c) ;
2089- runtime_state
2090- . show_notification ( "Choir mode: on" . to_string ( ) ) ;
2091- }
2092- Err ( e) => {
2093- runtime_state. show_notification ( format ! (
2094- "Choir init failed: {e}"
2095- ) ) ;
2096- }
2096+ if choir. is_some ( ) {
2097+ choir = None ;
2098+ runtime_state. show_notification ( "Choir mode: off" . to_string ( ) ) ;
2099+ } else {
2100+ match crate :: audio:: Choir :: try_new (
2101+ args. choir_volume . clamp ( 0.0 , 1.0 ) ,
2102+ ) {
2103+ Ok ( c) => {
2104+ choir = Some ( c) ;
2105+ runtime_state
2106+ . show_notification ( "Choir mode: on" . to_string ( ) ) ;
2107+ }
2108+ Err ( e) => {
2109+ runtime_state
2110+ . show_notification ( format ! ( "Choir init failed: {e}" ) ) ;
20972111 }
20982112 }
20992113 }
2100- #[ cfg( not( feature = "audio" ) ) ]
2101- {
2102- runtime_state. show_notification (
2103- "Choir requires --features audio" . to_string ( ) ,
2104- ) ;
2105- }
21062114 }
21072115 ControlAction :: None => { }
21082116 }
@@ -2287,7 +2295,7 @@ pub fn run_simulation(
22872295 } ;
22882296
22892297 // Re-render with updated pause state
2290- if args. species_colors && sim. config ( ) . separate_species_trails {
2298+ if args. species_colors_enabled ( ) && sim. config ( ) . separate_species_trails {
22912299 let species_trail_maps = sim. trail_maps_for_species_colors ( ) ;
22922300 let species_rgb_colors = extract_species_rgb_colors ( & current_config) ;
22932301 let combined: Vec < _ > = species_trail_maps
0 commit comments