Skill Tracer
Skills › HyperFrames › hyperframes › motion.md

motion.md

95 lines · skills/hyperframes/references/motion.md at a595755

Open on GitHub
1# Motion
2
3## Motion craft
4
5Measured frame by frame from the official HyperFrames launch films. These are defaults: a reference the person gave, or a Moment that does otherwise on purpose, wins for its own beat.
6
7- **Moves**: a fast move takes 0.3–0.6 s and carries motion blur on its own ease, peaking at its fastest frame: 6–12 px on text-sized elements, 15–20 px full-frame, horizontal-only on a horizontal move. One move is one tween.
8- **Render-time blur**: for fast 2D movers, `data-motion-blur="on"` on the composition root smears them along their real path in preview and render (opt-in; also `data-motion-blur-shutter` for a longer smear, 360 is strong; `-events="on"` when the motion is set from a timeline callback such as a `render(t)` function). Suggest it when the person asks for blur or a filmic look and the piece moves fast. It draws with a per-element filter that works over WebGL and in any Chrome (cost varies by film; on two real films it cost more than capture) (spins and zooms soften rather than streak); `data-motion-blur-tier="capture"` opts into the truer capture, which loses anything in front of a mover and ignores blend modes. It is off only for HDR and distributed renders. Opt a subtree out with `data-motion-blur="off"`, e.g. a seam that already carries its own blur. After adding it run `hyperframes check`. Guide: /guides/motion-blur.
9- **Arrive slow, leave clean**: long-tailed ease-outs on arrivals; landing takes longer than leaving. An exit is one smooth motion, never slide, stop, then leave. Entrances that are too snappy read as glitches; slowing the whole video by about a second often fixes it.
10- **Ease by role**: an arrival lands on a long tail (`expo.out`, `power4.out`), a camera move or a colour flood eases both ways (`power2.inOut`), a zoom through or an exit accelerates (`power3.in`). The same `power2.out` at 0.5 s on everything is the flat default that makes a film feel generated. Linear only for rotation, progress and constant speed that is the point.
11- **Springs** are named by damping ratio: 1.0 never bounces, 0.7-0.85 reads premium, 0.4-0.6 playful, under 0.3 a cartoon. Position and size may bounce; opacity and colour never do. GSAP's `elastic.out(1, 0.5)` and `back.out(1.4)` are the nearest built-ins; a closed-form spring of `t` keeps any frame renderable on its own.
12- **Exits** are 40-50% shorter than their entrances. **Overlap**: the next element starts when the previous is 30-50% done; fully sequential looks robotic, all at once looks cheap. **Stagger**: letters a frame apart, words 60-120 ms, list items 40-80 ms.
13- **Beat grid**: frames per beat = fps × 60 / BPM; compute each beat from its index and round it, never add a rounded beat repeatedly (at 128 BPM and 30 fps that drifts 2 frames in 32 beats). Cut on the beat, change the layout on the bar.
14- **Cuts**: cut at the fastest frame of a move, with matching direction and speed on both sides. A click into a new screen is a match cut on the click's rebound; the new screen comes in slightly large and settles.
15- **Titles**: a landed title is dead still; the motion moves to the next element, the camera or the world behind. Vary the entrance within a film, never a fade and slide-up for each:
16 - per word: `blur(6px)` → 0 and opacity 0 → 1 in 0.13 s, 0.067 s apart, no translate;
17 - per word from light grey to ink, 0.07–0.1 s apart, no position change;
18 - the whole line blurring in, 8 px → 0 in 0.13–0.2 s;
19 - per letter for a name, 0.1 s apart, opacity 0.3 → 1 with a slight blur;
20 - behind the subject: the title between the plate and a matte of the person;
21 - one word of the sentence rolling through options like a slot machine, about 0.1 s a roll.
22- **Holds**: a line the viewer must read holds about 0.5 s plus 0.3 s a word, the film's last line at least 2 s; a one- or two-word chapter line may hold 0.4 s. Then exit with a blur-out and fade of 0.13–0.25 s, word by word, or with the scene's move.
23- **Title size**: 4–9% of the frame height, one or two lines; quiet lines at 2.5–4% against hero words that fill 60–90% of the width. One highlighted word in the accent colour, which carries meaning.
24- **Rhythm**: contrast speeds. Montages cut every 0.13–0.8 s; a demo holds one framing for 7–10 s while the UI acts; shots average 1.8–3 s with motion inside them. Hold 0.3–0.75 s before the payoff, which plays at normal speed.
25- **Continuous motion that works**: the product's UI working, footage playing, a character acting, a 3D world turning, a slow orbit of a background stage (3–5° a second).
26- **Defaults that look generated**: breathing, floating or pulsing loops standing in for motion on titles and UI; titles that keep sliding or scaling after they land; a slow creeping scale on a title or a slow push late in a scene; bounce on UI; click rings; every scene entering the same way; every element fading and sliding up. A character's idle and overshoot are acting, not these (`types/character.md`).

