# Web Components Migration Spec Migrate to native Web Components under the **dawcore** brand, making the library truly framework-agnostic — works with vanilla JS, React 19+, Vue, Svelte, Angular, or any framework that supports Custom Elements. **Status:** Living spec — core shipped in `@dawcore/components`; remaining work tracked in epics [#452](https://github.com/naomiaro/waveform-playlist/issues/452)–[#458](https://github.com/naomiaro/waveform-playlist/issues/458). Last audited against code 2026-06-11. **Target:** dawcore 1.0.0 **npm:** `@dawcore/*` **GitHub:** [github.com/dawcore](https://github.com/dawcore) (repo transfer deferred — see Open Questions) --- ## Motivation - **Framework-agnostic** — usable in vanilla JS, Lit, Svelte, Vue, Angular, or React without adapters - **Smaller bundle** — no React/ReactDOM/styled-components runtime dependency - **Web standard** — Custom Elements, Shadow DOM, and CSS Parts are supported in all modern browsers - **Ecosystem alignment** — WAM plugins, Storybook, and @dnd-kit/dom all support Web Components natively - **Simpler API** — HTML elements with attributes, properties, methods, and events --- ## Package Landscape The original plan renamed every `@waveform-playlist/*` package into the `@dawcore/*` scope and replaced the React packages outright. **Decision (shipped): the two ecosystems coexist instead.** - **`@waveform-playlist/*`** remains the React surface (`browser`, `ui-components`, `recording`, `annotations`, `spectrogram`, `midi`) plus the shared framework-agnostic foundations (`core`, `engine`, `playout`, `worklets`, `webaudio-peaks`, `loaders`, `media-element-playout`). No renames. - **`@dawcore/*`** is the Web Components ecosystem, versioned independently at 0.x: | Package | Directory | Description | | ---------------------- | ------------------------------ | ---------------------------------------------------------------------------------- | | `@dawcore/components` | `packages/dawcore` | Web Components UI layer — Lit Custom Elements with Shadow DOM | | `@dawcore/transport` | `packages/transport` | Native Web Audio transport/scheduler (no Tone.js); provides `NativePlayoutAdapter` | | `@dawcore/spectrogram` | `packages/dawcore-spectrogram` | Framework-agnostic spectrogram compute (worker pool) | | `@dawcore/midi` | `packages/dawcore-midi` | Framework-agnostic MIDI parsing (optional peer of components) | | `@dawcore/wam` | `packages/dawcore-wam` | WAM 2.0 plugin hosting (optional peer) | | `@dawcore/faust` | `packages/dawcore-faust` | In-browser Faust DSP → WAM compilation (optional peer) | `@dawcore/components` consumes the shared foundations as peers (`@waveform-playlist/core`, `@waveform-playlist/engine`, `@waveform-playlist/worklets`) — the engine and type layer serve both surfaces. When a React package has framework-agnostic logic worth sharing, it follows the two-flavor split convention: `@dawcore/X` core + `@waveform-playlist/X` React wrapper (precedents: spectrogram, midi). React packages without a Web Components equivalent yet: the recording arming surface (epic #453). --- ## Custom Elements > **Implementation status:** the core editor elements are shipped. `` core (#473) is implemented. Annotation elements (epic #455) are implemented. Elements listed in this spec that don't exist yet are tracked in epics: transport/control elements (#452), record arming + VU meter (#453), `` follow-ups — effects (#475), `` (#476), transport-compat tests (#474), annotation hosting in `` (#477) — individual track-control elements (#457). ### Core Elements ```html ``` ### Element Registry | Element | Wraps | Responsibilities | | --------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `` | PlaylistEngine + external `PlayoutAdapter` | Root element. Manages engine, tracks, state. Requires a consumer-provided adapter (`editor.adapter`) — it creates no AudioContext or adapter of its own (#378). | | `` | Track state | Declares a track. Contains `` children. Attributes: `name`, `volume`, `pan`, `muted`, `soloed`, `record-armed`, `input-device`, `render-mode`. `src` is shorthand for a track with a single implicit clip. | | `` | AudioClip | Audio or MIDI clip within a track. Attributes: `src`, `peaks-src`, `start`, `duration`, `offset`, `gain`, `name`, `color`, `fade-in`, `fade-out`, `fade-type`. Multiple clips sharing the same `src` share one decoded AudioBuffer. | | `` | Canvas rendering | Waveform visualization. Renders peaks to canvas. | | `` | Transport controls container | Groups transport buttons, links to an editor via `for` attribute. | | `` | Track mixer strip | Shipped composite: name, volume, pan, mute, solo for one track, rendered by the editor in the frozen controls column. Dispatches a unified `daw-track-control` event (`{trackId, prop, value}`). Individual control elements below complement it (#457). | | `` | play() | Triggers playback. If recording is armed, starts overdub recording simultaneously. | | `` | pause() / togglePauseRecording() | Pauses playback. During recording, toggles pause/resume of the worklet capture (Audacity-style). Reflects state via `data-paused` attribute; sync handled by `daw-recording-pause` / `daw-recording-resume` events so the spacebar shortcut and the button stay consistent. | | `` | stop() | Stops playback and recording. Finalizes any in-progress recording into a new clip. | | `` | record() | Arms/starts recording on all armed tracks. When clicked during stop, arms the selected track (or first track). When clicked during play, starts overdub on armed tracks. | | `` | seekTo(0) | Rewinds playhead to the start of the timeline. | | `` | seekTo(duration) | Jumps playhead to the end of the timeline. | | `` | toggleLoop() | Toggles loop playback for the current selection. Reflects `aria-pressed` state. | | `` | currentTime | Shows formatted playback time. | | `` | setSelection() | Editable input showing selection start time. Updates selection on change. | | `` | setSelection() | Editable input showing selection end time. Updates selection on change. | | `` | setTimeFormat() | Select for time display format (`hh:mm:ss.sss`, `hh:mm:ss`, `seconds`). Affects time display and selection inputs. | | `` | editor.bpm property | Editable BPM input. Reflects current tempo. Drives grid/ruler musical time and snap. Display-only when consumer tick callbacks make the external tempo map authoritative (#407). | | `` | editor.timeSignature property | Editable time signature (e.g., `4/4`, `3/4`, `6/8`). Drives ruler subdivisions and snap grid. | | `` | setSnapTo() | Select for snap granularity. Controls clip drag/trim snapping and `` line density. See [Snap Subdivisions](#snap-subdivisions). | | `` | setScaleMode() | Select for ruler display mode (`beats`, `temporal`). Switches between bar:beat and minutes:seconds ruler. | | `` | zoomIn() | Zoom in button. Disabled when at maximum zoom. | | `` | zoomOut() | Zoom out button. Disabled when at minimum zoom. | | `` | undo() | Undo last structural edit. Auto-disables when `canUndo` is false. | | `` | redo() | Redo last undone edit. Auto-disables when `canRedo` is false. | | `` | setPlaybackRate() | Playback speed control. Works with both `` and ``. | | `` | HTMLMediaElement | Lightweight single-track player. Uses `