
OpenMontage 标记高亮动画指南用纯 CSS GSAP 复刻 MarkerHighlight 五种绘制模式【免费下载链接】OpenMontageWorlds 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/OpenMontageOpenMontage 将 HyperFrames 动画技能库 中的 CSS 标记模式规则固化为可直接复用的一组原子配方以纯 CSS 初始状态 GSAP 时间线驱动实现 MarkerHighlight.js 的全部五种手绘标注效果划词高亮、圆圈圈注、放射爆裂、波浪下划线、叉号划除在 HyperFrames 逐帧 seek 的渲染模型下做到完全确定、无外部库依赖。读完本文你将掌握五种模式的完整 HTML/CSS/JS 实现、其参数调优方法以及如何在字幕强调词与多组文本中轮换它们以控制视觉节奏。背景为什么在 HyperFrames 中用纯 CSS GSAP代替 MarkerHighlight.jsHyperFrames 是 OpenMontage 中从 HTML 渲染视频的运行时方案一段合成的本质是一个 HTML 文件DOM 用data-*属性声明时间动画运行时必须可被任意时刻直接 seek媒体播放由框架托管。其确定性渲染契约要求同一输入时间 → 同一帧像素渲染器对每一帧都是全新的采样确定性渲染规则不存在从上一帧播放到这一帧的累积过程。MarkerHighlight.js 这类库绘制方案在 seek 驱动的渲染器里会有状态不同步的风险因此本文档以纯 CSS GSAP重写其全部五种绘制模式初始/结束状态全部由静态 CSS 表达布局契约先写死可见终态再从该状态动画运动仅发生在属性白名单内scaleX/scaleY、rotation、opacity等变换别名与颜色类属性绝不 tweenwidth/height/top/left这类触发回流或与确定性渲染冲突的属性全程不使用Math.random()/Date.now()/performance.now()与事件驱动动画被编排进一条 paused 的 GSAP 时间线注册到window.__timelines由 HyperFrames 负责 seek。时间线骨架遵循 GSAP 适配器 的约定window.__timelines window.__timelines || {}; var tl gsap.timeline({ paused: true }); // 渲染时长由根元素>span classmh-highlight-wrap span classmh-highlight-bar idhl-1/span span classmh-highlight-texthighlighted text/span /span.mh-highlight-wrap { position: relative; display: inline; } .mh-highlight-bar { position: absolute; top: 0; left: -6px; right: -6px; bottom: 0; background: #fdd835; opacity: 0.35; transform: scaleX(0); transform-origin: left center; border-radius: 3px; z-index: 0; } .mh-highlight-text { position: relative; z-index: 1; }// Sweep in from left tl.to(#hl-1, { scaleX: 1, duration: 0.5, ease: power2.out }, 0.6); // Optional: skew for hand-drawn feel // gsap.set(#hl-1, { skewX: -2 });实现要点层叠关系色带z-index: 0、文字z-index: 1且文字必须position: relative才能参与 z 轴层叠——这是划在字后的关键左右各外扩 6pxleft/right: -6px让色带略微超出文字两端更像真实荧光笔的落笔扫出方向由transform-origin: left center决定保持初始scaleX(0)动画只 tweenscaleX到 1属于合成器廉价属性可安全 seekborder-radius: 3px圆滑两端想让笔触更手绘可在进入时用gsap.set预置skewX: -2的微小倾斜需先设置skewY兼容时把skewX一起放 transform。多行高亮stagger 逐行扫过跨多行文本时对每组mh-highlight-bar做 stagger让每行色带依次扫出tl.to( .mh-highlight-bar, { scaleX: 1, duration: 0.5, ease: power2.out, stagger: 0.3, }, 0.6, );stagger: 0.3表示行与行之间相隔 0.3s文档示例中整组 tween 放在时间线0.6秒处保证先出现/播完其他元素再做行级扫光。若某行 HTML 里 bar 和 text 顺序错乱导致 z-index 失效检查是否给 text 加了position: relative。2. Circle手绘圆圈 / 椭圆圈注用一个带轻微旋转的border-radius: 50%环把关键词圈起来出现时带弹性回摆模拟手绘画圈的有机感。span classmh-circle-wrap span classmh-circle-text idcircle-wordIMPORTANT/span span classmh-circle-ring idcircle-1/span /span.mh-circle-wrap { position: relative; display: inline; } .mh-circle-text { position: relative; z-index: 1; } .mh-circle-ring { position: absolute; top: 50%; left: 50%; width: 130%; height: 160%; transform: translate(-50%, -50%) rotate(-3deg) scale(0); border: 3px solid #e53935; border-radius: 50%; pointer-events: none; z-index: 0; }// Circle scales in with a wobble tl.to( #circle-1, { scale: 1, rotation: -3, duration: 0.6, ease: back.out(1.7), transformOrigin: center center, }, 0.7, );实现要点圆环定位在 wrap 正中心top/left: 50%translate(-50%, -50%)再以百分比宽高130% × 160%相对文字盒子缩放天然适配不同词长初始 transform 已含rotate(-3deg) scale(0)动画把scale抬到 1 并把rotation固定为-3——负度数的歪让圆看起来像人手画的而不是几何正圆弹性手感来自back.out(1.7)先冲过头再回落。transformOrigin须为center center以保证绕圆心缩放pointer-events: none保证装饰环不拦截交互虽然 HyperFrames 渲染期无输入事件但对复用同一 HTML 做浏览器演示时有意义。三种变体紧圆、圆角方、扁椭圆按词形选择比例与圆角/* Tighter circle (for short words) */ .mh-circle-ring.tight { width: 150%; height: 180%; } /* Squared circle (rounded rectangle) */ .mh-circle-ring.rounded { border-radius: 30%; width: 120%; height: 140%; } /* Ellipse (wider than tall) */ .mh-circle-ring.ellipse { width: 150%; height: 130%; border-radius: 50%; }.tight用于短词让圆更包字宽度收到 150%、高度拉到 180%.rounded是圆角矩形border-radius: 30%取代 50%更像 PPT 里的标注框.ellipse用于较长词或需要横向拉宽的场合150% 宽 × 130% 高。3. Burst从文字中心放射的爆裂线文字发光/爆发时的经典处理若干细线从中心向四周放射并逐根描出。每条线都是一个绝对定位、围绕中心旋转到各自角度的 div。span classmh-burst-wrap span classmh-burst-textWOW/span span classmh-burst-container idburst-1 span classmh-burst-line style--angle: 0deg; --len: 70px;/span span classmh-burst-line style--angle: 30deg; --len: 55px;/span span classmh-burst-line style--angle: 60deg; --len: 80px;/span span classmh-burst-line style--angle: 90deg; --len: 45px;/span span classmh-burst-line style--angle: 120deg; --len: 65px;/span span classmh-burst-line style--angle: 150deg; --len: 75px;/span span classmh-burst-line style--angle: 180deg; --len: 50px;/span span classmh-burst-line style--angle: 210deg; --len: 60px;/span span classmh-burst-line style--angle: 240deg; --len: 80px;/span span classmh-burst-line style--angle: 270deg; --len: 40px;/span span classmh-burst-line style--angle: 300deg; --len: 70px;/span span classmh-burst-line style--angle: 330deg; --len: 55px;/span /span /span.mh-burst-wrap { position: relative; display: inline; } .mh-burst-text { position: relative; z-index: 2; } .mh-burst-container { position: absolute; top: 50%; left: 50%; width: 0; height: 0; z-index: 1; } .mh-burst-line { position: absolute; display: block; width: 3px; height: var(--len); background: #1e88e5; left: -1.5px; top: calc(-1 * var(--len)); transform: rotate(var(--angle)); transform-origin: bottom center; opacity: 0; }// All lines burst outward simultaneously with slight stagger tl.fromTo( #burst-1 .mh-burst-line, { scaleY: 0, opacity: 0 }, { scaleY: 1, opacity: 1, duration: 0.4, ease: power2.out, stagger: 0.03 }, 0.7, );实现要点CSS 自定义属性驱动几何每根线用内联--angle旋转角与--len线长声明CSS 里height: var(--len)、top: calc(-1 * var(--len))、transform: rotate(var(--angle))各司其职——HTML 即数据符合 HyperFrames 数据可先于渲染期计算的思路旋转锚点容器被压缩成中心一点width/height: 0 50%/50% 定位线的transform-origin: bottom center让它以底端为轴旋转使所有线的根部聚拢于同一中心left: -1.5px是线宽 3px 的负一半用于水平居中这条旋转线动画用fromTo因静态样式里opacity: 0需显式给出起止值scaleY: 0→1、opacity: 0→1stagger: 0.03让 12 条线在约 0.36s 内依次弹出形成放射节奏。这里scaleY从底部生长视觉上即从中心刺出。调优建议线长在 40–80px 区间做变化示例中 40/45/50/55/60/65/70/75/80 交错才有手绘的有机感等长的放射线看起来非常机械。想更炸可提高 stagger 间隔或缩短单线 duration。4. Scribble会自己画出来的波浪下划线用一段 wavy 的 SVG path 放在文字底部靠stroke-dashoffset让线条从一端画到另一端做出手抖的波浪下划线改定位即可做删除线。span classmh-scribble-wrap span classmh-scribble-textunderlined text/span svg classmh-scribble-svg viewBox0 0 500 24 preserveAspectRationone path idscribble-1 dM0,12 Q31,0 62,12 Q93,24 125,12 Q156,0 187,12 Q218,24 250,12 Q281,0 312,12 Q343,24 375,12 Q406,0 437,12 Q468,24 500,12 fillnone stroke#FDD835 stroke-width3 stroke-linecapround / /svg /span.mh-scribble-wrap { position: relative; display: inline; } .mh-scribble-text { position: relative; z-index: 1; } .mh-scribble-svg { position: absolute; left: 0; bottom: -6px; width: 100%; height: 24px; z-index: 0; }// Measure path length and set initial dash state var path document.querySelector(#scribble-1); var len path.getTotalLength(); gsap.set(path, { strokeDasharray: len, strokeDashoffset: len }); // Draw the line tl.to( #scribble-1, { strokeDashoffset: 0, duration: 0.8, ease: power1.inOut, }, 0.7, );实现要点绘制自绘核心getTotalLength()取路径实际长度 →strokeDasharray len让整个线段变成一段与路径等长的虚线 → 初始strokeDashoffset len把虚线段完全藏到路径终点之后 → 动画把strokeDashoffset归零即模拟描线。这是 stroke-dash 系列技巧同技能库中的 svg-path-draw.md 有更广泛的用法路径几何即节奏viewBox0 0 500 24下的 path 以二次贝塞尔Q在y0与y24间交替摆动、波峰统一在y12preserveAspectRationonewidth:100%使波形成比例拉伸贴合文字宽度SVG 用bottom: -6px沉到文字基线下方z-index: 0位于文字之下无碍手绘压在字上/字下由需求决定此处示例为字下stroke-width: 3stroke-linecap: round让笔触两端圆润更像马克笔。代码细节提醒原文 HTML 片段以span开始、以/div收尾。为保证渲染正确请以/span一致闭合本规则面向可复用原子配方建议以 div 包裹时整体用 div。删除线变体把 SVG 从bottom: -6px改到垂直居中.mh-scribble-svg.strike { top: 50%; transform: translateY(-50%); bottom: auto; }即定位为top: 50%; transform: translateY(-50%)波浪线就落在文字的垂直中线上变成删除线。波浪路径生成器参数按文字宽度缩放 viewBox 宽度即可让波浪适配任意词长。波形的Q x1,y1 x2,y2在y0与y24间交替通过控制点决定疏密密波tight waves更小的 x 步进约每半波 25px疏波loose waves更大的 x 步进约每半波 50px振幅Amplitude改 y 取值范围即可——0–24 为标准振幅0–16 为含蓄的浅波。5. Sketchout交叉划线划除旧值用于旧价格被划掉这类去强调场景两道分别朝前斜、朝后斜的划线先后扫过文字形成手写叉号。文字本身保持可见但 z-index 低于划线层。span classmh-sketchout-wrap span classmh-sketchout-textold price/span span classmh-sketchout-lines idsketchout-1 span classmh-sketchout-line mh-sketchout-fwd/span span classmh-sketchout-line mh-sketchout-bwd/span /span /span.mh-sketchout-wrap { position: relative; display: inline; } .mh-sketchout-text { position: relative; z-index: 0; } .mh-sketchout-lines { position: absolute; top: 0; left: -4px; right: -4px; bottom: 0; overflow: hidden; z-index: 1; } .mh-sketchout-line { position: absolute; display: block; top: 50%; left: 0; width: 100%; height: 2px; background: #e53935; transform-origin: left center; transform: scaleX(0); } .mh-sketchout-fwd { transform: scaleX(0) rotate(-12deg); } .mh-sketchout-bwd { transform: scaleX(0) rotate(12deg); }// Forward slash draws first tl.to( #sketchout-1 .mh-sketchout-fwd, { scaleX: 1, duration: 0.3, ease: power2.out, }, 1.0, ); // Backward slash follows tl.to( #sketchout-1 .mh-sketchout-bwd, { scaleX: 1, duration: 0.3, ease: power2.out, }, 1.15, );实现要点层叠方向与其他模式相反文字z-index: 0、划线层z-index: 1——划线确实压在文字上而文字仍保留供阅读弱化而非遮挡划线层.mh-sketchout-lines铺满文字盒子上下满铺、左右外扩 4px并以overflow: hidden剪掉画到盒外的部分保证斜线只出现在文字范围内每条线是一根水平 2px 高的细棍通过scaleX(0→1)从left center向右生长同时静态rotate(-12deg)/rotate(12deg)给出正反斜角——划线本身也像被手写出来顺序即语义先fwd1.0s 处0.3s再bwd1.15s 处一前一后组成打叉的先后笔顺。若需要更真实的笔顺感可以让两条线错开更多、或在中间插入一个极短的提笔停顿。在字幕Captions组中轮换模式控制强调节奏单一模式重复 8 次会疲劳。规则文档给出的标准做法是按字幕分组做模式轮换让每个分组的强调词获得不同的视觉口音var MODES [highlight, circle, burst, scribble]; GROUPS.forEach(function (group, gi) { var mode MODES[gi % MODES.length]; // Apply the modes CSS pattern to emphasis words in this group group.emphasisWords.forEach(function (word) { applyMode(word.el, mode, tl, word.start); }); });用gi % MODES.length让模式随分组索引自动循环applyMode(word.el, mode, tl, word.start)将具体模式的样式类 对应 tween 挂到时间线的正确时间位置word.start上节奏档位高能high energy每 2–3 组轮换一次中能medium每 3–4 组轮换一次低能low每 4–5 组轮换一次。轮换本身完全确定模式序列由分组索引推得不依赖随机数与运行时状态天然符合 seek 渲染。与 OpenMontage 体系的整合与进一步阅读动画编排入口本规则属于 hyperframes-animation 技能库可通过其 rules-index.md 检索其他原子运动规则如同库的 svg-path-draw.md、gsap-effects.md并阅读 技术总览 了解更高层的运动设计方法运行时约束依据五种模式全部只 tween 变换别名与stroke-dashoffset其合法性与确定性要求见 GSAP 适配器 的属性白名单与 确定性渲染规则其中特别提醒scaleX/scaleY/transform对内联span无效被变换元素必须是块级且带真实宽高——本文档中各模式已通过position: absolute; display: block或显式width/height规避此坑色彩令牌化模式示例中的硬编码色值#fdd835等可直接升级为 OpenMontage 的 HyperFrames style bridge 在render_runtime hyperframes时输出到:root的 CSS 自定义属性如--color-accent、--color-primary这样强调色会随 playbook 自动切换而不是手工埋死在规则里——该桥接器同时会为工作区生成一份 DESIGN.md其中明确建议组合内通过var(...)引用令牌渲染管线侧HyperFrames 合成的编排与渲染可经 tools/video/hyperframes_compose.py 进入 OpenMontage 视频生产管线其合成结果有对应的契约测试如 tests/tools/test_hyperframes_compose.py与 QA 用例覆盖。常见坑与自查清单变换无效果对display: inline的 span 做scaleX/rotate会静默失败。给装饰元素position: absolute并display: block 显式尺寸z-index 不生效文字要与装饰层在同一层叠上下文内参与排序务必给文字设position: relative圆环/扫光则z-index: 0文字z-index: 1动画了布局属性出现/划除/扫光只动scaleX/scaleY/rotation/opacity/strokeDashoffset绝不 tweenwidth/height/top/left——静态布局交给 CSS运动交给变换时间线进异步所有 tween 必须在同步初始化阶段挂到 paused 时间线applyMode这类帮助函数也应只做同步 DOM 与时间线操作随机与无穷循环线长变化、角度变化都写死在 HTML/CSS/数据里需要随机感时使用种子化伪随机不要用repeat: -1非确定性测量Scribble 模式对getTotalLength()的调用属于初始化时一次性计算是可接受的但禁止在 tween 执行期调用getBoundingClientRect()等派生坐标的方法渲染器并行采样会失步后划线的元素越界Circle 的back.out(1.7)会冲出静止尺寸、Sketchout 斜线会超出文字盒为其按峰值尺寸预留空间并配合overflow: hidden裁切避免误伤邻层。完成组合后可用技能库自带的审计脚本node .agents/skills/hyperframes-animation/scripts/animation-map.mjs composition-dir --out composition-dir/.hyperframes/anim-map枚举全部 tween、采样包围盒并输出死区/节奏一致性报告再交付渲染。【免费下载链接】OpenMontageWorlds 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),仅供参考