Motion craft

Measured frame by frame from the official HyperFrames launch films. These are defaults: a reference the person gave, or a Moment that does otherwise on purpose, wins for its own beat.

  • Moves: a fast move takes 0.3–0.6 s and carries motion blur on its own ease, peaking at its fastest frame: 6–12 px on text-sized elements, 15–20 px full-frame, horizontal-only on a horizontal move. One move is one tween.
  • Render-time blur: for fast 2D movers, data-motion-blur="on" on the composition root smears them along their real path in preview and render (opt-in; also data-motion-blur-shutter for a longer smear, 360 is strong; -events="on" when the motion is set from a timeline callback such as a render(t) function). Suggest it when the person asks for blur or a filmic look and the piece moves fast. It draws with a per-element filter that works over WebGL and in any Chrome (cost varies by film; on two real films it cost more than capture) (spins and zooms soften rather than streak); data-motion-blur-tier="capture" opts into the truer capture, which loses anything in front of a mover and ignores blend modes. It is off only for HDR and distributed renders. Opt a subtree out with data-motion-blur="off", e.g. a seam that already carries its own blur. After adding it run hyperframes check. Guide: /guides/motion-blur.
  • Arrive slow, leave clean: long-tailed ease-outs on arrivals; landing takes longer than leaving. An exit is one smooth motion, never slide, stop, then leave. Entrances that are too snappy read as glitches; slowing the whole video by about a second often fixes it.
  • Ease by role: an arrival lands on a long tail (expo.out, power4.out), a camera move or a colour flood eases both ways (power2.inOut), a zoom through or an exit accelerates (power3.in). The same power2.out at 0.5 s on everything is the flat default that makes a film feel generated. Linear only for rotation, progress and constant speed that is the point.
  • Springs are named by damping ratio: 1.0 never bounces, 0.7-0.85 reads premium, 0.4-0.6 playful, under 0.3 a cartoon. Position and size may bounce; opacity and colour never do. GSAP's elastic.out(1, 0.5) and back.out(1.4) are the nearest built-ins; a closed-form spring of t keeps any frame renderable on its own.
  • Exits are 40-50% shorter than their entrances. Overlap: the next element starts when the previous is 30-50% done; fully sequential looks robotic, all at once looks cheap. Stagger: letters a frame apart, words 60-120 ms, list items 40-80 ms.
  • Beat grid: frames per beat = fps × 60 / BPM; compute each beat from its index and round it, never add a rounded beat repeatedly (at 128 BPM and 30 fps that drifts 2 frames in 32 beats). Cut on the beat, change the layout on the bar.
  • Cuts: cut at the fastest frame of a move, with matching direction and speed on both sides. A click into a new screen is a match cut on the click's rebound; the new screen comes in slightly large and settles.
  • Titles: a landed title is dead still; the motion moves to the next element, the camera or the world behind. Vary the entrance within a film, never a fade and slide-up for each:
  • per word: blur(6px) → 0 and opacity 0 → 1 in 0.13 s, 0.067 s apart, no translate;
  • per word from light grey to ink, 0.07–0.1 s apart, no position change;
  • the whole line blurring in, 8 px → 0 in 0.13–0.2 s;
  • per letter for a name, 0.1 s apart, opacity 0.3 → 1 with a slight blur;
  • behind the subject: the title between the plate and a matte of the person;
  • one word of the sentence rolling through options like a slot machine, about 0.1 s a roll.
  • Holds: a line the viewer must read holds about 0.5 s plus 0.3 s a word, the film's last line at least 2 s; a one- or two-word chapter line may hold 0.4 s. Then exit with a blur-out and fade of 0.13–0.25 s, word by word, or with the scene's move.
  • Title size: 4–9% of the frame height, one or two lines; quiet lines at 2.5–4% against hero words that fill 60–90% of the width. One highlighted word in the accent colour, which carries meaning.
  • Rhythm: contrast speeds. Montages cut every 0.13–0.8 s; a demo holds one framing for 7–10 s while the UI acts; shots average 1.8–3 s with motion inside them. Hold 0.3–0.75 s before the payoff, which plays at normal speed.
  • Continuous motion that works: the product's UI working, footage playing, a character acting, a 3D world turning, a slow orbit of a background stage (3–5° a second).
  • Defaults that look generated: breathing, floating or pulsing loops standing in for motion on titles and UI; titles that keep sliding or scaling after they land; a slow creeping scale on a title or a slow push late in a scene; bounce on UI; click rings; every scene entering the same way; every element fading and sliding up. A character's idle and overshoot are acting, not these (types/character.md).
