mcpField
R
roblox-sfx

roblox-sfx

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

关于 roblox-sfx

为 Roblox 游戏制作声音资源的技能,会搜索 Creator Store 音频,并在 Studio 中测量候选音频后筛选。它生成按角色组织的声音库代码,避免仅凭商店标注时长做判断。

主要功能

  1. 01按游戏声音角色搜索音频
  2. 02在 Studio 中测量候选音频
  3. 03按加载状态和时长筛选
  4. 04生成声音清单与 Luau 模块
  5. 05提供试听和安装脚本

适用场景

  1. 01为游戏中的脚步或音效寻找音频
  2. 02为环境音乐设定时长范围
  3. 03生成可按角色调用的声音库
  4. 04检查候选音频是否可加载

MCP 相关

该技能使用连接的 Studio MCP 执行 Luau 探测和报告脚本,以读取候选声音的加载状态与实际时长。

安装

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

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

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

包含的文件

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

LOCAL.template.md
examples/
spec.example.json
scripts/
emit_bank.py
emit_probe.py
find_sfx.py
pick.py

详细介绍

Roblox 声音,按 ID 验证

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

整个技能基于一个事实,而非假设:

免费的 Creator Store 音频资源可在未发布、未保存的场景中播放,无需 API 密钥、无需拥有资源,也无需上传。

因此,声音不需要 Open Cloud 音频配额(未经验证时每月上传 10 次, ID 验证后为 100 次,且仅支持创建,因此每次重新生成都会消耗一个名额)。它需要的是 搜索和检查。这让音频阶段完全脱离关键路径。

spec.json  (roles: what the game needs a sound FOR)
  -> find_sfx.py     unauthenticated toolbox search -> candidates.json
  -> emit_probe.py   probe.lua + report.lua
  -> Studio          create the Sounds, then MEASURE them   <- the gate
  -> pick.py         three gates, then score -> manifest.json
  -> emit_bank.py    SoundBank.luau + Sfx.luau + install.lua + tour.lua

搜索会产生候选项。Studio 会给出事实。只有事实才能决定选择。


测量了什么,以及何时测量

2026-08-30 在未保存的 Place1 中,通过已连接的第三方 robloxstudio-mcp 对 Studio 进行了实时验证 (placeId 0):

问题答案
toolbox-service/v1/marketplace/3 需要身份验证吗?不需要。 搜索 footstep 返回 200,共 1000 条结果
items/details 需要身份验证吗?不需要。 提供完整元数据,包括 audioType、艺术家、投票数和 isFree
能否下载音频文件进行分析?不能。 assetdelivery v1 和 v2 均返回 401
未拥有的免费音频 ID 能否在未发布的场景中加载?可以。 40 个候选项中有 40 个 IsLoaded = true
Sound:Play() 能否在编辑模式下工作?可以,在 Studio 中能听到,无需进行游戏测试
工具箱的 duration 字段可信吗?不可信。 一个实际长度为 0.500s 的声音被列为 0;8 个已选音频中有 2 个的列表时长与测量值不符

第四行正是选择不能投机取巧的原因。这里没有波形可供分析, 没有频谱图可供查看,也无法靠听觉判断。能用的只有列表信息和测量结果,而 此技能会如实说明仅使用这两者。


决定一切的规则

列表信息是一种说法。Sound.TimeLength 是测量结果。绝不以说法作为门槛。

find_sfx.py 会故意将列表中的时长存为 listed_duration,避免后续流程误将它当作数据;对于两者相差 超过 25% 的任何选项,pick.py 都会记录 listing_was_wrong。首次实际运行时,有 8 个选项中的 2 个触发了该标记。


两次 Studio 调用,绝不能只调用一次

execute_luau 只要脚本发生任何让出执行,就会丢弃所有输出;而且设置 SoundId 的那一帧无法解析 Sound 的时长。因此,探测分为两步:

call 1   probe.lua    creates every candidate Sound, returns immediately
         (a beat)
call 2   report.lua   returns role,id,loaded,length as CSV

如果第 2 次调用后仍有任何项目为 loaded=false,请再运行一次 report.lua,然后再作判断。只有第二次仍失败才算真正失败;这意味着 ID 无法解析、资源已删除,或此场景无权使用该音频。


三道门槛

只有 Studio 按顺序确认以下三项后,候选项才符合条件:

  1. IsLoaded == true — ID 已解析,且场景可以使用该音频
  2. TimeLength > 0 — 时长为零的声音是损坏的,不是短音频
  3. min_len <= TimeLength <= max_len — 符合该角色的时长范围

搜索分数只用于打破平局,而且只在平局时使用。排名最高的列表项若未通过门槛, 一定会输给排名最低但通过门槛的选项。首次运行时,这条规则淘汰了一个 6.55s 的“木门打开”音频,因为对应角色的时长范围上限是 5s。

