// brand-frame-snap —— figma-devmode 0:28–0:32 (brand-frame-snap) + 0:43–0:47 (frame-color-flip) // 一圈粗品牌色画框先于内容出现包住全屏 → 灰阶"录屏窗口"在框内落位 → // 停一拍 → 画框整圈蓝→绿同帧硬翻色,窗口内容同帧换布局。 // 一个 borderColor 完成章节导航/状态提示/品牌露出。 import React from 'react'; import { useCurrentFrame, spring, interpolate } from 'remotion'; import { G, FakeDashboard } from '../../_fixtures/Fixtures'; const FPS = 30; const FIGMA_BLUE = '#3E7BFA'; const DEV_GREEN = '#1BC47D'; const FLIP_FRAME = 78; // 同帧硬翻色时刻 const clamp01 = (t: number) => Math.min(1, Math.max(0, t)); const easeOut = (t: number) => 1 - Math.pow(1 - t, 3); export const BrandFrameSnap: React.FC = () => { const f = useCurrentFrame(); const mode: 'design' | 'dev' = f < FLIP_FRAME ? 'design' : 'dev'; const frameColor = mode === 'design' ? FIGMA_BLUE : DEV_GREEN; // 1) 画框先登场:厚度从 0 长到 44px(ease-out,前 18 帧) const frameGrow = easeOut(clamp01(f / 18)); const frameW = 44 * frameGrow; // 2) 窗口在框内落位:从下方 + 略缩,弹簧弹入(帧 14 起) const drop = spring({ frame: f - 14, fps: FPS, config: { damping: 16, stiffness: 110, mass: 1 } }); const winY = interpolate(drop, [0, 1], [560, 0]); const winS = interpolate(drop, [0, 1], [0.82, 1]); const winO = interpolate(drop, [0, 0.25], [0, 1], { extrapolateRight: 'clamp' }); // 3) 翻色瞬间给 2 帧白闪脉冲 + 画框轻微厚度弹跳,强化"换挡" const sinceFlip = f - FLIP_FRAME; const flash = sinceFlip >= 0 && sinceFlip < 3 ? 0.55 - sinceFlip * 0.18 : 0; const snapPulse = sinceFlip >= 0 ? Math.exp(-sinceFlip * 0.22) * Math.cos(sinceFlip * 0.9) * 10 : 0; // 模式标签 const label = mode === 'design' ? 'DESIGN' : 'DEV MODE'; return (