This repository has no description
0

Configure Feed

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

🚸 Encourage reproducible SVG frames

+147 -152
+1 -1
examples/dna-analysis-machine/src/main.rs
··· 44 44 .colored(Red) 45 45 .filtered(Filter::glow(5.0)); 46 46 47 - canvas.new_layer("red dot").add(red_dot.clone()); 47 + canvas.new_layer("red dot").add_anon(red_dot.clone()); 48 48 49 49 // Hatched circles & squares 50 50
+2 -2
examples/schedule-hell-bicolor/src/main.rs
··· 41 41 _ => panic!("souhldn't happend, update rand:: call"), 42 42 }; 43 43 44 - tiling.add(Object::Rectangle(point, point).colored(bgcolor)); 44 + tiling.add_anon(Object::Rectangle(point, point).colored(bgcolor)); 45 45 shapes 46 - .add(shape.colored(Color::random_except(&mut rand::rng(), bgcolor))); 46 + .add_anon(shape.colored(Color::random_except(&mut rand::rng(), bgcolor))); 47 47 } 48 48 49 49 canvas.add_layer(shapes);
+2 -2
examples/schedule-hell-starry-sky/src/main.rs
··· 44 44 for point in background_stars_in { 45 45 canvas 46 46 .root() 47 - .add(Object::Dot(point).filled(Fill::Translucent( 47 + .add_anon(Object::Dot(point).filled(Fill::Translucent( 48 48 Color::White, 49 49 rand::random_range(if rand::random_bool(0.01) { 50 50 0.8..=1.0 ··· 73 73 let mut layer = Layer::new(format!("cluster{}", rand::random::<u32>())); 74 74 75 75 for _ in 1..=rand::random_range(2..=5) { 76 - layer.add( 76 + layer.add_anon( 77 77 Object::random( 78 78 &mut rand::rng(), 79 79 &Region::from_center_and_size(
+7 -7
examples/schedule-hell/src/main.rs
··· 75 75 let Point(x, y) = canvas.world_region.end; 76 76 (x - 2, y - 2) 77 77 }; 78 - kicks.set_object("top left", circle_at(1, 1)); 79 - kicks.set_object("top right", circle_at(end_x, 1)); 80 - kicks.set_object("bottom left", circle_at(1, end_y)); 81 - kicks.set_object("bottom right", circle_at(end_x, end_y)); 78 + kicks.set("top left", circle_at(1, 1)); 79 + kicks.set("top right", circle_at(end_x, 1)); 80 + kicks.set("bottom left", circle_at(1, end_y)); 81 + kicks.set("bottom right", circle_at(end_x, end_y)); 82 82 canvas.add_or_replace_layer(kicks); 83 83 84 84 let mut ch = Layer::new("ch"); 85 - ch.set_object("0", Object::Dot(Point(0, 0))); 85 + ch.set("0", Object::Dot(Point(0, 0))); 86 86 canvas.add_or_replace_layer(ch); 87 87 88 88 Ok(()) ··· 192 192 layer.objects.retain(|name, _| dots_to_keep.contains(name)); 193 193 194 194 let object_name = format!("{}", ctx.ms); 195 - layer.set_object( 195 + layer.set( 196 196 &object_name, 197 197 Object::Dot( 198 198 world.resized(-1, -1).random_point(&mut ctx.extra.rng), ··· 206 206 }) 207 207 .when_remaining(10, &|canvas, _| { 208 208 let world = canvas.world_region; 209 - canvas.root().set_object( 209 + canvas.root().set( 210 210 "credits text", 211 211 Object::Text( 212 212 world.start.translated(2, 2),
+6 -6
src/graphics/canvas.rs
··· 201 201 match self.layer_safe(layer) { 202 202 None => Err(format!("Layer {} does not exist", layer)), 203 203 Some(layer) => { 204 - layer.set_object(name, ColoredObject::from((object, fill))); 204 + layer.set(name, ColoredObject::from((object, fill))); 205 205 Ok(()) 206 206 } 207 207 } ··· 313 313 pub fn debug_region(&mut self, region: &Region, color: Color) { 314 314 let layer = self.layer_or_empty("debug plane"); 315 315 316 - layer.set_object( 316 + layer.set( 317 317 format!("{}_corner_ss", region).as_str(), 318 318 Object::Dot(region.topleft()).colored(color), 319 319 ); 320 - layer.set_object( 320 + layer.set( 321 321 format!("{}_corner_se", region).as_str(), 322 322 Object::Dot(region.topright().translated(1, 0)).colored(color), 323 323 ); 324 - layer.set_object( 324 + layer.set( 325 325 format!("{}_corner_ne", region).as_str(), 326 326 Object::Dot(region.bottomright().translated(1, 1)).colored(color), 327 327 ); 328 - layer.set_object( 328 + layer.set( 329 329 format!("{}_corner_nw", region).as_str(), 330 330 Object::Dot(region.bottomleft().translated(0, 1)).colored(color), 331 331 ); 332 - layer.set_object( 332 + layer.set( 333 333 format!("{}_region", region).as_str(), 334 334 Object::Rectangle(region.start, region.end) 335 335 .filled(Fill::Translucent(color, 0.25)),
+8 -16
src/graphics/layer.rs
··· 89 89 self.flush(); 90 90 } 91 91 92 - pub fn add_object_named<N: Display>( 93 - &mut self, 94 - name: N, 95 - object: impl Into<ColoredObject>, 96 - ) { 92 + pub fn add(&mut self, name: impl Display, object: impl Into<ColoredObject>) { 97 93 let name_str = format!("{}", name); 98 94 99 95 if self.objects.contains_key(&name_str) { 100 96 panic!("object {} already exists in layer {}", name_str, self.name); 101 97 } 102 98 103 - self.set_object(name_str, object); 99 + self.set(name_str, object); 104 100 } 105 101 106 - pub fn add(&mut self, object: impl Into<ColoredObject>) { 107 - self.add_object_named(nanoid!(), object); 102 + pub fn add_anon(&mut self, object: impl Into<ColoredObject>) { 103 + self.add(nanoid!(), object); 108 104 } 109 105 110 - pub fn set_object<N: Display>( 111 - &mut self, 112 - name: N, 113 - object: impl Into<ColoredObject>, 114 - ) { 106 + pub fn set(&mut self, name: impl Display, object: impl Into<ColoredObject>) { 115 107 let name_str = format!("{}", name); 116 108 117 109 self.objects.insert(name_str, object.into()); ··· 140 132 141 133 pub fn replace_object(&mut self, name: &str, object: ColoredObject) { 142 134 self.remove_object(name); 143 - self.add_object_named(name, object); 135 + self.add(name, object); 144 136 } 145 137 146 138 pub fn add_objects( ··· 148 140 objects: impl IntoIterator<Item = ColoredObject>, 149 141 ) { 150 142 for obj in objects { 151 - self.add(obj); 143 + self.add_anon(obj); 152 144 } 153 145 } 154 146 ··· 163 155 164 156 impl ColoredObject { 165 157 pub fn add_to(self, layer: &mut Layer) { 166 - layer.add(self); 158 + layer.add_anon(self); 167 159 } 168 160 }
+1 -1
src/graphics/objects.rs
··· 25 25 // FittedText(Region, String), 26 26 Rectangle(Point, Point), 27 27 Image(Region, String), 28 - RawSVG(Box<dyn svg::Node>), 28 + RawSVG(svg::node::element::Element), 29 29 // Tiling(Region, Box<Object>), 30 30 } 31 31
+3 -3
src/main.rs
··· 127 127 canvas.root().clear(); 128 128 canvas 129 129 .root() 130 - .set_object("feur", Object::Dot(center).colored(Color::Red)); 131 - canvas.root().set_object( 130 + .set("feur", Object::Dot(center).colored(Color::Red)); 131 + canvas.root().set( 132 132 "text", 133 133 Object::CenteredText(center, ctx.timestamp.to_string(), 30.0) 134 134 .colored(Color::White), 135 135 ); 136 - canvas.root().set_object( 136 + canvas.root().set( 137 137 "beat", 138 138 Object::CenteredText( 139 139 center.translated(0, 3),
+108 -105
src/rendering/objects.rs
··· 15 15 object_sizes: crate::graphics::objects::ObjectSizes, 16 16 id: &str, 17 17 ) -> anyhow::Result<svg::node::element::Element> { 18 - let mut group = self.object.render_to_svg( 18 + let mut obj = self.object.render_to_svg( 19 19 colormap.clone(), 20 20 cell_size, 21 21 object_sizes, 22 22 id, 23 23 )?; 24 24 25 - let attributes = group.get_attributes_mut(); 26 - 27 - for (key, value) in self.transformations.render_to_svg_attributes( 28 - colormap.clone(), 29 - cell_size, 30 - object_sizes, 31 - id, 32 - )? { 33 - attributes.insert(key, value.into()); 34 - } 35 - 36 - let start = self.object.region().start.coords(cell_size); 37 - let (w, h) = ( 38 - self.object.region().width() * cell_size, 39 - self.object.region().height() * cell_size, 40 - ); 41 - 42 - attributes.insert( 43 - "transform-origin".to_string(), 44 - format!( 45 - "{} {}", 46 - start.0 + (w as f32 / 2.0), 47 - start.1 + (h as f32 / 2.0) 48 - ) 49 - .into(), 50 - ); 51 - 52 25 let mut css = String::new(); 53 26 if !matches!(self.object, Object::RawSVG(..)) { 54 27 css = self ··· 56 29 .render_to_css(&colormap.clone(), !self.object.fillable()); 57 30 } 58 31 59 - css += "transform-box: fill-box;"; 32 + if !self.transformations.is_empty() || !self.filters.is_empty() { 33 + obj = svg::node::element::Group::new() 34 + .set("data-object", id) 35 + .add(obj) 36 + .into(); 37 + 38 + let attributes = obj.get_attributes_mut(); 39 + 40 + for (key, value) in self.transformations.render_to_svg_attributes( 41 + colormap.clone(), 42 + cell_size, 43 + object_sizes, 44 + id, 45 + )? { 46 + attributes.insert(key, value.into()); 47 + } 48 + 49 + let start = self.object.region().start.coords(cell_size); 50 + let (w, h) = ( 51 + self.object.region().width() * cell_size, 52 + self.object.region().height() * cell_size, 53 + ); 54 + 55 + attributes.insert( 56 + "transform-origin".to_string(), 57 + format!( 58 + "{} {}", 59 + start.0 + (w as f32 / 2.0), 60 + start.1 + (h as f32 / 2.0) 61 + ) 62 + .into(), 63 + ); 60 64 61 - css += self 62 - .filters 63 - .iter() 64 - .map(|f| f.render_to_css_filled(&colormap)) 65 - .join(" ") 66 - .as_ref(); 65 + css += "transform-box: fill-box;"; 66 + 67 + css += self 68 + .filters 69 + .iter() 70 + .map(|f| f.render_to_css_filled(&colormap)) 71 + .join(" ") 72 + .as_ref(); 73 + } 67 74 68 - attributes.insert("style".into(), css.into()); 75 + obj.get_attributes_mut().insert("style".into(), css.into()); 69 76 70 - Ok(group) 77 + Ok(obj) 71 78 } 72 79 } 73 80 ··· 79 86 object_sizes: crate::graphics::objects::ObjectSizes, 80 87 id: &str, 81 88 ) -> anyhow::Result<svg::node::element::Element> { 82 - let group = svg::node::element::Group::new(); 83 - 84 - let rendered = match self { 89 + debug_time!("render_to_svg/object"); 90 + let mut rendered = match self { 85 91 Object::Text(..) | Object::CenteredText(..) => { 86 92 self.render_text(cell_size) 87 93 } ··· 100 106 Object::RawSVG(..) => self.render_raw_svg(), 101 107 }; 102 108 103 - Ok(group.set("data-object", id).add(rendered).into()) 109 + // Ok(group.set("data-object", id).add(rendered).into()) 110 + rendered 111 + .get_attributes_mut() 112 + .insert("data-object".into(), id.into()); 113 + Ok(rendered) 104 114 } 105 115 } 106 116 107 117 impl Object { 108 - fn render_image(&self, cell_size: usize) -> Box<dyn svg::node::Node> { 118 + fn render_image(&self, cell_size: usize) -> svg::node::element::Element { 109 119 if let Object::Image(region, path) = self { 110 120 let (x, y) = region.start.coords(cell_size); 111 - return Box::new( 112 - svg::node::element::Image::new() 113 - .set("x", x) 114 - .set("y", y) 115 - .set("width", region.width() * cell_size) 116 - .set("height", region.height() * cell_size) 117 - .set("href", path.clone()), 118 - ); 121 + return svg::node::element::Image::new() 122 + .set("x", x) 123 + .set("y", y) 124 + .set("width", region.width() * cell_size) 125 + .set("height", region.height() * cell_size) 126 + .set("href", path.clone()) 127 + .into(); 119 128 } 120 129 121 130 panic!("Expected Image, got {:?}", self); 122 131 } 123 132 124 - fn render_raw_svg(&self) -> Box<dyn svg::node::Node> { 133 + fn render_raw_svg(&self) -> svg::node::element::Element { 125 134 if let Object::RawSVG(svg) = self { 126 135 return svg.clone(); 127 136 } ··· 129 138 panic!("Expected RawSVG, got {:?}", self); 130 139 } 131 140 132 - fn render_text(&self, cell_size: usize) -> Box<dyn svg::node::Node> { 141 + fn render_text(&self, cell_size: usize) -> svg::node::element::Element { 133 142 if let Object::Text(position, content, font_size) 134 143 | Object::CenteredText(position, content, font_size) = self 135 144 { ··· 158 167 node = node.set("dominant-baseline", "hanging") 159 168 } 160 169 161 - return Box::new(node); 170 + return node.into(); 162 171 } 163 172 164 173 panic!("Expected Text, got {:?}", self); 165 174 } 166 175 167 - // fn render_fitted_text(&self, cell_size: usize) -> Box<dyn svg:node::Node> { 176 + // fn render_fitted_text(&self, cell_size: usize) -> svg::node::element::Element { 168 177 // if let Object::FittedText(region, content) = self { 169 178 // let (x, y) = region.start.coords(cell_size); 170 179 // let width = region.width() * cell_size as f32; ··· 183 192 // panic!("Expected FittedText, got {:?}", self); 184 193 // } 185 194 186 - fn render_rectangle(&self, cell_size: usize) -> Box<dyn svg::node::Node> { 195 + fn render_rectangle(&self, cell_size: usize) -> svg::node::element::Element { 187 196 if let Object::Rectangle(start, end) = self { 188 - return Box::new( 189 - svg::node::element::Rectangle::new() 190 - .set("x", start.coords(cell_size).0) 191 - .set("y", start.coords(cell_size).1) 192 - .set("width", start.distances(end).0 * cell_size) 193 - .set("height", start.distances(end).1 * cell_size), 194 - ); 197 + return svg::node::element::Rectangle::new() 198 + .set("x", start.coords(cell_size).0) 199 + .set("y", start.coords(cell_size).1) 200 + .set("width", start.distances(end).0 * cell_size) 201 + .set("height", start.distances(end).1 * cell_size) 202 + .into(); 195 203 } 196 204 197 205 panic!("Expected Rectangle, got {:?}", self); 198 206 } 199 207 200 - fn render_polygon(&self, cell_size: usize) -> Box<dyn svg::node::Node> { 208 + fn render_polygon(&self, cell_size: usize) -> svg::node::element::Element { 201 209 if let Object::Polygon(start, lines) = self { 202 210 let mut path = svg::node::element::path::Data::new(); 203 211 path = path.move_to(start.coords(cell_size)); ··· 211 219 }; 212 220 } 213 221 path = path.close(); 214 - return Box::new(svg::node::element::Path::new().set("d", path)); 222 + return svg::node::element::Path::new().set("d", path).into(); 215 223 } 216 224 217 225 panic!("Expected Polygon, got {:?}", self); 218 226 } 219 227 220 - fn render_line(&self, cell_size: usize) -> Box<dyn svg::node::Node> { 228 + fn render_line(&self, cell_size: usize) -> svg::node::element::Element { 221 229 if let Object::Line(start, end, width) = self { 222 - return Box::new( 223 - svg::node::element::Line::new() 224 - .set("x1", start.coords(cell_size).0) 225 - .set("y1", start.coords(cell_size).1) 226 - .set("x2", end.coords(cell_size).0) 227 - .set("y2", end.coords(cell_size).1) 228 - .set("stroke-width", *width), 229 - ); 230 + return svg::node::element::Line::new() 231 + .set("x1", start.coords(cell_size).0) 232 + .set("y1", start.coords(cell_size).1) 233 + .set("x2", end.coords(cell_size).0) 234 + .set("y2", end.coords(cell_size).1) 235 + .set("stroke-width", *width) 236 + .into(); 230 237 } 231 238 232 239 panic!("Expected Line, got {:?}", self); 233 240 } 234 241 235 - fn render_curve(&self, cell_size: usize) -> Box<dyn svg::node::Node> { 242 + fn render_curve(&self, cell_size: usize) -> svg::node::element::Element { 236 243 if let Object::CurveOutward(start, end, stroke_width) 237 244 | Object::CurveInward(start, end, stroke_width) = self 238 245 { ··· 300 307 } 301 308 }; 302 309 303 - return Box::new( 304 - svg::node::element::Path::new() 305 - .set( 306 - "d", 307 - svg::node::element::path::Data::new() 308 - .move_to(start.coords(cell_size)) 309 - .quadratic_curve_to((control, end.coords(cell_size))), 310 - ) 311 - .set("stroke-width", format!("{stroke_width}")), 312 - ); 310 + return svg::node::element::Path::new() 311 + .set( 312 + "d", 313 + svg::node::element::path::Data::new() 314 + .move_to(start.coords(cell_size)) 315 + .quadratic_curve_to((control, end.coords(cell_size))), 316 + ) 317 + .set("stroke-width", format!("{stroke_width}")) 318 + .into(); 313 319 } 314 320 315 321 panic!("Expected Curve, got {:?}", self); ··· 319 325 &self, 320 326 cell_size: usize, 321 327 object_sizes: ObjectSizes, 322 - ) -> Box<dyn svg::node::Node> { 328 + ) -> svg::node::element::Element { 323 329 if let Object::SmallCircle(center) = self { 324 - return Box::new( 325 - svg::node::element::Circle::new() 326 - .set("cx", center.coords(cell_size).0) 327 - .set("cy", center.coords(cell_size).1) 328 - .set("r", object_sizes.small_circle_radius), 329 - ); 330 + return svg::node::element::Circle::new() 331 + .set("cx", center.coords(cell_size).0) 332 + .set("cy", center.coords(cell_size).1) 333 + .set("r", object_sizes.small_circle_radius) 334 + .into(); 330 335 } 331 336 332 337 panic!("Expected SmallCircle, got {:?}", self); ··· 336 341 &self, 337 342 cell_size: usize, 338 343 object_sizes: ObjectSizes, 339 - ) -> Box<dyn svg::node::Node> { 344 + ) -> svg::node::element::Element { 340 345 if let Object::Dot(center) = self { 341 - return Box::new( 342 - svg::node::element::Circle::new() 343 - .set("cx", center.coords(cell_size).0) 344 - .set("cy", center.coords(cell_size).1) 345 - .set("r", object_sizes.dot_radius), 346 - ); 346 + return svg::node::element::Circle::new() 347 + .set("cx", center.coords(cell_size).0) 348 + .set("cy", center.coords(cell_size).1) 349 + .set("r", object_sizes.dot_radius) 350 + .into(); 347 351 } 348 352 349 353 panic!("Expected Dot, got {:?}", self); 350 354 } 351 355 352 - fn render_big_circle(&self, cell_size: usize) -> Box<dyn svg::node::Node> { 356 + fn render_big_circle(&self, cell_size: usize) -> svg::node::element::Element { 353 357 if let Object::BigCircle(topleft) = self { 354 358 let (cx, cy) = { 355 359 let (x, y) = topleft.coords(cell_size); 356 360 (x + cell_size as f32 / 2.0, y + cell_size as f32 / 2.0) 357 361 }; 358 362 359 - return Box::new( 360 - svg::node::element::Circle::new() 361 - .set("cx", cx) 362 - .set("cy", cy) 363 - .set("r", cell_size / 2), 364 - ); 363 + return svg::node::element::Circle::new() 364 + .set("cx", cx) 365 + .set("cy", cy) 366 + .set("r", cell_size / 2) 367 + .into(); 365 368 } 366 369 367 370 panic!("Expected BigCircle, got {:?}", self);
+1 -1
src/video/engine.rs
··· 303 303 }), 304 304 render_function: Box::new(move |canvas, ctx| { 305 305 let object = create_object(canvas, ctx)?; 306 - canvas.layer(layer_name).set_object(object_name, object); 306 + canvas.layer(layer_name).set(object_name, object); 307 307 Ok(()) 308 308 }), 309 309 })
+8 -8
src/wasm/layer.rs
··· 59 59 ) { 60 60 canvas() 61 61 .layer(name) 62 - .set_object(name, Object::Line(start, end, thickness).colored(color)) 62 + .set(name, Object::Line(start, end, thickness).colored(color)) 63 63 } 64 64 pub fn new_curve_outward( 65 65 &self, ··· 69 69 thickness: f32, 70 70 color: Color, 71 71 ) { 72 - canvas().layer(name).set_object( 72 + canvas().layer(name).set( 73 73 name, 74 74 Object::CurveOutward(start, end, thickness).colored(color), 75 75 ) ··· 82 82 thickness: f32, 83 83 color: Color, 84 84 ) { 85 - canvas().layer(name).set_object( 85 + canvas().layer(name).set( 86 86 name, 87 87 Object::CurveInward(start, end, thickness).colored(color), 88 88 ) ··· 90 90 pub fn new_small_circle(&self, name: &str, center: Point, color: Color) { 91 91 canvas() 92 92 .layer(name) 93 - .set_object(name, Object::SmallCircle(center).colored(color)) 93 + .set(name, Object::SmallCircle(center).colored(color)) 94 94 } 95 95 pub fn new_dot(&self, name: &str, center: Point, color: Color) { 96 96 canvas() 97 97 .layer(name) 98 - .set_object(name, Object::Dot(center).colored(color)) 98 + .set(name, Object::Dot(center).colored(color)) 99 99 } 100 100 pub fn new_big_circle(&self, name: &str, center: Point, color: Color) { 101 101 canvas() 102 102 .layer(name) 103 - .set_object(name, Object::BigCircle(center).colored(color)) 103 + .set(name, Object::BigCircle(center).colored(color)) 104 104 } 105 105 pub fn new_text( 106 106 &self, ··· 110 110 font_size: f32, 111 111 color: Color, 112 112 ) { 113 - canvas().layer(name).set_object( 113 + canvas().layer(name).set( 114 114 name, 115 115 Object::Text(anchor, text, font_size).colored(color), 116 116 ) ··· 122 122 bottomright: Point, 123 123 color: Color, 124 124 ) { 125 - canvas().layer(name).set_object( 125 + canvas().layer(name).set( 126 126 name, 127 127 Object::Rectangle(topleft, bottomright).colored(color), 128 128 )