Communitygithub.com

DawitLemmaBalcha/scenario-motion-loops

当用户需要为视频生成无缝循环的动态图形时使用,支持自定义品牌颜色,可用于标题背景、AI镜头之间的过渡、转场或形状动画,并可选择将Scenario MCP中的吉祥物、产品或角色合成到循环之上。

scenario-motion-loops 是什么?

该技能允许开发者通过纯代码方式生成无缝循环的动态图形,适用于视频制作中的标题背景、AI镜头衔接、转场和形状动画等场景。循环完全由`draw(ctx, w, h, t, P)`函数定义,以时间为输入,所有运动周期均为12秒的约数,从而确保第12秒帧与第0秒帧完全一致,实现无接缝循环。颜色完全基于品牌调色板P,修改一个颜色即可实现品牌换色,且同一代码可渲染任意分辨率。通过Scenario MCP,用户可以在循环上叠加其吉祥物、产品或角色(透明背景切图),使合成画面也保持循环。对于需要真正运动的主体,可先生成AI视频片段并移除背景,再通过ffmpeg将其与渲染的循环叠加。该技能适用于Claude Code、Cursor、Codex等平台,需要Node 18+、Playwright、ffmpeg和ffprobe环境,Scenario MCP仅在需要主体时使用。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/DawitLemmaBalcha/motion-graphics-studio/tree/HEAD/skills/motion-graphics/setup/templates/scenario-motion-loops

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

无缝循环动态图形(代码实现),可叠加Scenario MCP中的主体

概述

这里的循环是时间的纯函数。draw(ctx, w, h, t, P) 绘制 t 秒时的帧,其中每个运动的周期都是循环长度(12秒)的约数,因此12秒时的帧与0秒时的帧完全相同,片段无缝循环。无需生成任何内容:不变形、不闪烁,改变一种颜色即可完成品牌换色,同一代码可在任意尺寸下渲染。Scenario.com 上的 Motion Loops 探索页面展示了80个以这种方式制作的循环(40个背景,40个形状动画),每个都附有代码。scripts/loop-template.html 包含了这些循环所依赖的相同辅助函数(M.*)、调色板(P)和 tile(...) 注册方法,因此它们的切片代码可以在其中无修改运行。

Scenario MCP 提供了代码无法绘制的内容:用户的主体。吉祥物、产品或角色以透明背景切图的形式从 Scenario 输出,循环页面将其绘制在循环之上,并使用循环自身的时钟,因此可以获得相同的运动模糊效果,合成画面仍保持循环。对于真正需要运动的主体,会从该切图生成AI视频片段,在Scenario中移除其背景,然后通过 ffmpeg 将片段叠加在渲染的循环上。循环本身无需模型,渲染成本为零。

需要 Node 18 或更高版本、Playwright(npm install playwright,然后 npx playwright install chromium;如果已安装 Google Chrome,可使用 --channel chrome)、ffmpeg 和 ffprobe。仅当需要主体时才需要 Scenario MCP。连接、模型选择和生成循环:如果已安装 scenario 技能,则使用它;否则参考 references/scenario-mcp.md。

快速参考

cp scripts/loop-template.html loop.html            # 每个文件一个循环:设置、draw()、叠加
# 在浏览器中打开 loop.html:实时预览;?t=3 冻结画面,?tone=accent 或 ?tone=light 切换色调
node scripts/render-loop.mjs loop.html --check     # 确定性检查和循环接缝,不生成视频
node scripts/render-loop.mjs loop.html --stills look --at 0,3,6,9             # 生成静止帧以供查看
node scripts/render-loop.mjs loop.html --out loop.mp4                          # 12秒,1920x1080,24 fps
node scripts/render-loop.mjs loop.html --params "overlay=subject.png" --out loop.mp4   # 带切图
node scripts/render-loop.mjs loop.html --width 1080 --height 1920 --out loop-9x16.mp4  # 竖屏
node scripts/render-loop.mjs --qa loop.mp4 composite.mp4   # 对任意MP4进行接缝和格式检查

在已安装 Playwright 的文件夹中运行。不会覆盖现有文件,除非使用 --force。页面检查会渲染同一时刻两次(结果必须一致),将12秒整的帧与0秒帧进行比较,并将循环点处的步长与周围运动及其他周期边界处的运动进行比较。除非输出 PASS,否则渲染拒绝编码;--ignore-seam 仅用于特意设计在循环点处的剪切。

