mcpField
R
roblox-animation

roblox-animation

github.com/syphodev-yt创意与媒体11952 次安装4 天前更新
代码仓库

关于 roblox-animation

roblox-animation 是将 Roblox 角色动画编写为随时间变化的姿势数据,并在导出前渲染检查的技能,面向使用 Blender 骨骼的创作者。它结合骨骼数值校验与逐帧视觉审查,减少仅凭数值判断姿势的问题。

主要功能

  1. 01以 JSON 姿势数据编写动画规格
  2. 02校准骨骼控制器和 FK 轴向
  3. 03渲染帧与联系表供审查
  4. 04检查关节位置和骨骼完整性
  5. 05将动画转换为 Roblox Luau

适用场景

  1. 01制作并迭代 Roblox 战斗动作
  2. 02诊断无响应的骨骼控制器或 IK/FK 设置
  3. 03对照参考检查渲染姿势
  4. 04准备 Blender 动画并导出到 Roblox

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/syphodev-yt/roblox-ai-skills --skill roblox-animation

安装后在 Claude Code 中输入/roblox-animation确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

LOCAL.template.md
references/
example-fk-punch.json
example-fk-roundhouse.json
example-fk-wave.json
example-uppercut.json
pose-recipes.md
studio-binder.lua
traps.md
scripts/
anim_render.py
calibrate_rig.py
fk_crouch.py
fk_probe.py
probe_bone.py
r6_clip.py
r6_joint.py
r6_luau.py
rbx_axis_check.py
sweep_control.py
to_roblox.py
upload_animation.py
scripts/luau/
dump_kfs.luau

详细介绍

Roblox 动画,无头模式

第一次在这台机器上使用? 请阅读此文件夹中的 LOCAL.md。如果文件不存在,请运行 roblox-skills-setup 技能(或将 LOCAL.template.md 复制为 LOCAL.md 并填写)。 LOCAL.md 保存你的路径和工具位置;它属于你,不会共享。

将动画制作成数据(描述随时间变化的姿势的 JSON 规范),将其烘焙为真正的 Blender Action,渲染出来,并在相信结果前查看效果。

流程是:制作 → 渲染每一帧 → 拼成联系表 → 查看 → 修正 → 重复。 这里的一切,都是因为这个流程中的某个步骤发现了其他所有检查都遗漏的问题。

请先阅读:最浪费时间的陷阱

大多数 Roblox 骨架自带一个保存了静止姿势的 Blender Action。 Blender 会在渲染时重新计算该 Action。因此,如果你设置姿势值后直接渲染:

  • 每项数值探测都会报告姿势已完美应用
  • 每个渲染帧呈现的却都是骨架的默认姿势
  • 数据和图像始终无法吻合,而且不会报错

清除 Action 也无济于事,因为那个 Action 就是静止姿势—— 清除后,四肢会塌进躯干。

解决方法:在同一个 Action 中插入关键帧,然后逐帧调用 frame_set() 并渲染。 这样动画本身就是 Action,没有任何东西能覆盖它,未触碰的骨骼会通过常量外推保持静止值, 最终得到一个真正的 Action——这也是 Roblox 导出所需的格式。scripts/anim_render.py 已经实现了这一点。

完整列表见 references/traps.md——共 28 个陷阱。开始调试前请先阅读。

使用 FK,而非 IK。

Roblox 的 KeyframeSequence 是由每个关节的旋转构成的树,每个 Motor6D 对应一个旋转。 这就是 FK。每个 R15 骨架都为每个关节配备一根对应的控制骨骼。用 IK 目标驱动角色, 意味着要经过 Roblox 根本不需要的求解器,还要付出相应代价:

  • 仅包含位置的 IK 目标会让肢体滚转不受约束,因此块状的 Roblox 部件会呈现求解器选中的任意一面, 并在帧与帧之间突然切换。应用在带纹理的头像上时,看起来就像颜色瞬间变化——这是让动画显得有问题的症状
  • 求解器会在每一帧的等效分支之间跳转,所以即使每一帧都验证通过,肢体仍会突然跳动
  • 速度慢

FK 没有分支,没有奇异点,没有滚转歧义,角度精确 1:1 对应, 并且可以直接导出到 Roblox。

大多数骨架默认处于 IK 模式,这会让每根 FK_* 骨骼看起来都不起作用。切换模式——不要因此断定 FK 已经失效:

