this repo has no description
3
fork

Configure Feed

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

:memo: Start paper

+232 -96
+4 -2
Justfile
··· 27 27 example-video out="out.mp4" args='': 28 28 RUST_BACKTRACE=full ./shapemaker video --colors examples/colorschemes/palenight.css {{out}} --sync-with examples/schedule-hell.midi --audio examples/schedule-hell.flac --grid-size 16x10 --resolution 480 {{args}} 29 29 30 - example-image out="out.png" args='': 31 - ./shapemaker image --colors examples/colorschemes/palenight.css --resolution 1400 {{out}} {{args}} 30 + paper: 31 + just 32 + ./shapemaker examples dna-analysis-machine --resolution 1920 paper/dna-analysis-machine.png 33 + typst compile --root . paper/main.typ 32 34 33 35 readme: 34 36 #!/usr/bin/env bash
examples/dna-analysis-machine.png

This is a binary file and will not be displayed.

+4
paper/LICENSE
··· 1 + main.pdf, main.typ and all .png files in this directory are licensed, unlike the rest of the repository, as such: 2 + 3 + All Rights Reserved 4 + © Gwenn Le Bihan, 2025
paper/dna-analysis-machine.png

This is a binary file and will not be displayed.

paper/main.pdf

This is a binary file and will not be displayed.

