calesthio/gsap-animation-composition
Production guidance for authoring, integrating, and reviewing GSAP animation in browser-rendered media. Use for deterministic kinetic typography, SVG drawing and morphing, motion paths, FLIP transitions, responsive motion systems, or frame-seekable GSAP timelines inside HTML video composition and React-based renderers; not for ordinary CSS transitions or generic frontend development.
npx skills add https://github.com/calesthio/generative-media-skills --skill gsap-animation-composition
Use GSAP when a media composition needs choreography that is awkward to express as isolated CSS transitions or simple frame interpolation: overlapping multi-beat sequences, per-character typography, SVG stroke drawing or shape morphing, curved paths, layout-state transitions, or a reusable motion language controlled from one playhead.
This skill covers GSAP as an animation engine inside media production. It does not replace the composition contract, edit decisions, audio timeline, asset ledger, accessibility review, or delivery workflow of the host renderer.
The following labels are used throughout:
GSAP APIs, plugin packaging, licensing, and framework integrations are volatile. The API and license facts below were verified on 2026-07-12. Re-check the installed GSAP version, official installation guidance, plugin documentation, and current license before production use.
Choose GSAP when at least one of these is central to the deliverable:
Prefer a simpler mechanism when:
Do not add a plugin merely because it exists. Every plugin should eliminate meaningful implementation risk or improve the intended motion.
Before writing animation code, record:
If the renderer captures arbitrary frames, the composition must be correct when visited out of order. A beautiful real-time preview is not evidence of deterministic rendering.
Documented fact: a GSAP Timeline contains tweens and nested timelines and can control them as a unit. Its position parameter can place children at absolute times, relative to the timeline end, relative to labels, or relative to the most recently added child with markers such as < and >. Timelines expose controls including pause(), seek(), time(), progress(), and totalProgress().
Use semantic labels for editorial beats, not incidental implementation steps:
const timeline = gsap.timeline({
paused: true,
defaults: {duration: 0.42, ease: "power3.out"},
});
timeline
.addLabel("claim", 0.4)
.from(".claim-line", {yPercent: 110, stagger: 0.07}, "claim")
.addLabel("proof", "claim+=0.85")
.from(".proof-mark", {scaleX: 0, transformOrigin: "left"}, "proof")
.from(".proof-label", {opacity: 0, y: 16}, "<0.12")
.to(".claim-group", {opacity: 0, duration: 0.24}, ">+1.1");
This is an example, not a required timeline shape.
Production rules:
claim, proof, turn, and cta when they correspond to script, music, or edit events.fromTo() when both endpoints must be explicit, especially after rerenders, responsive rebuilds, or repeated state changes. Otherwise prefer the simpler to() or from() form.Documented fact: GSAP staggers can be numeric, objects, or functions. Object configuration can distribute start times with each or a total amount, choose a from origin, account for a grid, restrict an axis, and ease the distribution.
Use stagger to express hierarchy, direction, or rhythm. Do not use it to avoid designing individual beats. For text, keep the final phrase readable long enough after the last unit arrives. For grids, test the actual responsive layout rather than assuming DOM order matches visual order.
Normal GSAP playback is driven by the browser animation loop. Documented fact: gsap.ticker updates the global timeline from requestAnimationFrame; browser scheduling and hidden-tab throttling vary. A video renderer that requests exact frames should therefore own time explicitly rather than waiting for wall-clock playback.
Use this pattern when the host can seek a paused timeline:
const timeline = buildTimeline();
timeline.pause(0);
export function renderAtFrame(frame, fps) {
const time = frame / fps;
timeline.time(Math.min(time, timeline.duration()), false);
}
If the host expects normalized progress:
timeline.totalProgress(frame / Math.max(1, totalFrames - 1), false);
Renderer-specific integration may use another adapter, but preserve these invariants:
Math.random() during frame evaluation.Do not confuse gsap.ticker.fps(30) with deterministic 30 fps rendering. It throttles ticker callbacks; it does not make browser scheduling a frame-render contract.
Register only the plugins included in the actual build, using the official installation pattern for the current package version.
| Production problem | Appropriate capability | Main review risk |
|---|---|---|
| Word, line, or character choreography | SplitText | changed semantics, broken line wrapping, missing cleanup, text no longer accessible |
| Reveal an SVG stroke | DrawSVG | wrong path length, line too thin after compression, no meaningful final state |
| Transform one SVG shape into another | MorphSVG | poor point correspondence, self-intersections, unintended silhouette, incompatible source paths |
| Move or orient an object along a path | MotionPath | wrong coordinate space, unexpected rotation, path outside crop, motion sickness |
| Animate between measured layout states | Flip | stale measurements, reflow during capture, unclear end layout |
| Encode a project-specific motion curve | CustomEase | overfitted or extreme curve, inconsistent naming, inaccessible acceleration |
| Couple animation to page scroll | ScrollTrigger | unsuitable for fixed-time video unless scroll is converted into explicit timeline progress |
Treat split wrappers as implementation layers, not authored copy. Preserve the exact text in source and verify assistive-technology behavior in the target delivery. Wait for production fonts before splitting because line breaks and glyph metrics can change. Rebuild and revert split text when responsive line wrapping changes.
For a fixed video render, save the approved line breaks when the design requires them. Do not let an incidental browser width determine the hero copy.
viewBox.Capture the first state, apply the final layout, then animate the measured difference. Freeze the data and layout inputs for deterministic rendering. If the final state depends on font loading, network data, or a responsive measurement, resolve those before recording state.
Documented fact: gsap.matchMedia() can run setup for native media queries, collect animations in a context, and revert them when conditions stop matching. It can combine width queries with (prefers-reduced-motion: reduce).
Use responsive variants to preserve hierarchy, not to squeeze desktop choreography into a smaller frame. Change line breaks, path geometry, travel distance, stagger direction, and label timing when the aspect ratio changes. Rebuild the timeline after the relevant layout is stable.
For interactive delivery, honor the user preference and provide a control when required. Reduced motion can use cuts, short fades, local emphasis, and stable final states rather than large-field translation, parallax, rapid zoom, or spinning.
For prerecorded video, prefers-reduced-motion cannot change the pixels after export. Decide whether the audience or destination needs a separately rendered reduced-motion version.
Documented fact: WCAG 2.2 SC 2.3.3 says non-essential interaction-triggered motion animation can be disabled, unless essential. SC 2.3.1 requires content not to flash more than three times in any one-second period unless it remains below the general and red flash thresholds. Test rendered video at its largest intended presentation and test loops while looping.
Documented fact: gsap.context() can collect animations created within its function, scope selectors, and revert collected animations. gsap.matchMedia() uses a context internally. Reversion kills collected animation and restores recorded pre-animation state; custom event listeners still need explicit cleanup.
Create timelines once per mounted composition or responsive state. On teardown:
In React-based renderers, use the current official GSAP React integration or an equivalent lifecycle-safe effect. Do not instantiate timelines during every render.
Production heuristics:
Record empirical results: browser and GSAP versions, renderer, GPU/software path, frame size, fps, concurrency, dropped or duplicated frames, memory behavior, and any differences between preview and render.
The repository containing this skill is MIT-licensed. That does not change the license of GSAP.
Documented fact, verified 2026-07-12: the current official page identifies Webflow's Standard "No Charge" GSAP License as effective April 30, 2025 and last modified May 30, 2025. It grants use for permitted website, web application, and digital-interface implementations, including commercial projects. It prohibits use in tools that let users build visual animations without code when that use competes with Webflow's visual animation-building capabilities, absent consent. It also restricts reverse engineering for competitive products and removal of proprietary notices. The license page says it may be updated, so re-check it before production use.
The separate greensock/gsap-skills documentation repository may carry an MIT license; that does not relicense the GSAP runtime or plugins. Do not infer runtime rights from documentation-source licensing.
Before shipping:
This is production risk guidance, not legal advice.
Review the composition in this order:
Critical failures include nondeterministic frame output, unsafe flashing, missing required reduced-motion handling for an interactive surface, unreadable required text, broken final SVG silhouette, unlicensed use, or a timeline that depends on wall-clock/scroll state during fixed-time rendering.
This is a complete example, not a mandatory formula.
Production intent: create a six-second 9:16 product-launch insert with exact brand copy and no narration. The first claim must arrive quickly, the proof must remain readable, and a reduced-motion social variant is required.
Inputs and constraints: approved font files; copy Review less. Decide sooner.; 1080x1920 at 30 fps; final CTA lockup; no full-frame flashes; GSAP and SplitText available under reviewed terms.
Plan:
00:00.00-00:00.35 Background and clipping masks already stable.
00:00.35-00:01.15 Split headline by words; reveal from lower mask with 0.07 s stagger.
00:01.15-00:02.20 Hold complete claim.
00:02.20-00:03.05 Draw proof underline; reveal source-safe proof label 0.12 s later.
00:03.05-00:04.45 Hold claim and proof without motion.
00:04.45-00:05.10 Exit claim as one group; do not scramble characters.
00:05.10-00:06.00 CTA lockup, static final state.
Implementation direction:
claim, proof, and cta.frame / 30.Why this works: the word stagger expresses the sentence rhythm while the long proof hold protects comprehension. The deterministic playhead keeps preview and render aligned.
Expected result: exact copy, no line-wrap change between captures, stable final CTA, and matching frames across repeated renders.
Likely failures: font loads after splitting; a character stagger makes reading too slow; wrappers remain after a responsive rebuild; timeline callbacks fire twice during seeking; the CTA appears before the exit finishes.
Meaningful variation: for 16:9, preserve the labels but replace the vertical word stack with two lines and shorten travel distance rather than center-cropping the vertical design.
This is a complete example, not a mandatory formula.
Production intent: create an eight-second explainer transition in which a delivery route becomes the product's approved symbol, connecting a process explanation to the brand end card.
Inputs and constraints: approved SVG route and logo paths; 1920x1080 at 30 fps; muted navy background; no random particles; stroke must survive H.264 compression; logo geometry cannot be altered beyond the approved morph.
Workflow:
viewBox; simplify only redundant path points and archive originals.Why this works: each plugin has one semantic job: route progress, package movement, then transformation into identity. The extended final hold makes the brand mark usable as an edit point.
Expected result: the package follows the path without rotation, the morph has no self-intersection, and the final symbol matches the approved source exactly.
Likely failures: coordinate systems disagree; path stroke becomes too thin after compression; morph correspondence creates a knot; the marker drifts outside the crop; the final shape is nearly but not exactly the approved mark.
Meaningful variation: if the paths cannot morph cleanly without changing brand geometry, use a match cut or masked crossfade at the shared silhouette instead of forcing MorphSVG.
Official and authoritative sources checked 2026-07-12:
prefers-reduced-motion: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motionTake calesthio/gsap-animation-composition from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.