# Audio automation lanes Breakpoint envelopes on audio tracks, edited in the timeline the way Ableton Live edits arrangement automation: expand a lane under the track, pick a parameter, click to add points, drag to shape. Applies to track volume and to FX-chain parameters. Status: SPEC — not implemented. Builds on the `wa-*` Web Audio FX stack. --- ## 1. Why this shape Two facts make this cheaper here than in most editors: 1. **Web Audio has native envelope playback.** `AudioParam` scheduling (`linearRampToValueAtTime`, `setValueCurveAtTime`) is sample-accurate and runs on the audio thread. No per-frame JS evaluates the envelope; the studio only *schedules* it. 2. **Preview and render share one graph.** The render runs the same builders in an `OfflineAudioContext`, so an envelope scheduled the same way in both places is identical by construction. No parity harness needed. And one fact makes the UI cheap: the FX registry already declares `min` / `max` / `step` / `unit` / `scale` for every parameter. A lane's y-axis, clamping, and log/linear mapping are read from the registry — the lane component knows nothing about any specific effect (same principle as the panel). ## 2. What exists today (grounding) - **Static volume**: `data-volume` on the element; baseline gain. - **GSAP volume tweens**: `tl.to("#bgm", { volume: 0 })` — probed at 60 Hz into `volumeKeyframes`, applied in preview via `interpolateVolumeGain` (`runtime/media.ts`) and baked into PCM at render via `applyVolumeEnvelopeToWav` (sample-accurate) with an ffmpeg-expression fallback (`MAX_VOLUME_SEGMENTS = 32`). - **FX chains**: `data-fx-chain` serialised on the element; transport splices the graph between decoded source and gain (`attachElementFxChain`); render runs the same graph offline. Worklet params are set via `port.postMessage`, **not** AudioParams. - **Transport scheduling**: sources are (re)scheduled on play, seek, and rate change (`scheduleWebAudioForActiveClips`), started with an `elapsed` offset into the buffer. Envelope scheduling piggybacks on exactly these moments. - **Timeline lanes**: `TimelineLanes.tsx` renders track rows; `TimelinePropertyLanes.tsx` is the keyframe-lane precedent; `AudioWaveform.tsx` already draws the waveform the envelope will sit over. - **Edit plumbing**: `onSetAttributeLive` (coalesced, no preview refresh) for drags; `onSetAttribute` persists on gesture end. Proven by the wa-8 fix. ## 3. UX spec (Ableton mapping) | Ableton | Here | | --- | --- | | Automation triangle on track header | Expand toggle on audio track rows in the timeline gutter | | One parameter per lane, selector at lane left | Same. Selector lists `Volume` + every automatable param of every chain node (`Compressor · Threshold`) | | Breakpoint envelope over the clip | SVG envelope drawn over the existing waveform, clip-local | | Double-click segment → add point | Same | | Drag point (value tooltip) | Same; tooltip shows value + unit from the registry | | Drag segment vertically → bend curvature | Same (Phase 2; format supports it from v1) | | Delete key / right-click → remove point | Same | | Dimmed line when no automation | Flat line at the current static value; first edit creates the lane | Lane height ~48 px expanded. Multiple lanes per track may be open at once (one per parameter), matching Ableton's "+" lanes — Phase 2; V1 shows one lane per track with the selector. **Editing writes:** point drags go through `onSetAttributeLive`; release persists via `onSetAttribute`. The running graph follows the attribute (wa-8 observer), so edits are audible without a reload. Undo = attribute history, coalesced per gesture — free. ## 4. Data model Serialised on the element, versioned, same pattern as `data-fx-chain`: ```html