This repository has no description
1use anyhow::Result;
2use rand::{Rng, rngs::SmallRng, seq::IteratorRandom};
3use shapemaker::CornerPoint as P;
4use shapemaker::*;
5
6use crate::State;
7
8pub fn backbone() -> Scene<State> {
9 Scene::<State>::new("backbone")
10 .init(&|canvas, ctx| {
11 canvas.clear();
12
13 canvas.colormap = ColorMapping {
14 black: "#000000".to_string(),
15 white: "#FFFFFF".to_string(),
16 purple: "#da40f5".to_string(),
17 ..Default::default()
18 };
19
20 canvas.set_grid_size(16, 10);
21 canvas.set_background(Black);
22 canvas.object_sizes.dot_radius = 7.5;
23
24 iterate(&mut ctx.extra.rng, canvas)?;
25 Ok(())
26 })
27 // .each_n_frame(3, &|canvas, ctx| {
28 // canvas.clear();
29 // iterate(&mut ctx.extra.rng, canvas)?;
30 // Ok(())
31 // })
32 .on_note("anchor kick", &|canvas, ctx| {
33 canvas.clear();
34 iterate(&mut ctx.extra.rng, canvas)?;
35
36 let world = canvas.world_region.clone();
37 let flickers = canvas.layer("flickers")?;
38
39 let point = world.iter().choose(&mut ctx.extra.rng).unwrap();
40
41 flickers.tag_objects("rotate", |id, _| {
42 id == &format!("crosses-SWNE-{point}")
43 || id == &format!("crosses-NWSE-{point}")
44 });
45
46 ctx.animate(200, &move |t, canvas, _| {
47 canvas
48 .layer("flickers")?
49 .objects_with_tag("rotate")
50 .for_each(|(_, obj)| {
51 obj.recolor(Cyan);
52 obj.set_rotation(Angle::from_degrees(t * 90.0));
53 });
54
55 Ok(())
56 });
57
58 Ok(())
59 })
60 .dump_frame_when(&|_, ctx, _, _| match ctx.since_scene_start() {
61 Some(t) => t.as_millis() == 500,
62 None => false,
63 })
64}
65
66fn iterate(rng: &mut SmallRng, canvas: &mut Canvas) -> Result<()> {
67 // let mut rng = canvas.rng.clone();
68 let world = canvas.world_region.clone();
69
70 let grid_thickness = 2.0;
71
72 for point in
73 Region::from((world.topleft(), world.topright().translated(1, 1)))
74 {
75 canvas.root().set(
76 format!("grid-rows-{point}"),
77 Shape::Line(
78 P(point.x(), world.topleft().y()),
79 P(point.x(), world.bottomleft().y() + 1),
80 grid_thickness * 0.75,
81 )
82 .filled(White.translucent(0.05 + rng.random_range(0.0..0.3))),
83 );
84 }
85
86 for point in
87 Region::from((world.topleft(), world.bottomleft().translated(1, 1)))
88 {
89 canvas.root().set(
90 format!("grid-cols-{point}"),
91 Shape::Line(
92 P(world.topleft().x(), point.y()),
93 P(world.bottomright().x() + 1, point.y()),
94 grid_thickness * 0.75,
95 )
96 .filled(White.translucent(0.005 + rng.random_range(0.0..0.3))),
97 );
98 }
99
100 let occlusions = canvas.layer_or_empty("occlusions");
101
102 for point in world.enlarged(1, 1) {
103 occlusions.set(
104 format!("occlusion-{point}"),
105 Shape::Dot(point).colored(Color::Black),
106 );
107 }
108
109 let flickers = canvas.layer_or_empty("flickers");
110
111 for point in world {
112 flickers.set(
113 format!("crosses-SWNE-{point}"),
114 Shape::Line(point, point.translated(1, 1), grid_thickness)
115 .colored(Color::Purple)
116 .flickering(rng, 0.25)
117 .clipped_to((point, point)),
118 );
119 flickers.set(
120 format!("crosses-NWSE-{point}"),
121 Shape::Line(
122 point.translated(0, 1),
123 point.translated(1, 0),
124 grid_thickness,
125 )
126 .colored(Color::Purple)
127 .flickering(rng, 0.25)
128 .clipped_to((point, point)),
129 );
130 }
131
132 let flickers_occlusions = canvas.layer_or_empty("flickers_occlusions");
133 flickers_occlusions.object_sizes.dot_radius = 10.0;
134
135 for point in world.enlarged(1, 1) {
136 flickers_occlusions.set(
137 format!("crosses-occlusions-{point}"),
138 Shape::Dot(point).colored(Color::Black),
139 )
140 }
141
142 canvas.reorder_layers(vec![
143 "flickers_occlusions",
144 "flickers",
145 "occlusions",
146 "root",
147 ]);
148
149 Ok(())
150}