// popup-book-rise —— 立体书立起 // FakeDashboard(A) 打平躺下(场景 rotateX 75° 透视俯视),6 张卡片是贴在页上的 // 纸片,沿各自底边从平躺错峰立起(rotateX 90°→-5° 过冲→0° 回弹,即立到 95° 再回 90°), // 根部投影随立起角度收窄变淡。全部立起后整个场景轻微回正(75°→68°)收尾。 // 卡片用独立网格复刻 dashboard A 区布局(Fixtures 内嵌卡无法单独驱动)。 // 收尾 f108 后真静止 ≥52f。帧确定性:全由 frame 派生。 import React from 'react'; import { useCurrentFrame, interpolate, spring, Easing } from 'remotion'; import { G, Card } from '../../_fixtures/Fixtures'; const FPS = 30; const HOLD = 14; // 开头静置 const STAGGER = 7; const RISE_DUR = 34; // spring 视觉收敛帧数 const LAST_START = HOLD + 5 * STAGGER; // 49 const SETTLE = LAST_START + RISE_DUR; // 83:全部立起 const REST = SETTLE + 25; // 108:场景回正完成 // dashboard A 区几何(照抄 FakeDashboard:侧栏 220 + 顶栏 72 + padding 36 + gap 28) const AREA_X = 220 + 36; const AREA_Y = 72 + 36; const AREA_W = 1920 - 220 - 72; const AREA_H = 1080 - 72 - 72; const GAP = 28; const CELL_W = (AREA_W - 2 * GAP) / 3; const CELL_H = (AREA_H - GAP) / 2; const PageCard: React.FC<{ i: number; frame: number }> = ({ i, frame }) => { const col = i % 3; const row = Math.floor(i / 3); // 远排(row 0)先立,近排后立;同排从左到右 const order = row === 0 ? col : 3 + col; const start = HOLD + order * STAGGER; const s = spring({ frame: frame - start, fps: FPS, config: { damping: 11, stiffness: 130, mass: 0.9 }, durationInFrames: RISE_DUR, durationRestThreshold: 0.0001, }); // 平躺(贴页面 = local 0°)→ 立起(垂直页面 = local -90°,顶边朝观众翻起), // spring 过冲自然冲过 -90° 到约 -95°(纸的韧性)再回弹。 const rx = interpolate(s, [0, 1], [0, -90]); // 根部投影:躺平时长影(卡片盖在页面上),立起后收成窄条 const lie = 1 - Math.min(Math.abs(rx) / 90, 1); // 1 = 躺平, 0 = 立直 const shH = 14 + 90 * Math.max(lie, 0); const shAlpha = 0.1 + 0.16 * Math.max(lie, 0); return (
{/* 根部投影贴在页面上,不随卡片立起 */}
); }; export const PopupBookRise: React.FC = () => { const frame = useCurrentFrame(); // 场景(书页)俯视角:全程 75°,全部立起后轻微回正到 68° const sceneRx = interpolate(frame, [SETTLE, REST], [75, 68], { easing: Easing.inOut(Easing.cubic), extrapolateLeft: 'clamp', extrapolateRight: 'clamp', }); return (
{/* 书页底板:dashboard 的壳(侧栏+顶栏+空白页面) */}
{Array.from({ length: 7 }).map((_, i) => (
))}
{/* 6 张纸片卡沿底边立起 */} {Array.from({ length: 6 }).map((_, i) => ( ))}
); };