Motion Design (HyperFrames Edition)
The HyperFrames documentation teaches you the API; this file governs taste. The numbers below come from an actual shipped piece. Treat them as defaults: you may deviate, but only deliberately, not because you forgot.
Adapted from whaleyxbt/claude-motion's
motion-designskill (MIT, seeLICENSEin the same folder). The original targets Remotion; this version is rewritten for HyperFrames (HTML + GSAP), with Traditional Chinese typography rules added. Sections marked "(New)" are not part of the original.
Division of Labor with Official HyperFrames Skills (New)
This machine also has HeyGen's official HyperFrames skills (hyperframes, hyperframes-core, hyperframes-animation, etc.). Division of labor:
- Official skills manage "how-to": project structure,
data-*attributes, API syntax, routing, registry components. When API syntax conflicts with this file, the official ones take precedence. - This file manages "taste": easing, rhythm, hold time, typography, color, Chinese layout. When using official
hyperframes-animationrules/blueprints, still use this file's numbers for timing and easing as defaults. - Check: always use
review-loop, which already includes the officialhyperframes check.
0. HyperFrames Hard Rules (New)
Violating these will cause flickering, misalignment, or non-deterministic results in the output:
-
Time is driven by HTML: each scene is an element with
class="clip", usingdata-startanddata-durationfor timing. The root element must havedata-composition-idand an explicitdata-duration. -
Animation is handled by GSAP:
gsap.timeline({ paused: true }), registered towindow.__timelines["<composition-id>"], with the key matchingdata-composition-id. -
Every important tween gets an explicit position (third parameter). Use
fromTo()when both ends matter, because the renderer will seek around. -
Only animate
transformandopacity; do not repeatedly animatetop/left/width/height. -
Forbidden: CSS
transition/@keyframes,Date.now(),requestAnimationFrame,setTimeout, seedlessMath.random(), assets fetched during output. -
Do not use scripts to play, pause, or seek video/audio, nor to show/hide clips based on time. Delegate those to data attributes. To move video, animate the wrapper element.
-
All randomness must use a seeded 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 Centralized in One Place
-
Every beat is a named time point (in seconds), grouped by scene (
s1,s2…), written in the project root'stimeline.js: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 it before all composition scripts with<script src="timeline.js"></script>. -
All GSAP position parameters must be read from
TL(e.g.,TL.s1.title,TL.s1.exit + 0.05); do not hardcode seconds in scenes. -
The scene wrapper's
data-start/data-durationmust match the scene boundaries inTL. When re-timing, first updatetimeline.js, then sync these attributes. -
Sound effects and narration use
<audio data-start="…">aligned to the same beats. The review-loop's screenshot times are also read fromTL, so visuals, audio, and checks move together. -
All visuals are determined solely by time; see Section 0.
2. Easing
The original four curves are precisely rebuilt in GSAP using CustomEase. Load gsap@3/dist/CustomEase.min.js and 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) | Entrance, reveal, any "arriving" | expo.out (nearly identical) |
exit = bezier(0.6, 0, 0.9, 0.35) | Exit: fast, clean | Approx. power3.in |
move = bezier(0.65, 0, 0.35, 1) | Movement between states (flip, dock, morph) | power2.inOut (exact match) |
land = bezier(0.55, 0, 0.2, 1.12) | Values that "snap to place" (slider landing on a stop) | No good built-in; use CustomEase |
ease: "none" (linear) is used only for continuous motion: rotation, drift, particles, clock hands.
To make one animation follow another value (e.g., subtitles following a slider position), drive a proxy object with the same tween and derive in onUpdate; do not give it a separate clock.
3. Spring
The original uses Remotion's physics spring; GSAP has no spring physics. The table below lists approximate substitutions (new, not original numbers). After output, use the review-loop to verify feel:
| Feel | GSAP Setup | Used For |
|---|---|---|
| Default settle | back.out(1.2), 0.6 s | General UI entrances |
| Heavy, solid | power3.out, 0.8–1.0 s | Large panels, reversals |
| Knob click | back.out(1.7), 0.35 s | Controls snapping to positions |
| Pop out | back.out(2.2), 0.45 s | Labels, badges, success dots |
| Elastic accent | elastic.out(1, 0.4), 0.9 s | One climactic moment per video |
Use spring-like effects for physical objects (UI, items); use Bezier 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 is new); 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 a slight rotation (rotation: 3 → 0). - Exit is roughly half the entrance (0.35–0.55 s vs 0.7–1.25 s), using the
exitcurve. - Scenes must overlap: the next scene starts drawing before the previous one fully leaves (e.g.,
s2.drawOnat 4.02 s befores1.flipEndat 4.4 s). Hard cuts to blank look like "loading." - Typing: each character ~0.035 s; idle cursor blinks at ~2.4 Hz (schedule on the timeline via
stepsorset, not a timer). - Reading hold: every state meant to be read must pause after settling. Short phrases: at least 1 s; for more than three words, add ~0.25 s per additional word; Chinese: add ~0.25 s per additional 4 characters (new). Final concluding sentence: at least 2 s. The original 22-second version exists because the 15-second version flashed text too fast: when in doubt, hold longer and move less.
5. Typography
- Maximum three font families: serif for display, sans-serif for UI, monospace for labels, prompts, and numbers.
- English (original): Instrument Serif / Inter / JetBrains Mono.
- Traditional Chinese (new): Noto Serif TC / Noto Sans TC, with JetBrains Mono for numbers and labels. Font files go in the project's
assets/fonts/, loaded via@font-face; do not rely on system fonts (they vary across computers).
- English display text should be large (~138 px on a 1080-wide canvas), with tight letter-spacing (
-0.02em),line-height: 1. - Chinese display text (new): 96–120 px on 1080 width, no more than ~12 characters per line, letter-spacing
0to0.02em(no negative kerning for Chinese),line-height: 1.15–1.25. - One emphasis per line: English uses one italic word with accent color; Chinese has no true italic, so use accent color plus increased weight for emphasis (new).
- Monospace labels: uppercase,
letter-spacing: 0.2–0.24em, muted color. They are decorative; essential text for the audience must be larger. - Mobile test: at 360 px wide (actual size in social feeds), key messages must remain readable. Check using a contact sheet.
6. Color Palette
- (New) The entire video is defined by three colors set by the user, like a slide template: background
bg, main colorfg(text and lines), accent coloraccent, written in the project'stheme.json. Apply using themotion-explainer(or image-enhancedmotion-explainer-images) skill'stheme.py. The accent color is reserved for "answers, conclusions, key numbers, section cards." - Define the palette as
:rootCSS variables (--bg,--ink,--muted,--accent…) and do not introduce new hex codes in scenes. - Only one accent color, and it must be meaningful: the thing that changes, the answer, the winner. If everything is an accent, nothing is.
- Glow is driven by state, not time (
glow = effort): light must tell the story.
7. Texture: Nothing is Completely Static
- Film grain: overlay an SVG
feTurbulencefilter with opacity ~0.09, changing theseedevery two frames (schedule usingseton the timeline, seed derived from frame number). - Vignette + dot grid, drifting by a few pixels per second:
radial-gradientfor vignette, a single linear tween across the entire video for the grid. - Hand-drawn "line jitter" (
feTurbulence+feDisplacementMap, also changing seed every two frames): use for sketch-like, low-fidelity states; fade out as quality increases. - Idle elements must breathe: a moving clock, blinking cursor, slow rotation.
8. Coherence and Transitions
- Prefer continuity over hard cuts. The original's prompt bar, sparks, and slider traverse scenes and change roles — that's 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 an on-screen element (five result dots converge into one, which becomes an aperture ring). No generic wipe transitions.
- Use velocity: motion blur and squash-and-stretch derive from "difference between this frame and the previous" — do not fake them.
- Every video has one climactic moment (aperture ring + impact). Build up to it; do not use it too early.
9. Anti-patterns
- Everything fading in simultaneously, or all elements using the same duration.
- Using linear easing for elements that start and stop.
- Text still moving while it should be read.
- More than one focal point in a single frame.
- Content within ~60 px of the frame edge (safe zone), unless deliberate cropping.
- Frame 0 being blank or fully black: on social platforms with silent autoplay, the first frame is the thumbnail.
- (New) Controlling audio/video playback or clip visibility in scripts, using CSS animations, or using seedless randomness; see Section 0.
Workflow
- Write beats into
timeline.js(storyboard with numbers), confirm rhythm with the user before proceeding. - Use kinocut's
hyperframes_initto create the project; each scene is a composition incompositions/, shared components and cross-scene objects go inindex.html. - Run the
review-loopskill after each meaningful change. - Only after visuals are locked, handle audio: sound effects and music use
<audio data-start>aligned toTLbeats. For Chinese narration, let the user judge accent and emotion by ear; do not rely on ASR or similarity scores (new).