关于 roblox-animation
roblox-animation 是将 Roblox 角色动画编写为随时间变化的姿势数据,并在导出前渲染检查的技能,面向使用 Blender 骨骼的创作者。它结合骨骼数值校验与逐帧视觉审查,减少仅凭数值判断姿势的问题。
主要功能
- 01以 JSON 姿势数据编写动画规格
- 02校准骨骼控制器和 FK 轴向
- 03渲染帧与联系表供审查
- 04检查关节位置和骨骼完整性
- 05将动画转换为 Roblox Luau
适用场景
- 01制作并迭代 Roblox 战斗动作
- 02诊断无响应的骨骼控制器或 IK/FK 设置
- 03对照参考检查渲染姿势
- 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.mdreferences/example-fk-punch.jsonexample-fk-roundhouse.jsonexample-fk-wave.jsonexample-uppercut.jsonpose-recipes.mdstudio-binder.luatraps.mdscripts/anim_render.pycalibrate_rig.pyfk_crouch.pyfk_probe.pyprobe_bone.pyr6_clip.pyr6_joint.pyr6_luau.pyrbx_axis_check.pysweep_control.pyto_roblox.pyupload_animation.pyscripts/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.5s | 1 个视角,320x240,1 个采样 |
| 完整渲染,2 个视角 @ 640x560 | 9–17s | 只在最后做一次 |
| GIF 编码 | 0.3s | |
to_roblox.py → Luau | 0.1s | |
| 在 Studio 中构建 + 验证 | 一次 execute_luau 调用 |
完成动画并在 Studio 中验证,机器耗时不到一分钟。 真正花时间的是创作迭代,所以把时间花在预览上,绝不要花在完整渲染上。以 references/pose-recipes.md 为起点,第二个动作应该用 1–3 次预览就能完成——references/ 中的拳击动作第一次就做对了。挥手示例则不是:它通过了所有数值检查,看起来却仍像手放在头上,这只能靠人眼发现(已于 2026-10-23 修复)。数值能证明姿势符合规范;只有亲眼查看,才能证明规范选对了动作。
"report": true 会打印每个节拍中各关节的位置:姿势看起来不对时,一次运行就能指出关节,不必靠五轮渲染来猜。
探测能回答的问题,不要用渲染来回答。
不容妥协的要求
每一条都曾因被跳过而导致交付的内容出错,尽管看起来没问题:
- 绝不要相信退出码为 0 的运行。
anim_render.py会逐帧断言骨架完整性、断言帧已写入,否则会以非零状态码强制退出。 - 查看帧。 每一轮都要查看。
- 有参考图时,制作并排对比并据此判断——绝不要只看渲染结果。
- 检查最终 GIF 本身,不要只看编码前的 PNG。
- 绝不要放宽容差来把红灯变成绿灯。 修正规范。
工作流
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,武器进入身体的采样次数为零——结果游戏还是上线了一个倒拿的长柄武器。在这里编写的错误姿势,后续的所有检查都无法发现,因为它们检查的都是与这个姿势的一致性。 直到有人最终查看时,才判定它是倒拿的。他们是对的,而代价是:这里仅用十秒做出的决定,导致下游整个环节都白费了。
编写之前:
- 搜索这类武器的携带和使用方式。 看习武者的照片,不要看概念图,也不要看其他游戏。花十秒查阅资料,胜过四轮盲猜数值。
- **把结论写进规格的
_intent中,**用一句话描述武器:“戟头朝上,杆身斜跨前肩”,“刀身从下垂的手中斜向上方并朝前”。对照表会依据这句话来评判——参见步骤 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。
-
将
build.lua粘贴到execute_luau。它会在ReplicatedStorage.CustomAnims中为每个 spec 创建一个KeyframeSequence,替换 同名对象,然后验证每个对象是否能以创作时设定的时长加载 并输出报告。实际时长只要与创作时设定的不同,就算失败——请勿继续。 -
将
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 搜索并选择资源不算人工介入。