# TimelineEngine _(no submodules)_ ## Purpose `TimelineEngine` is the central state container for the `@suaveplan/audio-timeline` package. It owns the multi-track arrangement, playback transport, mixer state, zoom/selection view state, and a full undo/redo history. All rendering is delegated to a pluggable `TimelineAdapter`, keeping the engine headless and suitable for both web and native targets. ## Features - Track CRUD: `setTracks`, `addTrack`, `removeTrack`, `updateTrack`, `selectTrack` - Clip CRUD: `addClip`, `removeClip`, `moveClip`, `trimClip`, `splitClip` - Transport: `play`, `pause`, `stop`, `seek` guarded by an internal FSM - Mixer: `setMasterVolume`, `setTrackVolume`, `setTrackMute`, `setTrackSolo`, `setTrackPan` - View: `zoomIn`, `zoomOut`, `setZoomLevel`, `setSelection`, `setLoopRegion`, `setLoopEnabled` - Undo/redo with transaction support (`beginTransaction`, `commitTransaction`, `abortTransaction`) - Serialization via `toJSON` and static `fromJSON` - Typed events via `on` / `off` - OTel spans and counters for clip operations and transport ## Usage ### Basic ```ts import { TimelineEngine, NullTimelineAdapter } from "@suaveplan/audio-timeline"; const engine = new TimelineEngine({ sampleRate: 44100 }); engine.setAdapter(new NullTimelineAdapter()); engine.addTrack({ name: "Drums" }); engine.play(); ``` ### Advanced ```ts engine.beginTransaction(); engine.addClip(trackId, clip); engine.moveClip(trackId, clip.id, 500); engine.commitTransaction(); engine.undo(); ``` ## API Reference `TimelineEngine` exposes the full public surface documented in the spec. Key getters: `getState()` returns an immutable snapshot; `getCurrentTime()` reads from the adapter; `getTempo()` returns current BPM. ## Implementation Notes The engine is deliberately headless. It does not touch the DOM or Web Audio directly; every output goes through the adapter. State mutations push `Command` instances onto an `UndoStack`. On undo/redo, if the track count is unchanged the engine calls `adapter.updateTrack` per changed track instead of `adapter.setTracks` to avoid playback interruption. Events are emitted through an `EventBus` so UI layers can subscribe to granular changes without polling.