算法艺术创作
algorithmic-art
通过代码和可调参数创作生成艺术与交互式视觉效果。
sound【设计与创意】Make a game's sound effects and synthesized music on the creator's own computer, free, with no provider or account — a set of effects (jump, coin, hit, explosion, win, lose, UI) rendered from presets, a short synthesized theme or score from chords and patterns with stems and seamless section loops, a mix of any audio files and expressions — measured …
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Everything here runs on this computer with Node 22 and ffmpeg: nothing is sent anywhere and nothing
costs money. Sung songs and produced music from a model are the music skill (ElevenLabs, paid);
this skill is effects and synthesized music. They share the studio's music/ folder and manifest, so
a synthesized theme gets a song page just like a rendered one.
One script: scripts/sound.mjs in this skill's folder (Claude Code:
node "${CLAUDE_PLUGIN_ROOT}/skills/sound/scripts/sound.mjs" <command>), run from inside the studio
(the folder with studio.json). Every command takes --json.
node <sound.mjs> check # node, ffmpeg and its encoders, the studio and its games
node <sound.mjs> presets # every effect preset, instrument, groove and pattern, one line each
No ffmpeg: offer brew install ffmpeg (macOS) or the system package; the person approves.
Finish in this turn: an effect set takes seconds, a one-minute score under a minute.
node <sound.mjs> sfx <set> --kit arcade --for-game <id> # a kit: arcade, platformer, shooter, party, ui
node <sound.mjs> sfx <set> --only jump,coin,hit,win --style retro # just these, crunchy 8-bit
node <sound.mjs> sfx <set> --spec music/<set>/effects.json # your own list (below)
It writes music/<set>/sfx/<name>-<n>.wav and an Ogg copy of each, music/<set>/sfx.json (the
spec and every file's measured level), a reel to listen to (<set>.mp3) and its picture
(<set>-reel.png, a spectrogram over the waveform). Open the picture and look: a sound you
cannot hear is still a sound you can see. Then read the warnings; each one is something a person will
hear wrong, with the fix.
A spec is { "style": "clean", "variants": 3, "effects": [ { "name": "stomp", "preset": "land", "pitch": -3, "length": 1.2, "level": "big" } ] }:
preset is any name from presets (the effect's name is used when it is one), pitch in
semitones, length a stretch, seed another take, style clean, retro or soft, level ui,
small, normal, big or a number in dB. Name effects after what happens in the game (stomp,
gem, ko), not after the preset.
Write music/<slug>/score.json (the full language, with a worked example: references/SCORE.md):
tempo, key, instruments (presets with a level, pan, echo in beats, reverb send, a duck under the
kick), sections in whole bars with chords and one pattern per instrument, an arrangement, and the
sections to loop. Then:
node <sound.mjs> score <slug> --spec music/<slug>/score.json --loops main,chase
--lufs -18 for a bed under a game's effects), the page
mp3, a 24-bit master kept off the site, one stem per instrument plus the room (they sum to the
mix), and seamless loops of the sections you name: each is rendered three times in a row and
the middle copy kept, so reverb and echoes that ring over the loop point are already in its head.
The report gives each loop's seam (1 or less is seamless) and its exact bar length. A loop over 1
is in warnings and the summary says NOT SEAMLESS (loopsSeamless: false): an empty warnings
list means the loops were checked and pass. The master's limiter is applied across the three
copies, so a loud loop keeps its seam; nothing is faded at the loop point and no bar is shortened.plan.json holds the bar grid, so the video skill cuts a trailer on this music's bar lines.<slug>.png and read the numbers: loudness, true peak, and what it measures through a phone
speaker. Say them in your report, not adjectives.node <sound.mjs> mix <slug> --spec music/<slug>/mix.json
Parts are audio files (a recording, a render, a loop), ffmpeg aevalsrc expressions (one, or two for
left and right), or effect presets, each placed (at seconds), levelled (db), panned, faded, repeated
and filtered with an ffmpeg -af chain. They are summed at exactly the levels written (no automatic
normalisation), limited, and brought to master.lufs if you give one. Expressions have traps that
fail silently: read references/TRAPS.md before writing one.
node <sound.mjs> wire <set> <score slug> --game <id>
It copies the files into the game (public/sound/, or sound/ for a static game), writes
sound.json (what exists) and sound.js (the player) and prints the two lines to add. Then, in the
game's code:
import { createSound } from './sound.js';
const sound = createSound({ base: 'sound/' });
sound.music('<score slug>'); // once, at the top: it starts on the first touch
sound.play('coin'); // where the thing happens
sound.play('coin', { pitch: combo }); // a climbing combo; pan -1..1 for where it is
sound.section('chase'); // the next loop, exactly on the next bar line
sound.duck(0.4, 0.5); // music down for a big hit
play where the each browser
draw the event (a pickup that shows up in a snapshot, a hit that lands on screen), not only in the
rules handlers. In a rules game emit a declared effect and play it from room.on in the view; the server has no speaker.wire prints the real download size; keep a game's sound under about 3 MB.["jump.ogg", "jump.wav"]);
a list of one file is fine.references/GAME-SOUND.md, "A log for a recorder"): sound that goes
through sound.play and sound.music is in the trailer, sound made any other way is not.references/GAME-SOUND.md.@homie-rocks/audio has the building blocks; install it exactly
pinned (npm install --save-exact @homie-rocks/audio@0.1.0).Build, run the game, and let the playtest skill's sound row listen: it copies what the game really
sends to the speaker while it is played, and says how loud it is, whether it clips, what a phone loses,
whether actions answer with a sound, and whether the music ever started. Never say a game "has sound"
from the code alone.
node <sound.mjs> add <slug> --title "<Title>" --blurb "<one line>" [--for-game <id>] --publish
node <sound.mjs> publish <slug> # rebuild and redeploy the site; the page answers 200
An effect set gets a page with its reel and every effect to download; a score gets its player, its
loops and its stems. The credits line says they were synthesized from code (no samples, no model).
Commit music/<slug>/ specs and the manifest; the audio files stay out of git (the studio's
.gitignore) and regenerate from the spec, byte for byte.
The page or the game, what was made (how many effects, the theme's length and bars), the loudness numbers, the warnings you fixed and any you did not, and that it cost nothing.