"properties": {"ARM_IK_FK.L": 0.0, "ARM_IK_FK.R": 0.0,
               "LEG_IK_FK.L": 0.0, "LEG_IK_FK.R": 0.0}

在一个免费的社区 R15 骨架上测得的结果,而且一致性很好:每条肢体静止时都笔直朝下; 每根 FK_* 骨骼上,X 负向会向前摆动,Z 正向会朝角色右侧摆动,角度为 1:1 对应, 两侧完全一致——无需镜像反转。子骨骼角度相对于父骨骼计算。

无论使用什么骨架,都适用这条经验:如果控制骨骼不起作用,先检查是否有开关将其禁用,再决定放弃。 Rigify 风格的 R15 骨架带有默认值为 1.0(IK)的 ARM_IK_FK / LEG_IK_FK 自定义属性。 将它们设为 0.0 并为其插入关键帧(这样 frame_set 就无法将它们切回去),然后用 FK 制作动画。 上述方向约定是在一个骨架上测得的;calibrate_rig.py 和 sweep_control.py 会在你的骨架上重新测量, 因此,任何尚未使用过的骨架都应运行这两个脚本。你的骨架 .blend 路径应写入 LOCAL.md。

只有在肢体必须到达某个精确的世界坐标位置时,才使用 IK。此时请阅读陷阱 12–15。

让它看起来像 Roblox,而不是参考图

  • 30 FPS,一次战斗动作持续 0.3–0.7s。动画编辑器的默认帧率是 30fps。现实中的动作节奏对游戏来说太慢了。动作的机制取自真实动作的运作方式;节奏则取自 Roblox。
  • 五个姿势:待机、预备、接触、随势、恢复。
  • 每个片段单独缓动——用 "ease": "in" 加速出击,用 "out" 平稳收势。固定的 smoothstep 会在每个关键帧前减速,因此出击会在接触帧处停顿,整体看起来软绵绵的。
  • 夸张表现。 真正的 Roblox 战斗动画会远超人类动作范围,姿势从轮廓上就能一眼看出。
  • 渲染为纯灰色("plain": true)。繁杂的 Avatar 纹理会让方块状骨架变成一团难以辨认的混乱,结果你调试的是服装,而不是姿势。Roblox 动画正是出于这个原因,才会用纯色假人展示。

references/pose-recipes.md 中有实际数值——防御、预备、蓄势、接触和随势的实测角度表、时间骨架,以及两条容易让人失误的规则(肩部 + 肘部角度总和必须低于约 120;高踢腿需要 UpperLeg X 超过 −120,否则腿会与躯干融在一起)。从这些数值开始,再根据预览进行调整。不要重新推导。

提速——测量,不要猜

整个循环只需几秒。如果一轮要花几分钟,那就有问题。 在中端 PC 上测得,单个动画为 24–36 帧:

阶段时间备注
Blender 加载骨架0.7s启动从来不是问题
数值探测(完整 FK 控制映射)0.1s用数值向骨架提问
预览渲染("preview": true)4–6.5s1 个视角,320x240,1 个采样
完整渲染,2 个视角 @ 640x5609–17s只在最后做一次
GIF 编码0.3s
to_roblox.py → Luau0.1s
在 Studio 中构建 + 验证一次 execute_luau 调用

完成动画并在 Studio 中验证,机器耗时不到一分钟。 真正花时间的是创作迭代,所以把时间花在预览上,绝不要花在完整渲染上。以 references/pose-recipes.md 为起点,第二个动作应该用 1–3 次预览就能完成——references/ 中的拳击动作第一次就做对了。挥手示例则不是:它通过了所有数值检查,看起来却仍像手放在头上,这只能靠人眼发现(已于 2026-10-23 修复)。数值能证明姿势符合规范;只有亲眼查看,才能证明规范选对了动作。

"report": true 会打印每个节拍中各关节的位置:姿势看起来不对时,一次运行就能指出关节,不必靠五轮渲染来猜。

探测能回答的问题,不要用渲染来回答。

不容妥协的要求

每一条都曾因被跳过而导致交付的内容出错,尽管看起来没问题:

  1. 绝不要相信退出码为 0 的运行。 anim_render.py 会逐帧断言骨架完整性、断言帧已写入,否则会以非零状态码强制退出。
  2. 查看帧。 每一轮都要查看。
  3. 有参考图时,制作并排对比并据此判断——绝不要只看渲染结果。
  4. 检查最终 GIF 本身,不要只看编码前的 PNG。
  5. 绝不要放宽容差来把红灯变成绿灯。 修正规范。

