// ===== demos/rhythm/speed-ramp-freeze/FreezeAnnotateReal.tsx ===== // freeze-annotate 定格标注(轮 G)——真实卡片流运动中定格, // 马克笔琥珀圈注(feTurbulence 手绘抖动)圈住目标卡 + 箭头点题,解冻继续。 // remap:0–45 流动 → 45–100 定格(斜率0)→ 100–135 解冻(1.4x 补偿)。 import { useId } from 'react'; import { AbsoluteFill, Img, interpolate, staticFile, useCurrentFrame } from 'remotion'; import layout from '../../_textures/live-layout.json'; export const FREEZEANNOTATE_DUR = 135; const CARD_W = 460; const GAP = 60; const RAIL = layout.projects.cards.slice(0, 9); const TARGET_I = 5; const AMBER = '#b45309'; export const FreezeAnnotateReal: React.FC = () => { const frame = useCurrentFrame(); // 滤镜 ID 按实例生成,多实例同场不串引(useId 的 «:» 在 url() 里非法,需清洗) const roughId = `rough-${useId().replace(/[^a-zA-Z0-9]/g, '')}`; const src = interpolate(frame, [0, 45, 100, 135], [0, 45, 45, 94], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp', }); const dx = src * 22; const draw = interpolate(frame, [52, 60], [0, 1], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }); const arrowDraw = interpolate(frame, [60, 66], [0, 1], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }); const fade = interpolate(frame, [96, 104], [1, 0], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }); // 导轨起点 -880:定格时(dx=990)目标卡 k=5 中心 = -880+2600-990+230 = 960 屏中 const X0 = -880; const targetX = X0 + TARGET_I * (CARD_W + GAP) - dx + CARD_W / 2; const C = 1750; // 椭圆周长近似 return (
{Array.from({ length: 14 }).map((_, k) => { const c = RAIL[k % RAIL.length]; const isTarget = k === TARGET_I; return ( ); })}
); }; // ===== demos/rhythm/speed-ramp-freeze/SpeedRampReal.tsx ===== // speed-ramp 变速(轮 C)——真实卡片流帧号 remap:快(斜率2.2) → // 0.2x 慢速展示窗 → 快。慢速窗中目标卡(card4-hires)清晰滑过屏中。 // blur 联动速率:快段包 blur、慢段不包,反差即"凝视感"。 import { AbsoluteFill, Img, interpolate, staticFile, useCurrentFrame } from 'remotion'; import { CameraMotionBlur } from '@remotion/motion-blur'; import layout from '../../_textures/live-layout.json'; export const SPEEDRAMP_DUR = 135; const CARD_W = 460; const GAP = 60; const RAIL = layout.projects.cards.slice(0, 9); const TARGET_I = 5; const Scene: React.FC = () => { const frame = useCurrentFrame(); // remap:0–40f 走 88 源帧(快),40–85f 走 9 源帧(0.2x),85–135f 走 110(快) const src = interpolate(frame, [0, 40, 85, 135], [0, 88, 97, 207], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp', }); const dx = src * 28; return ( {/* 偏移 717:让慢速窗中点(src≈92.4,dx≈2587)时目标卡 k=5 中心落屏中 */}
{Array.from({ length: 16 }).map((_, k) => { const c = RAIL[k % RAIL.length]; const isTarget = k === TARGET_I; return ( ); })}
); }; export const SpeedRampReal: React.FC = () => { const frame = useCurrentFrame(); const fast = frame < 42 || frame > 83; return fast ? ( ) : ( ); };