- AI 技能
- 媒体生成
- 视频
【免费下载链接】video-shotcraft
AI video skill for Claude Code & Codex — cinematic product videos with Remotion: 152 shot recipe cards, 209 motion previews, a production-ready template
bezier-source-converge-merge是 video-shotcraft 仓库 ui-entrance 镜头卡集合 中的一张代表性动效卡:左侧四个来源节点各由一条细贝塞尔曲线连向右侧同一汇聚点,曲线错峰 draw-on,节点沿真实曲线滑向汇聚点并三段式加速缩小("被吸进去"),强调色数据包全程沿路径滑行,吞并完成后曲线反向擦除,只留圆形徽标与逐词加深字幕。本文以该镜头卡文档为主体,结合 BezierSourceConvergeMerge.tsx 参考实现 的源码级证据,完整拆解其路径几何、时间轴编排、参数表与已知坑,帮助你把它直接复用到"多源整合 / 统一接入 / 数据汇聚"类产品的宣传镜头中,或作为模板改出属于自己的汇聚动效。
镜头卡定位与适用场景
这张卡在仓库里归属ui-entrance(UI 入场)类别,gallery/api/library.json 中收录为 157 张镜头卡之一,并配有gallery/media/bezier-source-converge-merge.mp4的 214 个 motion 预览之一。它的官方定位是:
- 适用:"多源整合 / 统一接入 / 数据汇聚"的核心机制镜头;集成、聚合、单一入口类产品的说明段落。
- 时长:约 5.6s(168f @ 30fps),导出常量即
BEZIER_SOURCE_CONVERGE_MERGE_DURATION = 168。 - 能量:中(长镜慢速推进,靠数据包滑行维持活性;吞并瞬间是唯一小高点)。
也就是说,当你的产品页面要说"我们把四个来源统一了"、"所有渠道接入同一个入口"时,与其放一句抽象文案,不如用这张卡把过程演出来——这正是该镜头卡的设计哲学。
动效意图:把抽象话变成可看的物理过程
镜头卡文档在"意图"一节把这段动效拆成三段叙事,每段有明确的起止,观众不需要旁白就能读出因果:
- 先建立通路:四条独立曲线的 draw-on 是"连上了"——四个来源分别与汇聚点产生连接关系;
- 再让来源走进同一个点:节点沿自己的曲线滑向汇聚点、缩小到 0,是"被吞并"——来源真的被吸收进去了;
- 最后擦掉通路只留徽标:曲线从左端反向擦除、只剩汇聚徽标与字幕,读作"现在只有一个"。
这一意图在源码里也有对应的"三段式收束"注释(见 BezierSourceConvergeMerge.tsx 顶部注释):曲线先由左向右 draw-on,节点沿自己的曲线滑向汇聚点并三段式加速缩小(像被吸进去),强调色数据包小圆持续沿路径滑行,吞并完成后曲线从左端反向擦除,只留圆形徽标 + 逐词加深字幕。
动效核心拆解
路径几何:一条直线段 + 一段三次贝塞尔
每条路径的d属性固定为:
M -22,y L 74,y C 186,y 214,120 332,120- 起点在画框外
x = -22(依赖 SVGoverflow: visible才能露出画框外的一截); x = 74处是来源节点的驻留位(draw-on 完成后、滑动开始前节点停的位置);- 之后一段三次贝塞尔曲线弯向汇聚点
(332, 120); - 四条路径只差起始
y(36 / 92 / 148 / 204,间距 56),所以它们的曲率天然不同,汇入角度也不同。
源码中 SRCS 常量 以中性灰阶分层定义四路(S1#111111、S2#4A4A50、S3#7A7A82、S4#A3A3AA),灰度仅用于区分来源,不参与语义。
draw-on:用 stroke-dasharray / dashoffset 模拟"接通"
曲线绘制采用 SVG 虚线技巧:
stroke-dasharray = len stroke-dashoffset = len * (1 - draw) draw = seg(t, 0.04 + i * 0.045, 0.04 + i * 0.045 + 0.17, E.outQuad)len是路径全长(直线段定长 96 + 曲线段弧长,源码中由mkPathGeom预计算);draw从 0 走到 1 时,dashoffset从len归零,虚线视觉上表现为"由左向右刷出";0.045的错峰让四条线像被依次接通而不是一起亮(约 7 帧间隔);- 缓动用
E.outQuad(见 demos/_fixtures/Motion.tsx 的缓动表),起笔快、收笔慢,符合"连线"的手感。
节点定位:沿真实曲线走,而不是两点间插值
这是整张卡最值得借鉴的技术点。节点位置不是"起点到汇聚点"的直线插值,而是沿真实贝塞尔曲线移动:
- 先在"prime 阶段"以 40 步线性扫描,求出路径上
x ≈ 74(节点驻留位)对应的路径比例f0; - 运行时
frac = f0 + (1 - f0) * conv,其中conv = seg(t, 0.34, 0.74, E.inOutCubic)是汇聚主进度; - 用
getPointAtLength(len * frac)反查路径上的实际坐标。
值得注意的是:文档中该定位依赖 SVG 的getTotalLength/getPointAtLength,而参考实现做了进一步加固——为避免 Remotion 首帧渲染时 SVG 尚未挂载布局拿不到长度(文档"已知坑"第一条),源码在 mkPathGeom 里用纯数学替代了 DOM API:把三次贝塞尔段离散成 1600 段折线建累积弧长表(误差远低于 0.01px),再用二分反查"弧长 → 参数 u"。这是纯模块级预计算,无 DOM 依赖,完全满足 Remotion 逐帧确定性渲染的要求,也就彻底规避了首帧错位跳变。
三段式缩小:44 → 15 → 0,"被吸进去"的加速感
节点尺寸不是线性缩小,而是分两段:
tt < 0.75 时:size = lerp(tt / 0.75, 44, 15) // 前 75% 行程,缓慢瘦身 tt ≥ 0.75 时:size = lerp((tt - 0.75) / 0.25, 15, 0) // 后 25% 行程,掉光后段的尺寸变化率是前段的 4 倍多,这就是"被吸进去"的加速感。配套细节:
- 字号跟着
size * 0.26同步缩(下限 4px),标签不会脱离节点; - 节点 opacity 在
conv > 0.92后才开始淡出((1 - tt) / 0.08),而conv在t = 0.74就到 1,所以节点是尺寸缩到 0 时消失而不是淡出消失——这是有意的("被吸进去"不该淡出)。
数据包:整数周期 + 相位偏移 + 中段最亮
强调色小圆(7px、#3B82F6描边 + 淡色填充)沿路径持续滑行,给长镜慢速推进提供活性:
pkCycle = (seg(t, 0.1, 0.74, E.linear) * 2) % 1走两个整数周期——必须是整数周期,否则末帧包停在半路;- 各路加
i * 0.13相位偏移,错开四路的包,避免它们排成一行同时汇入; - 透明度用
1 - |cycle - 0.5| * 0.6,让包在路径中段最亮、两端淡——避免看到包在起点凭空出现; - 数据包整体由
pkOn = seg(t, 0.1, 0.16) * (1 - seg(t, 0.7, 0.76))控制启停。
擦除:dashoffset 取负,从起点方向反向退走
吞并完成后(erase = seg(t, 0.78, 0.9, E.outQuad)),把 dashoffset 推成负值(-erase * len):
off = erase > 0 ? -erase * len : len * (1 - draw)由于 dashoffset 为负,虚线从起点方向退走,方向与 draw-on 相反,读作"通路收回"。同时路径 opacity 在(erase - 0.85) / 0.15区间内淡出,保证擦除收尾干净。
徽标与字幕:吞并时刻的"接收脉冲"
汇聚点(332, 120)处是白底圆形徽标(内含四角星占位标记,BADGE_SIZE = 34):
- 入场:
seg(t, 0.16, 0.26, E.outCubic)淡入,并从 scale 0.7 放到 1; - 吞并瞬间(t = 0.7 → 0.78)用
E.outBack顶起 +12%,再在 0.78 → 0.86 用E.outQuad减回——这是一次"接收到了"的脉冲,量级 12% 是刻意控制的(>25% 会抢过汇聚本身的注意力); - 末尾字幕 "Four sources unified" 在
t = 0.84后淡入,且采用逐词加深语法(CAP_WORDS.split(' '),每个词按capInn进度从浅灰#C9C9CE插值到黑#111111,字距随加深收紧),整行透明度随capShow淡入。
参数表(完整继承 + 源码印证)
镜头卡文档给出的参数表是全卡调参的核心,逐行都能在源码中找到对应实现:
| 参数 | 典型值 | 调节手感 |
|---|---|---|
| 来源数 | 4 条(y=36/92/148/204,间距 56) | 4 条是曲率差异明显又不打结的甜点;>6 条中间几条的贝塞尔几乎重合,汇入角读不出区别 |
| draw-on | 起点0.04+i*0.045,窗 0.17,outQuad | 0.045 的错峰约 7f;归零会读作四条线一起刷出,失去"逐路接通"的语义 |
| 汇聚窗 | 0.34→0.74(inOutCubic) | 占全片 40%,是主段落;inOut 的缓起是"启动"、缓收是"到位",换 linear 立刻变成匀速传送带 |
| 三段缩小 | 44→15px(前 75%)→ 0(后 25%) | 拐点 0.75 越靠后吸入越突然;把它挪到 0.5 会变成"一路缩小",吞并的那一下就没了 |
| 数据包周期 | 2 个整数周期(0.1→0.74 线性) | 必须是整数周期,否则末帧包停在半路;周期加密到 4 会读作数据流很急,也更容易和节点重叠 |
| 包相位偏移 | i*0.13 | 错开四路的包,避免它们排成一行同时汇入;0 会看到四个包整齐并进,像一次发车 |
| 擦除 | 0.78→0.9,dashoffset 取负 | 12f 完成;擦除必须在节点全部消失(conv=0.74 结束、节点 0.92 前淡完)之后,否则线先没了节点悬在空中 |
| 徽标脉冲 | outBack +12%(0.7→0.78)→ 回落(0.78→0.86) | 12% 是"接收到了"的量级;>25% 会抢过汇聚本身的注意力 |
补充两条源码级的关联事实:seg/lerp/E缓动表 /useT都来自 demos/_fixtures/Motion.tsx;其中useT()把当前帧映射到全片归一化进度t ∈ [0,1],末帧恰为 1,与样片渲染逐帧一致——所以上表的0.04 / 0.34 / 0.74等时间点全部是归一化比例,换帧率或换分辨率时数值不需要改动。
已知坑与规避方案
镜头卡文档的"已知坑"一节全部值得落地前仔细阅读,这里逐条保留并补充源码证据:
getTotalLength/getPointAtLength必须在 SVG 已挂到文档且完成布局之后才有效。文档记载 motion-lab 原实现用ready标志在首帧prime()里做,移植到 Remotion 时首帧渲染可能拿不到长度(fallback 写了|| 380);稳妥做法是在useEffect/layout 后再算,或预先算好常量表,否则首帧会出现一次错位跳变。参考实现正是采用了"预先算好常量表"路线(1600 段折线弧长表 + 二分反查,模块级预计算、无 DOM 依赖),彻底规避了该问题。f0精度只有 1/40:f0是 40 步线性扫描找出的"x 首次 ≥74"的比例(源码第 79–83 行,初始值f0 = 0.2,逐步上探)。曲线形状改动大时节点驻留位会偏离 74,看起来"没停在该停的地方"——改路径后要提高扫描步数或直接标定。- 节点是"缩到 0 消失"而非淡出:节点 opacity 在
conv > 0.92后才开始淡出,而 conv 在 t=0.74 就到 1,所以节点是尺寸缩到 0 时消失。这是有意的(被吸进去不该淡出),但如果把三段式拐点改晚,会看到节点在有尺寸时突然消失。 - 节点是中性灰阶占位圆,落地要换真实来源 logo:强调色只留给数据包与徽标,不要给节点上色,否则汇聚点的视觉主体被夺走。
- 坐标是绑定的一组:汇聚点
(332,120)与 SVG 视口440×240、overflow: visible绑定。改画布比例要整套重标;路径起点-22依赖overflow: visible才能露出画框外的一截。此外外层用DesignStage的 480×270 设计坐标等比放大(见 demos/README.md),卡片参数表数值都在该坐标系下标定,改合成分辨率不需要动参数。 - 字幕是占位文案:"Four sources unified" 出现在 0.84 之后。如果要配旁白,这句的出现点应对齐旁白落词而非动画节点。
参考实现与复用方式
参考实现位于 demos/ui-entrance/bezier-source-converge-merge/BezierSourceConvergeMerge.tsx,属于 2026-08 并入的 48 张 Motion 系 demo(手法研究自公开发布的产品宣传片,全部从零重写、去品牌化、占位化,来源溯源见 references/shots/ATTRIBUTION.md)。复用步骤与这批卡的通用约定一致(详见 demos/README.md):
- 把
BezierSourceConvergeMerge.tsxcopy 进你的 Remotion 项目,同时带上 demos/_fixtures/Motion.tsx(E 缓动表 / seg / lerp / rand / useT / DesignStage),并修正 import 路径; - 以 30fps / 1920×1080 注册 Composition,直接用导出的时长常量:
import { BezierSourceConvergeMerge, BEZIER_SOURCE_CONVERGE_MERGE_DURATION } from './bezier-source-converge-merge/BezierSourceConvergeMerge'; <Composition id="BezierSourceConvergeMerge" component={BezierSourceConvergeMerge} durationInFrames={BEZIER_SOURCE_CONVERGE_MERGE_DURATION} // 168 fps={30} width={1920} height={1080} />- 落地产物时把
S1–S4占位圆换成真实来源 logo,把徽标四角星换成产品标识,字幕换成真实文案(并对齐旁白落词),其余时间轴与参数可直接沿用。
小结
bezier-source-converge-merge的价值在于它把"多源整合"这一抽象语义完整翻译成了一组可调参的物理过程:draw-on 建立通路、沿真实曲线滑入、三段式加速缩小、整数周期数据包维持活性、反向擦除收束成单一徽标。其核心技法——用stroke-dasharray/dashoffset实现双向绘制、用弧长表 + 二分反查替代 DOM 依赖的getPointAtLength、用两段缓动拼出"吸入"加速感——都不依赖特定业务,可以在 video-shotcraft 的其他镜头卡与你的 Remotion 工程中自由复用。
- AI 技能
- 媒体生成
- 视频
【免费下载链接】video-shotcraft
AI video skill for Claude Code & Codex — cinematic product videos with Remotion: 152 shot recipe cards, 209 motion previews, a production-ready template
相关推荐
video-shotcraft 动效卡拆解:用贝塞尔曲线贝塞尔汇流实现"多源统一"的产品镜头
video shotcraft 动效卡拆解:用贝塞尔曲线贝塞尔汇流实现"多源统一"的产品镜头 本文以 video shotcraft 仓库中的动效卡 bezie
AI 技能媒体生成视频video-shotcraft 镜头卡深度解析:AvatarBracketCarousel 对焦框头像轮换动效的实现与调参指南
video shotcraft 镜头卡深度解析:AvatarBracketCarousel 对焦框头像轮换动效的实现与调参指南 本篇技术指南以 video sh
AI 技能媒体生成视频video-shotcraft 里程表数字滚动动效卡:odometer-digit-roll 的实现原理与调校实战
video shotcraft 里程表数字滚动动效卡:odometer digit roll 的实现原理与调校实战 在 video shotcraft 这个 R
AI 技能媒体生成视频
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考