// icon-field-colorize —— 灰阶图标原野错峰浮现(错峰淡入+微弹),停一拍后 // 蓝色整场极快扫翻,随后橙/绿/红三道色波依次向下扫过,终态四色横带。 // 对标 bear-app.mp4 0–3s(密帧核实:非同帧硬翻,是极快多道波纹翻色)。 import React from 'react'; import { AbsoluteFill, interpolate, useCurrentFrame } from 'remotion'; const mulberry32 = (a: number) => () => { let t = (a += 0x6d2b79f5); t = Math.imul(t ^ (t >>> 15), t | 1); t ^= t + Math.imul(t ^ (t >>> 7), t | 61); return ((t ^ (t >>> 14)) >>> 0) / 4294967296; }; // 16 个简笔图标(viewBox 0 0 24 24,纯填充),求可辨认不求精致 const SHAPES: ((c: string) => React.ReactNode)[] = [ (c) => , (c) => , (c) => , (c) => , (c) => , (c) => , (c) => <>, (c) => , (c) => , (c) => , (c) => <>, (c) => , (c) => , (c) => , (c) => <>, (c) => , ]; const COLS = 17, ROWS = 10, CELL = 110, ICON = 44; const GRAYS = ['#9a9a9a', '#7c7c7c', '#b0b0b0', '#8b8b8b']; // 四道色波:蓝覆盖全场,橙/绿/红依次覆盖更低的行带 → 终态四色横带 const WAVES = [ { color: '#5b67e8', fromRow: 0, start: 78 }, { color: '#e7a03c', fromRow: 3, start: 90 }, { color: '#34a56f', fromRow: 6, start: 100 }, { color: '#e2606b', fromRow: 9, start: 110 }, ]; export const IconFieldColorize: React.FC = () => { const frame = useCurrentFrame(); const rand = mulberry32(20260718); const icons: React.ReactNode[] = []; for (let r = 0; r < ROWS; r++) { for (let c = 0; c < COLS; c++) { const r1 = rand(), r2 = rand(), r3 = rand(); // —— 错峰浮现:分 10 批,批内再抖动 const batch = Math.floor(r1 * 10); const t0 = 4 + batch * 4 + r2 * 3; const ap = interpolate(frame, [t0, t0 + 8], [0, 1], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp', }); if (ap <= 0) continue; // 微弹:0.55 → 1.07 → 1 const easeOut = 1 - Math.pow(1 - ap, 3); const appearScale = ap < 1 ? 0.55 + easeOut * 0.52 - Math.max(0, ap - 0.72) * 0.25 : 1; // —— 色波:每道波从起始行向下快扫(行 1.4 帧 + 列微倾 + 抖动) const gray = GRAYS[Math.floor(r2 * GRAYS.length)]; let color = gray; let flipPhase = 0; // 最近一次翻色的进行度,用于 pop for (const w of WAVES) { if (r < w.fromRow) continue; const arrive = w.start + (r - w.fromRow) * 1.4 + c * 0.25 + r3 * 1.5; const p = interpolate(frame, [arrive, arrive + 3], [0, 1], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp', }); if (p > 0) { color = w.color; flipPhase = p; } } const flipPop = flipPhase > 0 && flipPhase < 1 ? 1 + Math.sin(flipPhase * Math.PI) * 0.22 : 1; const shape = SHAPES[Math.floor(r3 * SHAPES.length) % SHAPES.length]; const x = 48 + c * CELL + (r % 2) * 26; const y = 26 + r * CELL; icons.push(
{shape(color)}
, ); } } return {icons}; };