Small library for generating claude-code like unicde block mascots, and providing animations when they do stuff
1
fork

Configure Feed

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

feat: add numlegs parameter, lower default height range

- numlegs: randomized to even numbers 0..8 (0=legless, 8=spider)
- Legs are evenly distributed across body width (inset 1 col from edges)
- Height default range lowered from 6..12 to 4..8

+53 -14
+53 -14
src/main.rs
··· 7 7 #[derive(Parser, Debug)] 8 8 #[command(name = "clood", version, about)] 9 9 struct Args { 10 - /// Height of the body in rows [default: random 6..12] 10 + /// Height of the body in rows [default: random 4..8] 11 11 #[arg(long)] 12 12 height: Option<usize>, 13 13 ··· 18 18 /// Width of each arm in columns [default: random 2..4] 19 19 #[arg(long)] 20 20 armsize: Option<usize>, 21 + 22 + /// Number of legs, even number [default: random even 0..8] 23 + #[arg(long)] 24 + numlegs: Option<usize>, 21 25 22 26 /// Length of each leg in rows [default: random 2..4] 23 27 #[arg(long)] ··· 52 56 format!("\x1b[38;2;{};{};{}m\u{2588}\x1b[0m", r, g, b) 53 57 } 54 58 59 + /// Build a leg row mask for the given body width and number of legs. 60 + /// Legs are distributed evenly across columns 1..(width-1) (one col inset from each edge). 61 + /// Each leg is 1 column wide. Returns a vec of bools (true = leg block). 62 + fn leg_mask(width: usize, numlegs: usize) -> Vec<bool> { 63 + let mut mask = vec![false; width]; 64 + if numlegs == 0 || width < 3 { 65 + return mask; 66 + } 67 + 68 + // Usable span: columns 1 through width-2 (inset 1 from each edge) 69 + let span_start = 1usize; 70 + let span_end = width - 2; // inclusive 71 + let span = span_end - span_start + 1; 72 + 73 + if numlegs == 1 { 74 + // Center it 75 + mask[width / 2] = true; 76 + return mask; 77 + } 78 + 79 + // Distribute numlegs evenly across the span 80 + for i in 0..numlegs { 81 + let col = if numlegs == 1 { 82 + span_start + span / 2 83 + } else { 84 + span_start + (i * (span - 1)) / (numlegs - 1) 85 + }; 86 + if col < width { 87 + mask[col] = true; 88 + } 89 + } 90 + 91 + mask 92 + } 93 + 55 94 fn main() { 56 95 let args = Args::parse(); 57 96 let mut rng = rand::thread_rng(); 58 97 59 - // Defaults: random between base and 2x base 98 + // Defaults: random within range 60 99 let width = args.width.unwrap_or_else(|| rng.gen_range(8..=16)).max(4); 61 - let height = args.height.unwrap_or_else(|| rng.gen_range(6..=12)).max(3); 100 + let height = args.height.unwrap_or_else(|| rng.gen_range(4..=8)).max(3); 62 101 let armsize = args.armsize.unwrap_or_else(|| rng.gen_range(2..=4)); 102 + let numlegs = args.numlegs.unwrap_or_else(|| rng.gen_range(0..=4) * 2); // even: 0,2,4,6,8 63 103 let legsize = args.legsize.unwrap_or_else(|| rng.gen_range(2..=4)); 64 104 let mood = args.mood.unwrap_or_else(|| rng.gen_range(-2..=2)); 65 105 ··· 120 160 } 121 161 122 162 // -- Leg rows -- 123 - let leg_width = (width / 3).max(1); 124 - let gap = width - 2 * leg_width; 163 + let legs = leg_mask(width, numlegs); 164 + let effective_legsize = if numlegs == 0 { 0 } else { legsize }; 125 165 126 - for _row in 0..legsize { 166 + for _row in 0..effective_legsize { 167 + // Left padding (arm area) 127 168 for _ in 0..arm_pad { 128 169 output.push_str(space); 129 170 } 130 - for _ in 0..leg_width { 131 - output.push_str(&body_block); 132 - } 133 - for _ in 0..gap { 134 - output.push_str(space); 135 - } 136 - for _ in 0..leg_width { 137 - output.push_str(&body_block); 171 + for col in 0..width { 172 + if legs[col] { 173 + output.push_str(&body_block); 174 + } else { 175 + output.push_str(space); 176 + } 138 177 } 139 178 output.push('\n'); 140 179 }