# Ring modulation implementation

Built directly from `prompt.txt` using plain HTML, CSS, JavaScript and native Web Audio. There are no external resources, libraries, services or installations.

## Chosen behavior

- AudioContext and oscillators are created only when Play is clicked. Presets, frequency controls, level and bypass can be configured silently beforehand.
- A sine carrier passes through a GainNode whose intrinsic gain is zero. A second bipolar sine oscillator drives that gain parameter. This implements waveform multiplication, rather than ordinary unipolar tremolo or a mix of the two oscillators.
- Start setting: carrier 440 Hz, multiplier 80 Hz, output gain −28 dB. Its expected sidebands are 360 Hz and 520 Hz. Each ideal sideband has half the multiplication output's gain amplitude.
- Quiet soundscape: carrier 220 Hz, multiplier 55 Hz, output gain −36 dB. The expected sidebands are 165 and 275 Hz, two harmonics of 55 Hz. It is a simple sustained layer, with no extra effects or sequencing.
- Play and Stop have short gain ramps. Frequencies, level and bypass changes are smoothed to reduce clicks. Selecting a preset updates a playing sound but does not start a stopped one.
- Bypass crossfades to the original carrier, while keeping the same output gain control. Bypassed audio can sound louder than the ring-modulated signal because its energy is concentrated in one tone.
- Frequency controls: integer hertz, carrier 20–1,200 Hz and multiplier 1–600 Hz. Number fields commit on change/blur or Enter; sliders update while dragging. Level is −48 to −12 dB.
- The spectrum analyzes the actual output with a 16,384-point FFT. Vertical dotted markers show expected component positions. Its frequency extent adapts to the current settings; its vertical scale is fixed from −90 to 0 dBFS.
- Equal carrier and multiplier frequencies produce a DC component and a doubled-frequency tone; the readout explicitly identifies DC as inaudible.

## Known limitations and verification

- `node --check app.js` passed (JavaScript syntax check). This does not verify browser rendering, interactions or sound.
- No listening or browser verification was performed by this implementation agent; the coordinating agent owns browser verification. Comfortable gain defaults are numerical starting points, and perceived loudness also depends on the user's device volume and speakers/headphones.
- The spectrum has finite FFT resolution and window leakage. Peaks may cover neighboring bins and their plotted heights can differ from ideal component amplitudes. In stereo hardware both channels receive the same mono signal.
- The page stops sound on page exit. Switching tabs alone does not automatically stop a soundscape. If the browser suspends the audio context, the transport resets to Stopped and requires another Play click.
- The initial implementation snapshot is preserved in `attempts/001/`. Changes, if needed after external review, should be made only in the live files.
