Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,50 @@
# Timeline Operations
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
The `timeline-operations.ts` module handles view-state mutations that do **not** affect the audio arrangement and therefore do not push undo commands. These helpers operate on `TimelineState` snapshots and return partial updates that the engine merges into its internal state. Keeping view logic separate from arrangement logic makes the engine easier to reason about and test.
## Features
- `setSelection` normalises reversed ranges and clamps to document duration
- `setLoopRegion` updates loop boundaries without clamping
- `zoomIn` / `zoomOut` step through a discrete zoom table
- `setZoomLevel` snaps arbitrary `samplesPerPixel` values to the table
## Usage
### Basic
```ts
import { setSelection, setLoopRegion } from "@suaveplan/audio-timeline/operations";
const sel = setSelection(state, 100, 50); // normalises to 50..100
const loop = setLoopRegion(state, 0, 5000);
```
### Advanced
```ts
import { zoomIn, zoomOut, setZoomLevel } from "@suaveplan/audio-timeline/operations";
const z1 = zoomIn(zoomTable, 3); // { zoomIndex: 4, samplesPerPixel: 16 }
const z2 = setZoomLevel(zoomTable, 150); // snaps to 128
```
## API Reference
| Export | Signature | Description |
|--------|-----------|-------------|
| `setSelection` | `(state, start, end) => { selectionStart, selectionEnd }` | Normalise and clamp |
| `setLoopRegion` | `(state, start, end) => { loopStart, loopEnd }` | Set loop bounds |
| `zoomIn` | `(table, index) => { zoomIndex, samplesPerPixel }` | Step in |
| `zoomOut` | `(table, index) => { zoomIndex, samplesPerPixel }` | Step out |
| `setZoomLevel` | `(table, spp) => { zoomIndex, samplesPerPixel }` | Snap to table |
## Implementation Notes
Zoom and selection are purely view state; they are not part of the undo history because users expect zoom gestures to be ephemeral. Keeping these helpers pure makes them trivial to unit-test without instantiating a full `TimelineEngine`. The clamping logic in `setSelection` guarantees that consumers always read `selectionStart <= selectionEnd`, even when the user drags the selection backwards. Loop boundaries are not clamped because the engine may allow loops that extend beyond the current document length for live expansion workflows.