| name | motiscope-recreate |
| description | Recreate an analyzed animation as working web code — GSAP (JavaScript), CSS/Web Animations, Framer Motion (React), or Lottie/SVG. Use after `motiscope-analyze`, or when the user asks to "build/recreate this animation in <framework>". Reads the motiscope animation spec and emits a runnable component. |
motiscope: recreate
Recreate an analyzed animation as working web code — GSAP (JavaScript), CSS/Web Animations, Framer Motion (React), or Lottie/SVG. Use after motiscope-analyze, or when the user asks to "build/recreate this animation in ". Reads the motiscope animation spec and emits a runnable component.
Arguments ([gsap|css|framer|lottie] [output-dir]): take them from the user's message. If they're missing, infer them or ask.
Running motiscope
motiscope is a shell command. If it isn't found it isn't on your PATH — see
https://github.com/KumarSashank/motiscope#install. The reference guides live under
$(motiscope home)/references/.
Invoking the sibling skills. In Codex, mention a skill with $motiscope-recreate. In
Cursor, use /motiscope-recreate. Elsewhere, just follow that skill's SKILL.md.
Seeing the frames — do not skip this. The curated keyframes are PNG files on disk, and
you must actually look at them. Codex: use the view_image tool (if it's unavailable,
enable tools.view_image = true in ~/.codex/config.toml, or have the user relaunch with
codex -i frame1.png,frame2.png). Cursor: the file-reading tool accepts .png and puts
the image in context. If you genuinely cannot open images, say so — you can still
report the measured timing, but you cannot know what is animating, and you must not
guess it from the filenames.
Translate a motiscope animation spec into real, runnable animation code for one target framework. Timing and easing come from the measured spec; you render it faithfully.
Step 1 — load the animation spec
Step 2 — choose the target
- From
$1 if given (gsap | css | framer | lottie).
- Otherwise read the default and ask:
motiscope config
Ask the user to confirm the target (offer all four; default from config).
Then Read the target guide and the easing map:
- read
$(motiscope home)/references/easing-map.md — maps each neutral ease token to a concrete value in every target.
- read
$(motiscope home)/references/targets/<target>.md — the rendering template for that target.
- read
$(motiscope home)/references/measurement-traps.md — if you are deriving any number yourself (a velocity, a parallax ratio, a period) rather than reading it from report.md.
Step 3 — generate the code
Split of responsibility (mirror the spec):
- Timing is measured — use it exactly.
start_ms, dur_ms, the bezier, stagger each_ms, loop period_ms come from motiscope's analysis; wire them verbatim (prefer the exact cubic-bezier over a named ease).
- The effect is yours — build what the spec's
animation field and the frames describe. You are not limited to opacity/translate/scale. If the animation is a mask/clip-path reveal, an SVG path draw, a morph, a 3D flip, a text split/typewriter, a blur or color shift, a parallax, a spring/physics bounce, or particles — build that directly in the target, going beyond the spec's simple props when needed. Re-Read the frames if you need to confirm the effect.
Map each timeline entry to the target (per-element from/to, the measured dur_ms/start_ms/bezier, stagger), then implement the described effect.
For GSAP, write idiomatic GSAP yourself: build the sequence with a gsap.timeline() and the position parameter, register a CustomEase for each measured cubic-bezier, use stagger for the measured each_ms, and reach for ScrollTrigger only if the spec has "scroll_driven": true. The rendering template in $(motiscope home)/references/targets/gsap.md has the patterns.
For css, framer, lottie, follow the corresponding references/targets/<target>.md template.
Always include a prefers-reduced-motion: reduce guard that drops the element(s) into their final state.
If the spec is scroll_driven: bind the motion to scroll position, not to a timer. A layer with parallax factor f translates by scroll x (1 - f); at f = 0 it is pinned, at f = 1 it rides the page. A time-driven object inside a scroll-driven scene (a train, a marquee) can be bound to scroll too — derive its constant from the recorded ratio, and say in your summary that the binding is a design decision rather than something the source did.
A backdrop must not have an edge. Anything that reads as behind everything — a sky, a page gradient, a vignette — belongs to the container, not to a moving layer. A gradient drawn as a <rect> inside a parallax layer has a top edge, and any travel large enough slides that edge into frame. If you are clamping travel to keep a background from being uncovered, you are bounding the symptom; remove the edge instead. And beware composition you never chose: tracing a frame recovers ridge shapes and layer speeds, never where the horizon should sit. That part is yours — say so.
Verify in the substrate, not in your own render. Re-measuring pixels of your own output is a second chance to be wrong the same way. Ask the runtime what it actually resolved — getBoundingClientRect, getComputedStyle, getBBox, DOMMatrix — and check the numbers against the spec. A layer's on-screen speed relative to the page is its parallax factor; that is a proof, a screenshot is not.
Step 4 — asset check (consent flow)
If the spec references an image/video asset (a hero image, a looping background, a texture), resolve it before writing code — ask the user:
- Point at an existing file the user already has (preferred) — wire its path in.
- Generate one — check what's configured, then generate:
motiscope assets --check
motiscope assets generate --type image --provider <name> --prompt "<desc>" --out "<path>"
If no key is configured, ask the user for the provider and hand off to motiscope-doctor to store the key. Image generation is real via the gemini/imagen provider (Imagen through the Gemini API — set GEMINI_API_KEY); pass --aspect-ratio 16:9|4:3|1:1|3:4|9:16. Other providers still write a labeled placeholder — if you get one, tell the user to use gemini or swap in a real asset.
- Use a placeholder — a neutral colored box, and note it.
Never write API keys into generated code or commit them.
Step 5 — write the output
Write to [output-dir] ($2), default ./motiscope-output/<target>/. Include a minimal runnable harness so the user can preview immediately:
- gsap / css → a self-contained
index.html (CDN GSAP for the gsap target) that plays the animation on load.
- framer → a
.tsx component plus a one-line usage note (and the framer-motion install command).
- lottie → the animated SVG (or
.json) plus a note on how to embed/play it.
Step 6 — tell the user how to preview + what to tune
- Give the exact preview step (e.g. "open
motiscope-output/css/index.html").
- List which values are exact (timing, easing, sequence — measured) vs estimated (transform magnitudes, colors, overshoot — eyeballed from frames) so they know precisely what to nudge. Offer to iterate.