commits
Use clood buddy blink,wave,shrug to play animations in sequence.
Each animation plays for one full ping-pong cycle (LCM of all its
parameter periods) before advancing to the next, then loops.
Each column of the arm going outward from the body steps this many
rows up (positive) or down (negative). Creates diagonal arm lines
for expressive poses like reaching up, drooping, or shrugging.
Animatable with --anim leftslope:-1:1 etc.
Positive = glance right, negative = left. Animatable with
--anim glance:-2:2 for a shifty-eyed look. Eyes stay clamped
within the body bounds.
- --delete <name>: remove a saved character from clood.json
- --deleteanim <name>: remove a saved animation from clood.json
- Using _ as the character name generates a random clood,
useful for previewing animations: clood _ blink
- --saveanim <name>: saves current --anim specs to disk
- clood <character> <animation>: recall both from save file
- clood buddy --anim mood:-1:3 --saveanim wave: define on existing char
- Save file now has 'characters' and 'animations' sections
- AnimParam and Animation are now serializable (serde)
- clood --save <name>: saves current character to disk
- clood <name>: recalls a saved character
- clood <name> --anim mood:-1:3: recall and animate
- Unknown names list all saved characters
- JSON file is human-readable and mergeable
The half block (▄) for closed eyes now sets the ANSI background
color to the body color, so the top half blends in instead of
showing the terminal background.
- src/color.rs: Color struct (hex parsing, random, block rendering)
- src/clood.rs: Clood + EyeState types, render(), leg layout
- src/animation.rs: AnimParam enum, Animation, FrameState, run_loop()
- src/main.rs: CLI arg parsing and wiring
Reorganized into clean logical modules:
- Color struct with from_hex(), random(), full_block(), half_block()
- AnimParam enum (replaces raw string matching) with FromStr/Display
- Animation struct with proper parse() returning Result
- EyeState struct groups eye offset + closed state
- Clood struct replaces flat CloodParams with named fields
- AnimState handles parameter override/restore for animation frames
- LegLayout struct encapsulates leg positioning logic
- ColumnRegion enum for body/arm classification
- Terminal helpers: hide_cursor(), show_cursor(), write_frame()
Edge cases fixed:
- Color::from_hex returns Option (no panics on short/invalid strings)
- Invalid --color/--eyecolor warns and falls back to random
- Invalid --anim specs produce descriptive error messages
- Unknown anim params list all valid options
- Animation tick uses wrapping_add to prevent overflow
- All row/col clamping uses signed arithmetic to avoid underflow
- sanitized() ensures minimum dimensions before rendering
When legs don't divide evenly into the span, the wider gaps are now
placed in the middle rather than at the end. e.g. 4 legs in span 8:
before: █ █ █ █ (gap at end)
after: █ █ █ █ (gap centered)
Legs now prefer being inset 1 col from body edges for a cleaner look.
Falls back to full body width if inset would be too cramped (adjacent
legs touching), then outset by 1 if even full width isn't enough.
Threshold: need span >= 2N-1 for N legs to have gaps between them.
- --round <n>: cuts n blocks from top corners (0 to width/2),
tapering by 1 per row for a dome/rounded head look
- --lefteyeclosed / --righteyeclosed: draws a half block (▄)
instead of full block for a closed/squinting eye
- Both are animatable: --anim round:0:3 or --anim lefteyeclosed:0:1
(blink animation)
- --lefteye and --righteye offset each eye vertically from the mood
baseline (positive = higher, negative = lower)
- Both are animatable: --anim lefteye:-1:1 --anim righteye:1:-1
- Arm baseline now follows the lower of the two eyes
New flags:
- --anim <param>:<min>:<max> — animate a parameter in a ping-pong
loop between min and max. Can be specified multiple times.
Supported params: mood, leftarm, rightarm, height, width,
armsize, legsize, numlegs
- --fps <n> — animation frame rate (default: 4)
Examples:
clood --anim mood:-1:3 # eyes bob up and down
clood --anim leftarm:-1:2 --anim rightarm:2:-1 # waving arms
clood --anim mood:-1:1 --anim leftarm:0:3 --fps 6
Uses cursor movement to redraw in-place. Hides cursor during
animation and restores it on Ctrl-C.
- Arms now render on the same row as the eyes by default
- --leftarm and --rightarm offsets move each arm up (positive) or
down (negative) relative to eye row, enabling expressions/animation
like celebrating (both up) or waving (asymmetric)
- Arms now render on a single row at the vertical midpoint
- Leg overhang (1 col outside body) only activates when legs would
be too cramped (numlegs > width/2), otherwise stays within body
Legs now distribute across width+2 columns (1 col overhang on each
side of the body), giving more space for higher leg counts.
- 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
All params are now Optional. When not specified, they're randomized:
- height: 6..12, width: 8..16, armsize: 2..4, legsize: 2..4
- mood: -2..2
- color and eyecolor: random RGB (components 40..255)
Specifying a flag explicitly pins that value.
Rust CLI tool that generates cute unicode block characters with
configurable parameters:
- height/width: body dimensions
- armsize: width of each arm
- legsize: length of each leg
- color: hex color for body/arms/legs
- eyecolor: hex color for eyes
- mood: vertical eye position offset from baseline
Reorganized into clean logical modules:
- Color struct with from_hex(), random(), full_block(), half_block()
- AnimParam enum (replaces raw string matching) with FromStr/Display
- Animation struct with proper parse() returning Result
- EyeState struct groups eye offset + closed state
- Clood struct replaces flat CloodParams with named fields
- AnimState handles parameter override/restore for animation frames
- LegLayout struct encapsulates leg positioning logic
- ColumnRegion enum for body/arm classification
- Terminal helpers: hide_cursor(), show_cursor(), write_frame()
Edge cases fixed:
- Color::from_hex returns Option (no panics on short/invalid strings)
- Invalid --color/--eyecolor warns and falls back to random
- Invalid --anim specs produce descriptive error messages
- Unknown anim params list all valid options
- Animation tick uses wrapping_add to prevent overflow
- All row/col clamping uses signed arithmetic to avoid underflow
- sanitized() ensures minimum dimensions before rendering
- --round <n>: cuts n blocks from top corners (0 to width/2),
tapering by 1 per row for a dome/rounded head look
- --lefteyeclosed / --righteyeclosed: draws a half block (▄)
instead of full block for a closed/squinting eye
- Both are animatable: --anim round:0:3 or --anim lefteyeclosed:0:1
(blink animation)
New flags:
- --anim <param>:<min>:<max> — animate a parameter in a ping-pong
loop between min and max. Can be specified multiple times.
Supported params: mood, leftarm, rightarm, height, width,
armsize, legsize, numlegs
- --fps <n> — animation frame rate (default: 4)
Examples:
clood --anim mood:-1:3 # eyes bob up and down
clood --anim leftarm:-1:2 --anim rightarm:2:-1 # waving arms
clood --anim mood:-1:1 --anim leftarm:0:3 --fps 6
Uses cursor movement to redraw in-place. Hides cursor during
animation and restores it on Ctrl-C.