规则原因
每个周期都是12秒的约数(1、1.5、2、3、4、6、12);使用 M.phase(t, period, offset)12秒时的帧等于0秒时的帧
滚动在每周期内移动整数个图案重复分数重复会在接缝处产生跳跃
仅通过 M.rand(i, salt) 生成随机性;帧之间不使用 Math.random、Date 或状态运动模糊和检查会按乱序渲染帧
尺寸使用 u = h / 100,数量使用 w在16:9、9:16、1:1和缩略图尺寸下均正确
颜色仅来自 P(bg、fg、fg2、mid、accent、paper、ink),每种品牌颜色有三种色调通过改变 BRAND 重新品牌;通过改变色调获得对比度
缓动函数来自 M.ease,包含预备动作、过冲和停顿;仅滚动使用恒定速度经过设计的运动,而非机械运动

渲染设置(与80个循环发布时一致,也是脚本的默认值):24 fps、8个运动模糊子帧(180度快门)、2倍超采样、H.264 High、CRF 16、4:2:0、BT.709有限范围、faststart。循环闭合的图案、深度技巧和审查习惯:references/loop-craft.md。

Scenario MCP 步骤调用的方法
连接,选择团队和项目teams_list(有多个时询问用户)
导入用户自己的素材upload_asset、对每个部分的curl PUT、upload_asset_complete
选择模型recommend(txt2img、img2img、img2video、video2video),或 search
读取其输入model_schema_get
估价,用户确认后运行model_run(先 dry_run: true),然后 model_run 和 jobs_wait
获取结果asset_download,然后 curl -L -o

工作示例:品牌吉祥物漂浮在编码循环之上

目标:创建一个12秒的无缝1920x1080循环,使用品牌颜色,品牌吉祥物漂浮其中,并可选择创建吉祥物挥手的版本。

  1. 连接。 调用 teams_list。如果返回多个团队或项目,询问使用哪一个,并将其 team_id 和 project_id 传递给后续所有调用:对于已登录账户,search、model_schema_get 和 model_run 在没有它们时会拒绝运行。

  2. 首先创建循环(本地,免费)。 cp scripts/loop-template.html mascot-loop.html,将 BRAND.accent 设置为品牌颜色,保留示例切片(透视地板,一个朝向摄像头的网格流)或编写你自己的 draw()。打开文件预览,然后:

    node scripts/render-loop.mjs mascot-loop.html --check
    node scripts/render-loop.mjs mascot-loop.html --stills look --at 0,3,6,9
    

    查看静止帧。--check 必须以 PASS 结束。

  3. 导入吉祥物。 如果用户有文件,则上传:

    {
      "file_name": "mascot.png",
      "content_type": "image/png",
      "kind": "image",
      "file_size": 482113
    }
    

    (file_size 来自 wc -c mascot.png。)使用 curl 将部分 PUT 到返回的 URL,然后调用 upload_asset_complete 并传入 {"upload_id": "<upload id>"},保留资产 ID。

  4. 选择模型。 使用以下参数调用 recommend:

    {
      "capability": "img2img",
      "prompt": "参考图像中的吉祥物,全身,四分之三视角,轻盈漂浮姿势,透明背景切图,边缘干净,无阴影,无文字",
      "limit": 5
    }
    

    如果没有文件,使用 "capability": "txt2img" 并描述吉祥物。如果 next_step.type 是 ask_user,显示选项并等待。优先选择模式中具有透明背景选项的模型;否则计划在之后进行背景移除步骤。

  5. 读取模式并估价。 使用 {"model_id": "<来自 recommend 的 id>"} 调用 model_schema_get。根据模式构建参数:参考图像字段接受上传的资产 ID(如果模式要求数组则使用数组),并设置透明背景选项。然后:

    {
      "model_id": "<来自 recommend 的 id>",
      "dry_run": true,
      "parameters": {
        "prompt": "<上述提示>",
        "<参考图像字段>": ["<吉祥物资产 id>"],
        "<背景字段>": "transparent"
      }
    }
    

    告知用户价格并等待确认。

  6. 运行并下载。 使用相同的参数和 "wait": false 调用 model_run,然后使用 {"job_ids": ["<job id>"]} 调用 jobs_wait。然后使用 {"asset_id": "<asset id>", "format": "png"} 调用 asset_download,并使用 curl -L -o subject.png "<url>" 将文件下载到 mascot-loop.html 所在文件夹。在循环背景色上以100%比例打开该PNG:深色色调上的边缘光晕会显现;建议重新生成而非隐藏它们。

  7. 在画布中合成并渲染。

    node scripts/render-loop.mjs mascot-loop.html --params "overlay=subject.png" --stills look --at 0,0.75,1.5,2.25 --force
    node scripts/render-loop.mjs mascot-loop.html --params "overlay=subject.png" --out mascot-loop.mp4 --psnr 4
    

    drawOverlay() 使吉祥物以3秒的上下浮沉和6秒的左右摆动运动,并带有接触阴影,所有周期均为12的约数,因此合成画面仍保持循环;在此调整其大小和位置。脚本会检查页面、渲染288帧、编码,并检查文件的循环点。--psnr 比较一个编码帧与其无损渲染版本。

  8. 可选:吉祥物运动的镜头。 使用 "capability": "img2video" 调用 recommend,以切图的资产ID作为起始图像,提示词如“吉祥物挥手并转头,纯色平背景,锁定的摄像机,无剪切”。然后执行模式读取、估价、确认、运行、jobs_wait、下载。接着使用 "capability": "video2video" 和“从此片段中移除背景,保留带alpha通道的主体”调用 recommend,选择 WebM VP9 带 alpha 作为输出。再次执行模式读取、估价、确认、运行、下载。不带 --params overlay=... 渲染循环一次(--out loop-plain.mp4),然后使用 ffmpeg 将片段叠加到循环之上(命令在 references/scenario-mcp.md 中)。合成片段的长度与片段相同;除非片段本身循环,否则不是无缝循环。

  9. 交付 HTML(循环保持可编辑)、MP4、静止帧以及任何合成文件。