+26
paper/main.typ
··· 1 + #import "template.typ": arkheion, arkheion-appendices 2 + 3 + #show: arkheion.with( 4 + title: "Shapemaker: Créations audiovisuelles procédurales musicalement synchrones", 5 + authors: ( 6 + (name: "Gwenn Le Bihan", email: "gwenn.lebihan@etu.inp-n7.fr", affiliation: "ENSEEIHT"), 7 + ), 8 + date: "22 Mars 2025", 9 + ) 10 + #set cite(style: "chicago-author-date") 11 + #show link: underline 12 + 13 + #pad(y: 2em, 14 + figure( 15 + image("./dna-analysis-machine.png", width: 75%) 16 + ) 17 + ) 18 + 19 + #columns(1, text(size: 0.75em, raw(read("../src/examples.rs").replace("use crate::*", "use shapemaker::*"), lang: "rust"))) 20 + 21 + #pagebreak() 22 + 23 + 24 + 25 + // Add bibliography and create Bibiliography section 26 + #bibliography("bibliography.bib")
+161
paper/template.typ
··· 1 + // From https://github.com/mgoulao/arkheion, slightly tweaked parce que le Français. 2 + #let arkheion( 3 + title: "", 4 + abstract: none, 5 + keywords: (), 6 + authors: (), 7 + custom_authors: none, 8 + date: none, 9 + logo: none, 10 + body, 11 + ) = { 12 + // Set the document's basic properties. 13 + set document(author: authors.map(a => a.name), title: title) 14 + set page( 15 + margin: (left: 25mm, right: 25mm, top: 25mm, bottom: 30mm), 16 + numbering: "1", 17 + number-align: center, 18 + ) 19 + set text(font: "New Computer Modern", lang: "fr") 20 + show math.equation: set text(weight: 400) 21 + show math.equation: set block(spacing: 0.65em) 22 + set math.equation(numbering: "(1)") 23 + set heading(numbering: "1.1") 24 + 25 + // Set run-in subheadings, starting at level 4. 26 + show heading: it => { 27 + // H1 and H2 28 + if it.level == 1 { 29 + pad( 30 + bottom: 10pt, 31 + it 32 + ) 33 + } 34 + else if it.level == 2 { 35 + pad( 36 + bottom: 8pt, 37 + it 38 + ) 39 + } 40 + else if it.level > 3 { 41 + text(11pt, weight: "bold", it.body + " ") 42 + } else { 43 + it 44 + } 45 + } 46 + 47 + if logo != none { 48 + pad( 49 + top: 1em, 50 + align(center)[ 51 + #image(logo, width: 80%) 52 + ] 53 + ) 54 + } 55 + 56 + if logo == none { 57 + line(length: 100%, stroke: 2pt) 58 + } 59 + // Title row. 60 + pad( 61 + bottom: 4pt, 62 + top: 4pt, 63 + align(center)[ 64 + #block(text(weight: 500, 1.75em, title)) 65 + #v(1em, weak: true) 66 + ] 67 + ) 68 + if logo == none { 69 + line(length: 100%, stroke: 2pt) 70 + } 71 + 72 + // Author information. 73 + if custom_authors != none { 74 + custom_authors 75 + } else { 76 + pad( 77 + top: 0.5em, 78 + x: 2em, 79 + grid( 80 + columns: (1fr,) * calc.min(3, authors.len()), 81 + gutter: 1em, 82 + ..authors.map(author => align(center)[ 83 + #if author.keys().contains("orcid") { 84 + link("http://orcid.org/" + author.orcid)[ 85 + #pad(bottom: -8pt, 86 + grid( 87 + columns: (8pt, auto, 8pt), 88 + rows: 10pt, 89 + [], 90 + [*#author.name*], 91 + [ 92 + #pad(left: 4pt, top: -4pt, image("orcid.svg", width: 8pt)) 93 + ] 94 + ) 95 + ) 96 + ] 97 + } else { 98 + grid( 99 + columns: (auto), 100 + rows: 2pt, 101 + [*#author.name*], 102 + ) 103 + } 104 + #author.email \ 105 + #author.affiliation 106 + ]), 107 + ), 108 + ) 109 + } 110 + 111 + align(center)[#date] 112 + 113 + // Abstract. 114 + if abstract != none { 115 + pad( 116 + x: 3em, 117 + top: 1em, 118 + bottom: 0.4em, 119 + align(center)[ 120 + #heading( 121 + outlined: false, 122 + numbering: none, 123 + text(0.85em, smallcaps[Introduction]), 124 + ) 125 + #set par(justify: true) 126 + #set text(hyphenate: false) 127 + 128 + #abstract 129 + ], 130 + ) 131 + } 132 + 133 + // Keywords 134 + if keywords.len() > 0 { 135 + [*_Mots clés_* #h(0.3cm)] + keywords.map(str).join(" · ") 136 + } 137 + // Main body. 138 + set par(justify: true) 139 + set text(hyphenate: false) 140 + 141 + body 142 + } 143 + 144 + #let arkheion-appendices(body) = { 145 + counter(heading).update(0) 146 + counter("appendices").update(1) 147 + 148 + set heading( 149 + numbering: (..nums) => { 150 + let vals = nums.pos() 151 + let value = "ABCDEFGHIJ".at(vals.at(0) - 1) 152 + if vals.len() == 1 { 153 + return "APPENDIX " + value 154 + } 155 + else { 156 + return value + "." + nums.pos().slice(1).map(str).join(".") 157 + } 158 + } 159 + ); 160 + [#pagebreak() #body] 161 + }
+3
src/cli/mod.rs
··· 14 14 15 15 Usage: shapemaker (image|video) [options] [--color <mapping>...] <file> 16 16 shapemaker beacon start [options] [--color <mapping>...] <file> 17 + shapemaker examples (dna-analysis-machine) [options] <file> 17 18 shapemaker --help 18 19 shapemaker --version 19 20 ··· 79 80 pub cmd_video: bool, 80 81 pub cmd_beacon: bool, 81 82 pub cmd_start: bool, 83 + pub cmd_examples: bool, 84 + pub cmd_dna_analysis_machine: bool, 82 85 pub arg_file: String, 83 86 pub flag_version: bool, 84 87 pub flag_color: Vec<String>,
+23 -88
src/examples.rs
··· 1 + use crate::*; 1 2 use rand::Rng; 2 - 3 - use crate::*; 4 3 5 4 pub fn dna_analysis_machine() -> Canvas { 6 5 let mut canvas = Canvas::new(vec![]); ··· 22 21 23 22 canvas.set_grid_size(16, 9); 24 23 canvas.set_background(Color::Black); 25 - let mut hatches_layer = Layer::new("hatches"); 26 24 27 - let draw_in = canvas.world_region.resized(-1, -1); 25 + let draw_in = canvas.world_region.resized(-2, -2); 28 26 29 - let splines_area = 27 + let filaments_area = 30 28 Region::from_bottomleft(draw_in.bottomleft().translated(2, -1), (3, 3)).unwrap(); 31 - let red_circle_in = 32 - Region::from_topright(draw_in.topright().translated(-3, 0), (4, 3)).unwrap(); 33 29 34 - let red_circle_at = red_circle_in.random_point(); 30 + let red_circle_at = Region::from_topright(draw_in.topright().translated(-3, 0), (4, 3)) 31 + .unwrap() 32 + .random_point(); 35 33 36 - let red_dot_layer = canvas.new_layer("red dot"); 37 - let mut red_dot_friends = Layer::new("red dot friends"); 34 + let mut hatches_layer = Layer::new("hatches"); 35 + let mut red_dot_layer = Layer::new("red dot"); 38 36 39 37 for (i, point) in draw_in.iter().enumerate() { 40 - if splines_area.contains(&point) { 38 + if filaments_area.contains(&point) { 41 39 continue; 42 40 } 43 41 ··· 48 46 .color(Fill::Solid(Color::Red)) 49 47 .filter(Filter::glow(5.0)), 50 48 ); 51 - 52 - for point in red_circle_at.region().enlarged(1, 1).iter() { 53 - red_dot_friends.add_object( 54 - format!("reddot @ {}", point), 55 - Object::SmallCircle(point).color(Fill::Solid(Color::Red)), 56 - ) 57 - } 58 49 } 59 50 60 51 hatches_layer.add_object( ··· 64 55 } else { 65 56 Object::Rectangle(point, point) 66 57 } 67 - .color( 68 - // Fill::Dotted(Color::White, (i + 8) as f32 / 10.0, (i + 3) as f32 / 10.0), 69 - if point == red_circle_at { 70 - Fill::Dotted(Color::White, 3.0, 2.0) 71 - } else { 72 - Fill::Hatched( 73 - Color::White, 74 - Angle(rand::thread_rng().gen_range(0.0..360.0)), 75 - (i + 5) as f32 / 10.0, 76 - 0.25, 77 - ) 78 - }, 79 - ), 58 + .color(Fill::Hatched( 59 + Color::White, 60 + Angle(45.0), 61 + (i + 5) as f32 / 10.0, 62 + 0.25, 63 + )), 80 64 ); 81 65 } 82 66 83 - red_dot_friends.add_object( 84 - "line", 85 - Object::Line( 86 - draw_in.bottomright().translated(1, -3), 87 - draw_in.bottomright().translated(-3, 1), 88 - 4.0, 89 - ) 90 - .color(Fill::Solid(Color::Cyan)) 91 - .filter(Filter::glow(4.0)), 92 - ); 67 + let mut filaments = canvas.n_random_linelikes_within("splines", &filaments_area, 30); 93 68 94 - canvas.layers.push(hatches_layer); 95 - canvas.layers.push(red_dot_friends); 96 - let mut splines = canvas.n_random_linelikes_within("splines", &splines_area, 30); 97 - for (i, object) in splines.objects.values_mut().enumerate() { 98 - object.fill = Some(Fill::Solid(if i % 2 == 0 { 69 + for (i, object) in filaments.objects.values_mut().enumerate() { 70 + object.recolor(Fill::Solid(if i % 2 == 0 { 99 71 Color::Cyan 100 72 } else { 101 73 Color::Pink 102 - })) 74 + })); 103 75 } 104 - splines.filter_all_objects(Filter::glow(4.0)); 105 76 106 - canvas.layers.push(splines); 107 - // let blackout = canvas.new_layer("black out splines"); 108 - // splines_area.iter_upper_strict_triangle().for_each(|point| { 109 - // println!("blacking out {}", point); 110 - // blackout.add_object( 111 - // point, 112 - // Object::Rectangle(point, point).color(Fill::Solid(Color::Black)), 113 - // ) 114 - // }); 115 - 116 - // canvas.put_layer_on_top("black out splines"); 117 - canvas.reorder_layers(vec!["red dot friends", "hatches", "red dot"]); 77 + filaments.filter_all_objects(Filter::glow(4.0)); 118 78 119 - canvas 120 - } 121 - 122 - pub fn title() -> Canvas { 123 - let mut canvas = dna_analysis_machine(); 124 - let text_zone = Region::from_topleft(Point(8, 2), (3, 3)).unwrap(); 125 - canvas.remove_all_objects_in(&text_zone); 126 - let last_letter_at = &text_zone.bottomright().translated(1, 0); 127 - canvas.remove_all_objects_in(&last_letter_at.region()); 128 - 129 - let text_layer = canvas.new_layer("title"); 130 - 131 - let title = String::from("shapemaker"); 132 - 133 - for (i, point) in text_zone 134 - .iter() 135 - .chain(last_letter_at.region().iter()) 136 - .enumerate() 137 - { 138 - println!("{}: {} '{}'", i, point, &title[i..i + 1]); 139 - let character = title[i..i + 1].to_owned(); 140 - 141 - text_layer.add_object( 142 - i.to_string(), 143 - Object::CenteredText(point, character, 30.0).color(Fill::Solid(Color::White)), 144 - ); 145 - } 146 - 79 + canvas.layers.push(red_dot_layer); 80 + canvas.layers.push(hatches_layer); 81 + canvas.layers.push(filaments); 147 82 canvas 148 83 }
+4
src/graphics/objects.rs
··· 63 63 pub fn clear_filters(&mut self) { 64 64 self.filters.clear(); 65 65 } 66 + 67 + pub fn recolor(&mut self, fill: Fill) { 68 + self.fill = Some(fill); 69 + } 66 70 } 67 71 68 72 impl std::fmt::Display for ColoredObject {
+2 -2
src/main.rs
··· 21 21 info_time!("run"); 22 22 let mut canvas = canvas_from_cli(&args); 23 23 24 - if args.cmd_image { 25 - canvas = examples::title(); 24 + if args.cmd_examples && args.cmd_dna_analysis_machine { 25 + canvas = examples::dna_analysis_machine(); 26 26 27 27 if args.arg_file.ends_with(".svg") { 28 28 std::fs::write(
+5 -4
src/vst/vst.rs
··· 18 18 19 19 impl Default for ShapemakerVST { 20 20 fn default() -> Self { 21 + let probe_id = rand::thread_rng().gen_range(1..=u32::MAX); 21 22 Self { 22 23 params: Arc::new(ShapemakerVSTParams::default()), 23 24 probe: Probe { 24 - id: rand::thread_rng().gen_range(1..=u32::MAX), 25 + id: probe_id, 25 26 added_at: chrono::Utc::now().to_rfc3339(), 26 - automation_name: "".to_string(), 27 - midi_name: "".to_string(), 28 - audio_name: "".to_string(), 27 + automation_name: format!("{probe_id}/automation"), 28 + midi_name: format!("{probe_id}/midi"), 29 + audio_name: format!("{probe_id}/audio"), 29 30 }, 30 31 } 31 32 }