Skip to main content

create-sound

Generate a SoundDefinition for @web-kits/audio from any input - a natural-language prompt, an audio file the user shares, or both. Use when the user says "create a sound", "/create-sound", "design a sound for X", shares a WAV/MP3/sprite, or asks to reverse-engineer a sample. Optionally renders a WAV preview and round-trip-validates the result.

Zur Installation springen

Quellinformationen

Repository
raphaelsalaja/audio
Letzte Quellaktivität
20. April 2026 um 10:37
Erkannte Sprache von SKILL.md
Englisch
Sterne
567
Forks
20

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

Datei-Explorer
60 Dateien

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
create-sound
description
Generate a SoundDefinition for @web-kits/audio from any input - a natural-language prompt, an audio file the user shares, or both. Use when the user says "create a sound", "/create-sound", "design a sound for X", shares a WAV/MP3/sprite, or asks to reverse-engineer a sample. Optionally renders a WAV preview and round-trip-validates the result.
# Create Sound > Generated from `rules/*.md` by `src/build.mjs`. Do not edit by hand. Pick a generation path with `pipeline-detect-input`, then walk the matching section. ## 1. Generation Pipeline _Procedural steps the agent runs end-to-end. Start here when handling any create-sound request._ ### 1.1 Detect input mode and route the request _(CRITICAL)_ Decide which path to run based on what the user provided. | Input | Path | | ---------------------------------------- | ------------------------------------------------------------ | | Prompt only (no audio attachment) | Skip `interpret-*`. Go to `pipeline-pick-base-layer`. | | Audio file only | Run all `interpret-*` rules. Skip `event-*` / `mood-*`. | | Both prompt and audio | Run `interpret-*` first, then treat the prompt as a refinement layer over the measured `SoundDefinition`. | #### Detecting audio Look for attached files matching `*.wav`, `*.mp3`, `*.flac`, `*.ogg`, or any path the user references that resolves to an audio file. A JSON manifest (`*.json` next to a sprite) is also an audio-path signal. #### Refinement examples (prompt + audio) | Prompt qualifier | Refinement on measured definition | | -------------------------- | -------------------------------------------------------------- | | "warmer" | add `filter: { type: "lowpass", frequency: 2500 }` | | "shorter" / "punchier" | clamp `envelope.decay` to `<= 0.06` | | "brighter" | drop or raise any lowpass cutoff | | "with reverb" | append `effects: [{ type: "reverb", decay: 0.5, mix: 0.15 }]` | | "lower octave" | halve `source.frequency` (or both `start`/`end`) | #### Output of this step Produce an internal note like: ``` Input: prompt + audio Plan: run interpret-* on out/click.wav, then refine with mood-warm. ``` Then proceed to the next pipeline step. ### 1.2 Pick a base layer from the prompt's event class _(CRITICAL)_ Tokenize the prompt and find the strongest event-class signal. Match against the `event-*` rules. #### Token map | Tokens in prompt | Event rule | | ------------------------------------------------------------- | ----------------------- | | click, tap, key, press, button | `event-click` / `event-tap` | | tick, scroll, snap, focus | `event-tick` | | success, complete, win, achievement, level-up, confetti | `event-success` / `event-complete` | | error, fail, wrong, invalid, delete, destroy | `event-error` | | modal, dialog, popup, drawer, sheet, sidebar, dropdown, menu | `event-modal-open` / `event-modal-close` | | swoosh, slide, transition, page, tab | `event-swoosh` / `event-whoosh` | | notification, alert, ding, bell, mention, badge | `event-notification` | | toggle, switch, on, off | `event-toggle` | #### Direction tokens (open vs close) - "open", "appear", "in", "show", "expand", "confirm" -> ascending pitch. - "close", "dismiss", "out", "hide", "collapse", "cancel" -> descending pitch. #### Output A starting `SoundDefinition` literal copied from the chosen event rule's `example`. The next step (`pipeline-apply-mood`) will mutate it. If no event class fires confidently, default to `event-click` and let mood adjectives do the work. ### 1.3 Apply mood adjectives onto the base layer _(HIGH)_ After `pipeline-pick-base-layer` produces a starting `SoundDefinition`, scan the prompt for adjective tokens and apply each `mood-*` rule's mutation in order. #### Order of application 1. Source-shape adjectives (`warm`, `bright`, `glassy`, `metallic`, `lofi`, `retro`, `organic`) - mutate `source.type`, `source.fm`, or add `filter`. 2. Envelope adjectives (`punchy`, `airy`) - mutate `envelope.attack` / `envelope.decay`. 3. Effect adjectives (`reverby`, `delayed`, `crushed`) - append to `effects`. #### Conflict resolution - `warm` + `bright` -> the later token wins. - `lofi` + `glassy` -> apply both, but cap `effects` at 2 entries. - `punchy` + `airy` -> they're orthogonal (envelope vs source); both apply. #### Refinement on existing definition (audio + prompt path) When the input mode is `prompt + audio`, treat each adjective as a refinement on the measured definition rather than from scratch: | Adjective | Refinement | | --------- | ----------------------------------------------------------------------------- | | warmer | add or lower `filter.frequency` (lowpass at ~2500 Hz) | | brighter | remove lowpass or raise its cutoff above 6 kHz | | punchier | clamp `envelope.decay <= 0.06`, set `envelope.attack: 0` | | longer | extend `envelope.decay` and add `release` if missing | | crisper | raise `gain` slightly and add `fm: { ratio: 0.5, depth: 50 }` | #### Output A mutated `SoundDefinition`. Hand off to `pipeline-decide-layering`. ### 1.4 Decide single-layer vs multi-layer _(MEDIUM-HIGH)_ | Event class | Default | | ------------------------------------------ | ---------------------------------------- | | click, tap, tick, hover, focus, swoosh | 1 layer (`Layer`) | | toggle, copy, send, sync | 2 layers (paired pitches with `delay`) | | success, complete, level-up, confetti | 3+ layers (chord with cascading `delay`) | | error, delete | 2 layers (`sawtooth` + `square`) | See `layer-single`, `layer-octave-pair`, `layer-ascending-chord`, `layer-click-plus-body` for the concrete shapes. #### Promoting a single Layer to MultiLayerSound If the prompt or refinement requires more than one layer, wrap: ```ts { layers: [<existing layer>, <new layer>], // optional global effects, e.g. sidechain compressor, master EQ } ``` Per-layer `gain` values should sum to no more than ~0.6 (see `validate-gain-budget`). #### Demoting MultiLayerSound to a single Layer If only one layer survives mood application, emit the inner `Layer` directly rather than a one-element `MultiLayerSound`. Both validate, but the single-layer form is the canonical compact shape. ### 1.5 Emit, optionally render, optionally round-trip _(HIGH)_ #### 1. Emit Always return a TypeScript snippet ready to paste into a `.web-kits/<patch>.ts` file: ```ts import type { SoundDefinition } from "@web-kits/audio"; export const myClick: SoundDefinition = { source: { type: "sine", frequency: 1300, fm: { ratio: 0.5, depth: 60 } }, envelope: { decay: 0.012, release: 0.004 }, gain: 0.18, }; ``` Plus a one-line rationale that names the prompt tokens you acted on: > "click" -> base from `event-click`; "warm" -> kept default sine, no extra filter needed at 1.3 kHz. #### 2. Optional preview render If the user asked for a WAV (or you want to grade your own output), use [`packages/audio/src/offline.ts`](../../../packages/audio/src/offline.ts): ```ts import { renderToWav } from "@web-kits/audio"; import { writeFile } from "node:fs/promises"; const blob = await renderToWav(myClick, { duration: 0.3 }); await writeFile("preview.wav", Buffer.from(await blob.arrayBuffer())); ``` `duration` should be `attack + decay + release + 0.05` (small tail) or longer if reverb is present. #### 3. Optional round-trip validation If you generated from a prompt and want to confirm the result matches intent, run the `interpret-*` rules against the rendered WAV and diff measured vs intended values: | Field | Acceptable drift | | ----------------- | ------------------------------------------- | | Fundamental Hz | ±5% | | Attack | ±2 ms | | Decay | ±10% | | Spectral centroid | ±20% of expected for the chosen waveform | If drift exceeds tolerance, refine the definition (often by raising/lowering `gain`, tightening `envelope`, or adjusting `filter.frequency`) and render again. ## 2. Audio Interpretation _FFT analysis sub-steps that fire when the user shares an audio file._ ### 2.1 Acquire and split source audio _(HIGH)_ The user shared a single file or a sprite (one file containing many sounds). Before any FFT work, get one mono WAV per sound on disk. #### Sprite from an npm package ```bash npm pack <package-name> --pack-destination /tmp tar -xzf /tmp/<package-name>-*.tgz -C /tmp ``` Look for the MP3/WAV plus any JSON manifest mapping sound names to time offsets. #### Manifest-driven slicing ```bash ffmpeg -i sprite.mp3 \ -ss <start_seconds> -t <duration_seconds> \ -acodec pcm_s16le -ar 44100 \ output/<name>.wav ``` #### Silence-detection slicing (no manifest) ```bash ffmpeg -i sprite.mp3 -af silencedetect=noise=-40dB:d=0.05 -f null - ``` Read the `silence_start`/`silence_end` lines and slice between gaps. #### Output convention Per-sound WAVs go in `out/<name>.wav` (mono, 44.1 kHz, 16-bit PCM). Downstream interpret rules call `analyze.load_mono(path)` from [src/analyze.py](../src/analyze.py). ### 2.2 Extract fundamental frequency and pitch sweep _(HIGH)_ Sample the spectrum at multiple time slices to detect both the static pitch and any sweep. ```python from analyze import load_mono, analyze_slice sample_rate, data = load_mono("out/click.wav") slices = [0, 5, 10, 20, 50] # ms freqs_over_time = [analyze_slice(data, sample_rate, t) for t in slices] ``` #### Mapping | Observation | Output |
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen