Files
hyperframes/skills/hyperframes-animation/rules/split-tilt-cards.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

124 lines
5.5 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: split-tilt-cards
description: Two cards side-by-side with opposing Y-rotation creating a symmetric 3D split-screen layout for comparisons or feature pairs.
metadata:
tags: 3d, cards, split, tilt, comparison, symmetric, layout
---
# Split Tilt Cards
Two cards side-by-side with opposing `rotateY` (left `+TILT`, right `TILT`) — a symmetric "book-open" 3D split for comparisons, before/after, feature pairs. Each card slides in from its own side (reinforcing "they came from their own worlds and met here"), then the pair idles in counter-phase.
## How It Works
`perspective` on the scene root (REQUIRED — without it `rotateY` flattens to a 2D layout) and `transform-style: preserve-3d` on the stage and both cards. Entry starts each card off-axis with `TILT + TILT_OVERSHOOT`, settling to `TILT` — a pivot-into-place. Idle is a gentle counter-phase y-bob (the two yoyo tweens run in opposite directions); copy fades up during the cards' settle, not after.
## Recipe
```html
<!-- inside a standard scene clip (hyperframes-core) -->
<div class="split-stage">
<div class="card card-left">
<div class="card-eyebrow">{leftEyebrow}</div>
<div class="card-headline">{leftHeadline}</div>
<div class="card-body">{leftBody}</div>
</div>
<div class="card card-right"></div>
</div>
```
```css
.scene-root {
display: grid;
place-items: center;
perspective: SCENE_PERSPECTIVE; /* REQUIRED */
}
.split-stage {
display: flex;
gap: STAGE_GAP;
transform-style: preserve-3d;
}
.card {
width: CARD_WIDTH;
transform-style: preserve-3d;
will-change: transform;
}
/* Shadow falls WITH the facing direction: left card faces right → shadow right. */
.card-left {
box-shadow: -CARD_SHADOW_OFFSET CARD_SHADOW_DROP CARD_SHADOW_BLUR {shadowColor};
}
.card-right {
box-shadow: CARD_SHADOW_OFFSET CARD_SHADOW_DROP CARD_SHADOW_BLUR {shadowColor};
}
```
```js
// Entry — from outside, opposing tilts settle with a small pivot
tl.fromTo(
".card-left",
{ x: -ENTRY_SLIDE_DIST, rotateY: TILT + TILT_OVERSHOOT, opacity: 0 },
{ x: 0, rotateY: TILT, opacity: 1, duration: ENTRY_DUR, ease: "power3.out" },
LEFT_AT,
);
tl.fromTo(
".card-right",
{ x: ENTRY_SLIDE_DIST, rotateY: -TILT - TILT_OVERSHOOT, opacity: 0 },
{ x: 0, rotateY: -TILT, opacity: 1, duration: ENTRY_DUR, ease: "power3.out" },
RIGHT_AT,
);
// Counter-phase idle bob — opposite signs = alive; synchronized = conveyor belt
tl.to(
".card-left",
{ y: -FLOAT_AMP, duration: FLOAT_DURATION / 2, ease: "sine.inOut", yoyo: true, repeat: 1 },
IDLE_START,
);
tl.to(
".card-right",
{ y: FLOAT_AMP, duration: FLOAT_DURATION / 2, ease: "sine.inOut", yoyo: true, repeat: 1 },
IDLE_START,
);
// Copy fades up during the settle
tl.from(
".card-eyebrow, .card-headline, .card-body",
{ opacity: 0, y: COPY_RISE, stagger: COPY_STAGGER, duration: COPY_DUR, ease: "power2.out" },
COPY_REVEAL_AT,
);
```
## Variations
- **Badges / floating labels**: position them on the PARENT, never inside a card — inside they inherit the `rotateY` and tilt off-axis.
- **3+ cards**: center card stays flat (`rotateY: 0`), outer two tilt inward — "old way / nothing / our way."
- **Zoom-through**: a separate camera tween scaling `.split-stage` reads as the viewer crossing the gap between the tilted pair.
## Values
| token | range | notes |
| ----------------- | -------------------------------- | ------------------------------------------------------- |
| SCENE_PERSPECTIVE | 10002400px | lower exaggerates the tilt; higher reads near-isometric |
| TILT | 1018° | < 10 reads almost flat; > 18 folds shut and copy blurs |
| TILT_OVERSHOOT | 412° | the pivot-into-place feel |
| STAGE_GAP | 40120px (~0.060.15×CARD_WIDTH) | small = fused pair; large = compared-but-separate |
| CARD_WIDTH | 480820px @1920 | `2×CARD_WIDTH + STAGE_GAP ≤ 0.95×stage` at full tilt |
| ENTRY_SLIDE_DIST | 200500px (~0.30.6×CARD_WIDTH) | |
| ENTRY_DUR | 0.61.2s | |
| RIGHT_AT | LEFT_AT + 00.3s | zero feels mechanical; large fragments the pair |
| FLOAT_AMP | 38px | subtle is the point |
| FLOAT_DURATION | 1.63.2s round trip | breathing cadence; IDLE_START ≥ entry end |
| COPY_REVEAL_AT | during the entry tail | copy popping in after cards are idle reads disconnected |
## Critical Constraints
- **`perspective` on the scene root is REQUIRED**; `preserve-3d` on the stage AND each card.
- **Shadow direction matches tilt** — left card faces right → shadow falls right (and mirrored). Wrong sign reads as broken 3D.
- **Counter-phase idle** — the two bobs run with opposite signs at the same position.
- **Badges outside the card divs** (they'd inherit the rotation).
- **Body copy ≤ 2 lines per card** — tilted long paragraphs collapse into perspective blur.
- **Symmetric weight** — same width, same vertical center, similar line counts; asymmetry breaks the comparison metaphor.
## See also
`card-morph-anchor` (the pair can morph into one unified shape afterward) · `counting-dynamic-scale` (numbers as each side's headline) · `sine-wave-loop` (the idle form).