在 HyperFrames 中实现 Motion-Blur Streak:为 seek 式渲染器伪造定向速度模糊的完整规则
【免费下载链接】OpenMontageWorld's first open-source, agentic video production system. 12 production pipelines, 100+ tools, 700+ agent skill and production-knowledge files. Turn your AI coding assistant into a full video production studio.项目地址: https://gitcode.com/GitHub_Trending/op/OpenMontage
导读
Motion-Blur Streak(运动模糊拖尾)是 OpenMontage 仓库所内嵌的hyperframes-animation技能中一条用于制作"快速入场 / 镜头推近"动效的原子规则(位于.agents/skills/hyperframes-animation/rules/motion-blur-streak.md)。由于 HyperFrames 的渲染器是"可被 seek 的"(按帧采样、时间线可跳转),它没有真实运动模糊所需的快门积分概念,因此这条规则用假模糊模拟出"元素拖着速度残影冲入画面、落位瞬间骤停变清晰"的打击感。读完本文你将掌握两种实现路径(定向 SVGfeGaussianBlur模糊 / 回声鬼影拖尾)、配套的 HTML/CSS/GSAP 代码骨架、全部关键参数的取值区间,以及它与 seek 安全、确定性渲染契约之间的耦合约束,可直接在 HyperFrames 场景(scene)HTML 中落地使用。
一、为什么"真正的运动模糊"在 HyperFrames 里不可行
HyperFrames 的渲染哲学是从 HTML 生成视频:一个合成场景就是一个 HTML 文件,DOM 用data-*属性声明时序(data-start、data-duration、data-track-index、data-composition-id),动画运行时是可 seek 的——渲染器会在任意时间点采样画面,如同把一条暂停的时间线拨到某个位置。真实运动模糊是对快门时间内画面做积分,而"暂停的时间线"没有快门的概念,因此 per-frame(逐帧)真实运动模糊对 seek 渲染器不可用。
这条规则的解决方案是伪造它:用于快速元素飞入或硬切镜头推近场景。模糊度在最高速度时达到峰值、并在落位时归零——元素看起来是"拖着一道速度残影冲进来,到达瞬间骤停、锐利清晰"。整个效果的关键在于耦合:模糊包络与位移补间(tween)共享同一条缓动曲线和同一个时间窗口,于是"峰值模糊恰好落在峰值速度上",元素一停下就瞬间清晰。
值得强调的是,HyperFrames 技能家族在 OpenMontage 中是作为一组完整技能目录引入的(其版本来源与同步记录见.agents/skills/hyperframes/PROVENANCE.md),而本规则属于其中hyperframes-animation的原子规则集——按.agents/skills/hyperframes-animation/SKILL.md的编排,动画技能的工作方式是"从 rules 索引里挑 2–4 条规则,用一条暂停的 GSAP 时间线把它们粘合"。在.agents/skills/hyperframes-animation/rules-index.md中,本规则被收录在 "Transition & Motion"(转场与运动)分类下,与之同类的还有kinetic-beat-slam、spring-pop-entrance、depth-of-field-blur等,因此它天然是这些"运动感"规则的互补选项。
二、规则适用范围
这条规则服务的是入场与镜头中段运动,典型场景包括:
- 快速到达(fast arrival):短语、字形或品牌字标从画框外/景深后冲入;
- 一个节拍从镜头前高速掠过(a beat that zooms past camera);
- 卡片砸进网格卡槽(
grid-card-assemble); - Logo 从虚焦中"穿透"进字标组合(
logo-assemble-lockup)。
它有明确的禁用边界:绝不可用于非最后一帧的出场——一个模糊元素在合成中途冲出画框会被读成"故障"(glitch);而场景与场景之间的硬切出场是转场的职责(参见.agents/skills/hyperframes-animation/transitions/overview.md),不属于单元素模糊的范畴。
两种实现路径一览
| 路径 | 机制 | 适用场景 | 代价/取舍 |
|---|---|---|---|
| A. 定向 SVG 模糊 | 内联<filter>+<feGaussianBlur stdDeviation="X 0">(X 沿运动轴,0 垂直运动轴),GSAP 通过代理对象把X从峰值补间到 0,onUpdate每帧写回setAttribute | 推荐默认值,追求"真正的定向涂抹"观感 | 需要 filter region 足够大避免裁切;一个元素即完成 |
| B. 回声 / 鬼影拖尾 | 2–4 个不透明度递减的重复副本,沿运动向量向后错开,随落位收拢进主角元素 | 想要"彩色 / 风格化"的拖尾而非字面光学模糊 | 无滤镜开销;读出"速度线"式频闪拖尾 |
两者都有限、确定、可安全 seek——这是它们能进 HyperFrames 合成的前提。
三、工作原理:让模糊包络骑在速度曲线上
快速运动有它的速度剖面:起步加速、峰值、减速直至落位。out族缓动(expo.out、power4.out)把速度前置——起步瞬间速度最高,末端趋零。伪造模糊的关键就是把模糊(或回声)包络映射到同一条曲线上:
- 位移补间——元素从画框外/推后位置移动到静止变换(飞入用
x/y,推近用scale),采用快速out缓动,持续MOVE_DUR; - 模糊包络——与位移同一窗口、同一缓动,涂抹值从
PEAK_BLUR→0。因为缓动前置了速度、包络共享这条曲线,最大模糊与最大速度恰好重合,元素落位时模糊正好归零; - 落位即清晰——到
MOVE_START + MOVE_DUR时刻,元素位于静止变换且模糊为 0(路径 A),或所有回声收拢进主角(路径 B),随后以完全清晰的姿态停留在高潮驻留(climax dwell)阶段。
路径 A 是通过代理对象补间滤镜的stdDeviation属性(它是一个非 DOM-style 的数字属性):GSAP 无法直接补间 SVG 属性,所以要补间一个普通{ v: PEAK_BLUR }对象,并在onUpdate中调用setAttribute写回。路径 B 则将鬼影放置在确定的向后偏移(i * ECHO_STEP_PX)上,并在同一包络上淡出/收拢。
从代码结构看,这正对应 GSAP 适配器的通用约定:动画注册到
window.__timelines["<composition-id>"],时间线必须paused: true,供 HyperFrames 运行时统一 seek(详细契约参见.agents/skills/hyperframes-animation/adapters/gsap.md与.agents/skills/hyperframes-animation/adapters/gsap-timeline-and-labels.md)。
四、HTML 骨架
所有场景根节点都遵循统一的data-*声明(data-composition-id即该场景在window.__timelines注册表中的键,本规则默认叫streak-scene)。
路径 A —— 定向 SVG 模糊(推荐默认)
<div class="scene" id="streak-scene" ><div class="scene" id="streak-scene" >.scene { position: relative; width: 100%; height: 100%; display: grid; place-items: center; background: {sceneBg}; font-family: {font}; overflow: hidden; /* 涂抹/回声在落位前会超出静止位置 */ } .streak-stage { position: relative; display: grid; place-items: center; } .streak-el { position: relative; z-index: 2; font-size: EL_FONT_SIZE; font-weight: 900; letter-spacing: EL_TRACKING; color: {textColor}; /* 路径 A 专用——引用定向滤镜(路径 B 请省略此行) */ filter: url(#streak); will-change: transform, filter; } /* 路径 B 鬼影——与主角同形的字形,透明度递减 */ .streak-ghost { position: absolute; inset: 0; display: grid; place-items: center; z-index: 1; font-size: EL_FONT_SIZE; font-weight: 900; letter-spacing: EL_TRACKING; color: {textColor}; opacity: 0; will-change: transform, opacity; pointer-events: none; }设计取向上,拖尾效果要求:元素要足够厚重(大号加粗字形,涂抹才有"质量"可拖)、背景要足够干净(纯色或低细节场,忙碌背景会吞掉涂抹)。
六、GSAP 时间线
路径 A —— 代理补间写回 SVG 属性
<!-- GSAP 3.x 全局 gsap 对象由运行时/脚手架按适配器约定引入(见 hyperframes-animation/adapters/gsap.md) --> <script> window.__timelines = window.__timelines || {}; const tl = gsap.timeline({ paused: true }); // GSAP 不能直接补间 SVG 属性——补间代理对象,每帧写回。 const blurNode = document.getElementById("streak-blur"); const blurProxy = { v: PEAK_BLUR }; const writeBlur = () => blurNode.setAttribute("stdDeviation", `${blurProxy.v} 0`); // 仅 X 轴 writeBlur(); // 首帧预置:seek 到 t=0 时应显示"已涂抹的起始",而不是一瞬间清晰的前置帧 // 位移:以快速 out 缓动(速度前置)从画框外移动到静止位 tl.fromTo( "#streak-el", { x: ENTER_FROM_X, opacity: 0 }, { x: 0, opacity: 1, duration: MOVE_DUR, ease: MOVE_EASE }, MOVE_START, ); // 模糊包络:SAME 窗口 + SAME 缓动,峰值模糊==峰值速度,落位归零 tl.to(blurProxy, { v: 0, duration: MOVE_DUR, ease: MOVE_EASE, onUpdate: writeBlur }, MOVE_START); window.__timelines["streak-scene"] = tl; </script>这段代码示范了两个 HyperFrames 级技巧:代理补间(GSAP 只补间普通对象属性,onUpdate写回setAttribute)与首帧预置(writeBlur()在 setup 时执行一次,保证 seek 到第 0 帧渲染的是拖尾起点而非瞬间清晰的前置帧)。
路径 B —— 确定性鬼影收拢
<script> window.__timelines = window.__timelines || {}; const tl = gsap.timeline({ paused: true }); // 主角:与路径 A 相同的快速 out 位移 tl.fromTo( "#streak-el", { x: ENTER_FROM_X, opacity: 0 }, { x: 0, opacity: 1, duration: MOVE_DUR, ease: MOVE_EASE }, MOVE_START, ); // 鬼影:每个都从沿运动向量更靠后的位置(按索引确定)出发、更暗, // 并在同一缓动/窗口内收拢到主角上——落位时刚好全部消失。 const ghosts = gsap.utils.toArray(".streak-ghost"); ghosts.forEach((g) => { const i = Number(g.dataset.i); // 1..N-1,在 HTML 中设定(无 Math.random) tl.fromTo( g, { x: ENTER_FROM_X - i * ECHO_STEP_PX, opacity: GHOST_BASE_OPACITY / i }, { x: 0, opacity: 0, duration: MOVE_DUR, ease: MOVE_EASE }, MOVE_START, ); }); window.__timelines["streak-scene"] = tl; </script>鬼影的起始偏移与透明度都由索引i决定(i * ECHO_STEP_PX与BASE / i),保证每次 seek 的画面完全一致。
七、变体(Variations)
1. 垂直拖尾(上升 / 下落入场)
把运动轴换掉:位移补间用y替代x;路径 A 用stdDeviation="0 Y"(Y 轴模糊、X 为 0);路径 B 用ENTER_FROM_Y与垂直错位偏移。一条"向上冲入位"的短语可与kinetic-type-beats的 rise-rotate 节拍搭配。
2. 镜头推近(scale 拖尾冲入字标组合)
不再平移,而是元素冲向镜头:scale: SCALE_FROM → 1配快速out缓动,用对称的stdDeviation="B B"包络近似径向 / 变焦模糊(因为涂抹是纵深向而非方向性,两个轴都要模糊):
tl.fromTo( "#streak-el", { scale: SCALE_FROM, opacity: 0 }, { scale: 1, opacity: 1, duration: MOVE_DUR, ease: MOVE_EASE }, MOVE_START, ); tl.to( blurProxy, { v: 0, duration: MOVE_DUR, ease: MOVE_EASE, onUpdate: () => blurNode.setAttribute("stdDeviation", `${blurProxy.v} ${blurProxy.v}`), }, MOVE_START, );这正是logo-assemble-lockup蓝图里的推近——字标从虚焦中"顶出"、在锁定瞬间锐利定住。
3. 网格卡片错峰拖尾入场(cards assemble)
针对grid-card-assemble:每张卡从各自的后退偏移拖入卡槽、错峰排布。所有卡共享同一条缓动/窗口,仅用索引派生延迟;入场偏移与起始时间都由卡片索引决定(不用Math.random),每张卡落进卡槽的瞬间就是清晰的:
gsap.utils.toArray(".grid-card").forEach((card, i) => { const at = MOVE_START + i * CARD_STAGGER; tl.fromTo( card, { x: ENTER_FROM_X, opacity: 0 }, { x: 0, opacity: 1, duration: MOVE_DUR, ease: MOVE_EASE }, at, ); // + 在相同 `at` 上的每卡模糊代理补间(路径 A),或每卡鬼影(路径 B) });4. 驻留拖尾(whip 强调单一节拍)
对单条"高速掠过"的动能短语,可让模糊比位置略慢一点消散:位置用expo.out、模糊用power3.out,元素先到、最后一丝涂抹再散去。默认仍是锁定包络,此变体需克制使用。
八、参数取值指南
运动类参数
| 参数 | 取值 | 效果 | 约束 |
|---|---|---|---|
| MOVE_EASE | expo.out(最硬 snap)→power4.out(硬砸,默认)→power3.out(硬但稍柔) | out越硬 → 速度越前置 → 拖尾读起来越锐利、越晚才消解 | 必须out族(速度前置);inOut/in会把峰值速度放到中/后期,模糊-速度耦合断裂。位置与模糊必须同缓动(除非刻意用 Hold-the-streak) |
| MOVE_DUR | 0.25–0.6 s | 越短越暴力甩入;越长越像滑入,拖尾失去冲击 | 拖尾必须"快"——超过约 0.7 s 就不像速度模糊,而像对焦拉动 |
| MOVE_START | 时间线中的入场点 | — | 在MOVE_START + MOVE_DUR之后须留≥1 s 驻留再结束合成(高潮 dwell);若拖尾落在t = DURATION − 0.2 s会读成"一闪而过" |
| ENTER_FROM_X / Y | 元素在该轴上自身尺寸的 40–120% | 越大 → 行程越长 → 拖尾有更多跑道可读;太小则没有速度感 | 必须足够远以读成"从画框外来" |
路径 A —— SVG 模糊
| 参数 | 取值 | 效果 | 约束 |
|---|---|---|---|
| PEAK_BLUR | 8(轻微)→ 18(默认)→ 30(极端甩动) | 越高 → 峰值速度处涂抹越重 | ≤约 30,超过后元素开头几帧不可读,变成"消失后出现";滤镜区域需 ≥-50% … 200%否则涂抹在盒边缘被裁 |
| SCALE_FROM(推近变体) | 1.3(轻柔推)→ 2.5(猛烈穿透) | 决定推近的侵略性 | — |
路径 B —— 回声拖尾
| 参数 | 取值 | 效果 | 约束 |
|---|---|---|---|
| N(鬼影数) | 2–4 | 越多 → 越长越顺的涂抹;>4 读成频闪/卡顿而非拖尾 | 由 HTML 里写多少个.streak-ghost决定 |
| ECHO_STEP_PX | 12–40 px | 越大 → 拖尾越铺开可见;越小 → 更紧的"似模糊"簇 | N × ECHO_STEP_PX应 ≲ENTER_FROM_X,让最远鬼影仍落在行程跑道内 |
| GHOST_BASE_OPACITY | 0.3(淡)→ 0.6(重) | 最近鬼影(i = 1)的不透明度,按BASE / i衰减 | ≤约 0.6,否则不透明鬼影会读成重复元素而非拖尾 |
版式与排布
| 参数 | 取值 | 说明/约束 |
|---|---|---|
| EL_FONT_SIZE / EL_TRACKING | 1080p 下建议 ≥120 px、字重 ≥800 | 厚重展示字重才能让涂抹有质量可拖;细字会被涂抹吞没到不可见 |
| CARD_STAGGER(网格变体) | 0.05–0.12 s | 足够紧才能读成"一波组装",而不是若干次独立到达 |
模板令牌(Tokens)
| 令牌 | 含义 |
|---|---|
{sceneBg} | 背景;纯色/低细节场下拖尾最清晰(繁忙背景会与涂抹互抢注意力) |
{font} | 字体栈;拖尾元素若是文字,建议内嵌展示字面(见.agents/skills/hyperframes-creative/references/typography.md) |
{textColor} | 元素颜色;路径 B 中鬼影继承此色,若要更淡的拖尾可单独着色.streak-ghost |
{phrase} | 拖入的文字 / 字形 / 字标 |
九、关键原则
- 模糊峰值落在峰值速度、落位归零——这是规则全部精髓。位移补间与模糊/回声包络必须共享缓动与窗口,二者锁定。若元素停止后模糊还滞留,或模糊在元素已减速后才达到峰值,读出来的是"对焦拉动"而非速度。
- 始终用
out族缓动——速度必须前置(起步即快、减速进场)。expo.out/power4.out/power3.out。in或inOut会把峰值速度放错位置,耦合随即失效。 - 模糊只沿运动轴定向(路径 A)——横向用
stdDeviation="X 0",纵向用"0 Y",仅纵深/缩放推近才用"B B"。侧向移动配对称模糊看起来像失焦,而不是速度。 - 补间代理、写回属性(路径 A)——GSAP 补间普通
{ v }对象,onUpdate里setAttribute("stdDeviation", …);SVG 属性无法被直接补间,且 setup 时必须预置一次,让 seek 到t=0就显示拖尾起点。 - 鬼影按索引全确定(路径 B)——偏移
i * ECHO_STEP_PX、透明度BASE / i,绝不用Math.random生成拖尾,每次 seek 画面一致。 - 只做入场、绝不做合成中段出场——拖尾是一种"到达"。非末帧离开的模糊元素读起来是故障;场景间出场交给转场(
.agents/skills/hyperframes-animation/transitions/overview.md)。 - 配得上这段锐利驻留——骤停后,清晰元素必须驻留 ≥1 s。"暴烈拖尾 ↔ 静止锐利落位"的对比本身就是效果。
- 重元素、干净底——细字与忙碌背景都会吞掉涂抹;大号粗重的字块立在干净场地上才读得出来。
十、关键约束(HyperFrames 契约)
- 时间线必须暂停:
gsap.timeline({ paused: true }),绝不能tl.play()。 - 注册键 = 根节点
data-composition-id,写入window.__timelines。 - 拖尾元素(含鬼影)不得加 CSS
transition——它会独立于 HF seek 插值并造成闪烁;运动与模糊只由 GSAP 驱动。 - 无
repeat/yoyo/ infinite——拖尾是单次有限到达,只能用有限补间。 - 无
Math.random/Date.now——鬼影偏移/透明度与错峰均由索引派生,保证每次 seek 确定。 - 只用 GSAP 变换别名:
x、y、scale、rotation;绝不补间width/height/left/top。补间filter(经代理 →stdDeviation)与opacity是可安全 seek 的。 - setup 时预置 SVG
stdDeviation(路径 A)——播放前写一次,让 seek 到首帧渲染的是拖尾起点,而非一瞬间清晰的前置帧。 - 滤镜区域必须慷慨(路径 A)——
<filter x="-50%" y="-50%" width="200%" height="200%">,否则涂抹在元素盒边缘被裁切。 - 场景容器
overflow: hidden——涂抹/最远鬼影在运动途中会超出静止位置,需将其约束在画框内。
这些约束与.agents/skills/hyperframes-animation/SKILL.md顶部引用的hyperframes-core非协商规则(单一暂停时间线、data-duration决定时长、禁repeat: -1、禁gsap.set后期场景片段等)一脉相承;布局常量须在 setup 时预算、运动只用变换别名等动画工艺约定也适用于本规则。
十一、与其他规则、蓝图及技能的组合
相邻规则(Rules)
- kinetic-beat-slam.md——在节拍序列里用本条拖尾作为某一短语的入场(scale-slam 拍本质上就是一次运动模糊飞入),其起点从共享的
BEATS[]数组读取; - center-outward-expansion.md——网格拖尾入场即"中心外扩 + 每个元素行程上的速度模糊包络";
- 3d-text-depth-layers.md——给拖入的短语叠加挤出深度(深度层跟随主角的变换);
- scale-swap-transition.md——同一足迹状态互换的替代方案(本条规则服务的是从画框外/纵深"快速到达",而非形态变换)。
在 OpenMontage 仓库的既有技能体系里也能找到实际引用:skills/meta/bespoke-composition.md的组合清单中就把motion-blur-streak与kinetic-beat-slam、3d-text-depth-layers等规则并列,作为"回响幽灵拖尾"类运动效果的候选——印证了这条规则在真实合成编排中的可组合地位。
配套的 HyperFrames 技能
/hyperframes-animation——out族缓动、代理驱动的onUpdate属性补间、锁定包络协调(详见 .agents/skills/hyperframes-animation/adapters/gsap-easing-and-stagger.md);/hyperframes-creative——文字拖尾的展示字面选择(.agents/skills/hyperframes-creative/references/typography.md)与涂抹背后干净场地的构图(.agents/skills/hyperframes-creative/references/video-composition.md);/hyperframes-core——合成接线与确定性(有限补间、无Math.random);/hyperframes-cli——hyperframes lint/hyperframes validate(validate 能捕获缺失的#streak-blur节点或未被引用的滤镜,详见 .agents/skills/hyperframes-cli/references/lint-validate-inspect.md)。
十二、落地建议
把本条规则投入实际场景时,推荐的编排方式是:先在 .agents/skills/hyperframes-animation/rules-index.md 确认选中的规则组合,再按本文的 HTML/CSS/GSAP 骨架填写场景,把上表中的占位常量(MOVE_EASE、MOVE_DUR、PEAK_BLUR、ENTER_FROM_X等)预计算为确定性常量,最后用hyperframes validate校验滤镜节点与注册键。只要守住"位移与模糊包络共享同一缓动窗口""只做入场不做中段出场""落位后驻留 ≥1 s""所有随机量替换为索引派生"这四条底线,就能稳定产出那种"冲入即定格"的 HyperFrames 高速入场动效。
【免费下载链接】OpenMontageWorld's first open-source, agentic video production system. 12 production pipelines, 100+ tools, 700+ agent skill and production-knowledge files. Turn your AI coding assistant into a full video production studio.项目地址: https://gitcode.com/GitHub_Trending/op/OpenMontage
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考