--- id: workflow-approve-press role: workflow duration_seconds: [4, 6] phases: 4 visual_arc: headline-entry → steps-progress → video-demo → button-press-confirm uses_rules: [press-release-spring] element_roles: headline: Top concept statement with one emphasized accent word video_demo: Center product video / animation showing the feature step_indicators: Left-flank 3D-tilted step list with pending → active → complete states action_button: Right-flank 3D-tilted button that receives the press and changes state when_to_use: - Scene emphasizes user control over an automated process - Multi-step workflow needs visualization (e.g. generate → review → approve) - Button press is the narrative climax (user confirms / approves) - Left-right 3D symmetry flanks a center demo when_not_to_use: - Workflow has more than 3-4 steps (cannot read in a ~5s scene) - No user-action metaphor needed (fully automated) - Scene is purely informational without interaction triggers: [review and approve, step-by-step workflow, user control, approve button, with-you metaphor] --- # Workflow · Approve & Press (HyperFrames) This is an "agency → confirmation" arc: the headline announces the verb, the demo shows what the system is doing, the step list ticks through pending → active → complete to remind the viewer "you're inside the loop," and the right-flank button takes the press as the payoff — color flips green, a checkmark stamps, the scene ends saying "you approved it." The 3D-tilted left/right flanks frame the demo like a cockpit, so the user-action feels grounded in the device. A single paused GSAP timeline drives everything. State transitions that would be `if (frame < N)` in an imperative renderer become snap `tl.set({ attr })` toggles at concrete timeline positions, so any seek lands on a deterministic state. ## When to Use - Feature scene that emphasizes user agency ("AI works with you, not just for you") - The workflow can be shown in 2–3 steps; 4+ steps will not read in ~5s - A button press serves as the narrative payoff (not a passing gesture) - Not for: fully automated stories, pure-information scenes, or scenes whose climax is something other than a confirm ## Orchestration Four phases. Only Phase 4 is rule-driven; everything else is inline because each is a single tween or a snap state machine — wrapping them in their own rule would be overengineering. - **Phase 1 — headline drop**: inline. One `fromTo` with `back.out(HEADLINE_BOUNCE)`, sliding from a small negative y to 0. Keep the bounce on the editorial end (≤1.4) — a title that oscillates reads as marketing-y, not workflow-y. - **Phase 2 — center demo scale-in**: inline. One `to` from `DEMO_ENTRY_SCALE` to `1`, eased with `power3.out`. The demo enters quietly because it is the _background_ of the scene — the steps and button are the foreground story; an overshoot here would steal focus from Phase 3. - **Phase 3 — step indicators**: inline, split into two layers driven from the same timeline. (a) A staggered `tl.to(".step", { x: 0, opacity: 1, stagger: { each: STEP_STAGGER, from: "start" } }, STEPS_START)` slides the rows in from the left. (b) A series of `tl.set(".step-N", { attr: { "data-state": "…" } })` fires at `STEPS_START` / `STEP_ACTIVE_T2` / `STEP_ACTIVE_T3` to flip the discrete state. **CSS responds to `[data-state]`**; the timeline never animates state. See "Phase 3 seam: snap state machine" below. - **Phase 4 — button press climax**: use [press-release-spring](../rules/press-release-spring.md) in its **"state change at release (approve / confirm pattern)" variation** — the button's terminal state is `{successColor}` + checkmark, not a return to rest. We also follow the rule's **color-shift-during-press** variation for the bg/glow transition. The press dip itself follows the rule's default linear `power1.in/out` (the rule explains why); the checkmark uses the rule's `back.out(CHECK_BOUNCE)` stamp. The rule's burst + bg-glow layers are optional embellishments and this blueprint omits them by default — the workflow's quiet, in-app aesthetic doesn't want a hero-CTA pyrotechnic moment. The button's pre-press life — entry pop and ambient glow pulse — is also inline. Both predate the press and don't share the rule's state-continuity contract, so they live alongside the rule's tweens rather than inside the rule's scope. See "Phase 4 seam: pre-press life" below. ## Phase Timing | Phase | Start ≥ | Internal duration | Notes | | ------- | ------------------------------------------- | ---------------------------------------- | -------------------------------------------- | | 1 | `0.1–0.3s` (opening beat of empty frame) | `HEADLINE_END − HEADLINE_START` | Headline lands fully before demo dominates | | 2 | `HEADLINE_END − ~0.05s` (overlap) | `VIDEO_DUR` | Slight overlap on tail = flow, not cut | | 3a | `VIDEO_START + ~0.15s` | `numSteps × STEP_STAGGER` | First step appears as demo finishes settling | | 3b | `STEPS_START` (active-1), then `+readDwell` | snap (zero duration) | `readDwell` ≥ 1.0–1.5s between transitions | | 4 entry | `STEP_ACTIVE_T(last) + ~0.1s` | `BTN_ENTRY_DUR` | Button pops as last step goes active | | 4 press | `BUTTON_ENTER + BTN_ENTRY_DUR + ~0.2s` | `PRESS_DUR` (= `PRESS_DIP_DUR + return`) | Button must settle before press fires | Why the gaps are what they are. The −0.05s overlap from Phase 1 to 2 is the "two beats read as flow" trick — large enough that the demo's first frame is already visible while the headline is still settling, but not so large that the eye sees them as one event. The +0.15s gap to Phase 3 exists because the demo's `power3.out` decays to near-zero velocity, not actually zero; starting the staggered step entry on top of an unsettled scale produces faint chatter on each step's left edge. The +1.0–1.5s `readDwell` between step state changes is human-perception driven, not motion-driven: the viewer needs to actually read the active step label before it becomes complete, otherwise the state machine reads as a blink. The +0.2s gap before `PRESS_FRAME` is the most critical timing constant in the scene — the button enters with `back.out(BTN_ENTRY_BOUNCE)` and its spring tail oscillates past 1.0 for ~0.15–0.2s; firing the press on top of that residual motion makes the dip "skip" because GSAP layers velocities on the same property. ## Initial DOM Nesting The scene's structure is "three columns around a center demo." The only non-obvious bit is where `perspective` lives: ``` #root .bg ← background gradient .headline-wrap ← Phase 1 target (top center) .headline .accent ← emphasized word .demo-wrap ← Phase 2 target (center) .demo-frame