Dev.to WebDev πŸ›  Dev πŸ‘ 0 πŸ“– 5 min read

White, Pink and Brown Noise in the Browser: Mix Five Noise Layers and Export a WAV

Disclosure first: I work on OnePassApps. Everything below was measured on our own build today - 6 November 2026 - in one signed-out Chrome session, and the numbers come from files the app actually produced. The panel op

Disclosure first: I work on OnePassApps. Everything below was measured on our own build today - 6 November 2026 - in one signed-out Chrome session, and the numbers come from files the app actually produced.

The panel opens with one line: "Mix white, pink and brown noise with a sleep timer, then download a WAV. Generated in this tab."

Try the Ambient Noise Mixer in your browser

Five layers, each with its own description

Stage 01 Layers holds five sliders - white, pink, brown, rain-like and fan-like - and each layer carries its own line of copy:

  • White noise - "Even energy at every frequency. Bright and hissy."
  • Pink noise - "Energy falls with frequency. Softer and more natural."
  • Brown noise - "Deep and rumbling, with little treble."
  • Rain-like - "Filtered noise with a steady, patter-like texture."
  • Fan-like - "Warm, low-passed noise like a distant fan."

The mixer opens with pink noise at 60% and every other layer at 0%, with master volume at 70%. Four presets sit above the sliders, and each one writes a specific mix. These are the levels I read back after pressing each preset in turn:

Preset White Pink Brown Rain-like Fan-like
Steady hush (the opening mix) 0% 60% 0% 0% 0%
Rainy window 0% 0% 25% 70% 0%
Distant fan 15% 0% 0% 0% 70%
Deep rumble 0% 20% 70% 0% 0%

Every layer also has a mute button named after the layer. Pressing one flips its accessible name to Unmute, drops that layer's readout to 0% and the panel says "White noise muted." Press it again and the name flips back to Mute and the panel says "White noise unmuted."

The sleep timer

Stage 02 offers Off, 15 min, 30 min, 60 min, 90 min and Custom. Choosing 15 min changes the panel to "Sleep timer set for 15 minutes. Audio fades out over the last 30 seconds." Choosing Custom opens a minutes field that came up at 45, and the same line read "Sleep timer set for 45 minutes. Audio fades out over the last 30 seconds." I did not change that 45.

While the mixer runs, the countdown ticks in real time: I watched it fall from 15:00 to 13:28 over ninety seconds. The panel's own rule is "Playback fades out over the last 30 seconds, then stops. Pausing pauses the timer." I did not let a timer run to its end, so the fade-out itself is the app's claim, not something I watched happen.

Playback

Press Play and the panel reads "Playing your mix"; the button becomes Pause, and until you press it the panel says "Press play to listen". The hint "Space play or pause" is on screen the whole time.

There is one real gate: with every layer at 0%, both Play and the download button are disabled and the panel says "Turn a layer up to listen". Raise one layer and both enable.

The WAV export

Stage 03 describes the file it will write: "A mono 16-bit WAV at 44.1 kHz, about 25.2 MiB, with a short fade in and out. Rendered in this tab and not uploaded." The length field takes 1 to 10 minutes and opens at 5, and the button label follows it - "Download 5 min WAV" until you change the number.

I exported three one-minute files, one per colour, each with only that layer up. Every file was named ambient-noise-1min.wav and every file was 5,292,044 bytes. That is not a rounded figure: 60 seconds x 44,100 samples x 2 bytes plus a 44-byte header is 5,292,044, so the file is one header and nothing else wrapped around uncompressed PCM. The header bytes read RIFF and WAVE, one channel, 44100 Hz, 16-bit.

The panel's "about 25.2 MiB" is what a five-minute export of the same format weighs - 26,460,044 bytes - so the size in the copy is right.

The fade is in the file. Measuring RMS over quarter-second windows, the white-noise export starts at 1197 in its first window, reaches about 4184 within half a second, holds there, and then falls across its last three seconds: 4170, 4068, 3941, 3726, 3472, 3127, 2745, 2306, 1849, 1342, 820, 314 - down to silence in the final window.

What the three colours actually are

I ran my own FFT over the three exports - 215 Hann-windowed 4096-sample frames taken from the steady middle of each file, averaged per octave band:

Export Octave-band power in dB, 20-40 Hz up to 10-20 kHz Slope above 320 Hz
White only 14.0, 14.0, 14.2, 14.1, 13.9, 13.9, 14.0, 13.9, 13.9, 14.0 0.0 dB per octave
Pink only 34.1, 29.2, 25.1, 21.9, 18.6, 15.5, 12.5, 9.5, 6.5, 3.5 -3.0 dB per octave
Brown only 30.9, 30.7, 29.0, 25.7, 20.5, 14.6, 8.8, 2.8, -3.0, -7.7 -5.7 dB per octave

White is flat to within a tenth of a dB across every band. Pink falls 3 dB per octave and brown falls about 5.7. The labels are not decorative: the three layers are spectrally different in the way the panel says they are.

How it is rendered, and where the bytes go

The export is rendered offline in the page. I wrapped the Web Audio constructors before the app's own scripts ran: playback built one live AudioContext, and the download built OfflineAudioContexts of 1,323,000 samples at 44,100 Hz - exactly 30 seconds each - so a one-minute file is two half-minute renders joined together.

The same trace answers the privacy question. Over the whole session the page made 135 requests, none of them a non-GET, and not one carried a request body. The hosts were app.onepassapps.com, api.onepassapps.com, clerk.onepassapps.com and Cloudflare's own beacon. The panel's "Nothing leaves this tab." and "Generated live in this tab. Some phones pause audio when the screen locks." line are consistent with that, and the first is backed by the trace rather than only by the copy.

The step-by-step version is in the app guide.

Limits

  • One browser, one signed-out session, one build on 6 November 2026.
  • Only the white, pink and brown exports were analysed spectrally. Rain-like and fan-like were mixed in the app but not exported and measured.
  • The files I analysed were one minute long, not the five-minute default.
  • I did not run a sleep timer to its end, so the 30-second fade-out at the end of a timer is the app's claim.
  • The custom timer opened at 45 minutes; I did not change it.
  • I did not take a second reading of the layer readouts after unmuting, so I am not quoting restored levels.
  • The network trace covers the HTTP requests the page made; I did not capture WebSocket frames.

I work on OnePassApps, so the mixer, the timer and the file writer are ours - and every number above came out of files this app wrote on this machine.

πŸ“° Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.