常见错误

  • 在12秒处出现接缝跳跃。 周期不是12的约数(如5秒周期),或滚动移动了2.5个重复。--check 报告 SEAM JUMP(12秒帧与0秒帧不同)。修复周期;切勿在两端进行交叉淡入淡出。
  • 在切片中使用状态、Math.random 或 Date。 相同的 t 会产生不同的帧,运动模糊子帧不一致,循环无法闭合。--check 报告 NOT DETERMINISTIC。所有计算应基于 t 和 M.rand(i, salt)。
  • 仅读取十六进制的颜色辅助函数。 P.mid 和 M.mixColor 返回 rgb() 字符串,仅支持十六进制的解析器会静默地将其转为黑色。模板的 M.rgba 和 M.mixColor 两者都能读取。
  • 快速运动时出现闪烁。 对于整帧推进,8个子帧不够;会显示步进复制的痕迹。构建中的全页滑动需要40个子帧。对于非常快的循环,增加 --samples。
  • 线框被视为杂乱。 一个3D波浪网格就曾如此;重新构建为隐藏线山脊线(每行填充自身下方的背景,从远到近绘制),看起来就是地形了。
  • 深度除以两次。 一个投影将焦距再次按深度缩放,导致场景收缩到中心。使用 M.proj 投影一次。
  • 每1.5秒采样静止帧来检查3秒周期。 这只显示了两个姿态。应在单个周期内以及循环点两侧采样(--at 11.9,11.95,0,0.05)。
  • 将所有标记视为错误。 设计好的快切(弹出、爆发)或循环点处的停顿可能触发接缝或闪烁检测。先查看帧。脚本会将循环点与周围运动以及其他周期边界进行比较,这避免了大部分此类问题:构建中的所有80个循环均通过了检查。
  • 标签或计数器换行错误。 任何按周期索引的内容必须使用 M.mod 进行换行;在构建中,页面计数器在循环点处显示“06 / 05”,直到修正后才正常。
  • 在某一种色调下对比度低。 为该循环更改色调(深色、强调色、浅色),而不是添加颜色。
  • 从磁盘加载叠加PNG。 从 file:// 打开的页面绘制本地图像并回读像素会失败,因为图像会污染画布。render-loop.mjs 通过本地地址提供文件夹服务;浏览器预览仅用于显示,因此不受影响。
  • 字体加载前绘制文字。 Canvas 文字不会等待网页字体;在第一帧之前应 await document.fonts.load(...),否则在循环中不要绘制文字。
  • 追求高码率。 在纯色区域上,x264 会使用很少的比特,文件看起来很小。在构建中,PSNR 显示编码器几乎没有增加损失;唯一的实际损失是在细饱和线条上的4:2:0色度采样。使用 --psnr 检查,并通过加粗细彩色线条而不是提高码率来解决。
  • 丢失 VP9 片段的 alpha 通道。 ffmpeg 内置的 VP9 解码器会忽略 alpha;请在 -i shot.webm 之前加上 -c:v libvpx-vp9。
  • 使用视频模型创建循环。 生成的片段最后一帧很少与第一帧完全匹配。请保持循环由代码生成,仅在需要主体时使用 Scenario。
  • 凭记忆使用模型 ID 或价格,或在 model_run 中使用本地路径。 使用 recommend 或 search 选择模型,读取 model_schema_get,通过 dry_run 估价并等待确认,并先上传文件。
  • 有多个团队但不询问。 如果 teams_list 返回多个团队或项目,请询问用户。

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

相关技能