工作流

1. 校准骨架(任何你尚未使用过的骨架)
blender --background <rig>.blend --enable-autoexec --python scripts/calibrate_rig.py
blender --background <rig>.blend --enable-autoexec --python scripts/sweep_control.py -- FK_UpperLeg.R:rot TORSO:rot

calibrate_rig.py 会报告变形骨架与控制骨架、Action 陷阱、IK/FK 切换状态,以及哪些控制项确实能驱动骨骼。 sweep_control.py 会给出各轴的方向、正负号和可用范围——它会测量骨骼的方向和位置,因此不会漏掉仅控制旋转的项目。

如果 FK_* 骨骼没有反应,那是 IK/FK 切换开关的问题,不是骨架失效。

2. 编写规格

fps、duration、w、h、margin、views、properties、plain、preview、 report,以及由 {t, ease, bones: {Bone: {rot|loc|target|aim}}} 组成的 keyframes[]。

绝大多数情况下,你想要的都是 rot。无末端执行器的控制器(ROOT)使用 loc。 target / aim 是 IK 的应急方案——参见陷阱 12–15。

如果忘记以下三点,每次都会出问题:

  • FK 子级角度会与父级叠加。 肩部 50° + 肘部 70°,会使前臂相对垂直方向偏转 120°,指向肩部上方。做格挡时,肩部 + 肘部角度要控制在约 110° 以内。
  • 身体倾斜和扭转要施加在 UpTorso 上,它只控制上半身。TORSO 也会带动双腿,因此倾斜它会让角色倾倒、支撑脚滑动。该骨骼还会放大动作:X = +15 会让头部摆动 23°。
  • 支撑脚踝要做反向旋转,即 FK_Foot.X ≈ -(FK_UpperLeg.X + FK_LowerLeg.X),否则脚会随着腿倾斜,角色看起来像是站在斜坡上。

请参阅 references/example-fk-roundhouse.json(0.8 秒踢击)和 references/example-fk-punch.json(0.5 秒直拳),以及 references/pose-recipes.md。

2a. 如果手里拿着道具,先研究它在现实中是如何握持的。

这一步必须在编写关键帧之前完成,而且不能省略。 片段中一旦出现武器或工具,“姿势看起来是否合理”就不再是关于骨骼架构的问题,而是关于该物品的问题。这是一个关于现实世界的事实,不能靠矩阵推断出来。

这一步旨在避免的失误,确实发生过:有人制作戟的动作时,把戟头朝下放在使用者的胯部。之后的每个环节都完美完成了自己的工作——引擎重现了编写好的握持姿势,姿势条带与对照表逐帧吻合,握持误差为 0.000,武器进入身体的采样次数为零——结果游戏还是上线了一个倒拿的长柄武器。在这里编写的错误姿势,后续的所有检查都无法发现,因为它们检查的都是与这个姿势的一致性。 直到有人最终查看时,才判定它是倒拿的。他们是对的,而代价是:这里仅用十秒做出的决定,导致下游整个环节都白费了。

编写之前:

  1. 搜索这类武器的携带和使用方式。 看习武者的照片,不要看概念图,也不要看其他游戏。花十秒查阅资料,胜过四轮盲猜数值。
  2. **把结论写进规格的 _intent 中,**用一句话描述武器:“戟头朝上,杆身斜跨前肩”,“刀身从下垂的手中斜向上方并朝前”。对照表会依据这句话来评判——参见步骤 3。
  3. **参考下表,先检查那些显而易见的情况,**再进行搜索。
类别静止时挥动时
长柄武器、戟、薙刀、长矛头部朝上——扛在肩上、尾端抵地,或保持格挡姿势,刀刃位于胸部或更高处。绝不能垂在脚边头部带动运动轨迹;杆身斜跨身体前方,绝不能与手臂处于同一垂直平面
剑从下垂的手中斜向上方并朝前,约 +35 度。笔直朝下会看起来像是掉落了刀刃带动动作;手腕不是铰链,整条手臂都要带动运动轨迹
斧、锤头部朝上或扛在肩上,将重量举高头部是重物——最后到达,而且撞击力最强
拳套武器、护手穿戴,而不是握持;采用拳手的格挡姿势,双拳举起由胯部发力,而不是肩部

让道具保持在穿戴者自己的身体能够摆出的姿势中。 单手携带任何长度超过角色身高的物品时,物品都不能与手臂处于同一平面,否则会穿模。

