// counter-tick-sparks —— 数字跳动溅火 // 中央大计数器 0 → 12,847(easeOut 逐位跳动),每逢跳过整千的 tick 帧, // 数字顶部溅 6–10 颗大火星(初速向上 9–13px/f、重力下坠 14–18f 内坠灭); // 终值揭晓那跳翻倍 20 颗 + 数字弹 1.1x 回落。 // 结尾所有火星寿命耗尽条件卸载,真静止 ≥40f。 // 帧确定性:tick 帧从同一 easeOut 曲线预解析(模块级求出),火星 = 纯 age 闭式弹道。 import React from 'react'; import { useCurrentFrame, interpolate, Easing } from 'remotion'; import { G, TitleBlock } from '../../_fixtures/Fixtures'; const AMBER = '#b45309'; const TARGET = 12847; const COUNT_END = 78; // 计数结束帧 const easeOutCubic = (t: number) => 1 - Math.pow(1 - t, 3); const valueAt = (f: number) => Math.round(TARGET * easeOutCubic(Math.min(Math.max(f / COUNT_END, 0), 1))); const frac = (x: number) => x - Math.floor(x); const rnd = (i: number, salt: number) => frac(Math.sin(i * 12.9898 + salt * 78.233) * 43758.5453); // 预解析 tick 帧:跳过整千的那一帧 + 终值揭晓帧 const TICKS: { f: number; big: boolean }[] = (() => { const out: { f: number; big: boolean }[] = []; let prev = 0; for (let f = 1; f <= COUNT_END; f++) { const v = valueAt(f); if (Math.floor(v / 1000) > Math.floor(prev / 1000)) out.push({ f, big: false }); prev = v; } out.push({ f: COUNT_END, big: true }); // 终值揭晓 return out; })(); const SPARK_LIFE = 18; const GRAV = 0.9; export const CounterTickSparks: React.FC = () => { const frame = useCurrentFrame(); const value = valueAt(frame); // 终值揭晓弹 1.1x 回落 const popScale = 1 + 0.1 * interpolate(frame, [COUNT_END, COUNT_END + 5, COUNT_END + 16], [0, 1, 0], { easing: Easing.out(Easing.quad), extrapolateLeft: 'clamp', extrapolateRight: 'clamp', }); const TOP_Y = 452; // 数字顶缘(火星发射线) const CX = 960; return (