Raw lines 3 to 27
28## Transitions with a cause
30Use 3–5 kinds in a film, each caused by something on screen. Hard cuts belong inside a scene (punch-ins); at most a third of the seams between beats are hard cuts, and worlds never crossfade into each other. Measured on the official films:
32| Transition | How it is built |
33| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
34| Zoom through a button | the camera tracks to the button with blur (0.6 s), then the button scales from ~8% to ~250% of the frame in 0.35 s, strong ease-in; its fill becomes the next frame |
35| Object becomes the world | a pill or card grows past the frame in 0.65 s, ease-in-out, its radius shrinking; what was around it blurs ~15 px and fades in 0.3 s; the new content fades in while it still grows |
36| Morph | one container widens into the next (icon card → prompt box, ~110 → ~880 px in 0.2 s `power3.out`) with a horizontal blur 12 → 0 |
37| Carry across | the result shrinks 1 → 0.6 with blur peaking at 6 px mid-move and lands inside the next app as it builds around it |
38| Colour flood | the hero object stays while the whole ground changes colour in ~0.4 s `power2.inOut` |
39| Whip | a horizontal or vertical smear of 0.13–0.3 s; the arriving element lands blurred and sharpens in ~0.13 s |
40| Iris from the click | `clip-path: circle()` opens from the clicked point onto the next world in 0.15 s |
41| Dip cut | the outgoing frame darkens ~40% for 3 frames before a hard cut, so the cut reads as meant |
42| Blur swap on one stage | out: opacity → 0 with ~8 px blur in 0.13–0.2 s; in: blur → 0 in 0.13 s; the ground never cuts |
44Registry versions: `npx hyperframes catalog --tag transition --json`.
46| The person says | Change |
47| ---------------------- | ------------------------------------------------------------------------------ |
48| "too fast" | Slow every zoom and pan to 0.7× of its speed, nothing else |
49| "speed this up" | Speed the content and shorten the beat by the same amount; later beats move up |
50| "the titles move" | Land them, then hold them dead still until they leave |
51| "it feels like slides" | Enter the next scene through an object on screen; cut a move mid-flight |

Transitions with a cause

