Skip to main content

Determinism

Every animation in Cleya is a pure function of time.

A compiled scene exposes window.CLEYA.seekTo(t). To capture frame n, the renderer seeks to n / fps and screenshots. Nothing is played in real time, so nothing depends on when a callback fired or how loaded the machine was.

This is the single constraint that makes everything else work:

  • A preview frame is the master's pixels. --at 3.2 renders exactly what second 3.2 of the final file will contain, so an agent can check one frame instead of rendering thirty seconds.
  • Frames render in parallel. Work is sliced across workers, one Chrome process per worker. Sharing one browser across tabs does not work — background tabs get their animation frames throttled, and unthrottled tabs then contend.
  • Regression checks mean something. diff compares two renders and reports PSNR. That is only useful because an unchanged scene renders bit-identically.

The one rule when writing raw HTML

CSS @keyframes do not sample. They advance on wall-clock time, so seeking gives you the same frame over and over — the classic symptom is a "video" that looks like a slideshow.

If you drop to --html, the page must define window.CLEYA.seekTo(t) and move everything from that function. With --runtime gsap you author a paused timeline and call cleya.scene(tl), which wires seekTo(t) to tl.time(t) for you.

Readiness

Every capture path awaits window.CLEYA.ready before the first frame — scenes resolve it on document.fonts.ready, bounded at 15 seconds. Fonts therefore never pop in mid-render.

Render tuning

VariableEffect
CLEYA_RENDER_WORKERSOverride the worker count (defaults to half your cores, capped at 4).
CLEYA_NO_GPU=1Force software rasterisation. GPU is on by default; it is dramatically faster for full-frame filter effects and produces bit-identical output GPU-to-GPU.
CLEYA_RENDER_ENGINEchrome (default) or webkit.
CLEYA_CHROME / CLEYA_CHROME_FLAGSPoint at a specific binary, or pass flags such as --no-sandbox.