3. 渲染并验证
blender --background <rig>.blend --enable-autoexec --python scripts/anim_render.py -- spec.json out/
ffmpeg -start_number 0 -i "out/side_%03d.png" -vf "scale=240:-1,tile=6x6" sheet.png

摄像机会根据整个动画的边界调整自身取景,并根据视野计算距离,确保画面不会漏掉任何内容;margin(默认值为 1.10)是唯一可调参数。至少渲染两个角度——从左侧看不到右腿踢击。

**然后对照参考资料评判图集,而不是对照图集本身。**打开步骤 2a 中的 _intent 句子,逐帧对照图集检查:头部是否抬起,刀刃是否朝前,刀柄是否从身体前方穿过。联系表只能证明渲染结果符合规格,无法告诉你规格本身是否正确;后续每个阶段都会将其视为真实依据——因此,这是流程中最后一个可以低成本修正错误姿势的环节。如果图集与参考资料不符,以参考资料为准,并修改规格。

4. 交付 GIF,然后检查 GIF
ffmpeg -framerate 30 -start_number 0 -i "out/side_%03d.png" -framerate 30 -start_number 0 -i "out/tq_%03d.png" -filter_complex "[0]scale=420:-1[a];[1]scale=420:-1[b];[a][b]hstack=2,split[s0][s1];[s0]palettegen=stats_mode=diff[p];[s1][p]paletteuse=dither=bayer:bayer_scale=3" -loop 0 anim.gif

**只读取一次图集,大小达到所需即可,不要更大。**联系表是整个流程中成本最高的对象:在同一上下文中,每次后续工具调用都会重新发送图像,因此,运行早期读取一张全分辨率图集,到运行结束时会耗费数十万 token。缩小图块;如果问题只涉及某个肢体,就裁剪出该肢体;不要为了重新检查本可测量的内容而再次打开图集。如果某项检查可以用数字表示——武器是否脱手、是否穿过肢体、所处角度是多少——就将其量化,然后只读取一行文本。

接着,从最终 GIF 中提取帧并查看——动态效果和静态图像的观感不同,而且编码设置可能悄无声息地失效:

ffmpeg -i anim.gif -vf "select='not(mod(n,2))',tile=4x3" -vsync 0 verify.png

一个自定义动画片段会破坏你未自定义的动画片段

Roblox 默认的 Animate 脚本以 Core 优先级播放 idle、walk、run、jump、fall 和 climb 动画。你自定义并以 Idle 或更高优先级播放的任何动画,都会在播放期间屏蔽它所设置姿势的每个关节上的默认动画。

因此,为角色制作全身 idle 循环——这是解决角色持武器站立不动的正确方法——会导致玩家行走时双腿无法移动,因为你的动画片段以高于 walk 循环的优先级设置了腿部姿势。它看起来就像“行走动画缺失”,而且只会出现在为其自定义了 idle 动画的角色身上,因此很容易被误认为是该角色的武器出了问题。

选择一种方案,并明确说明:

  • 将 idle 动画设为 Core 优先级,这样默认的 walk 动画仍会生效;或
  • 不要为腿部设置姿势——只自定义手臂和躯干,让默认的移动动画驱动臀部以下的所有部位;或
  • 也自定义移动动画组(将 walk 和 run 设为 Movement),如果持武器姿势必须改变角色的行走方式,这是唯一的选择。

**并在试玩中逐个角色检查:**站立不动、行走、奔跑、跳跃、着陆。观察双腿。每个战士只需约 15 秒,而且没有任何静态检查可以发现这个问题——动画片段正确,骨架也正确,缺陷只会在两个动画片段同时播放时出现。

R15 与 R6

优先选择 R15。 R15 有肘部和膝部,因此参考图显示的每个角度都有对应的关节,而且 FK 会将每个控制骨骼映射到一个关节。

没有 .blend 的自定义网格 R6 骨架(刚性 GLB 部件 + 探测得到的 Motor6D C0/C1):使用 scripts/r6_clip.py 在关节空间中制作动画(通过精确的 Motor6D 链渲染实际部件,为每个关键帧将根部放置在地面上,并报告脚部 y 坐标、站姿滑动和肢体重叠情况),再使用 scripts/r6_luau.py 输出 Luau(原样输出 Pose CFrames,也支持 R15 规格,并整体替换一个文件夹)。转换逻辑位于 scripts/r6_joint.py。参见陷阱 39-40。 标准 R6 角色也采用相同方式(已于 2026-10-22 验证):探测 CreateHumanoidModelFromDescription(desc, Enum.HumanoidRigType.R6) 虚拟角色的六个 Motor6D(它们在编辑模式下也存在),在链条静止中心处按真实部件尺寸构建盒状 GLB,并写入 rig.json;在 Studio 中播放的动画与接触关键帧的渲染结果相差 0.00002 studs。

