# Gsap Explainer

> Build a Kurzgesagt-quality GSAP-powered animated explainer video — a self-contained HTML file that plays like a produced YouTube video: layered worlds, character populations, physics-feeling choreography, a flying host mascot, seekable player chrome. Use when the user wants a high-production explainer/YouTube video, a "GSAP video", or a step up from a CSS-only animated explainer.

- **Type:** Skill
- **Install:** `agentstack add skill-busybee3333-animated-explainer-skills-gsap-explainer`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [BusyBee3333](https://agentstack.voostack.com/s/busybee3333)
- **Installs:** 0
- **Category:** [Content & Media](https://agentstack.voostack.com/c/content-and-media)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [BusyBee3333](https://github.com/BusyBee3333)
- **Source:** https://github.com/BusyBee3333/animated-explainer-skills/tree/main/skills/gsap-explainer

## Install

```sh
agentstack add skill-busybee3333-animated-explainer-skills-gsap-explainer
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# GSAP explainer — the produced-video tier

Builds a **self-contained HTML/SVG/GSAP explainer** that reads like a produced YouTube animation, not a slideshow: one GSAP timeline per scene driving physics-feeling choreography, a persistent flying host mascot, layered gradient worlds with depth, character populations, a vignette-and-grain "camera", and a seekable player. Use a CSS-only harness for tiny funnel embeds; use THIS for YouTube-grade content videos.

**The reference build is `scaffold.html`** in this skill folder — a runnable 5-scene worked example (topic: "How Compound Interest Snowballs") with every pattern below in context, retention + zero-overlap passed. It ships with GSAP stripped: run `python3 inline-gsap.py scaffold.html` once (fetches GSAP 3.13 into a gitignored `vendor/`, then inlines it) and open the file — it must play. Read it whenever a pattern below is unclear.

## Start here — the path that cannot fail

1. **Write the shot script FIRST** as a markdown doc: per scene — timestamp, duration, VISUAL, ON-SCREEN text, VO line. End with an accuracy checklist and verify every claim in it. Scene durations become the `SCENES` array; VO lines become the `sr-only` transcript.
2. **Copy `scaffold.html`** to `.html`. It has every gotcha pre-fixed: harness clock, seek chrome, host flights, world backgrounds, camera overlays, population characters, reduced-motion, transcript. Run `inline-gsap.py` on it and open it before touching anything — it must play.
3. **Replace scenes one at a time**, keeping the five worked examples as your idiom source until each is replaced: S0 = dark hook with a flip-reveal; S1 = drop-with-bounce physics; S2 = pour/motionPath flight + DrawSVG; S3 = the forced-overlap collision proof (the peak pattern); S4 = CTA hold. Update `SCENES`, `FL`, `ACTS`, `CH_STARTS` together — they are parallel structures keyed by scene index.
4. **QA every scene with freeze-frames** (see *QA*), fix, then publish (self-contained file).

Never write a scene's choreography from scratch when a pattern below matches — adapt the pattern. That is how you hit the bar regardless of model.

## Architecture contract (already wired in the scaffold)

- Fixed **800×500 stage** scaled to container (`fitScale`). Scene clock is **setTimeout** (`SCENES` array, seconds per scene; last entry `999` = CTA hold; `advance()` calls `done()` on it).
- **Text/chips/captions enter via CSS primitives** (`.fu` fade-up, `.pp` pop, `.fi` fade-in) with inline `animation-delay` — cheap and replayable. **Hero choreography is GSAP**: `runScene(i)` (called from `showScene`) kills the previous timeline and builds `gsap.timeline()` from `FL[i]` (host flight) + `ACTS[i]` (scene act).
- **Every `ACTS[i]` MUST start with `gsap.set(...)` resets** for all elements it touches — scenes re-activate on replay/seek and killed tweens leave stale inline styles.
- GSAP-owned elements get class `g-hero` (or live inside one) and **never** carry `.fu/.pp/.fi` — one owner per element.
- `pause()/resume()` call `curTl.pause()/play()`; CSS side is frozen by the `.paused` class. **Navigation always resumes playback** (a paused freshly-cut scene sits at opacity-0 entrances — never "seek and stay paused").
- Player: click-to-seek progress bar (`sceneAt(frac)`), prev/next buttons, ←/→ keys, chapter ticks (`CH_STARTS`), autoplay on scroll, auto-pause on tab-hide.
- Deliverable is the **silent visual track** (master stays silent); VO ships as a separate `-vo.html` preview variant built by the ElevenLabs pipeline (see *VO production*). The `sr-only` transcript IS the VO script. Retiming to a read = EXTEND `SCENES[i]` to clip+1.5–2s (extending never strands beats; only trims do).

## The pattern library (adapt, don't invent)

All of these exist verbatim in `scaffold.html` — copy the nearest one.

- **Host flight** — `FL[i] = [[fraction, x, y, pointing], ...]`. First waypoint = previous scene's last (seamless cuts). Long legs auto-swoop via MotionPath (in `fly()`). The pencil tip sits at actor-offset ≈ (−10, +95): to point at a target, park the host **above-right** of it. Send the host offstage (x=850) when a scene needs the frame.
- **Drop with weight** — `gsap.set(els,{y:-300,opacity:0})` then `.to(els,{y:0,opacity:1,ease:'bounce.out',stagger:.09})`. The stagger + bounce IS the physics feel. (`layMarbles` packs rows inside the vessel; row width is 168, not 180 — wider and drops poke through the wall.)
- **Forced-overlap collision (the proof peak)** — two bars drop into one track that can't hold both; the second **tries to dodge** (`x` yoyo), fails, settles; the overlap segment pops in with `back.out` and glows (`boxShadow` yoyo repeat:-1); then two both-badge character minions pop inside it. Intent → failure → consequence is what makes it feel alive.
- **Pour/transform** — container rotates (`transformOrigin` at the spout), contents fly out one-by-one on `motionPath` arcs (`{path:[{x,y},{x,y}],curviness:1.6}, ease:'power1.in'`), land in a row, cross-fade into the new shape drawn with DrawSVG.
- **Flip-reveal** — a tempting ✓ pops (`back.out(2.4)`), wiggles, then swaps for the ✗ slamming in (`scale:3→1, power4.out`) + a background flash (`backgroundColor` yoyo).
- **Tempt-then-shatter** — answer glows/pulses (`scale` yoyo ×3), then dies (`opacity:.25, scale:.92, rotation:-3, power2.in`); the right answer stamps in after.
- **Stamp slam** — `gsap.set(stamp,{opacity:0,scale:2.6,rotation:-14})` → `.to({opacity:1,scale:1,rotation:0,duration:.35,ease:'power4.out'})`.
- **DrawSVG** — `gsap.set(path,{drawSVG:'0%'})` → `.to({drawSVG:'100%'})`; snap-back = draw to 72% then reverse fast. **DrawSVG overwrites `stroke-dasharray`** — dashed lines render solid while drawing; design accordingly.
- **Population as characters** (the single most Kurzgesagt move) — `minion(size, badges)` mini-character factory: quantities are little characters, not dots. Ambient 3-character swarm on 35–55s CSS loops; groups contain their character cast; the proof moment is characters wearing both badges.
- **Scene-cut wipe** (built into `runScene`) — two skewed panels (accent leads, ink trails .09s) sweep the stage at every cut. Leave it on; it's the cheapest "real transitions" win. Prop-rich scene ideas worth stealing: a living page character, a highlighter ruin, a file cabinet, a gauge needle, a progress-bar race.

## The free plugin suite (GSAP 3.13 — ALL free since Webflow's acquisition)

`inline-gsap.py` fetches + inlines core + DrawSVG + MotionPath + **MorphSVG, SplitText, Physics2D, PhysicsProps, CustomEase, CustomWiggle, CustomBounce, Flip, ScrambleText**. Everything is free-licensed. `inline-gsap.py ` injects everything + a registerPlugin block at the `` marker; `--refresh` swaps the suite in an already-inlined file. Proven patterns (all live in the scaffold):

- **SplitText char cascade** — split ONCE at init via a registry (`splitOnce(key,sel)` caching in `SPL{}` — re-splitting on every scene re-run nests spans). Kicker: chars from `{opacity:0,y:14}`, stagger .016, start ≤.15s. Hero word: chars from `{y:-64,rotation:-9}` with `back.out(1.9)` stagger .07; or `{scale:2.7}` power4 stagger .11 = stamp-slam. Scenes hide via opacity (not display:none) so init-time splitting is safe.
- **ScrambleText definition lock** — a payoff line scrambles into place: `scrambleText:{text:'≥ 1',chars:'<>=~≠≤≥',speed:.6}`. Prefer JS `\u` escapes for symbols in JS strings. Themed char sets (math symbols for definitions) read better than 'upperCase' — a long random-caps scramble reads as a loading glitch.
- **CustomWiggle settle** — `CustomWiggle.create('wigSettle',{wiggles:4,type:'easeOut'})`, then `rotation:'+=10', ease:'wigSettle'` — oscillates and RETURNS TO START, so relative values never accumulate across replays. Use for: stamp landings, character reactions, the host's pencil tap-tap on arrival (`if(wp[i][3]&&!wp[i-1][3])` in `fly()`).
- **CustomBounce drop with squash** — `CustomBounce.create('thud',{strength:.58,squash:2.4})` creates paired eases `'thud'`+`'thud-squash'`. The `drop(tl,targets,time,dur,stagger)` helper runs 3 synced tweens: opacity pop, `y` with 'thud', `scaleX:1.45,scaleY:.55` with 'thud-squash' (`transformOrigin:'50% 100%'` in the reset). Strictly better than `bounce.out` — the squash IS the weight.
- **Physics2D burst** — `burst(tl,scene,x,y,n,time,colors)`: celebration/debris particles where landing doesn't matter (collision peaks, victory stamps). Index-seeded angles/velocities (`(i*53)%140`) = replay-identical, no Math.random. Removes stale `.pfx` on re-entry; fade-out before scene end so nothing lingers.
- **MorphSVG fuse** — the top Kurzgesagt move: N objects "become" the concept. Items land in a row → a capsule path fades in over them → `morphSVG` to the arrow silhouette while `fill` tweens ("same objects, new shape", literally). Reset needs `gsap.set(path,{morphSVG:ORIGINAL_D})` — a morphed path keeps its mutated `d`.
- **Flip: DON'T, here** — in a fixed 800×500 absolute-coordinate stage you always know the delta; a plain `y:` tween is deterministic under `tl.pause(t)` QA, while Flip's measure-at-runtime breaks freeze-frame scrubbing (and callbacks don't fire on suppressed seeks). Flip earns its keep only in real reflow layouts (DOM-driven lists, responsive containers). A "claim the vacated spot" beat is a known-delta tween.

## Asset craft (10x-pass patterns — how props stop looking like styled divs)

> Deep-dive: the full asset-generation discipline (build order, factories, SVG contracts, quality gates) lives in the **explainer-assets** skill — use it whenever CREATING or rebuilding an asset; this section is the quick reference.

- **The one-recipe sticker** — depth entirely from layered `box-shadow`: hard down-right ink drop (`3px 3px 0 var(--ink)`) + `inset 0 2px 0 rgba(255,255,255,.3-.5)` top gloss + `inset 0 -3px 0 rgba(0,0,0,.1)` bottom shade + `inset 0 0 0 1-2px rgba(255,255,255,.14)` die-cut rim. Translucent insets ride ANY background color, so one CSS pass on `.xchip/.qbar/.stamp/.l3 span` elevates every variant, light and dark. Keep one radius scale (sm 10 / base 13 / lg 16) and ONE light direction (top-left) film-wide.
- **Two-tone any flat fill** — swap `background:rgba(...)` for `linear-gradient(180deg, lighter, base)` + the gloss/shade insets. Semantic color survives; the surface reads lit.
- **Crafted-vessel recipe** (buckets/jars/cups) — base-shadow ellipse → gradient body → 2 tapered hoop bands with 1px white highlight → rim ring + a DARKER INNER-OPENING ELLIPSE (that one dark ellipse is what makes a mouth read 3D) → soft specular curve. Interpolate band endpoints along the trapezoid sides.
- **Crafted line-art in one selector** — static `filter:drop-shadow(0 1.5px .5px rgba(0,0,0,.17))` on all drawn strokes gives every arrow/box a 2-tone underside and reveals WITH the DrawSVG animation (filter is independent of dashoffset).
- **Decorate GSAP-driven props with pseudo-elements** — `::before/::after` (ruled lines, tape strips, cracks, meniscus lines) ride the timeline's transform automatically: zero new choreography, zero footprint change. Track which pseudos are "taken" per class — collisions are silent.
- **Factory characters: ids only on singletons** — the host (one instance) may carry `uid`-suffixed gradients/speculars; a many-inlined factory (mini-characters) must stay id-FREE (plain fills only) or ids duplicate across the document.
- **Preserve the choreography contract while re-crafting** — build a selector inventory from the script FIRST; positional selectors are landmines (`.bkt3 path` = FIRST path must stay the tweened body — lead with ellipses, not paths). New decorative transforms go on wrapper ``s.
- **Text-safe gloss caveat** — on chips carrying SplitText/hero text, gloss must be inset box-shadows (paint UNDER text), never a positioned `::before` overlay (paints OVER the chars and dims them).
- **Paper-stack + dog-ear recipe** (any sheet prop) — 2 offset back-rects (±0.6–1.5° rotate, darker cream, `overflow:visible` on the svg), corner-cut shadow triangle + folded flap, a margin rule, top-left sheen path. Footprint unchanged, only visual bleed.
- **Drawer/furniture front kit** — front rect + top gloss strip + label plate + recessed handle bar + inter-unit depth-shadow line; parameterize palette for the highlighted unit, keep its animation class.
- **2-tone vector cloud** — tinted base ellipse + 3 overlapping white circles + one brighter top ellipse; recolor the base tint per mood variant.
- **Blueprint-card overlay** — absolutely-positioned child svg (faint ruled grid + 4 corner ticks) as a card's first child: technical-drawing texture with zero effect on the card's tween class or text child.

## The cinema layer (Kurzgesagt-pass patterns)

- **Camera rig `#xplCam`** — a content-only wrapper INSIDE `#xplStage` holding the scenes (env layers, actor, vig/grain stay outside). Per-beat push-ins on payoffs (~1.02–1.05, transformOrigin at the hero), pull-outs on reveals, reset scale to 1 in `runScene` every cut. Never scale `#xplStage` itself — that's `fitScale`'s. The peak scene earns ONE unbroken slow creep across its whole act. Check clip risk against the VISIBLE pill/prop bounds, not full-width containers.
- **Host acting handle `actorBody`** — `.xpl-actor > [data-host]` div, independent of `fly()` (outer x/y) and `armEl`. Helpers: hop (y-8 yoyo), lean (±4° toward pointed target), startle (recoil+tilt), 360 spin at the biggest win. Reset each cut. Mini-character entrance personality: peek from behind an edge (x offset → 0) BEFORE the pop.
- **Payoff light** — one shared `#xplGlow` blurred radial (`mix-blend-mode:screen`, tint via CSS var), positioned + bloomed behind the hero object at each scene's biggest beat, reset per cut. Instant "lit" feel for ~15 lines.
- **Time-of-day drift** — seed a base `filter` on `#envFar` at init (so tweens interpolate, never jump from `none`), then ease brightness/hue per chapter in `runScene`. Composes with the CSS translate loop and the GSAP x dolly because it's a different property.
- **Hybrid injection into a CSS-only harness** — CSS beats stay the base layer; a guarded `GACTS{}` + `runG(i)` bridge (called from showScene, wired into pause/resume, expose `tl()` on `__xpl`) adds GSAP hero accents to money scenes only. Everything additive, `typeof gsap` guarded, FX classes swept per cut. The file must still play if GSAP never loads.

## Movement craft (10x Wave B patterns)

- **Anticipation windup on any slam** — one pre-frame of reverse motion sells weight: `scale .975` (cards) or `.86` (stamps) with `power2.in` BEFORE the overshoot + elastic/back settle. One keyframe, deterministic under `tl.pause()`.
- **CSS-owned-motion rule (hybrid files)** — if a CSS keyframe animates the `transform` SHORTHAND on a node, GSAP cannot layer rotation/x/y there (the running animation overrides inline styles). Let CSS own the motion; GSAP sells it with impact FX synced to the CSS times (dust puffs, impact rings, a racing bloom along the cascade). Bonus: no reset burden on nodes GSAP never touches.
- **Frame-shake in a CSS-base file → actor startle instead** — the scene container's transform is reserved by the Ken-Burns animation, so container shakes are invisible; use a host recoil+tilt (`wigSettle`, returns to rest).
- **`dust()` vs confetti** — impact dust = low velocity (54–94), low gravity (~140), near-horizontal angles, round, `box-shadow:none`, quick fade; keep `.pfx` class for the per-cut sweep.
- **Tight-band placement audit** — measure in logical stage coords (`(rect − stageRect)/scale`); when a caption is squeezed between a prop and a FROZEN lower-third with ` block and run `node --check` on it. A silent syntax error = no `__xpl`, no host, blank harness.
- Check console logs after every reload; serve the folder with `python3 -m http.server`.
- Finish with a multi-lens critic pass (motion craft, persuasion, brand, a11y/robustness, fresh creative-director) — integrate the top fixes, re-verify.

## Gotchas (

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [BusyBee3333](https://github.com/BusyBee3333)
- **Source:** [BusyBee3333/animated-explainer-skills](https://github.com/BusyBee3333/animated-explainer-skills)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-busybee3333-animated-explainer-skills-gsap-explainer
- Seller: https://agentstack.voostack.com/s/busybee3333
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
