Skip to content
Back to skills

Plonk

ASecurity

Use when a web game needs music, a soundtrack, a theme, background music or a jingle, or sound effects (pickups, hits, combos, ambience), or the user asks to compose, edit or tweak game music or sounds. It is the default for sound in debuff games, especially when the game draws its art in code or must stay small (Poki, CrazyGames, game jams). plonk makes music in code: songs are small text patterns synthesized live with Web Audio, under 4 kB brotli, any engine.

  • 12 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 11, 2026
ai-agentsgobashreactaws

Works with

  • cli

Security analysis

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

Pro shows the line behind each finding and how to fix it

Scanned November 11, 2026

npx -y skills add debuffjp/debuff --skill plonk --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Plonk?

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

Security grade badge for Plonk
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/debuffjp-plonk/badge)](https://www.skillsdirectory.com/skills/debuffjp-plonk)

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: plonk
description: Use when a web game needs music, a soundtrack, a theme, background music or a jingle, or sound effects (pickups, hits, combos, ambience), or the user asks to compose, edit or tweak game music or sounds. It is the default for sound in debuff games, especially when the game draws its art in code or must stay small (Poki, CrazyGames, game jams). plonk makes music in code: songs are small text patterns synthesized live with Web Audio, under 4 kB brotli, any engine.
---

# Writing game music with plonk

plonk plays songs written as data: instruments plus patterns of sixteenth-note steps, synthesized live with Web Audio.
No audio files. The engine is under 4 kB brotli; a song is a few hundred bytes.

Docs: https://debuff.jp/plonk/ · Notation: https://debuff.jp/plonk/songs · Playground: https://debuff.jp/plonk/playground

## Set up

```bash
npm install plonkjs
```

```ts
import { Player, type Song } from "plonkjs";
const player = new Player(); // or new Player({ context, destination }) to share an engine's audio context and bus
player.play(song, { fade: 1 });
```

In a debuff game: `new Player({ context: audio.ctx, destination: audio.bus("music") })`, so the mute covers music.

## The notation

Steps separated by spaces; each is a sixteenth note (4 per beat):

- `C4`, `Eb5`, `F#3`: a note (A4 = 440 Hz). `C4+E4+G4` or `Am7@3`, `Cmaj7@4`, `G@3`: a chord.
- `^1`, `^5`, `^3@5`: a scale degree of the song's `key` (prefer these: the melody always fits the key).
- Endings on any note, chord or hit: `!` accent, `_` ghost (quiet), `?` half the time, `?30` 30% (seeded).
- `x`: a drum hit; `X`: an accented hit.
- `.`: silence. `-`: hold the step before. `|`: ignored, for marking bars.

A song: `{ bpm, swing?, key?, transpose?, instruments, sections: { name: { instrument: pattern | [variants] } }, order }`.
A section lasts as long as its longest pattern; shorter ones repeat (a 4-step drum loop under a 16-step melody). A
list of patterns takes turns each time the section plays (fills). The song loops. Keys: "C major", "A minor",
"D dorian", "E phrygian", "F lydian", "G mixolydian", "C pentatonic", "A minor pentatonic", "A blues".

## Instrument recipes

```ts
lead: { wave: "square", decay: 0.14, sustain: 0.35, volume: 0.13, echo: 0.28, vibrato: 6 },
bass: { wave: "sawtooth", octave: -1, decay: 0.18, sustain: 0.4, volume: 0.22, filter: { cutoff: 380, q: 9, sweep: 1400 } },
pad: { wave: "triangle", attack: 0.15, decay: 0.4, sustain: 0.5, release: 0.4, volume: 0.06, detune: 8 },
kick: { wave: "sine", drop: 24, decay: 0.12, sustain: 0, volume: 0.5 },
snare: { wave: "noise", decay: 0.08, sustain: 0, volume: 0.12, filter: { cutoff: 2200, q: 3 } },
hat: { wave: "noise", decay: 0.03, sustain: 0, volume: 0.08, filter: { cutoff: 9000 } },
```

Fields: `wave` (sine, square, sawtooth, triangle, noise), `attack`/`decay`/`sustain`/`release`, `volume`, `octave`,
`detune` (cents, second oscillator), `filter` `{ cutoff, q, sweep }`, `drop` (semitones, pitch falls into the note),
`vibrato` (cents), `echo` and `reverb` (0-1 sends), `pan` (-1 to 1). A master compressor and limiter stop clipping,
but balance is still yours: check it with `mix()` (below).

## Writing a good game theme

- Keep it short and loopable: 2 to 4 sections of 4 bars (64 steps each at most). Players hear it for minutes.
- A memorable lead over a simple bass that follows the chord roots; drums mostly on the beat (`x . . .`), hats off it.
- Make it react instead of writing more songs: `player.tempo(1.12)` when time runs low, `player.layer("kick", 0)` on
  menus, then back to 1 in play.
- Music is a creative call: write a draft, describe what it should feel like, and let the human listen and decide.

## Sound effects in the song's key

```ts
const POP = { wave: "sine", drop: 7, decay: 0.12, sustain: 0, volume: 0.3 };
player.sfx(POP, { degree: [1, 3, 5, 8, 10][combo - 1], octave: 5 }); // combos climb the song's arpeggio
player.sfx(BELL, { degree: 1, quantize: "beat", after: 2 }); // celebrations land on the beat
```

Quantize celebrations and stingers; never the player's own taps (feedback must be instant).

## Check a mix without hearing it

In a browser (it renders offline, faster than real time):

```ts
import { mix } from "plonkjs";
const report = await mix(song, 20);
// report.song.lufs (aim for about -16), report.song.clipped (must be 0), report.song.bands (low/mid/high shares),
// report.tracks[name].belowMix (LU under the mix: lead and bass 0-5, pads 3-8, drums 10-15),
// report.warnings: plain words, e.g. "hat: buried (32 LU under the mix); raise its volume". Fix every warning.
```

Iterate: change volumes, run `mix()` again, until there are no warnings and the balance reads right. Then hand it to a
person to listen: numbers can't judge a melody.

## Check a song without hearing it

```ts
import { notes, parse } from "plonkjs";
parse("C5 . E5 G5"); // throws on an unreadable step, naming it
notes(song, 0, 64); // every note in steps [0, 64): { time, instrument, freq, duration, velocity }
```

Use `notes()` to confirm the structure you meant (which instruments play in which section, lengths, that the drums
drop out where intended). `player.played` lists what a running player scheduled.

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.

View all in ai-agents →

Comments

Loading comments…

Newsletter

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