--- id: metric-video-text-pivot role: metric duration_seconds: [5, 8] phases: 4 visual_arc: video-center → video-slides-aside → text-typing → stat-reveal uses_rules: [3d-text-depth-layers, sine-wave-loop] element_roles: video: Product demo video that starts centered, then slides to make room for the stat typing_text: Character-by-character typed lines, with accent-colored keywords stat: Giant metric label rendered with 3D depth layers pill: Gradient background pill that scales in behind a closing phrase when_to_use: - Scene transitions from showing a feature to stating its impact - Metric needs dramatic typographic treatment, not just a number overlay - Video provides context, text provides the "so what" payoff - Pivot from visual demonstration to textual impact statement when_not_to_use: - Video should remain the focal point throughout - Stat is secondary information (use overlay) - Scene is purely typographic with no video triggers: [ accuracy rate, engagement increase, show feature then stat, video moves aside, big number reveal, metric emphasis, ] --- # Metric · Video Text Pivot (HyperFrames) This is a "show → yield → pivot → stamp" emotional arc: the product video lands centered and breathes, claiming the viewer's full attention; then it slides aside _into_ the space the stat fills, so the viewer reads it as a single weight-transfer rather than two events; then both visual citizens clear out and kinetic text types into the vacated center, with accent words carrying the meaning the video used to carry; finally a gradient pill snaps shut around the closing line, sealing the impact statement as one graphic. Single paused GSAP timeline. Four phases, but the second and third phase each pair an exit with a same-anchor entrance, so the timeline reads as two beats not four. ## When to Use - Two narrative beats: "see the feature" then "see the impact" - Stat / metric needs dramatic, frame-filling typographic treatment (not an overlay) - Video provides context and must remain visible during the stat reveal — it slides, doesn't cut - Not for: video-as-focal-point throughout, secondary stats, purely typographic scenes ## Orchestration Four phases, two rules, three inline patterns. The inline patterns dominate because most of the scene is bespoke layout choreography, not motif reuse. - **Phase 1 — video enters + floats**: inline `power3.out` scale/opacity tween on `.video-pos` for the entry. The float (a small `y` bob) is [sine-wave-loop](../rules/sine-wave-loop.md) in its **multiplicative `onUpdate` form**, written to `.video-float` (the middle wrapper). The rule's `fromTo` + yoyo form would not survive the Phase 2 slide tween — see Phase 1 seam below. - **Phase 2 — video slide + stat reveal**: video gets an inline `power3.out` `x` + `scale` slide on `.video-pos`. Stat enters with an inline `back.out(STAT_BOUNCE_FACTOR)` on `.stat-pos`. The stat's 3D type uses [3d-text-depth-layers](../rules/3d-text-depth-layers.md) in its **static-depth variation** (layers built at composition setup, no cascade, no depth-grow tween); the cascade default would fight the bounce entry. The stat's breath is again [sine-wave-loop](../rules/sine-wave-loop.md) in its multiplicative onUpdate form, gated to the Phase 2 window only. - **Phase 3 — pivot (both exit + typing enters)**: three concurrent inline tweens at `PIVOT_AT` — video exit, stat exit, typing-stage fade/scale entry. The character-by-character typing itself is inline: a single proxy tween advances `idx: 0 → totalChars` with `ease: "none"`, and `onUpdate` slices five pre-segmented spans by index. We are deliberately _not_ using `discrete-text-sequence` — that rule models discrete state swaps (typos, corrections), not a clean character stream through segmented spans. See "Rule gap" in the report. - **Phase 4 — pill stamp**: inline `power3.out` on `.pill-bg` `scaleX: 0 → 1` + `scaleY: PILL_INITIAL_SCALE_Y → 1`. The glow halo (`.pill-glow`) fades on the same anchor with a longer `power2.out` duration so the silhouette resolves before the bloom registers. ## Phase Timing | Phase | Start ≥ | Internal duration | Notes | | ----- | --------------------------------------------------- | ---------------------------------------- | ------------------------------------------------------------------------- | | 1 | `VIDEO_ENTRY_AT` (≥ 0) | `VIDEO_ENTRY_DUR` | Float starts at t=0 and runs continuously, gated by Phase 2/3 window | | 2 | `VIDEO_ENTRY_AT + VIDEO_ENTRY_DUR + ~1.0s` | `max(VIDEO_SLIDE_DUR, STAT_ENTRY_DUR)` | The ~1s gap is the "breathing room" — see seam | | 2b | `SLIDE_AT + STAT_ENTRY_DUR + ~0.1s` | until `PIVOT_AT` | Stat breath activates here, gated off at `PIVOT_AT` | | 3 | `STAT_BREATH_START + ~0.5s` | `EXIT_DUR` + `TYPING_STAGE_DUR` + typing | Pivot starts here; `TYPING_START_AT = PIVOT_AT + TYPING_STAGE_DUR` | | 4 | `TYPING_START_AT + (BOUNDS.accent2End / TYPE_RATE)` | `PILL_DUR` | Anchored to the character index where line 2 begins — derived, not chosen | The ~1s gap before Phase 2 (`SLIDE_AT − VIDEO_ENTRY_AT − VIDEO_ENTRY_DUR ≥ 1.0s`) is the most-tuned gap in the blueprint: shorter and the float never registers as "alive," so the slide reads as the video's first action rather than its second; longer and the scene drags. The 0.1s gap between stat entry end and breath start is the standard `back.out` settle buffer (overshoot tail and sine cannot coexist — same constraint as Phase 5 of brand-reveal). The ~0.5s minimum between breath start and `PIVOT_AT` exists to make the breath _visible_ — at least one half-cycle has to land before the exit. The pill anchor (`PILL_AT`) is not chosen, it's derived from the typing index. The full formula: ``` PILL_AT = TYPING_START_AT + (BOUNDS.accent2End / TYPE_RATE) = (PIVOT_AT + TYPING_STAGE_DUR) + (line1Length / TYPE_RATE) ``` so the pill snaps in _at the instant_ line 2's first character types. Anchoring it earlier reads as the pill predicting the phrase; later reads as the pill catching up. Pick `TYPE_RATE` first, then this anchor falls out. ## Initial DOM Nesting (Critical) Every moving element gets **three nested wrappers**: outer `-pos` carries the GSAP entry/slide/exit tween, middle `-float` (or `-breath`) carries the onUpdate-driven continuous motion, inner `-tilt` carries a static CSS 3D rotation. This is the structural seam unique to the blueprint — without the separation, the float's `y` onUpdate would clobber the slide's `x` tween (and vice versa) every frame. ``` .stage .video-pos ← Phase 1 entry, Phase 2 slide, Phase 3 exit .video-float ← onUpdate: y (sine-wave float, gated by t < PIVOT_AT) .video-tilt ← CSS: rotateY(VIDEO_TILT_Y) rotateX(VIDEO_TILT_X) — static .video-content