@waveform-playlist/browser 9.1.2 → 9.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1112,7 +1112,7 @@ export declare const PlaylistVisualization: default_2.FC<PlaylistVisualizationPr
1112
1112
 
1113
1113
  export declare interface PlaylistVisualizationProps {
1114
1114
  renderTrackControls?: (trackIndex: number) => ReactNode;
1115
- renderTimestamp?: (timeMs: number, pixelPosition: number) => ReactNode;
1115
+ renderTick?: (label: string, pixelPosition: number) => ReactNode;
1116
1116
  /** Custom playhead render function. Receives position (pixels) and color from theme. */
1117
1117
  renderPlayhead?: RenderPlayheadFunction;
1118
1118
  annotationControls?: AnnotationAction[];
@@ -1189,6 +1189,43 @@ export declare const SkipForwardButton: default_2.FC<{
1189
1189
  className?: string;
1190
1190
  }>;
1191
1191
 
1192
+ declare type SnapTo = 'bar' | 'beat' | 'off';
1193
+
1194
+ declare interface SnapToGridBeatsOptions {
1195
+ mode: 'beats';
1196
+ snapTo: SnapTo;
1197
+ bpm: number;
1198
+ timeSignature: [number, number];
1199
+ samplesPerPixel: number;
1200
+ sampleRate: number;
1201
+ }
1202
+
1203
+ /**
1204
+ * dnd-kit modifier that quantizes clip drag movement to a grid.
1205
+ *
1206
+ * Two modes:
1207
+ * - "beats": Snaps to beat/bar grid using PPQN tick space for exact musical timing.
1208
+ * - "temporal": Snaps to a sample-based grid derived from timescale markers.
1209
+ *
1210
+ * Designed to compose with ClipCollisionModifier — snap first,
1211
+ * then collision constrains the snapped position.
1212
+ */
1213
+ export declare class SnapToGridModifier extends Modifier<DragDropManager<any, any>, SnapToGridOptions> {
1214
+ apply(operation: DragOperation): {
1215
+ x: number;
1216
+ y: number;
1217
+ };
1218
+ static configure: (options: SnapToGridBeatsOptions | SnapToGridTemporalOptions) => PluginDescriptor<any, any, typeof SnapToGridModifier>;
1219
+ }
1220
+
1221
+ declare type SnapToGridOptions = SnapToGridBeatsOptions | SnapToGridTemporalOptions;
1222
+
1223
+ declare interface SnapToGridTemporalOptions {
1224
+ mode: 'temporal';
1225
+ gridSamples: number;
1226
+ samplesPerPixel: number;
1227
+ }
1228
+
1192
1229
  /**
1193
1230
  * Caches parsed SoundFont2 data and AudioBuffers for efficient playback.
1194
1231
  *
@@ -1608,10 +1645,19 @@ declare interface UseAnnotationKeyboardControlsOptions {
1608
1645
  * { src: 'audio/drums.mp3', name: 'Drums' },
1609
1646
  * ]);
1610
1647
  *
1611
- * // Progressive loading (tracks appear as they load)
1612
- * const { tracks, loading, loadedCount, totalCount } = useAudioTracks(
1613
- * [{ src: 'audio/vocals.mp3' }, { src: 'audio/drums.mp3' }],
1614
- * { progressive: true }
1648
+ * // Immediate rendering with deferred engine build (recommended for multi-track)
1649
+ * const { tracks, loading } = useAudioTracks(
1650
+ * [
1651
+ * { src: 'audio/vocals.mp3', name: 'Vocals', duration: 30 },
1652
+ * { src: 'audio/drums.mp3', name: 'Drums', duration: 30 },
1653
+ * ],
1654
+ * { immediate: true }
1655
+ * );
1656
+ * // All tracks render instantly as placeholders, peaks fill in as files load
1657
+ * return (
1658
+ * <WaveformPlaylistProvider tracks={tracks} deferEngineRebuild={loading}>
1659
+ * ...
1660
+ * </WaveformPlaylistProvider>
1615
1661
  * );
1616
1662
  *
1617
1663
  * // Pre-loaded AudioBuffer (skip fetch/decode)
@@ -1623,11 +1669,6 @@ declare interface UseAnnotationKeyboardControlsOptions {
1623
1669
  * const { tracks } = useAudioTracks([
1624
1670
  * { waveformData: preloadedPeaks, name: 'Peaks Only' }, // Renders immediately
1625
1671
  * ]);
1626
- *
1627
- * if (loading) return <div>Loading {loadedCount}/{totalCount}...</div>;
1628
- * if (error) return <div>Error: {error}</div>;
1629
- *
1630
- * return <WaveformPlaylistProvider tracks={tracks}>...</WaveformPlaylistProvider>;
1631
1672
  * ```
1632
1673
  */
1633
1674
  export declare function useAudioTracks(configs: AudioTrackConfig[], options?: UseAudioTracksOptions): {
@@ -1643,10 +1684,16 @@ export declare function useAudioTracks(configs: AudioTrackConfig[], options?: Us
1643
1684
  */
1644
1685
  declare interface UseAudioTracksOptions {
1645
1686
  /**
1646
- * When true, tracks are added to the playlist progressively as they load,
1647
- * rather than waiting for all tracks to finish loading.
1648
- * Default: false (wait for all tracks)
1687
+ * When true, all tracks render immediately as placeholders with clip geometry
1688
+ * from the config. Audio fills in progressively as files decode, and peaks
1689
+ * render as each buffer becomes available. Use with `deferEngineRebuild={loading}`
1690
+ * on the provider for a single engine build when all tracks are ready.
1691
+ *
1692
+ * Requires `duration` or `waveformData` in each config so clip dimensions are known upfront.
1693
+ * Default: false
1649
1694
  */
1695
+ immediate?: boolean;
1696
+ /** @deprecated Use `immediate` instead. */
1650
1697
  progressive?: boolean;
1651
1698
  }
1652
1699
 
@@ -1688,7 +1735,7 @@ declare interface UseAudioTracksOptions {
1688
1735
  * );
1689
1736
  * ```
1690
1737
  */
1691
- export declare function useClipDragHandlers({ tracks, onTracksChange, samplesPerPixel, sampleRate, engineRef, isDraggingRef, }: UseClipDragHandlersOptions): {
1738
+ export declare function useClipDragHandlers({ tracks, onTracksChange, samplesPerPixel, sampleRate, engineRef, isDraggingRef, snapSamplePosition, }: UseClipDragHandlersOptions): {
1692
1739
  onDragStart: (event: Parameters<DragStartEvent>[0]) => void;
1693
1740
  onDragMove: (event: Parameters<DragMoveEvent>[0]) => void;
1694
1741
  onDragEnd: (event: Parameters<DragEndEvent>[0]) => void;
@@ -1704,6 +1751,9 @@ declare interface UseClipDragHandlersOptions {
1704
1751
  * skips engine rebuilds so engine keeps original clip positions. On drag end,
1705
1752
  * engine.trimClip() commits the final delta. Obtain from usePlaylistData(). */
1706
1753
  isDraggingRef: default_2.MutableRefObject<boolean>;
1754
+ /** Optional function that snaps a sample position to the nearest grid position.
1755
+ * Used for boundary trim snapping (move snapping is handled by the SnapToGridModifier). */
1756
+ snapSamplePosition?: (samplePosition: number) => number;
1707
1757
  }
1708
1758
 
1709
1759
  /**
@@ -2166,6 +2216,10 @@ declare interface WaveformPlaylistProviderProps {
2166
2216
  /** SoundFont cache for sample-based MIDI playback. When provided, MIDI clips
2167
2217
  * use SoundFont samples instead of PolySynth synthesis. */
2168
2218
  soundFontCache?: SoundFontCache;
2219
+ /** When true, tracks render visually but the engine build is deferred.
2220
+ * Use this during progressive loading to avoid rebuilding the engine for
2221
+ * each track — flip to false when all tracks are ready for a single build. */
2222
+ deferEngineRebuild?: boolean;
2169
2223
  children: ReactNode;
2170
2224
  }
2171
2225
 
@@ -2226,6 +2280,10 @@ declare interface WaveformPlaylistTheme {
2226
2280
 
2227
2281
  export declare interface WaveformProps {
2228
2282
  renderTrackControls?: (trackIndex: number) => ReactNode;
2283
+ /** Custom render function for timescale tick labels. `label` is a formatted string
2284
+ * (bar/beat notation like "2.3" in beats mode, or "m:ss" in temporal mode). */
2285
+ renderTick?: (label: string, pixelPosition: number) => ReactNode;
2286
+ /** @deprecated Use `renderTick` instead. */
2229
2287
  renderTimestamp?: (timeMs: number, pixelPosition: number) => ReactNode;
2230
2288
  /** Custom playhead render function. Receives position (pixels) and color from theme. */
2231
2289
  renderPlayhead?: RenderPlayheadFunction;