How a frame is made
A tiny state machine — idle, walk, hop,
drag, throw — runs a few physics steps a frame and produces a pose: bob, leg swing, foot
lift, blink, arm flags, expression. The pose is rendered procedurally onto a supersampled canvas and
downsampled for smooth edges, the speech bubble is composed above it, and the whole image is uploaded
with a single PutImage. The window itself just moves to follow her.
Because the character is code and not a
sprite sheet, adding a personality means writing a Go package: its own palette, drawing functions and
phrase list, registered at startup and picked with -character. Two characters can never
collide, because they share nothing but the pose contract.
XShape is deliberately not used: under
XWayland, shrinking a shaped window's region can stop updates from being presented, so the plain
transparent window composites correctly everywhere instead.
Worth knowing
characters/One self-contained package per personality — onidia, kama, and a template for yours.
behavior.goThe buddy brain: idle / walk / hop / drag / throw FSM plus the throw and parachute physics.
bubble.goComic speech-bubble rendering, word wrapping, and the scene layout that reserves headroom for the cloud.
events*.goThe celebration framework: hearts, confetti, floating Zs, the lightbulb, the robot suit-up.
internal/fxShared supersample compositing, the built-in bitmap font, alpha and easing maths.
single instanceA kernel flock per display, so a second launch exits and names the pid holding it.