Use 3–5 kinds in a film, each caused by something on screen. Hard cuts belong inside a scene (punch-ins); at most a third of the seams between beats are hard cuts, and worlds never crossfade into each other. Measured on the official films:

TransitionHow it is built
Zoom through a buttonthe camera tracks to the button with blur (0.6 s), then the button scales from ~8% to ~250% of the frame in 0.35 s, strong ease-in; its fill becomes the next frame
Object becomes the worlda pill or card grows past the frame in 0.65 s, ease-in-out, its radius shrinking; what was around it blurs ~15 px and fades in 0.3 s; the new content fades in while it still grows
Morphone container widens into the next (icon card → prompt box, ~110 → ~880 px in 0.2 s power3.out) with a horizontal blur 12 → 0
Carry acrossthe result shrinks 1 → 0.6 with blur peaking at 6 px mid-move and lands inside the next app as it builds around it
Colour floodthe hero object stays while the whole ground changes colour in ~0.4 s power2.inOut
Whipa horizontal or vertical smear of 0.13–0.3 s; the arriving element lands blurred and sharpens in ~0.13 s
Iris from the clickclip-path: circle() opens from the clicked point onto the next world in 0.15 s
Dip cutthe outgoing frame darkens ~40% for 3 frames before a hard cut, so the cut reads as meant
Blur swap on one stageout: opacity → 0 with ~8 px blur in 0.13–0.2 s; in: blur → 0 in 0.13 s; the ground never cuts

Registry versions: npx hyperframes catalog --tag transition --json.

The person saysChange
"too fast"Slow every zoom and pan to 0.7× of its speed, nothing else
"speed this up"Speed the content and shorten the beat by the same amount; later beats move up
"the titles move"Land them, then hold them dead still until they leave
"it feels like slides"Enter the next scene through an object on screen; cut a move mid-flight
Raw lines 28 to 52
53## The right mechanism
55| Request | Mechanism |
56| --------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
57| Punch-in, zoom, pan, Ken Burns, reframe | Tween `scale` and `x`/`y` on a wrapper inside the clip, never on the timed media element; chain the states on one timeline |
58| Crop or mask reveal | Tween `clip-path` or a mask on an inner wrapper; source time is untouched |
59| Constant speed change | `data-playback-rate` on the media, 0.1–10 (picture and pitch-preserved sound) |
60| Speed ramp | A `rate` lane in `data-automation` on the media (`t` in clip seconds, `v` 0.1–10); it overrides the constant rate |
61| Hold or freeze | Hold a final frame or a finished scene; a freeze mid-source needs a still exported first and placed as its own clip |
63Ready-made moves: `npx hyperframes catalog --tag camera --json`, or `catalog --query "<the move>" --tag motion-primitive --json`.

The right mechanism

RequestMechanism
Punch-in, zoom, pan, Ken Burns, reframeTween scale and x/y on a wrapper inside the clip, never on the timed media element; chain the states on one timeline
Crop or mask revealTween clip-path or a mask on an inner wrapper; source time is untouched
Constant speed changedata-playback-rate on the media, 0.1–10 (picture and pitch-preserved sound)
Speed rampA rate lane in data-automation on the media (t in clip seconds, v 0.1–10); it overrides the constant rate
Hold or freezeHold a final frame or a finished scene; a freeze mid-source needs a still exported first and placed as its own clip

Ready-made moves: npx hyperframes catalog --tag camera --json, or catalog --query "<the move>" --tag motion-primitive --json.