角色未填充属于失败,不是警告。 emit_bank.py 拒绝生成有空缺的音频库;如需覆盖,必须明确指定 --allow-holes,这意味着有意发布无声事件。


编写规范

每个游戏需要声音的对象对应一条,而不是每个你想象出来的声音对应一条。

{
 "name": "farm",
 "roles": [
  { "name": "sheep_bleat", "query": "sheep bleat", "kind": "SoundEffect",
    "min_len": 0.3, "max_len": 4.0, "volume": 0.5 },
  { "name": "ambience",    "query": "countryside ambience", "kind": "Music",
    "min_len": 20, "max_len": 300, "volume": 0.2, "looped": true }
 ]
}
  • kind 为 SoundEffect 或 Music。这是资产上的真实字段,类型不匹配会受到严厉扣分,因为让一首 Music 曲目承担 SoundEffect 的角色,是把一段九分钟混音当成脚步声的经典做法。
  • 频段是设计决策。持续时间超过 1.5s 的脚步声就不是脚步声,把这一点写下来,机器就能在不听声音的情况下将其排除。
  • volume 和 looped 会传递到生成的资源库中。

示例规范见 examples/spec.example.json;复制它并编辑各个角色即可。


运行

cd ~/.claude/skills/roblox-sfx
python scripts/find_sfx.py spec examples/spec.example.json --out work/candidates.json --per-role 5
python scripts/emit_probe.py work/candidates.json --out work
# execute_luau work/probe.lua      -> "created N sounds across M roles"
# execute_luau work/report.lua     -> save the return value verbatim to work/report.txt
python scripts/pick.py work/candidates.json work/report.txt --out work/manifest.json
python scripts/emit_bank.py work/manifest.json --out work
# execute_luau work/install.lua    -> SoundService.SFX, audible in this place
# execute_luau work/tour.lua       -> plays the whole bank in order, so a human can judge it

一次性查询,无需规范:

python scripts/find_sfx.py search --query "wolf howl" --kind SoundEffect --limit 20

交付内容

文件放入位置用途
SoundBank.luausrc/shared/Config/仅包含数据:角色 -> id、测量时长、音量、循环状态、署名
Sfx.luausrc/shared/Sfx.play(role, parent, pitchVary)、Sfx.preload()、Sfx.stop()
install.luaexecute_luau直接构建 SoundService.SFX,适用于没有 Rojo 同步的场景
tour.luaexecute_luau按顺序播放每个声音,间隔为其实际时长

生成的代码会遵循两条规则:

  • 资源库之外的代码绝不会引用资产 id。 游戏逻辑代码只写 Sfx.play("wolf_howl", head)。调整音量或替换资产只需修改数据,无需修改代码。
  • 声音绝不能影响游戏逻辑。 Sfx.luau 中的每个入口点都通过 pcall 隔离,失败时返回 nil。缺少声音不能阻止射击或绵羊移动。

tour.lua 使用 task.delay 而不是通过 task.wait 循环,原因与探测脚本拆成两部分相同:会让出执行权的脚本会丢失输出。


陷阱

列表中的时长不准确。 上文已提及。如果有人“优化”掉 Studio 往返流程,这是最可能导致该流水线交付错误声音的问题。

MCP 上的 search_assets 行不通。 它会返回 HTTP 403 Scope not authorized,改参数名也无济于事。因此,该技能会直接调用工具箱端点,完全不需要身份验证。

你听不到任何声音,模型也听不到。 没有 Cookie 时,assetdelivery 会返回 401,因此无法获取波形、频谱图或响度数据。该技能对声音做出的所有判断都来自列表或 TimeLength。需要凭听感判断时,运行 tour.lua,让人来评估。对于无人值守的运行,过滤条件加上评分就是诚实的上限;这是值得明确说明的结论,而不是该掩盖过去的事。

免费素材包不等于免费音频。 免费的 Creator Store 素材包 必须由人将其添加到账户后才能加载(我们在 VFX 收集器上吃过亏)。按 id 使用的单个音频资产没有这一步,这正是该技能按 id 操作、从不要求任何人添加素材的原因。

探测期间将音量设为 0 是有意为之。 在打开的 Studio 中同时播放 40 个候选声音会让人不适。probe.lua 会设置 Volume = 0;audition.lua、install.lua 和 tour.lua 则会设置实际音量。

Roblox 自带的素材库会获得有意设置的加分。 Creator id 为 1 的资产(形如 91207… 的 id)质量稳定、始终获准使用,且永远不会被删除。如果运行结果必须在数月后仍可复现,优先选择这些资产。


为什么选择素材库,而不是生成音频

从素材库中选择无需配额、id 验证、审核等待或上传;Agent 搜索并从 Creator Store 中选择素材,也无需人工干预。

生成音频会消耗仅限创建用途的上传配额,生成的内容却无人能在整个流程中听到。这种交换不值得,而这正是该技能要表达的观点。

评论

支持 Markdown