mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-07 18:26:17 +00:00
* 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.
134 lines
9.6 KiB
Markdown
134 lines
9.6 KiB
Markdown
---
|
||
name: ambient-glow-bloom
|
||
description: Un-triggered soft radial glow that blooms in behind a hero element and holds with a bounded idle breathe, or a single-pass traveling sweep across a surface. No click, no word-sync — it just blooms. Finite, deterministic, seek-safe.
|
||
metadata:
|
||
tags: glow, bloom, ambient, radial, sweep, hero, presence, finite, un-triggered
|
||
---
|
||
|
||
# Ambient Glow Bloom
|
||
|
||
A soft radial glow that **blooms in behind a hero element** (card, logo, metric) and holds, giving it presence. Unlike `press-release-spring`'s click-triggered burst or `asr-keyword-glow`'s word-timed envelope, this glow is **un-triggered** — it blooms on the hero's settle and stays lit. Two forms: a **hero bloom** that swells behind a settling element then breathes, and a **traveling sweep** that translates a soft highlight across a surface exactly once.
|
||
|
||
## How It Works
|
||
|
||
A radial-gradient layer sits **behind** the hero (glow `z-index: 1`, hero `z-index: 2` — a glow in front occludes it), starting at `opacity: 0`. Over the bloom-in window it ramps `opacity: 0 → peak` with a gentle `scale` swell, timed so `BLOOM_START + BLOOM_DUR` lands on the hero's settle — glow and hero resolve as ONE beat ("powering on"), never glow-then-card. After bloom-in:
|
||
|
||
1. **Hero bloom** — a **bounded idle breathe** during the hold: a finite `ease: "none"` tween advances a `phase` proxy and `onUpdate` nudges opacity + scale a hair around peak (never a `yoyo` loop). `sin(0) = 0` → the breathe starts exactly at the bloom's resting state.
|
||
2. **Traveling sweep** — a narrow highlight band at one edge translates **once** across to the other (`x` off-surface to off-surface), clipped to the surface (`overflow: hidden`). One pass, no return — a repeating sweep reads as a loading shimmer, not a reveal accent (the shimmer-sweep variation below is the sanctioned exception).
|
||
|
||
Peak opacity stays restrained (**≤ 0.45 hard ceiling**) so the glow gives presence without washing the frame; the glow color is **darker + more saturated** than the element it backs (a same-hue, same-lightness glow disappears into the surface).
|
||
|
||
## Recipe
|
||
|
||
```html
|
||
<!-- inside a standard scene clip -->
|
||
<div class="bloom-stage">
|
||
<div class="bloom-glow" id="bloom-glow"></div>
|
||
<!-- z-index: 1; inset: GLOW_INSET (negative); background: {glowGradient} -->
|
||
<div class="hero-card" id="hero-card">{HeroLabel}</div>
|
||
<!-- z-index: 2 -->
|
||
</div>
|
||
<!-- sweep form: <div class="sweep" id="sweep"> inside the overflow:hidden surface -->
|
||
```
|
||
|
||
```js
|
||
// ── Form A: HERO BLOOM ── bloom in soft, landing on the hero's settle.
|
||
tl.fromTo(
|
||
"#bloom-glow",
|
||
{ opacity: 0, scale: GLOW_START_SCALE },
|
||
{ opacity: GLOW_PEAK_OPACITY, scale: 1, duration: BLOOM_DUR, ease: "power2.out" },
|
||
BLOOM_START,
|
||
);
|
||
// Bounded breathe during the hold — finite phase tween, NOT a yoyo loop.
|
||
const glow = document.getElementById("bloom-glow");
|
||
const phase = { p: 0 };
|
||
tl.to(
|
||
phase,
|
||
{
|
||
p: Math.PI * 2 * BREATHE_CYCLES,
|
||
duration: BREATHE_DUR,
|
||
ease: "none",
|
||
onUpdate: () => {
|
||
const s = Math.sin(phase.p);
|
||
glow.style.opacity = String(GLOW_PEAK_OPACITY + s * OPACITY_AMP);
|
||
glow.style.transform = `scale(${1 + s * SCALE_AMP})`;
|
||
},
|
||
},
|
||
BLOOM_START + BLOOM_DUR,
|
||
);
|
||
|
||
// ── Form B: TRAVELING SWEEP ── one finite pass, constant glide.
|
||
tl.fromTo(
|
||
"#sweep",
|
||
{ x: SWEEP_START_X, opacity: 0 },
|
||
{ x: SWEEP_END_X, opacity: SWEEP_PEAK_OPACITY, duration: SWEEP_DUR, ease: "none" },
|
||
SWEEP_START,
|
||
);
|
||
tl.to("#sweep", { opacity: 0, duration: SWEEP_FADE_DUR, ease: "power1.in" }, SWEEP_FADE_START);
|
||
```
|
||
|
||
## Variations
|
||
|
||
- **Bloom-and-hold** — for scenes <3s or a hero with its own idle, skip the breathe: the single `fromTo` is the whole recipe.
|
||
- **Pulse-on-arrival** — bloom slightly PAST peak (`GLOW_OVERSHOOT_OPACITY`, `scale: 1.06`), then a second adjacent tween eases down to a steady hold — one breath punctuating the landing, no ongoing loop.
|
||
- **Multi-hero relay** — stagger per-glow `BLOOM_START` by ~0.15–0.3s across a row; shrink `OPACITY_AMP` / `SCALE_AMP` per the `/√N` rule below.
|
||
- **Diagonal raked sweep** — angle `{sweepGradient}` (~105°) across a wordmark: the classic one-pass logo sheen. Narrower `SWEEP_WIDTH`, higher `SWEEP_PEAK_OPACITY`.
|
||
|
||
### Shimmer sweep (text-clipped status-phrase working-state)
|
||
|
||
The sweep re-aimed **inside type**: a soft highlight gradient clipped into a status phrase ("Thinking…", "Analyzing dataset…") via `background-clip: text` travels left→right through the letterforms — the grey-on-grey shimmer that says _still working_. Unlike every other form here it legitimately **repeats while the status is live**: the repetition is diegetic working-state, not idle wobble (same defense as a blinking caret — the motion performs status). Two things keep it honest: it is **bounded** (one finite tween whose pass count is computed from the status window, never `repeat: -1`), and it is **killed at resolve** — the moment the status completes, the shimmer stops dead; a shimmer surviving into the answer beat turns a working indicator into decoration.
|
||
|
||
```js
|
||
// Status shimmer — N passes as ONE bounded tween. Killed at resolve.
|
||
const status = document.getElementById("status-phrase");
|
||
// CSS on #status-phrase: background: {shimmerGradient}; background-size: 300% 100%;
|
||
// -webkit-background-clip: text; background-clip: text; color: transparent;
|
||
const shimmer = { p: 0 };
|
||
const PASSES = Math.round(STATUS_DUR / PASS_PERIOD); // whole passes, computed up front
|
||
tl.to(
|
||
shimmer,
|
||
{
|
||
p: PASSES,
|
||
duration: STATUS_DUR,
|
||
ease: "none",
|
||
onUpdate: () => {
|
||
const t = shimmer.p % 1; // 0→1 within each pass; percent axis inverted → left→right travel
|
||
status.style.backgroundPosition = `${(1 - t) * 100}% 50%`;
|
||
},
|
||
},
|
||
STATUS_START,
|
||
);
|
||
tl.set(status, { backgroundPosition: "100% 50%" }, STATUS_START + STATUS_DUR); // resolve: dead.
|
||
```
|
||
|
||
Keep it a whisper: `{shimmerGradient}` is the status text's own grey with one slightly-lighter band (highlight stop a step above the base, nothing near white); `background-size` ~300% keeps the band narrow in the glyphs; `PASS_PERIOD` 1.2–1.8s — slower reads as a sheen accent, faster as a spinner. Whole-number `PASSES` lands the band at its start position exactly at the kill frame, so the `tl.set` is visually a no-op. This is the working-state cousin of `gradient-text-sweep`: reach **here** when the sweep _means_ "in progress," **there** when the gradient is the typographic treatment itself.
|
||
|
||
## Values
|
||
|
||
| token | range / default | notes |
|
||
| ----------------------- | ------------------------------------------------------ | -------------------------------------------------------------------------- |
|
||
| GLOW_PEAK_OPACITY | 0.15 (subtle) → 0.30 (default) → **0.45 hard ceiling** | higher washes the frame; a glow you consciously notice is too strong |
|
||
| GLOW_INSET | −200 to −450px (1920×1080) | negative so the halo extends past the hero; too small reads as a tight rim |
|
||
| GLOW_START_SCALE | 0.80–1.0 | ≤1.0 — grow into place, never shrink |
|
||
| BLOOM_DUR / BLOOM_START | 0.6–1.4s | `BLOOM_START + BLOOM_DUR` ≈ the hero's settle frame |
|
||
| OPACITY_AMP / SCALE_AMP | 0.02–0.05 / 0.01–0.03 default | `PEAK + OPACITY_AMP ≤ 0.45`; push only when the glow is the sole motion |
|
||
| BREATHE_CYCLES | period 2.5–4s per breath | glow breathes slower than element breathing |
|
||
| SWEEP_WIDTH | 15–35% of surface (grid) / 8–15% (wordmark) | |
|
||
| SWEEP_DUR | 0.8–1.6s | one deliberate pass — slow enough to read as light |
|
||
| SWEEP_PEAK_OPACITY | 0.10 → 0.25 (default) → 0.40 | same ≤ ~0.45 wash limit; tight sweeps tolerate the high end |
|
||
| SWEEP_START_X / END_X | fully off-surface both ends | no visible spawn/despawn mid-surface; fade reaches 0 as the band clears |
|
||
| PASS_PERIOD (shimmer) | 1.2–1.8s | with whole-number PASSES |
|
||
|
||
## Critical Constraints
|
||
|
||
- **Glow peak opacity ≤ 0.45** — including breathe amplitude; default to the LOW end (0.15–0.30).
|
||
- **Glow behind, hero in front**; glow color darker + more saturated than the hero surface.
|
||
- **Land glow and hero as one beat** — before or after reads as two separate events.
|
||
- **Breathe is bounded, sweep is one pass** — the only sanctioned repetition is the shimmer sweep, bounded and killed at resolve.
|
||
- **Concurrent halos compound** — per-glow amps ≤ default `/√N`, stagger breathe periods (2.6s / 2.9s / 3.3s) so they don't pulse in lockstep.
|
||
- **Don't combine a `boxShadow` glow on the hero with this halo layer** — they compete and read muddy; the glow lives on the dedicated layer.
|
||
|
||
## See also
|
||
|
||
`sine-wave-loop` (hero breathes on scale/y while the glow breathes on opacity, out of phase) · `press-release-spring` (the click-triggered sibling — never both behind one element) · `counting-dynamic-scale` / `stat-bars-and-fills` (bloom behind a landing stat) · `center-outward-expansion` (sweep across the assembled grid) · `gradient-text-sweep` (the design-beat gradient counterpart).
|