Skip to content
Back to skills

Sound

ASecurity

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 for loudness, clipping, late starts and what a phone speaker loses, then wired into the game with a small player that starts on the first touch a...

  • 1,531 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 7, 2026
ai-agentsgonodeexpressgit

Works with

  • claude code
  • cli
  • mcp

Security analysis

A92/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro scans all 11 files and shows the line behind each finding

Scanned November 7, 2026

npx -y skills add hashgraph-online/awesome-codex-plugins --skill sound --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Sound?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Sound
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/hashgraph-online-sound/badge)](https://www.skillsdirectory.com/skills/hashgraph-online-sound)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: sound
description: 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 for loudness, clipping, late starts and what a phone speaker loses, then wired into the game with a small player that starts on the first touch and switches music on bar lines. Use when someone asks for sound effects, SFX, game audio, a chiptune or synth theme, background music without a paid service, music that changes with the game, or says a game is silent.
compatibility: Node 22 and ffmpeg for local synthesis; official ElevenLabs MCP for requested generated sound.
metadata:
  providers: elevenlabs
---

# Sound for a studio's game

Local synthesis 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`.

```sh
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.

## 1. Effects

```sh
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.

- **Variants** (three by default) are the same recipe a touch higher or lower, so a sound heard fifty
  times a round does not machine-gun. Signals heard once a round (win, lose, go, countdown) get one take.
- **Levels** are set by the loudest 50 ms of each effect into four classes (ui -20, small -16,
  normal -12, big -9 dB), then held under -1 dBFS. The set sits together in a mix without balancing.
- **Every effect must start at once** (a hit that starts 30 ms late feels laggy) and **must reach a
  phone speaker**: under about 300 Hz a phone plays almost nothing, so a thud needs a knock on top.
  The warnings measure both.

## 2. A synthesized theme or score

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:

```sh
node <sound.mjs> score <slug> --spec music/<slug>/score.json --loops main,chase
```

- It renders the mix (-14 LUFS for a page; `--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.
- Look at `<slug>.png` and read the numbers: loudness, true peak, and what it measures through a phone
  speaker. Say them in your report, not adjectives.
- Write music a person would hum: a hook in the first bars, a clear melody over simple chords, a
  change every 4 or 8 bars. A score for a game is sections of the same tempo and key (calm, chase,
  final seconds) so the game can move between them on a bar line.

## 3. A mix of anything

```sh
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.

## 4. Into the game

```sh
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:

```js
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
```

- **Sound starts on the first touch or key, with no "tap for sound" screen**: the player resumes audio
  inside the first gesture. A sound asked for before that is dropped, not queued.
- **Every browser plays its own sounds** for what it sees: call `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.
- Loops go out as Ogg with a WAV fallback (older Safari cannot decode Ogg): the player takes the first
  one the browser decodes. `wire` prints the real download size; keep a game's sound under about 3 MB.
- Each variant of an effect, and each loop, is a list of files tried in order (`["jump.ogg", "jump.wav"]`);
  a list of one file is fine.
- A trailer filmed frame by frame gets its sound from this player's own log of what it scheduled
  (off unless a recorder asks; `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.
- Rules for game sound (every action answers, what repeats, music under effects, intensity changes on
  bar lines, the live-loop traps): `references/GAME-SOUND.md`.
- For sound made live in the browser (a synth voice per player, pitch that follows speed, a beat
  clock), the open engine package `@homie-rocks/audio` has the building blocks; install it exactly
  pinned (`npm install --save-exact @homie-rocks/audio@0.1.0`).

## 5. Prove it, and publish it

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.

```sh
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.

## Tell the person

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.

## Never

- Never ship a sound you have not measured and looked at.
- Never use a mp3 for an effect or a loop: encoders pad the start with silence (a late hit) and the
  ends (a gap at the loop). WAV or Ogg.
- Never imitate a real song, artist or brand jingle.

## Generated sound on request

Use the official ElevenLabs MCP for requested generated effects. Discover its current
sound capabilities and schema through the official plugin; never assume a tool exists.
If the hosted connection lacks sound generation, say so; keep local synthesis available
as Homie-owned, free functionality. Specify duration, loopability, envelope and material
from the scene. Audition on phone speakers, remove clicks, and trigger it only on the
intended game event after the browser audio unlock gesture.

## Official generation workflow

The owner's AI uses the provider's official plugin/MCP in its own client. Homie never
asks for, stores, reads or prints provider credentials. Read the current provider
skill and discover its available tools and input schemas; host prefixes vary.
Connection instructions and verified sources: [official integrations](../studio-setup/references/OFFICIAL-MEDIA.md).
If tools are missing, connect that official plugin once in the client's browser flow.
Do not fall back to a Homie client, key file, environment key or CLI generation wrapper.

Before spending, state the model, count/duration, estimated cost and remaining approved
budget. Use the owner's existing authorization; ask only if the spend is outside it.
Record the request ID as soon as accepted. Poll that same request; never resubmit to
retry a slow job. Unknown cost is unknown, never zero. Provider billing is authoritative;
Homie's local receipt cannot enforce spending in another client.

## Place and prove the result

Download the completed tool's output using the AI client's file/download facilities.
Keep temporary signed URLs out of committed records. Keep the original in the studio's
art/job folder; put the optimized delivered asset beside its game/app, or in music/ or
videos/ for a published work. Record a receipt with these fields:

```json
{
  "provider": "elevenlabs",
  "tool": "actual discovered tool",
  "model": "exact endpoint returned by the provider",
  "requestId": "actual request ID",
  "prompt": "the actual prompt, including style constraints",
  "styleRevision": "revision from the studio's style",
  "rights": {"source": "provider/model terms URL", "checkedAt": "YYYY-MM-DD", "commercial": false, "note": "record the actual plan and permitted use"},
  "cost": {"status": "unknown"}
}
```

For ElevenLabs use its actual discovered tool and model, and its flow/session or request
identifier. A measured cost uses `{"status":"actual","amount":1,"unit":"credits"}`;
a quote uses `estimate`. Never claim commercial rights from the fact that generation
succeeded. Read the provider and model terms for the account's plan; record attribution,
reference-image permissions and any restrictions. Mark test fixtures `"fixture": true`.

Wire the delivered path into the scene or manifest, then run:

```sh
npx --no-install homie-studio media import --file <downloaded-file> --receipt <receipt.json> --out games/<id>/assets/<name> --used-by games/<id>/view.ts
```

This copies bytes, verifies a static reference, hashes the asset and records allowlisted
provenance in `media/provenance.json`. Reimporting the same output is idempotent; it
never generates or charges. Include each generation step's receipt for derived assets.
Run the scene and look/listen: a file and static reference are not proof that it renders
or plays. Report the placed path, usage evidence, rights and actual/estimated cost.

The toolkit’s `lib/media-workflows.mjs` declares this skill’s verified tool references.
Validate them against the host’s current tool inventory before execution; tool discovery
is required for generation capabilities that have no stable documented name.

Files in this skill

  • SKILL.md13.2 KB
  • references/GAME-SOUND.md6.1 KB
  • references/SCORE.md7.1 KB
  • references/TRAPS.md6.4 KB
  • scripts/lib/measure.mjs15.9 KB
  • scripts/lib/score.mjs25.8 KB
  • scripts/lib/sfx.mjs13.8 KB
  • scripts/lib/synth.mjs23.6 KB
  • scripts/player/sound.d.ts2.5 KB
  • scripts/player/sound.js14.3 KB
  • scripts/sound.mjs32.8 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.