Files
hyperframes/skills/hyperframes-animation/rules/kinetic-beat-slam.md
T
WaterrrForever 853256403b feat(skills): c2v mining pass — 7 new blueprints, 10 new rules, compacted recipe corpus (#2680)
* feat(skills): c2v mining pass over animation blueprints and rules

Compacts ~45 existing animation rules/blueprints into tighter recipe form
(net -3.4k lines) and adds 17 mined from the c2v corpus:

- 7 blueprints: agent-progress-theater, camera-journey, fixed-anchor-cycle,
  panel-edit-live-sync, prompt-type-submit-generate,
  transcript-scroll-artifact-reveal, zoom-out-workspace-reveal
- 10 rules: 3d-camera-flight, anchored-layout-expand, chart-scrub-readout,
  chromatic-glitch, control-target-sync, cursor-drag, gradient-text-sweep,
  multi-cursor-choreography, particle-burst, theme-crossfade-morph






Both indexes updated.

* feat(skills): sync product-launch script bank with mined blueprint roles

The role->blueprint script bank in product-launch-video/story-design.md is
kept 1:1 with blueprints-index role declarations, which the c2v mining pass
expanded. Adds the 25 missing entries (script-shape descriptor + example
lines + pattern): 13 for the 7 new blueprints, 12 for role widenings on 7
existing ones (cursor-ui-demo, dataviz-countup, titlecard-reveal, et al.),
and states the 1:1 sync contract in the bank's intro.

* docs(skills): cover constellation-hub scatter-drift variant in the script bank

Review follow-up on #2680: the SOCIAL_PROOF constellation-hub entry
patterned only the orbit shape; the c2v pass added a scatter-drift
end-card variant with the opposite geometry (no hub, no ring). Adds an
example line and extends the pattern so a scatter-drift beat's VO isn't
steered toward the orbit shape.
2026-07-21 17:28:55 +08:00

138 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: kinetic-beat-slam
description: Percussive kinetic typography — short phrases slam in on a steady beat with distinct per-phrase entrances, optional rhythm chrome (metronome ticks, beat bar), then a locked finale.
metadata:
tags: text, kinetic, typography, beat, rhythm, slam, percussive, punchy
---
# Kinetic Beat Slam
Short phrases hit one at a time on a **steady beat**, each with a _different_ entrance, then stack into a locked finale — the recipe for "punchy / rhythmic" text-forward pieces (taglines, manifestos, hype intros). The difference between generic and rhythmic is (1) one shared **onset array** driving every element, (2) **distinct** entrances per phrase rather than one reused helper, and (3) optional **rhythm chrome** that visibly keeps the beat.
## How It Works
A single tempo grid — `PULSE` seconds per sub-beat, `BEATS = [t0, t1, t2, …]` on that grid — is the rhythmic spine; every phrase entrance, accent, and chrome tick reads its time from it, so the piece locks to one pulse instead of drifting hand-tuned offsets. Each phrase gets a different transform axis (scale+blur slam / side snap / rise+rotate) with short attacks (0.350.6s on the hit), then the stack holds with a finite low-amplitude breath.
## Recipe
```html
<!-- inside a standard scene clip (hyperframes-core) -->
<div class="kbs-stage">
<div class="kbs-line" id="p1"><span class="verb">Notice</span> more.</div>
<div class="kbs-line" id="p2"><span class="verb">Decide</span> faster.</div>
<div class="kbs-line" id="p3"><span class="verb">Act</span> now.</div>
</div>
<!-- optional rhythm chrome -->
<div class="kbs-metronome" aria-hidden="true"><i></i><i></i><i></i><i></i><i></i></div>
```
```css
.kbs-stage {
position: absolute;
inset: 0;
display: flex;
flex-direction: column;
justify-content: center;
padding: 120px 160px; /* title-safe margin */
}
.kbs-line {
font-family: "Archivo Black", "League Gothic", sans-serif; /* embedded display face */
font-size: 150px;
line-height: 0.96;
letter-spacing: -0.03em;
color: #f5f5f5;
}
.kbs-line .verb {
color: #ff5b2e; /* exactly one accent hue */
}
.kbs-metronome {
position: absolute;
bottom: 64px;
left: 50%;
transform: translateX(-50%);
display: flex;
gap: 14px;
}
.kbs-metronome i {
width: 6px;
height: 28px;
background: #ff5b2e;
opacity: 0.25;
}
```
```js
// ONE tempo grid drives everything — phrases AND the metronome read it.
const PULSE = 0.4; // seconds per sub-beat
const BEATS = [PULSE * 1, PULSE * 5, PULSE * 9]; // phrase onsets, on the grid
// Distinct entrances per phrase (NOT one reused helper).
tl.fromTo(
"#p1",
{ scale: 1.5, filter: "blur(16px)", opacity: 0 },
{ scale: 1, filter: "blur(0px)", opacity: 1, duration: 0.5, ease: "power4.out" },
BEATS[0],
);
tl.fromTo(
"#p2",
{ x: -320, opacity: 0 },
{ x: 0, opacity: 1, duration: 0.45, ease: "expo.out" },
BEATS[1],
);
tl.fromTo(
"#p3",
{ y: 90, rotation: 6, opacity: 0 },
{ y: 0, rotation: 0, opacity: 1, duration: 0.55, ease: "circ.out" },
BEATS[2],
);
// Rhythm chrome: each tick flashes on the SAME grid, not a magic offset.
gsap.utils.toArray(".kbs-metronome i").forEach((tick, i) => {
tl.to(tick, { opacity: 1, duration: 0.08, yoyo: true, repeat: 1, ease: "none" }, PULSE * (i + 1));
});
// Finale hold: floor (not ceil) so the repeat never overshoots data-duration;
// max(0,…) so a short hold never yields a negative repeat (GSAP reads negative as -1 = infinite).
const holdStart = BEATS[2] + 0.7,
cycle = 1.6,
holdDur = SCENE_DURATION - holdStart;
tl.to(
".kbs-stage",
{
scale: 1.01,
duration: cycle / 2,
ease: "sine.inOut",
yoyo: true,
repeat: Math.max(0, Math.floor(holdDur / cycle) - 1),
},
holdStart,
);
```
## Variations
- **Entrance easing by attack character** — `power4.out` hard slam ⭐ default hit · `expo.out` hardest snap (side-snaps, whip-ins) · `back.out(2)` overshoot pop (accents only, not body words) · `circ.out` heavy rise with momentum. Use **at least 3 distinct easings** across the piece.
- **Rhythm chrome alternatives** — a center beat bar or a `// label` monospace tag pulsing on-beat instead of the 5-tick metronome; mark any decorative that must survive a shader transition per `../../transitions/overview.md`.
- **Finale dressing** — stack + accent underline sweep ([css-marker-patterns](css-marker-patterns.md)); don't just leave the last phrase sitting.
## Values
| token | range | notes |
| ----------------- | -------------------- | -------------------------------------------------------------------------------------------- |
| BEATS spacing | 1.21.8s | <0.8s frantic, >2.5s loses the pulse; keep spacing even — it's a beat |
| entrance duration | 0.350.6s | the hit must resolve before the next beat; exits ≤0.25s |
| accent hue | exactly 1 | the verbs; the rest mono white / near-black |
| display face | 150px+, heavy weight | Archivo Black / League Gothic / Oswald — see `hyperframes-creative/references/typography.md` |
## Critical Constraints
- **One beat array, not scattered offsets** — every element times off `BEATS[]` / `PULSE`; this is the single biggest lever for "rhythmic".
- **Different entrance per phrase** — a reused `punchIn()` for all lines is the flat-but-competent tell. Vary the motion axis, reuse the ease _family_.
- **Finale repeat math**: `repeat: Math.max(0, Math.floor(dur / cycle) - 1)``Math.ceil` overshoots `data-duration` and trips the `gsap_repeat_ceil_overshoot` lint rule; a negative repeat is read by GSAP as `-1` (infinite).
- **No banned exit animations between scenes** — in a montage the _transition_ is the exit (`../../transitions/overview.md`); only a final scene may fade out.
- **Display font must be embedded** or it silently falls back at render — Anton / Bebas-as-literal are NOT embedded (`Bebas Neue` aliases to League Gothic; verify in `typography.md`).
## See also
`3d-text-depth-layers` (extruded depth on the slammed words) · `css-marker-patterns` (finale underline/circle) · `sine-wave-loop` (the finale breath) · `../adapters/gsap-easing-and-stagger.md` (easing vocabulary).