Files
teamai-test/.teamai/skills/common/hyperframes-animation/rules/kinetic-beat-slam.md
T

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.35–0.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.2–1.8s | <0.8s frantic, >2.5s loses the pulse; keep spacing even — it's a beat |
| entrance duration | 0.35–0.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).