This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

1mod scenes; 2 3use anyhow::anyhow; 4use rand::{SeedableRng, rngs::SmallRng}; 5use shapemaker::{ui::Log, *}; 6use std::{fs, path::PathBuf, time::Duration}; 7 8pub struct State { 9 bass_pattern_at: Region, 10 kick_color: Color, 11 rng: SmallRng, 12 kick_counter: u32, 13} 14 15impl Default for State { 16 fn default() -> Self { 17 Self { 18 bass_pattern_at: Region::from_topleft(Point(1, 1), (2, 2)).unwrap(), 19 kick_color: Color::White, 20 rng: SmallRng::seed_from_u64(0), 21 kick_counter: 0, 22 } 23 } 24} 25 26#[tokio::main] 27pub async fn main() { 28 let mut canvas = Canvas::with_layers(vec![]); 29 30 canvas.set_grid_size(16, 9); 31 canvas.colormap = ColorMapping { 32 black: "#000000".into(), 33 white: "#ffffff".into(), 34 red: "#cf0a2b".into(), 35 green: "#22e753".into(), 36 blue: "#2734e6".into(), 37 yellow: "#f8e21e".into(), 38 orange: "#f05811".into(), 39 purple: "#6a24ec".into(), 40 brown: "#a05634".into(), 41 pink: "#e92e76".into(), 42 gray: "#81a0a8".into(), 43 cyan: "#4fecec".into(), 44 }; 45 46 let mut video = Video::<State>::new(canvas); 47 let mut args = pico_args::Arguments::from_env(); 48 49 video.duration_override = args 50 .value_from_str("--duration") 51 .ok() 52 .map(Duration::from_secs); 53 54 if video.duration_override.is_some_and(|d| d.is_zero()) { 55 video.duration_override = None; 56 } 57 58 video.start_rendering_at = args 59 .value_from_str("--start") 60 .ok() 61 .map(Timestamp::from_seconds) 62 .unwrap_or_default(); 63 64 video.resolution = args.value_from_str("--resolution").ok().unwrap_or(480); 65 video.fps = args.value_from_str("--fps").ok().unwrap_or(30); 66 67 video.audiofile = PathBuf::from("schedule-hell.wav"); 68 video = video 69 // Sync inputs // 70 .sync_audio_with("schedule-hell.midi") 71 .sync_audio_with("schedule-hell.wav") 72 // Scenes // 73 .with_scene(scenes::starry_sky()) 74 .with_init_scene(scenes::intro()) 75 .with_marked_scene(scenes::first_break()) 76 .assign_scene_to("end of first break", "starry sky") 77 .assign_scene_to("second break", "intro") 78 // Credits // 79 .when_remaining(10, &|canvas, _| { 80 let world = canvas.world_region; 81 canvas.root().set( 82 "credits text", 83 Object::Text( 84 world.start.translated(2, 2), 85 "Postamble / Schedule Hell".into(), 86 12.0, 87 ) 88 .colored(Color::White), 89 ); 90 Ok(()) 91 }); 92 93 let destination: String = args 94 .free_from_str() 95 .unwrap_or(String::from("schedule-hell.mp4")); 96 97 if destination.starts_with("localhost:") { 98 video.serve(&destination).await; 99 } else { 100 let result = if destination.ends_with(".svg") { 101 let render_ahead = 10; 102 103 let frame_no = destination 104 .trim_end_matches(".svg") 105 .parse::<usize>() 106 .expect("Provide a integer when rendering a frame"); 107 108 video.progress_bars.loading.log( 109 "Constrained", 110 &format!( 111 "to frame #{frame_no}, with {render_ahead}-frame context" 112 ), 113 ); 114 115 video.render_frame(frame_no, render_ahead).and_then(|svg| { 116 fs::write(destination, svg.to_string()) 117 .map_err(|e| anyhow!("{e:?}")) 118 }) 119 } else { 120 video.encode(destination).map(|_| ()) 121 }; 122 123 match result { 124 Ok(_) => (), 125 Err(e) => { 126 let _ = video.progress.clear(); 127 ().log_error("Failed", &format!("{e:?}")); 128 } 129 }; 130 } 131}