Raw lines 53 to 64
65## Seeing motion
67The whole-film pass (beat sheet, cuts, phone width, the craft warnings) is `review.md`. For one move:
69- `npx hyperframes keyframes --json [--selector '#id'] [--runtime all]` lists keyframes and motion paths (GSAP, CSS, anime.js): property, time, value, ease.
70- `npx hyperframes keyframes --shot motion.png --selector '#id'` draws the real element's samples over time with its path (9 samples; `--samples N`). `--layout strip` for motion in place, `--from`/`--to` for one stretch, `--angle iso|top|side|'yaw,pitch'` for 3D, `--ghost` for a `<canvas>`.
71- `npx hyperframes snapshot --range 2,4 --frames 8` samples one stretch; `--composition <id>` samples one scene; `--at <t,…>` exact instants; `--zoom '#id'` a sharp crop; `--angle iso` depth and overlap.
72- Against a reference video: `snapshot --at <t,…> --against ref.mp4` writes a side-by-side sheet.
73- Assert intent instead of eyeballing it: a `<name>.motion.json` next to the composition makes `check` verify it on the seeked timeline, as errors (`motion_appears_late`, `motion_out_of_order`, `motion_off_frame`, `motion_frozen`):
75```json
77 "assertions": [
78 { "kind": "appearsBy", "selector": "#headline", "bySec": 0.5 },
79 { "kind": "before", "a": "#headline", "b": "#cta" },
80 { "kind": "staysInFrame", "selector": ".card" },
81 { "kind": "keepsMoving", "withinSelector": ".scene" }
82 ]
84```

Seeing motion

The whole-film pass (beat sheet, cuts, phone width, the craft warnings) is review.md. For one move:

  • npx hyperframes keyframes --json [--selector '#id'] [--runtime all] lists keyframes and motion paths (GSAP, CSS, anime.js): property, time, value, ease.
  • npx hyperframes keyframes --shot motion.png --selector '#id' draws the real element's samples over time with its path (9 samples; --samples N). --layout strip for motion in place, --from/--to for one stretch, --angle iso|top|side|'yaw,pitch' for 3D, --ghost for a <canvas>.
  • npx hyperframes snapshot --range 2,4 --frames 8 samples one stretch; --composition <id> samples one scene; --at <t,…> exact instants; --zoom '#id' a sharp crop; --angle iso depth and overlap.
  • Against a reference video: snapshot --at <t,…> --against ref.mp4 writes a side-by-side sheet.
  • Assert intent instead of eyeballing it: a <name>.motion.json next to the composition makes check verify it on the seeked timeline, as errors (motion_appears_late, motion_out_of_order, motion_off_frame, motion_frozen):
{
  "assertions": [
    { "kind": "appearsBy", "selector": "#headline", "bySec": 0.5 },
    { "kind": "before", "a": "#headline", "b": "#cta" },
    { "kind": "staysInFrame", "selector": ".card" },
    { "kind": "keepsMoving", "withinSelector": ".scene" }
  ]
}
Raw lines 65 to 85
86## Common faults
88| Symptom | Usual cause |
89| -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
90| Blank or frozen scene | Timeline registered before an async build finished, `visibility` tweened on a `.clip`, or a host id that differs from its scene's timeline key |
91| Stutter or drift between renders | Layout measured in `onUpdate`, `requestAnimationFrame` or clock time; two timelines on one property |
92| Jump at a cut | Outgoing and incoming states differ at the seam: snapshot just before and after it |
93| Ease looks off at a handoff | Speeds don't match across the seam: mirror the ease (`power3.in` out, `power3.out` in) |
95Studio's keyframe diamonds and motion-path handles rewrite the GSAP script in the composition file, so the person may have changed motion since you wrote it.

Common faults

SymptomUsual cause
Blank or frozen sceneTimeline registered before an async build finished, visibility tweened on a .clip, or a host id that differs from its scene's timeline key
Stutter or drift between rendersLayout measured in onUpdate, requestAnimationFrame or clock time; two timelines on one property
Jump at a cutOutgoing and incoming states differ at the seam: snapshot just before and after it
Ease looks off at a handoffSpeeds don't match across the seam: mirror the ease (power3.in out, power3.out in)

Studio's keyframe diamonds and motion-path handles rewrite the GSAP script in the composition file, so the person may have changed motion since you wrote it.

Raw lines 86 to 95