Skip to main content

When the DSL isn't enough

The scene grammar covers the common 80%. For a launch film — bespoke choreography, custom filters, SVG construction — drop to raw HTML with the batteries-included runtime:

cleya render --html film.html --runtime gsap --duration 20 --output film.mp4

That injects GSAP with every plugin registered — SplitText, MotionPath, DrawSVG, MorphSVG, Physics2D, ScrambleText, CustomEase, CustomBounce, CustomWiggle — plus window.cleya helpers (maskLines, splitText, counter, and the scene bridge).

The contract

Author a paused timeline and register it:

<script>
const tl = gsap.timeline({ paused: true });
tl.from(".headline", { y: 40, opacity: 0, duration: 0.8 })
.to(".rule", { scaleX: 1, duration: 0.6 }, "-=0.3");

cleya.scene(tl); // wires window.CLEYA.seekTo(t) → tl.time(t)
</script>

Remember determinism: CSS @keyframes do not sample. Everything that moves must be driven from the timeline.

Mount gating

cleya.visible(sel, t0, t1) hides an element outside its window with display: none, applied on every seek. This structurally eliminates the most common craft defect in bespoke work — the pre-roll leak, where an element is visible before its entrance because a base state was missed.

What you give up

Raw HTML forfeits --check validation, multi-format export, $brand token resolution and data binding. Prefer a scene spec when a spec can express it — and note that the instruments still work either way, because they read pixels.

Craft guidance

The repository ships docs/craft.md — read it before authoring ambitious work. Its short version: use the real logo and asset files rather than redrawing a mark from memory; design three or four acts with one idea each before writing code; set base states for everything that enters later; and iterate on a contact sheet plus two or three single frames before committing to one full render. Add --motion-blur 2-3 only on the final master — it multiplies capture time.