R6 肢体是没有肘部的刚性单块部件。R6 根本无法摆出收臂的拳击防守姿势;要求它这样做会抬起整条手臂。仅在游戏有此要求时才使用 R6,并预期动作会僵硬地在各姿势间切换——这是 R6 原生的外观,并非缺陷。

导入 Roblox——完整流程

已端到端验证,无需上传。

# 1. author + preview until it reads right   ("preview": true)
blender --background <rig>.blend --enable-autoexec --python scripts/anim_render.py -- spec.json out/

# 2. generate the Studio builder for one or many specs
python scripts/to_roblox.py kick.json punch.json wave.json > build.lua

2b. 在 Studio 中验证导出结果: blender --background <rig>.blend --enable-autoexec --python scripts/rbx_axis_check.py -- spec.json --mid。 此命令会比较渲染结果与 Roblox CFrame 链中每个带关键帧部件的完整旋转(陷阱 35–37)。 to_roblox.py --folder ReplicatedStorage.X.Y --no-verify 会生成一个不含 yield 的构建器,并返回摘要;spec 中的 markers 会变成 KeyframeMarkers。

  1. 将 build.lua 粘贴到 execute_luau。它会在 ReplicatedStorage.CustomAnims 中为每个 spec 创建一个 KeyframeSequence,替换 同名对象,然后验证每个对象是否能以创作时设定的时长加载 并输出报告。实际时长只要与创作时设定的不同,就算失败——请勿继续。

  2. 将 references/studio-binder.lua 复制到 StarterPlayer.StarterPlayerScripts 下的 LocalScript 中,编辑其 BINDS 表,即可在玩家角色上播放按键触发的动画(支持重生),并可选择同步到虚拟人偶上。

导出器读取的 spec 字段:rbx_name(Studio 名称)、priority(默认值为 Action,会覆盖默认的行走/待机动画)、loop。

无需上传: KeyframeSequenceProvider:RegisterKeyframeSequence(seq) 会返回一个 ContentId,可直接赋值给 Animation.AnimationId。它只需要 Animation capability,因此 LocalScript 可以在运行时调用——无需上传资源、审核或账号。只有不带前缀的字符串有效(hash:// 和 rbxasset:// 都会失败)。这些 id 仅在当前会话有效:适合测试,但发布时需要使用实际上传的资源 ID。scripts/upload_animation.py 可在无界面模式下完成此操作(2026-10-08):从 Studio 导出 KeyframeSequence,用 Rojo 将每个对象重建为真正的 .rbxm,通过 Open Cloud 以 Animation 作为 assetType 上传,轮询状态,并生成 apply_ids.luau,为每个序列设置 AnimationId 属性。已验证可无损保留(80/80 个姿势及标记),并且能在角色上正常播放,无需手动右键选择“Save to Roblox”。

以下情况可能让你遇到问题(详情见陷阱 29–34):

  • 现代 Rig 可能包含 AnimationConstraint,而不是 Motor6D——可能有 15 个 AnimationConstraint,但一个 Motor6D 都没有。动画仍会按部件名称绑定并正常播放。
  • Enum.PoseEasingStyle 没有 Quad——可用值为 Linear、Constant、Cubic、Elastic、Bounce。
  • 在编辑模式下,无法通过写入 .Transform 来预览姿势;它属于动画通道,只有 Animator 会应用它。应改为通过附件进行正向运动学计算,以验证轴映射。
  • Studio 工具存在盲区:显示脚本标签页而非 3D 视口时,capture_screenshot 会失败;播放模式下的输出也可能无法访问——因此应让运行时脚本在屏幕上自行诊断,就像 binder 一样。

坐标系不同:Roblox 的上方向为 +Y、前方向为 −Z;Blender 的上方向为 +Z、前方向为 −Y。

免费资源库备用方案

如果动画创作始终无法收敛,Creator Store 提供免费的 R15 动画,search_asset 可以找到它们——免费、预先获许可、无配额、无需上传或审核,而且已经是 Animation 资源 ID。按照无人值守 Agent 规则,Agent 搜索并选择资源不算人工介入。

评论

支持 Markdown