// 文字沿曲线流入(text-on-path)——字符沿一条上升贝塞尔曲线(像图表增长线) // 鱼贯滑入,行进中按切线角旋转;到达各自终点后再从"贴线姿态"lerp 到水平基线位 // 拼成正常标题。曲线本身随字符前进同步 evolve(dashoffset 生长)。 // 关键帧:字符 i 于 i*2 起跑、45f 沿线到达 t_i(out cubic)→ 到达后停 8f → // 12f 摆正到水平基线(y 拉平、rotate→0)→ 全部落定约 f103 → 103–150 真静止。 import React from 'react'; import { useCurrentFrame, interpolate, Easing } from 'remotion'; import { G, TitleBlock } from '../../_fixtures/Fixtures'; // 上升贝塞尔:左下 → 右上,先缓后陡(增长线形状) const P0 = { x: 200, y: 820 }; const P1 = { x: 760, y: 810 }; const P2 = { x: 1240, y: 660 }; const P3 = { x: 1500, y: 320 }; const bez = (t: number) => { const u = 1 - t; return { x: u * u * u * P0.x + 3 * u * u * t * P1.x + 3 * u * t * t * P2.x + t * t * t * P3.x, y: u * u * u * P0.y + 3 * u * u * t * P1.y + 3 * u * t * t * P2.y + t * t * t * P3.y, }; }; // 切线角(度) const tangent = (t: number) => { const u = 1 - t; const dx = 3 * u * u * (P1.x - P0.x) + 6 * u * t * (P2.x - P1.x) + 3 * t * t * (P3.x - P2.x); const dy = 3 * u * u * (P1.y - P0.y) + 6 * u * t * (P2.y - P1.y) + 3 * t * t * (P3.y - P2.y); return (Math.atan2(dy, dx) * 180) / Math.PI; }; const TEXT = 'GROWTH ALL THE WAY'; const N = TEXT.length; const CHAR_W = 46; // 64px fontWeight 800 的近似字宽 const FINAL_Y = 300; // 水平基线(标题最终落位) const FINAL_X0 = 960 - (N * CHAR_W) / 2; export const TextOnPath: React.FC = () => { const frame = useCurrentFrame(); // 曲线 evolve:随最前字符推进同步生长 const evolve = interpolate(frame, [0, 82], [0, 1], { extrapolateLeft: 'clamp', extrapolateRight: 'clamp', easing: Easing.out(Easing.quad), }); return (