CETI Animated Explainer
Course occupancy (E0). When the brief is a short-course film
(2-minute lecture, optional 5-minute seam test) rather than a
deterministic SVG episode, occupy Tailor/Commit of noether-harness.
ceti-research proposes the atlas. Command: /sheaf-run course.
See COURSE-E0.md. Persist every generated asset immediately.
Two formats. This file specifies the short episode (8 beats, 40s, anchor + working zone + detail band) — the default for one tight mechanism. For a feature cut (1:50–2:15, seven movements, scene archetypes A1–A7, brand-assembly bookends, speed chips, resume) read LONGFORM.md — choose it when the brief says video, two minutes, a lay audience, or a topic too broad for one anchor. The deterministic contract below (one clock, build-once, seg-not-pulse, paused == playing, token roles only) binds both formats.
You are building one episode: a single animated diagram that teaches one technical idea by building it on screen over ~40 seconds, the way the gold-standard reference/self-attention.js teaches attention. The goal is not the math for its own sake — it is a complex, interconnected flow made effortless to follow through smooth, paced, reproducible animation.
Read this top to bottom once. Then read reference/self-attention.js in full — it is the bar. Then build.
What you produce
A single self-contained .html file (no external JS, opens straight from disk) containing: the hero (eyebrow / italic title / lede), the player (stage + caption band + transport + scrub + chapter rail + keyboard), the closing synthesis, and a dependency-free Tweaks panel. You write one file — the content module — and run a build script that inlines everything else.
You write: <ep-id>.js ← the content module (DATA · BEATS · build · render)
Build: python3 assets/build.py <ep-id>.js "<Title>" → "<Title>.html"
Verify: node assets/gate.mjs <ep-id>.js ← must print PASS
Everything else — the clock, scrub, captions, chapters, keyboard, persistence, Tweaks, all styling — is inherited from assets/engine.js + the shell. Do not reimplement them.
Method — decide before you draw
Treat this like a design director, not a coder reaching for SVG. Resolve these on paper first; they determine everything downstream:
- Audience & purpose — who's watching and what's the ONE thing they leave knowing? That's beat 8.
- Critique the obvious version — the naive take on this topic (a static labelled diagram, a wall of formulae) and why it fails. Your job is the version that moves to teach.
- Archetype — which row of the catalog below fits (derivation / process / code / state / transformation / comparison)? This fixes your anchor and your motion.
- The anchor — the single element that persists across all 8 beats. Continuity is the pedagogy.
- The worked example — the concrete instance with real, derivable artifacts (numbers, payloads, trace). The spine of the diagram.
- The 8-beat arc — each beat adds exactly one idea; name the focal motion of each.
- Hierarchy & motion — one focal animation per beat; what fades as what arrives. (Palette, type, spacing are already fixed by the theme — don't reinvent them.)
Then build, and render-validate every step (gate + snapshots). Don't accumulate unseen frames.
Build procedure
- Get the content brief. You need: the mechanism (how it actually works), a worked example with real numbers, the 8 beats, and the aha (the one-line payoff). If the user hasn't supplied one, write it first (see "The content brief" below) and make the numbers real — look them up if unsure. The diagram is only as good as the brief.
- Copy the template.
cp assets/_episode-template.js <ep-id>.js.
- DATA — implement the math. Derive every on-screen number in code (compute the softmax / average / score; never hand-type a derived value). Lock one fully-worked example.
- BEATS — transcribe the 8 labels + captions; tune
dur so the total is 35–45s.
- BUILD — lay out the anchor, the working-zone scenes, and the math lower-third. Create every node once; start everything at opacity 0.
- RENDER — gate each element on its beat window with
ex.ramp / ex.win / ex.pulse. Gate the lower-third by flags.math. One scene visible at a time.
- AUDIT — fill in
window.__AUDIT() to recompute and assert the worked figures.
- Gate —
node assets/gate.mjs <ep-id>.js. Every assertion must PASS. Fix and re-run until it does.
- Build —
python3 assets/build.py <ep-id>.js "<Title>". Open the HTML to spot-check.
The non-negotiables
MUST
- One deterministic clock. The episode is a pure function of time
t. render(t) must reconstruct the exact frame for any t. This is what makes scrub / replay / reduced-motion correct for free.
- Build once, mutate forever. Create all SVG nodes in
build(); in render() only set attributes / opacity / transform. Never create or destroy nodes in render().
- Reuse
engine.js unchanged. Write only a content module.
- Exactly 8 beats, total ~35–45s. Beat 1 introduces the anchor; beat 8 is titled exactly "Why it matters" and lands the aha.
- Real, consistent artifacts, derived in code. Whatever the detail band shows — numbers, a payload, a trace, a count — derive it in code so it can't contradict itself. One example worked in full. (For math: compute the softmax; for a protocol:
JSON.stringify the real message; for a process: the real counts.)
- Paused frame == playing frame. Because
render(t) is pure, pausing just lets you stare at instant t — so any frame a viewer can scrub to must be clean. No two scenes half-lit in the same region. For same-region cross-fades use ex.seg, never ex.pulse (pulse spills its fades outside the window, so adjacent scenes double-expose into mush). Expose your scene groups via window.__REGIONS so the gate proves it.
- No two visible blocks overlap. Make every top-level block one
<g> and list them in window.__LAYOUT; the gate (§15d) computes real bounding boxes every frame and fails the build on any collision. See "Preventing overlaps" — this is non-negotiable.
- Label every illustration. Each scene carries a short mono eyebrow saying what it is; numbers/axes/strips are labelled. No unlabelled abstract shapes.
- Token roles only (
var(--ex-*), the three --font-*). No raw hex inside the diagram — that's what lets any brand re-skin it.
- Canvas is 1000 × 464, with a persistent anchor + a detail band gated by
setMath/setDetail.
- End the module with
window.EXPLAINER = <module>;
MUST NOT
- No
setTimeout / setInterval / CSS-keyframe sequencing to drive the animation. The clock is the only driver.
- No scroll-, IntersectionObserver-, or hover-triggered animation state.
- No new colors or gradients (beyond the ground wash), no emoji, no AI-slop.
- No hype words ("unlock", "supercharge", "revolutionize", "powerful", "seamless", "game-changing").
- No SVG text below 11px.
- No
ex.pulse for two scenes that share a region — use ex.seg.
- Don't introduce brand-new layout in the final beat — reuse the anchor you already built (see "The last beat" below).
- Don't fake the chrome with raw HTML — the shell already provides it.
Architecture
assets/engine.js the reusable clock + player wiring (DO NOT EDIT)
assets/ceti-tokens.css colors, type, spacing (inlined at build)
assets/ceti-motion.css the warm ease vocabulary (inlined at build)
assets/shell.template.html the self-contained shell + vanilla Tweaks
<ep-id>.js YOUR content module
Content-module API (exact)
window.EXPLAINER = {
meta: { id, eyebrow, title, lede, synthTitle, tag, synthesis },
beats: [ { id, label, dur, caption }, … ], // engine adds .start/.end/.index
build(stage, opts), // opts = { beats(computed), duration, ex }. Create nodes once.
render(t, ctx), // ctx = { t, duration, beats, activeBeat, ex }. Pure mutation.
setMath(on), // toggle the detail band (Tweaks hook; alias: setDetail)
};
// strongly recommended — the gate uses these:
window.__AUDIT = () => ({ ok: true/false, msg, note }); // consistency invariant
window.__REGIONS = () => ({ working: [g,…], detail: [g,…] }); // shared-region scene groups
In build, capture computed beats: opts.beats.forEach(b => D.beats[b.id] = b).
__REGIONS returns, per shared region, the array of scene <g> nodes whose opacity you drive — the gate sweeps every frame and fails if more than one is lit at once.
The ex toolkit (window.CetiExplainer)
ex.ease { glaser, warmIn, defer, collect, rest, linear } — CETI eases only
ex.clamp(v,a=0,b=1) ex.lerp(a,b,t)
ex.win(t, start, end, ease?) 0→1 progress across a window
ex.ramp(t, start, dur, ease?) 0→1 over `dur` seconds from `start`
ex.pulse(t, a, b, fade=0.35) ~1 inside [a,b], fades at both edges (LONE element only)
ex.seg(t, a, b, fade=0.4) fades CONTAINED in-window — same-region cross-fades
ex.fit(textNode, maxWidth, min=9) shrink an SVG <text> to fit maxWidth (call in build)
ex.fmt(seconds) ex.cubicBezier(x1,y1,x2,y2)
Visual grammar
- viewBox
0 0 1000 464. Three horizontal zones: Anchor (top, y≈34–200), Working zone (middle, one scene at a time), Lower-third (y≈300–460) gated by flags.math.
- Show the mechanism as motion, not as a static labeled picture.
- One focal animation per beat. Max ~3 focal points. Whitespace ≥ ~30%.
Preventing overlaps
Three layers, all required:
- Three zones, fixed y-bands. One block = one
<g>. Same-region scenes use ex.seg. Fade an anchor device out before a panel lands where it sits. Wrap variable text in ex.fit.
- Gate enforcement:
window.__LAYOUT (§15d block overlap), window.__REGIONS + ex.seg (§15b), ex.fit + tag width (§15a).
- Browser overlap auditor after any font/brand change.
Token roles only. Default fonts: Fraunces 300 italic, DM Sans, Space Mono. Presets change colors only.
See LONGFORM.md for the feature-cut format. See COURSE-E0.md for film occupancy. Command: /sheaf-run course.
Files in this skill
assets/engine.js — deterministic clock + player (reuse unchanged).
assets/ceti-tokens.css, assets/ceti-motion.css — token + motion layer.
assets/shell.template.html — self-contained shell.
assets/_episode-template.js — copy this to start a new episode.
assets/build.py — inline everything into one .html.
assets/gate.mjs — quality gate (§15a tag, §15b region, §15d block-overlap).
assets/snapshot.mjs — headless single-frame snapshot.
assets/audit-overlaps.js — browser overlap auditor.
presets/ — ceti.css, owala.css.
themes/ — theming README + example-helio.css.
briefs/ — BRIEF-rag.md, BRIEF-mcp.md.
reference/ — gold-standard modules: self-attention.js, oauth.js, tcp.js, binary-search.js.
LONGFORM.md — feature-cut format.
COURSE-E0.md — film / short-course occupancy.
HANDOFF.md — operational guide.
1---2name: ceti-explainer3description: Build a gold-standard animated technical explainer: one moving SVG diagram that builds a complex concept step by step with real numbers, in a video-like player (scrub, captions, chapters, keyboard) on a deterministic clock so every frame is reproducible. Output is a single self-contained HTML file that works offline. Use when the user wants to explain how something works as a smooth, followable animation — ML/AI internals (attention, embeddings, RAG, MCP), systems and protocols (TCP, OAuth), algorithms, data structures, or any interconnected technical flow. Triggers: animated explainer, explainer video, explain X visually, show how X works step by step, animated diagram of X. Two formats: the ~40s 8-beat episode (default) and the ~2-min 7-movement feature cut (LONGFORM.md) — for video requests, lay audiences, or broad topics. Not for marketing pages, scroll-driven essays, slide decks, or static posters.4---56# CETI Animated Explainer78**Course occupancy (E0).** When the brief is a short-course *film*9(2-minute lecture, optional 5-minute seam test) rather than a10deterministic SVG episode, occupy Tailor/Commit of `noether-harness`.11`ceti-research` proposes the atlas. Command: `/sheaf-run course`.12See **`COURSE-E0.md`**. Persist every generated asset immediately.1314**Two formats.** This file specifies the **short episode** (8 beats, ~40s, anchor + working zone + detail band) — the default for one tight mechanism. For a **feature cut** (~1:50–2:15, seven movements, scene archetypes A1–A7, brand-assembly bookends, speed chips, resume) read **`LONGFORM.md`** — choose it when the brief says *video*, *two minutes*, a lay audience, or a topic too broad for one anchor. The deterministic contract below (one clock, build-once, seg-not-pulse, paused == playing, token roles only) binds both formats.1516You are building one episode: a single animated diagram that teaches one technical idea by **building it on screen over ~40 seconds**, the way the gold-standard `reference/self-attention.js` teaches attention. The goal is not the math for its own sake — it is **a complex, interconnected flow made effortless to follow** through smooth, paced, reproducible animation.1718> Read this top to bottom once. Then read `reference/self-attention.js` in full — it is the bar. Then build.1920---2122## What you produce2324A **single self-contained `.html` file** (no external JS, opens straight from disk) containing: the hero (eyebrow / italic title / lede), the player (stage + caption band + transport + scrub + chapter rail + keyboard), the closing synthesis, and a dependency-free Tweaks panel. You write **one file** — the content module — and run a build script that inlines everything else.2526```27You write: <ep-id>.js ← the content module (DATA · BEATS · build · render)28Build: python3 assets/build.py <ep-id>.js "<Title>" → "<Title>.html"29Verify: node assets/gate.mjs <ep-id>.js ← must print PASS30```3132Everything else — the clock, scrub, captions, chapters, keyboard, persistence, Tweaks, all styling — is inherited from `assets/engine.js` + the shell. **Do not reimplement them.**3334---3536## Method — decide before you draw3738Treat this like a design director, not a coder reaching for SVG. Resolve these on paper first; they determine everything downstream:39401. **Audience & purpose** — who's watching and what's the ONE thing they leave knowing? That's beat 8.412. **Critique the obvious version** — the naive take on this topic (a static labelled diagram, a wall of formulae) and why it fails. Your job is the version that *moves to teach*.423. **Archetype** — which row of the catalog below fits (derivation / process / code / state / transformation / comparison)? This fixes your anchor and your motion.434. **The anchor** — the single element that persists across all 8 beats. Continuity is the pedagogy.445. **The worked example** — the concrete instance with real, derivable artifacts (numbers, payloads, trace). The spine of the diagram.456. **The 8-beat arc** — each beat adds exactly one idea; name the focal motion of each.467. **Hierarchy & motion** — one focal animation per beat; what fades as what arrives. (Palette, type, spacing are already fixed by the theme — don't reinvent them.)4748Then build, and **render-validate every step** (gate + snapshots). Don't accumulate unseen frames.4950## Build procedure51521. **Get the content brief.** You need: the *mechanism* (how it actually works), a *worked example with real numbers*, the *8 beats*, and the *aha* (the one-line payoff). If the user hasn't supplied one, write it first (see "The content brief" below) and make the numbers real — look them up if unsure. The diagram is only as good as the brief.532. **Copy the template.** `cp assets/_episode-template.js <ep-id>.js`.543. **DATA** — implement the math. Derive every on-screen number in code (compute the softmax / average / score; never hand-type a derived value). Lock one fully-worked example.554. **BEATS** — transcribe the 8 labels + captions; tune `dur` so the total is 35–45s.565. **BUILD** — lay out the anchor, the working-zone scenes, and the math lower-third. Create every node once; start everything at opacity 0.576. **RENDER** — gate each element on its beat window with `ex.ramp` / `ex.win` / `ex.pulse`. Gate the lower-third by `flags.math`. One scene visible at a time.587. **AUDIT** — fill in `window.__AUDIT()` to recompute and assert the worked figures.598. **Gate** — `node assets/gate.mjs <ep-id>.js`. Every assertion must PASS. Fix and re-run until it does.609. **Build** — `python3 assets/build.py <ep-id>.js "<Title>"`. Open the HTML to spot-check.6162---6364## The non-negotiables6566### MUST67- **One deterministic clock.** The episode is a pure function of time `t`. `render(t)` must reconstruct the exact frame for any `t`. This is what makes scrub / replay / reduced-motion correct for free.68- **Build once, mutate forever.** Create all SVG nodes in `build()`; in `render()` only set attributes / opacity / transform. Never create or destroy nodes in `render()`.69- **Reuse `engine.js` unchanged.** Write only a content module.70- **Exactly 8 beats**, total ~35–45s. Beat 1 introduces the anchor; beat 8 is titled exactly **"Why it matters"** and lands the aha.71- **Real, consistent artifacts, derived in code.** Whatever the detail band shows — numbers, a payload, a trace, a count — derive it in code so it can't contradict itself. One example worked in full. (For math: compute the softmax; for a protocol: `JSON.stringify` the real message; for a process: the real counts.)72- **Paused frame == playing frame.** Because `render(t)` is pure, pausing just lets you stare at instant `t` — so any frame a viewer can scrub to must be clean. **No two scenes half-lit in the same region.** For same-region cross-fades use **`ex.seg`**, never `ex.pulse` (pulse spills its fades outside the window, so adjacent scenes double-expose into mush). Expose your scene groups via `window.__REGIONS` so the gate proves it.73- **No two visible blocks overlap.** Make every top-level block one `<g>` and list them in **`window.__LAYOUT`**; the gate (§15d) computes real bounding boxes every frame and fails the build on any collision. See "Preventing overlaps" — this is non-negotiable.74- **Label every illustration.** Each scene carries a short mono eyebrow saying what it is; numbers/axes/strips are labelled. No unlabelled abstract shapes.75- **Token roles only** (`var(--ex-*)`, the three `--font-*`). No raw hex inside the diagram — that's what lets any brand re-skin it.76- **Canvas is 1000 × 464**, with a persistent anchor + a detail band gated by `setMath`/`setDetail`.77- **End the module with `window.EXPLAINER = <module>;`**7879### MUST NOT80- No `setTimeout` / `setInterval` / CSS-keyframe sequencing to drive the animation. The clock is the only driver.81- No scroll-, IntersectionObserver-, or hover-triggered animation state.82- No new colors or gradients (beyond the ground wash), no emoji, no AI-slop.83- No hype words ("unlock", "supercharge", "revolutionize", "powerful", "seamless", "game-changing").84- No SVG text below 11px.85- No `ex.pulse` for two scenes that share a region — use `ex.seg`.86- Don't introduce brand-new layout in the final beat — reuse the anchor you already built (see "The last beat" below).87- Don't fake the chrome with raw HTML — the shell already provides it.8889---9091## Architecture9293```94assets/engine.js the reusable clock + player wiring (DO NOT EDIT)95assets/ceti-tokens.css colors, type, spacing (inlined at build)96assets/ceti-motion.css the warm ease vocabulary (inlined at build)97assets/shell.template.html the self-contained shell + vanilla Tweaks98<ep-id>.js YOUR content module99```100101### Content-module API (exact)102```js103window.EXPLAINER = {104 meta: { id, eyebrow, title, lede, synthTitle, tag, synthesis },105 beats: [ { id, label, dur, caption }, … ], // engine adds .start/.end/.index106 build(stage, opts), // opts = { beats(computed), duration, ex }. Create nodes once.107 render(t, ctx), // ctx = { t, duration, beats, activeBeat, ex }. Pure mutation.108 setMath(on), // toggle the detail band (Tweaks hook; alias: setDetail)109};110// strongly recommended — the gate uses these:111window.__AUDIT = () => ({ ok: true/false, msg, note }); // consistency invariant112window.__REGIONS = () => ({ working: [g,…], detail: [g,…] }); // shared-region scene groups113```114In `build`, capture computed beats: `opts.beats.forEach(b => D.beats[b.id] = b)`.115`__REGIONS` returns, per shared region, the array of scene `<g>` nodes whose opacity you drive — the gate sweeps every frame and fails if more than one is lit at once.116117### The `ex` toolkit (`window.CetiExplainer`)118```119ex.ease { glaser, warmIn, defer, collect, rest, linear } — CETI eases only120ex.clamp(v,a=0,b=1) ex.lerp(a,b,t)121ex.win(t, start, end, ease?) 0→1 progress across a window122ex.ramp(t, start, dur, ease?) 0→1 over `dur` seconds from `start`123ex.pulse(t, a, b, fade=0.35) ~1 inside [a,b], fades at both edges (LONE element only)124ex.seg(t, a, b, fade=0.4) fades CONTAINED in-window — same-region cross-fades125ex.fit(textNode, maxWidth, min=9) shrink an SVG <text> to fit maxWidth (call in build)126ex.fmt(seconds) ex.cubicBezier(x1,y1,x2,y2)127```128129---130131## Visual grammar132133- **viewBox `0 0 1000 464`.** Three horizontal zones: Anchor (top, y≈34–200), Working zone (middle, one scene at a time), Lower-third (y≈300–460) gated by `flags.math`.134- **Show the mechanism as motion**, not as a static labeled picture.135- **One focal animation per beat.** Max ~3 focal points. Whitespace ≥ ~30%.136137### Preventing overlaps138Three layers, all required:1391. Three zones, fixed y-bands. One block = one `<g>`. Same-region scenes use `ex.seg`. Fade an anchor device out before a panel lands where it sits. Wrap variable text in `ex.fit`.1402. Gate enforcement: `window.__LAYOUT` (§15d block overlap), `window.__REGIONS` + `ex.seg` (§15b), `ex.fit` + tag width (§15a).1413. Browser overlap auditor after any font/brand change.142143Token roles only. Default fonts: Fraunces 300 italic, DM Sans, Space Mono. Presets change colors only.144145See `LONGFORM.md` for the feature-cut format. See `COURSE-E0.md` for film occupancy. Command: `/sheaf-run course`.146147## Files in this skill148149- `assets/engine.js` — deterministic clock + player (reuse unchanged).150- `assets/ceti-tokens.css`, `assets/ceti-motion.css` — token + motion layer.151- `assets/shell.template.html` — self-contained shell.152- `assets/_episode-template.js` — copy this to start a new episode.153- `assets/build.py` — inline everything into one `.html`.154- `assets/gate.mjs` — quality gate (§15a tag, §15b region, §15d block-overlap).155- `assets/snapshot.mjs` — headless single-frame snapshot.156- `assets/audit-overlaps.js` — browser overlap auditor.157- `presets/` — `ceti.css`, `owala.css`.158- `themes/` — theming README + `example-helio.css`.159- `briefs/` — `BRIEF-rag.md`, `BRIEF-mcp.md`.160- `reference/` — gold-standard modules: `self-attention.js`, `oauth.js`, `tcp.js`, `binary-search.js`.161- `LONGFORM.md` — feature-cut format.162- `COURSE-E0.md` — film / short-course occupancy.163- `HANDOFF.md` — operational guide.