Motion Design (HyperFrames Edition)
HyperFrames documentation teaches you the API. This file governs taste. The numbers below come from an actual production piece. Treat them as defaults: you may deviate, but only intentionally, not out of neglect.
Adapted from whaleyxbt/claude-motion's
motion-designskill (MIT, seeLICENSEin the same folder). The original targeted Remotion; this version is rewritten for HyperFrames (HTML + GSAP) and includes Traditional Chinese typography rules. Sections marked "(New in this edition)" are not from the original.
Division of Labor with Official HyperFrames Skills (New in this edition)
This machine also has HeyGen's official HyperFrames skills (hyperframes, hyperframes-core, hyperframes-animation, etc.). The division is as follows:
- Official skills handle the "how": project structure,
data-*attributes, API syntax, flow routing, registry components. In case of conflict, the official API takes precedence. - This file handles the "taste": easing, rhythm, dwell times, fonts, colors, Chinese typography. When using rules/blueprints from the official
hyperframes-animation, still default to the timing and easing numbers in this file. - Review: Always use
review-loop, which already includes the officialhyperframes check.
0. Hard Rules of HyperFrames (New in this edition)
Violating these will cause flickering, misalignment, or non-deterministic output:
-
Time is determined by HTML: each scene is an element with
class="clip", usingdata-startanddata-durationfor the timeline. The root element must havedata-composition-idand an explicitdata-duration. -
Motion is handled by GSAP:
gsap.timeline({ paused: true }), registered atwindow.__timelines["<composition-id>"]. The key must equaldata-composition-id. -
Every important tween must have an explicit position (third parameter). Use
fromTo()when both endpoints matter, because the output will seek at arbitrary points. -
Animate only
transformandopacity. Do not repeatedly animatetop/left/width/height. -
Prohibited: CSS
transition/@keyframes,Date.now(),requestAnimationFrame,setTimeout, unseededMath.random(), resources fetched during output. -
Do not use scripts to play, pause, or seek audio/video, nor to show or hide clips based on time. All that is handled by data attributes. To move a video, animate its outer wrapper element.
-
Always use a seeded random function:
function rand(seed) { let t = (seed += 0x6D2B79F5); t = Math.imul(t ^ (t >>> 15), t | 1); t ^= t + Math.imul(t ^ (t >>> 7), t | 61); return ((t ^ (t >>> 14)) >>> 0) / 4294967296; }
1. Time in One Place
-
Every beat is a named time point (in seconds), grouped by scene (
s1,s2…), written intimeline.jsat the project root:window.TL = { s1: { start: 0, title: 0.3, items: [1.2, 1.45, 1.7], exit: 3.6 }, s2: { start: 3.4, drawOn: 3.5, hook: 5.2, end: 8 }, };In
index.html, load<script src="timeline.js"></script>before any composition script. -
GSAP position parameters always refer to
TL(e.g.,TL.s1.title,TL.s1.exit + 0.05). Do not hardcode seconds in scenes. -
The
data-start/data-durationof the scene wrapper must match the scene boundaries inTL. When retiming, first edittimeline.js, then sync these two attributes. -
Sound effects and voiceovers use
<audio data-start="…">placed on the same beats. The review-loop screenshot timing is also taken fromTL, so visuals, audio, and checks all move together. -
All visuals must be determined solely by time — see Section 0.
2. Easing
The four curves from the original are precisely reconstructed in GSAP using CustomEase. Load gsap@3/dist/CustomEase.min.js, then register with gsap.registerPlugin(CustomEase):
CustomEase.create("enter", "0.16,1,0.3,1"); // easeOut
CustomEase.create("exit", "0.6,0,0.9,0.35"); // easeIn
CustomEase.create("move", "0.65,0,0.35,1"); // easeInOut
CustomEase.create("land", "0.55,0,0.2,1.12"); // overshoot
| Curve | Use | Closest Built-in Name |
|---|---|---|
enter = bezier(0.16, 1, 0.3, 1) | Entry, reveal — any "arrival" | expo.out (nearly identical) |
exit = bezier(0.6, 0, 0.9, 0.35) | Exit: fast, no trailing | Approx. power3.in |
move = bezier(0.65, 0, 0.35, 1) | Movement between two states (flip, dock, morph) | power2.inOut (identical) |
land = bezier(0.55, 0, 0.2, 1.12) | Values that "settle" (slider to a snap) | No good built-in; use CustomEase |
ease: "none" (linear) is only for continuous motion: rotation, drift, particles, second hands.
To make one animation follow another value (e.g., captions follow a slider position), drive a proxy object with a single tween and derive in onUpdate — do not give it a second independent clock.
3. Elasticity
The original used Remotion's physics spring. GSAP has no spring physics. The table below shows the approximations chosen for this edition (new, not from the original). After output, verify the feel with review-loop:
| Feel | GSAP Setting | Used For |
|---|---|---|
| Default settle | back.out(1.2), 0.6 s | General UI entry |
| Heavy, solid | power3.out, 0.8–1.0 s | Large panels, reversals |
| Knob snap | back.out(1.7), 0.35 s | Control jumping to a notch |
| Pop out | back.out(2.2), 0.45 s | Labels, badges, success dots |
| Elastic accent | elastic.out(1, 0.4), 0.9 s | The one climactic moment per video |
Use elasticity for physical things (UI, objects). Use Bézier curves for text and camera-like movements.
4. Rhythm
- Stagger: English words ~0.09 s; Chinese per character ~0.04–0.05 s, per word ~0.09 s (Chinese part new in this edition); list items and tags ~0.2–0.25 s; rings and dots ~0.06 s.
- Text reveal ~0.8 s, using a mask: outer
overflow: hidden, inneryPercent: 100 → 0plus slight rotation (rotation: 3 → 0). - Exit is about half of entry (0.35–0.55 s vs 0.7–1.25 s), using the
exitcurve. - Scenes must overlap: the next scene starts drawing in before the previous one has fully left (e.g.,
s2.drawOnat 4.02 s earlier thans1.flipEndat 4.4 s). Hard cuts to blank space look like "loading." - Typing ~0.035 s per character. During idle, the cursor blinks at ~2.4 Hz (using
stepsorseton the timeline, not a timer). - Reading dwell: every state meant to be read must pause after settling. Short sentences: at least 1 s. For more than three words, add ~0.25 s per additional word; for Chinese, add ~0.25 s per additional 4 characters (new in this edition). The final closing sentence: at least 2 s. The original had a 22-second version precisely because the 15-second version's text flashed too fast: when in doubt, pause longer and animate less.
5. Typography
- At most three font families: a display serif, an interface sans-serif, and a monospace (for labels, prompt words, numbers).
- English (original): Instrument Serif / Inter / JetBrains Mono.
- Traditional Chinese (new in this edition): Noto Serif TC / Noto Sans TC, numbers and labels with JetBrains Mono. Font files go in the project's
assets/fonts/, loaded via@font-face— do not rely on system fonts (they differ per machine).
- English display text should be large (~138 px on a 1080-width canvas), with tight letter-spacing (
-0.02em),line-height: 1. - Chinese display text (new in this edition): 96–120 px on a 1080-width canvas, no more than ~12 characters per line, letter-spacing
0to0.02em(no negative letter-spacing for Chinese),line-height: 1.15–1.25. - One emphasis per line: English uses one italic word with an accent color; Chinese has no true italic, so use accent color with weight to carry emphasis (new in this edition).
- Monospace labels: uppercase,
letter-spacing: 0.2–0.24em, color muted. They are decorative; if the audience must read it, make it large. - Mobile test: at 360 px width (the actual size seen in social feeds), key messages must still be legible. Check with a contact sheet.
6. Color Palette
- (New in this edition) The entire video is defined by three core colors, like a slide template decided by the user: background
bg, primaryfg(text and line art), accentaccent. They are written in the project'stheme.jsonand applied via themotion-explainer(or image-enhancedmotion-explainer-images) skill'stheme.py. The accent color is reserved for "answer, conclusion, key number, section card." - Swatches are defined as CSS variables on
:root(--bg,--ink,--muted,--accent…). No new color codes should appear in scenes. - Only one accent color, and it has meaning: the thing that changed, the answer, the winner. If everything is an accent, nothing is.
- Glow is state-driven, not time-driven (
glow = effort). Light should tell the story.
7. Texture: Nothing Is Completely Still
- Film grain: an SVG
feTurbulencefilter overlaid, opacity ~0.09, seed changes every two frames (scheduled viaseton the timeline, with seed calculated from frame number). - Vignette + dotted grid, drifting a few px per second:
radial-gradientfor vignette, grid as a single linear tween across the entire video. - Hand-drawn "line wobble" (
feTurbulence+feDisplacementMap, also seed every two frames): used for sketchy, low-fidelity states; fades out as quality improves. - Idle elements must breathe: a ticking clock, a blinking cursor, a slow rotation.
8. Coherence & Transitions
- Prefer continuity over hard cuts. The original's prompt bar, sparks, and slider traverse scenes and change roles — that is the difference between "designed" and "stitched together." In HyperFrames, cross-scene objects live in the root composition, not inside a single scene.
- Every transition must be motivated by something on screen (five result dots merge into one, then become a light ring). No generic wipe transitions.
- Use speed: motion blur and squash/stretch are derived from the difference between this frame and the last — do not fake them.
- Every video has one climactic moment (light ring + impact). Build up to it; do not exhaust it too early.
9. Anti-Patterns
- Everything fading in at once, or everything using the same duration.
- Linear easing on things that start and stop.
- Text still animating when it should be read.
- More than one focal point in a single frame.
- Content within ~60 px of the frame edge (safe zone) unless deliberately cropped.
- Frame 0 is blank or black: on social platforms with muted autoplay, the first frame is the thumbnail.
- (New in this edition) Controlling audio/video playback or clip visibility via script, using CSS animations, or using unseeded randomness — see Section 0.
Workflow
- Write the beats into
timeline.js(storyboard using numbers). Confirm the rhythm with the user before proceeding. - Use kinocut's
hyperframes_initto create the project; each scene is a composition insidecompositions/. Shared components and cross-scene objects go inindex.html. - Run the
review-loopskill after every meaningful change. - Lock visual timing before handling audio: sound effects and music use
<audio data-start>aligned to theTLbeats. For Chinese voiceover, rely on the user's ear for accent and emotion — do not rely on ASR or similarity scores (new in this edition).