byheygen-com· 46 skills
The technique catalog: five velocity-matched SEAMS (zoom-through, INVERSE zoom-through, cut-the-curve, waterfall cut, rack-focus blur-cut) plus the two in-scene techniques — waterfall ENTRY (staggered arrival cascades for title cards / segment openers) and the nudge curve (slow-fast-slow three-phase group slides). Covers partial-travel (~12% of frame) velocity matching via mirrored power4 eases, the Z scale-sign rule, size-scaled blur (10px text / 18-20px full-frame), word-by-word staggered cuts, cascade pacing by element weight, and the 10/65/25 slide ratio. Read before authoring any transition, text-beat handoff, kinetic text entry, or group reposition. [depth, zoom, inverse-zoom, scale-sign, mirrored-zoom, rack-focus, pacing, velocity, cut-the-curve, waterfall, stagger, cascade, kinetic-text, title-card, segment-opener, nudge, slide, easing, group-motion, z-depth, motion-graphics, cinematic, transition, blur, directional-continuity]
$npx -y skills add heygen-com/hyperframes --skill cut-the-curveInstalls into the current project.
Run `npx skills use "https://github.com/heygen-com/hyperframes" --skill "heygen-com/hyperframes/cut-the-curve"` and follow the generated skill instructions now. Read its complete output, redirecting it to a temporary file first if necessary. Resolve relative paths from the supporting-files directory it provides.
Use the skills in "https://github.com/heygen-com/hyperframes" that are relevant to the current task. Run `npx skills add "https://github.com/heygen-com/hyperframes"` and select the relevant skills, then follow their instructions.
| 1 | # Cut the Curve — the technique catalog |
| 2 | |
| 3 | Five SEAM techniques, one principle: **cut at peak velocity, match direction and speed |
| 4 | on both sides of the cut** — plus the two in-scene techniques (§6 arrivals, §7 slides). |
| 5 | The seam LAW — vector law, the current, the ledger, the Seam Gate — lives in |
| 6 | `motion-doctrine`; read it first. This skill is the parameters and mechanics. |
| 7 | All GSAP code templates (worker + registry): `examples/gsap-implementation.md`. |
| 8 | |
| 9 | ## Catalog |
| 10 | |
| 11 | | # | Technique | Scope | Axis | Use for | |
| 12 | | --- | -------------------------- | ------------------------------ | ------------------- | ------------------------------------------------------ | |
| 13 | | 1 | **Zoom-Through** (forward) | Within-scene text swap | Z, toward viewer | progressing deeper into the same thought | |
| 14 | | 2 | **Inverse Zoom-Through** | Arrival / payoff beat | Z, away from viewer | something bigger lands | |
| 15 | | 3 | **Cut the Curve** | Between scenes | X / Y | the default boundary, the film's current | |
| 16 | | 4 | **Waterfall Cut** | Text-to-text seam | X, per-word | word-level handoff between big-text beats | |
| 17 | | 5 | **Rack-Focus Blur-Cut** | Same-surface state swap | X / Y / Z | the one cut you want SEEN — a DSLR focus-pull flourish | |
| 18 | | 6 | **Waterfall Entry** | In-scene ARRIVAL (no seam) | Y, from below | title cards, segment openers, list intros | |
| 19 | | 7 | **Nudge Curve** | In-scene group slide (no seam) | X / Y | repositioning a composed group to make room | |
| 20 | |
| 21 | ## Z direction is a sign |
| 22 | |
| 23 | "Same axis" is not enough on Z — the sign of d(scale)/dt must match across the cut: |
| 24 | |
| 25 | | Z vector | Exit scale | Entry scale | Variant | |
| 26 | | -------------- | ------------------- | -------------------- | -------------------- | |
| 27 | | Push (forward) | growing `1 → 1.2` | growing `0.75 → 1` | zoom-through | |
| 28 | | Pull (back) | shrinking `1 → 0.8` | shrinking `1.25 → 1` | inverse zoom-through | |
| 29 | |
| 30 | Banned mirrors: a receding exit answered by a grow-from-small entry (pull flips to push — |
| 31 | the common one, since grow-from-small is the default element entrance), and a push exit |
| 32 | answered by an oversized retraction. This binds the incoming scene's OWN entrances during |
| 33 | the seam window (cut + ~0.5s), not just the wrapper tween: hold the incoming frame |
| 34 | composed, or author its entrance to match the sign. Verify per Seam Gate rule 7. |
| 35 | |
| 36 | ## Blur logic (all Z variants) |
| 37 | |
| 38 | | Subject | Peak blur | Why | |
| 39 | | --------------------------------------------- | ----------- | -------------------------------------------------------------- | |
| 40 | | Text-scale (headline, word group) | **10px** | 20px smears letterforms — the cut reads as a glitch, not speed | |
| 41 | | Full-frame surface (window, card, screenshot) | **18–20px** | lighter blur on a big surface reads as a rendering hiccup | |
| 42 | |
| 43 | Same peak blur on both sides at the swap frame. Blur the WRAPPER, never children. |
| 44 | |
| 45 | --- |
| 46 | |
| 47 | ## 1. Zoom-Through (forward) |
| 48 | |
| 49 | Z-axis velocity-matched cut; **never both texts visible.** Everything GROWS: the outgoing |
| 50 | text accelerates toward camera, a hard swap hides at peak blur, the incoming text keeps |
| 51 | growing into the focal plane. Headlines and short phrases only. Total ≈ 0.4s. |
| 52 | |
| 53 | | Phase | Scale | Blur | Opacity | Ease | Duration | |
| 54 | | -------------- | -------- | -------- | ----------------- | ------------------------------------------ | -------- | |
| 55 | | Exit | 1 → 1.2 | 0 → 10px | 1 → 0.15 | power3.in (opacity: separate `none` tween) | 0.2s | |
| 56 | | Cut (`tl.set`) | in: 0.75 | 10px | out: 0 / in: 0.15 | — | — | |
| 57 | | Entry | 0.75 → 1 | 10 → 0px | 0.15 → 1 | expo.out | 0.5s | |
| 58 | |
| 59 | Exit opacity MUST be its own linear tween — `power3.in` holds opacity near 1 too long. |
| 60 | On entry all properties share `expo.out`. |
| 61 | |
| 62 | ## 2. Inverse Zoom-Through (backward) |
| 63 | |
| 64 | The pull-back mirror: the outgoing element RECEDES; the incoming arrives OVERSIZED (as if |
| 65 | just behind camera) and retracts into the focal plane. Everything SHRINKS. Spend on |
| 66 | ARRIVAL/payoff beats — a payoff line, a giant reply, a held end-state — never ordinary |
| 67 | boundaries. Total ≈ 0.7s (30% exit / 70% entry). |
| 68 | |
| 69 | | Phase | Scale | Blur | Opacity | Ease | Duration | |
| 70 | | -------------- | -------- | -------- | ----------------- | ------------------------------------------ | -------- | |
| 71 | | Exit | 1 → 0.8 | 0 → 10px | 1 → 0.15 | power3.in (opacity: separate `none` tween) | ~0.2s | |
| 72 | | Cut (`tl.set`) | in: 1.25 | 10px | out: 0 / in: 0.15 | — | — | |
| 73 | | Entry | 1.25 → 1 | 10 → 0px | 0.15 → 1 | expo.out | ~0.5s | |
| 74 | |
| 75 | Blur is 10px text-scale; 18–20px only when both sides are full-bleed surfaces. |
| 76 | |
| 77 | **Sign discipline:** the incoming scene arrives as a composed frame inside the retracting |
| 78 | wrapper — no grow-from-small intro in the seam window. Staged entrances happen after the |
| 79 | retraction settles, or start ≥1 and retract. |
| 80 | |
| 81 | ## 3. Cut the Curve (default scene boundary) |
| 82 | |
| 83 | X/Y velocity-matched cut — the default for ALL scene-to-scene boundaries, in the film's |
| 84 | current, not an accent. The outgoing hero accelerates in one direction, the cut lands |
| 85 | mid-motion, the incoming hero continues the SAME direction and decelerates. Total ≈ 0.6s; |
| 86 | directions LEFT / RIGHT / UP / DOWN (default LEFT). |
| 87 | |
| 88 | **Partial travel:** ~12% of frame (≈230px at 1920) — never full off-screen moves. |
| 89 | |
| 90 | | Direction | Exit | Entry start → end | |
| 91 | | --------- | ------------- | ----------------- | |
| 92 | | Leftward | `x: 0 → −230` | `x: +230 → 0` | |
| 93 | | Rightward | `x: 0 → +230` | `x: −230 → 0` | |
| 94 | | Upward | `y: 0 → −230` | `y: +230 → 0` | |
| 95 | | Downward | `y: 0 → +230` | `y: −230 → 0` | |
| 96 | |
| 97 | Mechanics: |
| 98 | |
| 99 | - **Mirrored eases:** exit `power4.in` + entry `power4.out`, same distance and duration — |
| 100 | the two halves of one `power4.inOut`, so velocity matches exactly at the cut. |
| 101 | - **The fade trick:** exit opacity completes at ~25–30% of its travel (fade ≈ 0.18–0.3s |
| 102 | vs motion 0.3–0.34s); entry ignites at ~0.35 opacity mid-path. Time the last fading |
| 103 | element to die right at the cut — a gap where nothing moves reads as dead air. |
| 104 | - Exit 0.2–0.4s; entry ≥ exit. Optional blur 8–10px. |
| 105 | - **Stage ground:** `#root` must be opaque |
| 106 | (`background: var(--canvas-deep, var(--canvas, #000))`) — the mid-window cut opens a |
| 107 | summed-opacity < 1 window that flashes white otherwise (see `seam-craft`). |
| 108 | |
| 109 | `push-slide` exists but violates partial-travel and mid-motion phase; prefer cut-the-curve. |
| 110 | |
| 111 | ## 4. Waterfall Cut (word-by-word cut-the-curve) |
| 112 | |
| 113 | Cut-the-curve at WORD granularity — the strongest leftward cut for text-to-text seams. |
| 114 | Outgoing words ramp out on their own curves; incoming words cascade in mid-flight — a |
| 115 | wave the eye rides across the seam. |
| 116 | |
| 117 | **Scope:** worker-authored inside one multi-beat comp (stacked full-frame `.beat` layers), |
| 118 | NOT a registry/injector type — it tweens word spans, not clip wrappers. The boundary into |
| 119 | and out of the text-beat block still gets a normal registry transition. Does not count |
| 120 | against the 2–3 transition budget. |
| 121 | |
| 122 | | Parameter | Value | Why | |
| 123 | | ------------------- | --------------------- | ------------------------------------------- | |
| 124 | | Travel | ±230px (~12% frame) | partial travel + velocity > full-frame push | |
| 125 | | Exit | 0.34s `power4.in` | the acceleration IS the cut | |
| 126 | | Exit fade | 0.18s, starts with x | word gone by ~25–30% of travel — no smear | |
| 127 | | Exit stagger | +0.022s reading order | the line peels, not a block slide | |
| 128 | | Entry | 0.3s `power4.out` | back half of the composite — velocity match | |
| 129 | | Entry start opacity | 0.35 | mid-path ignition; binary 0→1 pops | |
| 130 | | Entry gaps | 0.05s × 0.84 decay | accelerating cascade, resolves composed | |
| 131 | |
| 132 | Rules: |
| 133 | |
| 134 | - One direction per chain, riding the current. Inverse zoom is the chain's ARRIVAL beat only. |
| 135 | - Pre-set all words to `x: +230, opacity: 0` at build time — `immediateRender: false` |
| 136 | alone leaves un-started words visible at rest. |
| 137 | - A short first beat may exit whole-line: its fade ends ~0.02s before the cut so it is |
| 138 | still streaking when the next words ignite — no dead gap. |
| 139 | - Transform/opacity only (seek-safe); opaque stage ground applies. |
| 140 | |
| 141 | ## 5. Rack-Focus Blur-Cut (the visible cut) |
| 142 | |
| 143 | The one variant where the cut is SEEN: a defocus blur SPIKE hides a single-frame hard |
| 144 | swap — a handheld-DSLR focus-pull. Use as an occasional flourish for a state swap of the |
| 145 | SAME surface within one visual theme; never the default boundary. |
| 146 | |
| 147 | Differences from the others: outgoing stays FULLY OPAQUE until the cut (the blur hides |
| 148 | the swap — no early fade); eases `power2.in` / `power2.out` (soft optics, not momentum). |
| 149 | |
| 150 | Rules: |
| 151 | |
| 152 | - Fire only at a narrative beat, ≤ once per ~8s; never mid-caption or during a hold. |
| 153 | - Cut at PEAK blur (≥6px; peak 8–12px, ≤16–18px max) — swapping on the way up shows the cut. |
| 154 | - A subtle scale (~1.06 lens-breathing) sells it as optics. |
| 155 | - Same direction on both sides — the vector law still holds. Entry ≥ exit duration. |
| 156 | - Blur the wrapper; never blur + opacity in one tween on one element (headless |
| 157 | compositing bug); never blur a `<video>` directly (wrap it). |
| 158 | |
| 159 | --- |
| 160 | |
| 161 | ## 6. Waterfall Entry (in-scene arrival — not a seam) |
| 162 | |
| 163 | Staggered ARRIVAL cascade: words/elements whip in from below (one consistent direction), |
| 164 | each starting before the previous settles — an accelerating wave that resolves into a |
| 165 | composed layout. Title cards, segment openers, list/feature intros. The seam sibling is |
| 166 | §4; do not mix their rules: |
| 167 | |
| 168 | | | §6 Entry (arrival) | §4 Waterfall Cut (seam) | |
| 169 | | ------------- | --------------------------------------------- | --------------------------------------------------------- | |
| 170 | | Opacity | BINARY 0→1 via `tl.set` at entry — never fade | ignites at 0.35 mid-path — the fade IS the velocity trick | |
| 171 | | Axis default | Y, from below | X, riding the current | |
| 172 | | Outgoing side | none | words ramp out on mirrored power4.in | |
| 173 | |
| 174 | Choreography: |
| 175 | |
| 176 | - **Overlap, don't queue** — next element starts within ±2 frames of the previous |
| 177 | settling; gaps SHRINK across the cascade; the last element snaps. |
| 178 | - **Velocity varies by weight** — heavy/anchor elements travel further and longer; |
| 179 | light words/punctuation snap in tight: |
| 180 | |
| 181 | | Parameter | Anchor/heavy | Normal word | Light/punctuation | |
| 182 | | --------- | ------------ | ----------- | ----------------- | |
| 183 | | Y offset | 60–80px | 40–50px | 30–48px | |
| 184 | | Duration | 0.16–0.20s | 0.13–0.16s | 0.10–0.13s | |
| 185 | | Overlap | 0–2f gap | 1f overlap | 1–2f overlap | |
| 186 | |
| 187 | - Ease `power4.out` (expo.out for extra snap); never `.inOut` on an entry. |
| 188 | - One direction per cascade. |
| 189 | - Split the FINAL word into fragments to extend the climax; fragments travel further. |
| 190 | - Post-settle, the group usually slides to make room for the next beat — that's §7. |
| 191 | |
| 192 | ## 7. Nudge Curve (in-scene group slide — not a seam) |
| 193 | |
| 194 | Slow-fast-slow repositioning of a composed group (word rows, card stacks, lists) to |
| 195 | reveal content or make room. No single built-in ease produces it — `power4.inOut` |
| 196 | smacks to a stop. Chain three tweens on one property: |
| 197 | |
| 198 | | Phase | Ease | Distance | Time | Feel | |
| 199 | | --------- | --------------- | -------- | ---- | ---------------------------------------- | |
| 200 | | 1 ramp-in | `power3.in` | ~10% | ~20% | barely moves — motion registers, no jolt | |
| 201 | | 2 burst | `none` (linear) | ~65% | ~18% | ~2× average px/frame — purposeful | |
| 202 | | 3 tail | `power4.out` | ~25% | ~62% | decaying creep to rest — kills the smack | |
| 203 | |
| 204 | Rules: |
| 205 | |
| 206 | - The tail is ≥3× the ramp-in in TIME. If it still smacks: extend the tail's time (not |
| 207 | distance) or use `power5.out`. |
| 208 | - Phase 2 stays linear — easing it loses the burst contrast. |
| 209 | - Reveal new content DURING phase 2 — the burst masks its appearance. |
| 210 | - Same ratios vertical; scale distances proportionally, keep the time ratios. |
| 211 | |
| 212 | --- |
| 213 | |
| 214 | ## Choosing a Variant |
| 215 | |
| 216 | | | Zoom-Through | Inverse Zoom | Cut the Curve | Waterfall Cut | |
| 217 | | ------------- | ---------------------------- | ---------------------------- | ---------------------- | ---------------------- | |
| 218 | | Scope | Within-scene text swap | Arrival/payoff beat | Between scenes | Text-to-text seam | |
| 219 | | Z sign / axis | growing (push) | shrinking (pull) | X / Y | X, per-word | |
| 220 | | Travel/scale | 1→1.2, then 0.75→1 | 1→0.8, then 1.25→1 | ±230px | ±230px | |
| 221 | | Peak blur | 10px text / 18–20 full-frame | 10px text / 18–20 full-frame | 8–10px optional | none | |
| 222 | | Eases | power3.in / expo.out | power3.in / expo.out | power4.in / power4.out | power4.in / power4.out | |
| 223 | | Feel | progressing through | arriving at | carried sideways | a wave across the seam | |
| 224 | |
| 225 | ## Anti-Patterns |
| 226 | |
| 227 | | Don't | Instead | |
| 228 | | -------------------------------------------------------------------------- | --------------------------------------------------------------------------------- | |
| 229 | | Two texts visible during a zoom-through | Hard cut at blur peak, one text at a time | |
| 230 | | 20px blur on text-scale subjects | 10px text; 18–20px only full-frame | |
| 231 | | Inverse-zoom exit → grow-from-small entry (or push → oversized retraction) | Match the scale-velocity SIGN; verify at cut±0.1s | |
| 232 | | Incoming comp's own scale-up intro under a Z-seam wrapper tween | Arrive composed; stage entrances after the seam settles or match the sign | |
| 233 | | Mismatched blur/opacity at the swap | Identical values at the cut frame | |
| 234 | | Gentle entry easing (`power2.out`) | Mirror the exit: `power4.out` / `expo.out` | |
| 235 | | Full off-screen exits/entries | Partial travel (~12%) + early fade | |
| 236 | | `.inOut` eases on either side of a cut | Mirrored `power4.in` / `power4.out` | |
| 237 | | Lone element fading long before its cut | Fade ends ~0.02s before the cut, or word-cascade | |
| 238 | | Equal gaps across a waterfall cascade | Shrink gaps ×0.84 per word | |
| 239 | | Zoom-through on body text | Headlines and short phrases only | |
| 240 | | Scene cuts without cut-the-curve | It is the default boundary | |
| 241 | | Consecutive boundaries in opposing directions | One current; reserved vectors spent on meaning | |
| 242 | | Unpainted `#root` behind a mid-window cut | Opaque stage ground | |
| 243 | | Queued entries (each waits for the previous to settle) | Overlap ±1–2 frames — the cascade is a wave, not a queue | |
| 244 | | Same offset/duration for every cascade element | Vary by weight: anchors travel further, punctuation snaps | |
| 245 | | Gradual opacity fade on a §6 arrival | Binary 0→1 via `tl.set` — fading fights the snap (seam cuts fade; arrivals don't) | |
| 246 | | Single ease for a group slide (`power4.inOut`, `slow()`) | The §7 three-phase chain | |
| 247 | | Nudge tail shorter than 3× the ramp-in | Extend the tail's TIME, not its distance | |
| 248 | |
| 249 | ## Code |
| 250 | |
| 251 | All GSAP templates — worker-authored versions, registry `gsap_template`s, the combined |
| 252 | cut-the-curve + zoom, waterfall DOM/CSS/JS, rack-focus — live in |
| 253 | `examples/gsap-implementation.md`. |