A Luzir project
Turn any string
into a living face.
Deterministic SVG avatars, with a motion engine for when they need to move.
Empty seed shows a curated set of shapes below. Type one to see it everywhere on this page.
npm install @luzir/bolota Determinism
Same seed. Same bytes. Every time.
Three renders. Byte-identical.
Faces
Expressions
17 faces, one held pose at a time.
Wander
Specimens
States
Every state, live, looping, side by side.
Idle
Wander
Thinking
Wink
Wide
Alert
Notify
Exclaim
Snooze
Play
Orbit
Swirl
Burst
Comet
Sequences
Four signature moves, one stage, looping on its own.
Idle
Reference
The whole surface
Six imports. Nothing else to learn.
bolota — static render
import { bolota } from "@luzir/bolota";
// deterministic: same seed, same bytes, always
const svg = bolota("any-string", { size: 64 });
container.innerHTML = svg; parts — framework adapter
import { parts } from "@luzir/bolota";
// { cls, bg, inner, vars }: build your own element,
// wire `inner` through an innerHTML-style sink
const { cls, inner, vars } = parts("any-string", opts); mountEngine — bloub engine
import { mountEngine } from "@luzir/bolota/engine";
const handle = mountEngine(svgEl, "any-string");
// starts on "idle"; handle.destroy() unmounts handle — play / loop / stop / follow / setExpression
handle.play("burst"); // one-shot, auto-returns to idle
handle.loop("orbit"); // sugar for play(id, { loop: true })
handle.stop(); // freezes the current frame
handle.follow("window"); // eyes track the pointer; false disables
handle.setExpression("wander"); expressions
handle.expressions; // every id, stable order
handle.setExpression("wander"); // held pose, only while idle/wander/swirl
handle.setExpression(null); // clears back to the playing state sequences
import { runSequence } from "@luzir/bolota/sequences";
// "entrance" | "burst" | "orbit" | "comet"
runSequence(handle, "entrance");