声音实验室使用指南
声音实验室是 SpecEnvoy 游戏背后的音频引擎, 在这里变成一件乐器。它里面没有任何录音——每件乐器、每个音效、每段音乐都是由代码在你的浏览器里当场合成的。 这一页就是说明书:六个面板、导出格式,以及一个你做出的声音如何进入游戏。
一切的基础:一个想法
这里的每个声音都是确定性的:相同的设置加相同的种子(一个整数), 永远产生完全相同的声音——今天、明年、在任何游戏里都一样。种子就像菜谱编号。 所以"你设计的一个声音"从来不是一个需要保存的文件,而是一小段描述 (音效是预设 + 参数 + 种子,音乐是风格 + 种子),任何游戏都能完美重放。 这也是导出按钮同时提供 JSON(描述)和 WAV(渲染出的音频,随处可听)的原因。
六个面板
1 · 乐器
从 26 件乐器中任选一件,弹屏幕上的键盘——或者用电脑键盘:白键在 A S D F G H J K,黑键在 W E T Y U,Z / X 升降八度。 力度滑块是你"弹多重":它改变的是亮度和起音,而不只是音量——这正是这些声音听起来像乐器而不是蜂鸣的关键。
2 · 鼓组
一套十二件的合成鼓。点一点鼓垫;每次敲击都略有不同,就像真的鼓手。
3 · 音效
40 个命名预设就是我们游戏里实际使用的声音——拳击、枪炮、爆炸、科幻电击、脚步、界面音。 选中一个,它的生成器参数会变成滑块(体量、锐度、距离、金属感……)。拖动它们再按播放; 按 🎲 换种子可以听到同一个设计的自然变化。
- ⬇ WAV 下载你正听到的音频。
- ⧉ JSON 复制那段小描述,例如
{"gen":"impact","p":{"size":0.9,"metallic":0.5}}——游戏可以直接播放这个对象。
4 · 环境声
循环的背景声——风、雨、夏夜、海岸、洞穴、城市、篝火、远处的战场、人群。 它们天生无缝循环(接近结尾的声音事件会绕回开头)。同时只放一条,切换时自动交叉淡变。 WAV 导出给你一段干净的循环。
5 · 引擎
六种载具声——螺旋桨飞机、喷气机、直升机、坦克、燃油车、电动车——由一个实时油门滑块驱动。 音高会真实地跟随油门,就像引擎转速上升时的声音。
6 · 作曲机
先用种子生成原创音乐——再把它变成你自己的曲子。选一个风格(每种是一种情绪:英雄、紧张、战斗、平静、神秘、晴朗、像素、竞速、夜曲), 掷一下🎲 种子,按播放。然后动手:
- 编配。走带下方的方框列出乐队的每个声部——主旋律、对旋律、伴奏、铺底、贝斯、点缀、鼓组。 给任何声部换乐器(战斗铜管换成独奏弦乐?)、🎲 只重掷那个声部而其它声部保持原样、 静音不想要的声部、再调速度和调性。这就是这里的做曲方式:先生成,再雕琢。
- 录音。先选伴奏——乐队,或仅节拍器(带重音的节拍声,开头两小节就是数拍, 适合在乐队之前先写出旋律)——再打开 ⏺,用录音键盘或 A–K 演奏。你弹的每个音都会 按网格量化(默认 1/16)记录在循环中的位置;关掉 ⏺,下一遍循环就会用同样的伴奏把你放回来。 你的演奏会以"你的演奏"出现在编配里——可以换乐器、静音、撤销一个音或全部清除—— 并随所有导出一起走。
- 强度。音乐播放时拖动滑块,乐器层会淡入淡出——同一首曲子,探索时清淡、开打时浓烈。 这就是我们游戏使用的自适应配乐技巧。
- 短句。胜利 / 失败 / 升级 / 发现——与当前风格同调的音乐标点。
导出:乐谱 JSON(整首曲子的数据——游戏可逐音重放)、WAV 混音(离线渲染的一整个循环), 以及集成代码。导出的就是你听到的——静音的声部不会包含在内;一旦你改过编配, 集成代码会自动切换成"乐谱 JSON"形式,因为自定义的曲子要以乐谱本身随游戏一起走,而不只是一个风格名。
实用流程:给游戏找声音
- 1. 在实验室里试听,直到找到合适的——乐器、音效、环境声,或一对"风格 + 种子"。
- 2. 记下配方:音效记预设名(或复制的 JSON);音乐记风格 + 种子。 种子让品味可以传递——"heroic,种子 48213"就是一份完整的规格。
- 3. 把配方交给游戏(见下文)。不需要搬运任何文件;游戏用同一套代码把声音重新生成出来。
我们的游戏如何接入引擎
游戏只需引入一个模块,使用一个小小的 API。下面就是全部的集成面:
import { GameAudio } from '/games/lib/audio/engine.js?v=1';
const audio = new GameAudio({ game: 'mygame' });
audio.attachUnlock(); // 第一次点按解锁声音(iOS 规则)
audio.attachAutoSuspend(); // 切后台 / 失焦时静音
audio.play('punch.heavy', { pan: 0.3, duck: 0.35 });
audio.play({ gen: 'impact', p: { size: 0.9, metallic: 0.5 } });
audio.ui('confirm');
audio.music.start('battle', { seed: 12345, intensity: 0.4 });
audio.music.setIntensity(0.9); // 战斗——乐层随节拍淡入
audio.music.stinger('win');
await audio.ambient.start('night.field');
const eng = audio.createEngine('heli');
await eng.ready; eng.start(0.3); eng.set(throttle01);
音量设置按游戏各自保存;引擎负责混音、共享的生成混响,以及大音效下的音乐闪避。 因为一切都是代码,一个游戏的整套声景——连管弦乐在内——只有几百 KB,而且完全离线可用。
与 AI 编码会话协作
我们的游戏由 AI 编码会话开发。有两种提示词——一行版和填空模板——区别只在于由谁来做声音上的选择:
- 什么都还没选?用一行版。会话会自己读引擎手册、看这个游戏,然后自行挑选音效、音乐风格和种子。 适合"给这个游戏配上好声音就行"。
- 已经选好了什么?用填空模板。你在实验室里试听过、想让会话落实你的选择——特定的风格 + 种子、指定的音效、某条环境声——或者想限定范围("只做音乐"、"只做引擎声")。 保留你关心的行,删掉其余的;最后两行(离线条目 + 质量门)永远保留。
提示词本身保持英文——编码会话读英文指令最可靠。
一行版
Use the shared audio engine — read docs/prompts/game-audio.md.
填空模板
只有三个要填的空,其余都是给会话看的指令,不用你管:
| 空位 | 是什么 | 去哪里拿值 |
|---|---|---|
<GAME> | 游戏的文件夹名 | emberfist · lanternfall · wirecut · frontline · sixthwing · skyenvoy · roadenvoy · goalburst · phyloca · crumbrun · worldie |
<STYLE> | 九种音乐情绪之一 | 下面的风格表——或直接在作曲机里试听 |
<SEED> | 任意整数——这首曲子的"菜谱编号" | 在作曲机里按 🎲 直到喜欢,然后把种子框里的数字抄下来 |
Use the shared audio engine — read docs/prompts/game-audio.md, then wire up
<GAME>:
- SFX: use engine presets (audition list: /apps/studio/soundlab/#sfx);
replace or augment the game's own audio.js gradually.
- Music: audio.music.start('<STYLE>', { seed: <SEED> }) — drive
music.setIntensity() from game state (threat / wave / speed), don't
leave it constant. Add stingers on win/lose.
- Ambience: pick a bed that fits the map; crossfade between areas.
- Add shared: ['/games/lib/audio'] to the game's entry in
tools/offline/build-sw.mjs (offline support — do not skip).
- Run the audio gates AND the game's own gates before finishing.
三个可以直接粘贴的例子
三类游戏各一个,所有空位都已填好。这里的种子只是示例——在作曲机里掷出你自己喜欢的,换掉数字即可。
1 · 格斗游戏(燧拳 Emberfist)——拳拳到肉的音效,随回合升温的战斗音乐:
Use the shared audio engine — read docs/prompts/game-audio.md, then wire up
emberfist:
- SFX: punch.light / punch.heavy / punch.body / kick.heavy for strikes,
block + metal.hit for guards and armoured fighters, whoosh.fast on
dodges, ui.confirm / ui.back in menus.
- Music: fights use audio.music.start('battle', { seed: 41007 });
drive music.setIntensity() from the round — 0.4 while feeling out,
0.9 when either fighter drops below 30% health.
- Stingers: 'win' and 'lose' at round end.
- Add shared: ['/games/lib/audio'] to emberfist's entry in
tools/offline/build-sw.mjs (never regenerate on a dirty shared tree).
- Run the audio gates AND the game's own gates before finishing.
2 · 黑夜生存游戏(Lanternfall)——环境声营造气氛,音乐随波次切换:
Use the shared audio engine — read docs/prompts/game-audio.md, then wire up
lanternfall:
- Ambience: night.field while resting, battle.far during waves.
- SFX: gun.pistol / gun.rifle / gun.heavy mapped to weapon tiers,
explosion.small for bursts, step.grass for movement, ui.pickup on
ammo and ui.coin on salvage.
- Music: audio.music.start('nocturne', { seed: 77120, intensity: 0.2 })
while resting; on a wave, switch to 'tense' seed 88231 and drive
music.setIntensity() from the game's threat value.
- Stingers: 'found' on a lantern, 'lose' on going down.
- Add shared: ['/games/lib/audio'] to lanternfall's entry in
tools/offline/build-sw.mjs (never regenerate on a dirty shared tree).
- Run the audio gates AND the game's own gates before finishing.
3 · 竞速游戏(RoadEnvoy)——引擎声是主角,音乐跟着速度走:
Use the shared audio engine — read docs/prompts/game-audio.md, then wire up
roadenvoy:
- Engine sound: audio.createEngine('car-ice') for petrol models and
'car-ev' for the EV; call eng.set(rpm01) every frame from the drivetrain.
- SFX: whoosh.fast on close passes, explosion.small on crashes (a crunch,
nothing burns), ui.click / ui.confirm in menus.
- Ambience: wind.calm on open road, rain.storm when the weather rolls in.
- Music: audio.music.start('racing', { seed: 52941, intensity: 0.6 });
raise music.setIntensity() with speed; stinger 'win' at the finish line.
- Add shared: ['/games/lib/audio'] to roadenvoy's entry in
tools/offline/build-sw.mjs (never regenerate on a dirty shared tree).
- Run the audio gates AND the game's own gates before finishing.
取值大全
音乐风格——每种情绪是什么、适合放在哪里:
| 风格 | 听起来像 | 适合 |
|---|---|---|
heroic | 明亮、进行曲式的冒险感 | 菜单、翱翔场景、SkyEnvoy |
tense | 持续低音上的步步逼近 | 潜行、波次将至、Wirecut |
battle | 小调驱动、通鼓滚动的战斗 | Frontline 2030、打斗场面 |
calm | 失重而温柔 | 轻松的游戏、Phyloca、暂停画面 |
mystery | 好奇的钟声与暗影 | 解谜、探索未知 |
sunny | 轻快的马林巴弹跳 | Goalburst 菜单、Crumb Run |
chip | 纯正街机能量 | Glowcade 街机、Worldie |
racing | 四踩底鼓的高速感 | RoadEnvoy、计时赛 |
nocturne | 安静的夜晚钢琴,无鼓 | 休整场景、夜晚的标题画面 |
音效预设——提示词里可以点名的名字(在音效面板都能试听):
| 类别 | 预设 |
|---|---|
| 格斗 | punch.light punch.heavy punch.body kick.heavy block metal.hit whoosh.fast whoosh.big land.soft land.hard |
| 枪炮与战场 | gun.pistol gun.rifle gun.heavy gun.mg gun.cannon gun.far mg.far explosion.small explosion.big explosion.far artillery.far alarm.base |
| 科幻 | zap.small zap.heavy zap.chip hit.shield |
| 移动与世界 | step.hard step.gravel step.grass thunder.near thunder.far |
| 界面 | ui.click ui.confirm ui.back ui.error ui.coin ui.pickup ui.powerup ui.win ui.lose |
环境声:wind.calm wind.strong rain.soft
rain.storm night.field sea.shore cave.deep
city.hum fire.camp battle.far crowd.murmur
crowd.excited
引擎:prop(轻型飞机)· jet · heli ·
tank · car-ice(燃油)· car-ev(电动)
强度该由什么驱动?游戏里真正的"紧张程度":格斗 → 血量差和最后几秒;
波次射击 → 威胁值或波次数;竞速 → 速度和最后一圈;体育 → 比赛阶段;
解谜 → 保持低强度,用 'found' 短句庆祝解出。
值得知道
- 为什么零采样?一举三得:游戏下载量保持极小(整套配乐是代码,不是几 MB 的音频)、 完全离线可用、也没有任何授权负担——每个声音都是本站自研合成,每段旋律都是原创。
- 同一个种子,永远同一个声音。确定性同时也是我们的质量门:引擎的测试套件会验证 浏览器与构建机渲染出的每一个比特都相同。
- 界面音效刻意不变化。每次按下都不一样的确认音听起来像坏了;而拳击和枪声每次触发都有变化,像真实世界。
- 你的导出归你。你在这里设计并导出的 WAV 和 JSON 归你使用——详见实验室的授权说明。