Inspiration

Most "AI ambient music" tools are either an opaque model you can't reason about, or a static preset player. I wanted the middle ground: a procedural engine where the same seed always reproduces the same piece, but with enough real parameters to actually shape the sound — not just pick from a few mood presets.

What it does

Ambient.Studio generates continuous procedural ambient music, live in the browser or exported as WAV. A seed drives the whole piece deterministically. From there you shape it directly:

  • Scale — diatonic mode selection (e.g. Major Pentatonic), changing the harmonic character of the piece
  • Tempo, Complexity, Space — sliders that shape density and mix in real time
  • Beatless mode — drop the rhythm section entirely for a pure drone
  • Drone Layers — add up to 8 sustained layers on top of the generator
  • Drums — switchable drum styles (e.g. Euclidean) with a Swing control
  • Duck — sidechain ducking that pulls the tonal bus down on every kick, the classic ambient-techno/dub pump
  • Sample Bank — the newest layer: deterministic triggering of real field-recording/soundscape samples alongside the procedural synthesis, ducked by the same sidechain as everything else
  • Export WAV — render any length offline, not just live playback

How I built it — and how Codex fit in

The engine (scales, drones, drum styles, swing, sidechain ducking) was already working going into Build Week. During the week, I used Codex to design and build the Sample Bank feature end to end — a new deterministic event type that lets the engine trigger real audio samples with the same seeded-RNG guarantees as everything else it generates.

This wasn't one-shot prompting. The process was:

  1. A spec with hard constraints up front: the sample logic has to stay pure and deterministic like the rest of the engine core, no Web Audio dependencies leaking into it, and it must not touch the engine's existing live-upload Track system — sample references stay plain JSON so they're compatible with a future automated/MCP-driven pipeline.
  2. A design note required before any code — Codex had to commit to answers on open questions (how to handle async sample decoding against a synchronous playback clock, how duplicate sample IDs should resolve) before writing anything.
  3. A second review pass, run like a real code-review cycle, caught a genuine race condition: duplicate sample IDs were resolving based on whichever network fetch happened to finish last, not deterministically. Codex fixed it by routing both the trigger logic and the decoder through the exact same exported function, so the two layers can't disagree. That same pass added a bounded fetch timeout (a stalled request could otherwise hang playback indefinitely) and fixed a lifecycle bug where triggered samples kept playing after the engine was stopped.
  4. Codex ran out of free-tier credits before the UI hookup was done — the engine logic shipped fully tested, but the controls you see in the Sample Bank panel above were wired into the existing React UI by hand afterward, following the same patterns the rest of the app already used.

GPT-5.6, via Codex, powered every one of those rounds — the design-note responses, the race-condition fix, and the lifecycle/ timeout fixes.

Challenges I ran into

  • Sample decoding is asynchronous; the rest of the engine's beat clock is synchronous and deterministic. Deciding what happens if a sample event fires before its buffer finishes decoding needed to be an explicit, committed design decision (skip it, don't queue it) — not something left implicit.
  • The duplicate-ID race was invisible in casual testing and only surfaced under review — a good reminder that green tests alone don't catch timing-dependent bugs.
  • Running out of Codex credits mid-project meant deciding, honestly, to ship the engine work as engine-complete-and-tested first, and do the UI wiring by hand rather than fake a "fully AI-built" feature that wasn't.

What I learned

Treating Codex like a review partner rather than an autocomplete — requiring a design note before code, verifying every diff against the original spec — caught a real concurrency bug that one-shot prompting almost certainly would have missed.

What's next

Making the drone/scale/drum-style/sample-bank parameters controllable by an AI agent through an MCP server, so a single instruction like "5 hours of lo-fi for studying" or "8 hours for deep sleep" could generate a full piece — the engine's core logic is already Node-importable and Web-Audio-free specifically to make that possible later.

Built With

Share this project:

Updates