// 功能卡 3D 翻面揭示(card-flip-reveal)——Apple bento 翻转段。 // 横排 3 张占位卡逐张错峰沿 Y 轴翻 180°(perspective 1200px,双面结构 // backface-visibility hidden),背面白卡中央大号结论数字。翻转先加速后 // 弹性落定(末端过冲 +12° 回 180°);翻到侧棱(90°)附近闪过一道随角度 // 移动的加深灰高光带(白底用加深而非提亮)。 // 关键帧(卡 i 起点 = 18 + i*10,i = 0/1/2): // 0–18 hold → 卡0: 18–36 翻至 192° → 36–44 回弹落 180° → // 卡1: 28–46–54,卡2: 38–56–64 → 64–145 三卡全静止(81f ≥ 40f)。 import React from 'react'; import { useCurrentFrame, interpolate, Easing } from 'remotion'; import { G, Card, TitleBlock } from '../../_fixtures/Fixtures'; const CW = 440; const CH = 300; const GAP = 60; const X0 = (1920 - (CW * 3 + GAP * 2)) / 2; // 240 const Y = (1080 - CH) / 2; // 390 const FLIP_START = 18; const STAGGER = 10; const FLIP_DUR = 18; const SETTLE = 8; const OVERSHOOT = 12; // 末端过冲角度(原案 8°,肉眼存疑加码到 12°) const RESULTS = ['4.9×', '−38%', '99.9%']; // 卡 i 在帧 f 的翻转角:0 → 192(先加速后减速)→ 180(弹性落定),帧确定 const angleAt = (f: number, i: number): number => { const s = FLIP_START + i * STAGGER; if (f < s + FLIP_DUR) { return interpolate(f, [s, s + FLIP_DUR], [0, 180 + OVERSHOOT], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: Easing.bezier(0.55, 0, 0.3, 1), }); } return interpolate(f, [s + FLIP_DUR, s + FLIP_DUR + SETTLE], [180 + OVERSHOOT, 180], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: Easing.out(Easing.poly(5)), }); }; // 随角度移动的加深高光带:位置从卡左外扫到右外,强度在 90°(侧棱)达峰 const Sheen: React.FC<{ angle: number }> = ({ angle }) => { const pos = interpolate(angle, [35, 145], [-25, 115], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp', }); const op = Math.max(0, 1 - Math.abs(angle - 90) / 55); if (op <= 0.004) return null; return (
); }; const FlipCard: React.FC<{ i: number; frame: number }> = ({ i, frame }) => { const angle = angleAt(frame, i); return (