D
DreamLake

API

Recipes

Short, copy-friendly recipes for the common edge-cases that aren't core API. For how to write a view, see Custom Views.

Core API without React

TimelineClock and Playlist are framework-agnostic:

import { Playlist, TimelineClock } from '@vuer-ai/vuer-m3u';
 
const engine = new Playlist({ url: '/data.m3u8' });
const parsed = await engine.init();
 
const clock = new TimelineClock();
clock.extendDuration(parsed.totalDuration);
clock.on('tick', async ({ time }) => {
  const result = await engine.getDataAtTime(time);
  if (result) {
    // result.decoded is whatever the decoder produced
    // result.segment carries the PlaylistSegment metadata
  }
});
clock.play();

Use this when you want timeline-driven data without a React tree — headless tests, server-side rendering of annotations, or plumbing into another animation framework.

Custom decoders

Register a decoder globally by chunkFormat name (the file extension of the segment URL):

import { registerDecoder } from '@vuer-ai/vuer-m3u';
import { decode as mpkDecode } from '@msgpack/msgpack';
 
registerDecoder('mpk', (raw) => mpkDecode(new Uint8Array(raw)));

Or override decoding for a single engine (useful when the format has no agreed-upon extension):

new Playlist({
  url: '/data.m3u8',
  decoder: (raw, segment, playlist) => myCustomDecode(raw),
});

Built-in: jsonl, vtt (text), ts (raw ArrayBuffer).

Authenticated fetch

Pass a wrapping fetchFn — applies to both the playlist and every segment fetch:

new Playlist({
  url: 'https://api.example.com/experiment/abc/imu.m3u8',
  fetchFn: (url, init) =>
    fetch(url, {
      ...init,
      headers: {
        ...init?.headers,
        Authorization: `Bearer ${token}`,
      },
    }),
});

This does not apply to VideoPlayer — hls.js fetches the HLS playlist itself with its own loader.

Live streaming

Omit #EXT-X-ENDLIST from your playlist. The engine polls at pollInterval (default: targetDuration * 1000ms) and emits playlist-updated events as new segments appear. usePlaylist auto-extends the clock duration on each update.

const { engine, playlist } = usePlaylist({
  url: '/live/stream.m3u8',
  pollInterval: 3000,
});

Polling stops automatically the first time the playlist includes #EXT-X-ENDLIST.

Authoring an m3u8 playlist

Minimal VOD playlist with three JSONL chunks:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
 
#EXTINF:10.000,
chunk-000.jsonl
#EXTINF:10.000,
chunk-001.jsonl
#EXTINF:10.000,
chunk-002.jsonl
#EXT-X-ENDLIST

Rules:

  • #EXT-X-TARGETDURATION is the max EXTINF in the playlist. Required.
  • #EXTINF:<seconds>, precedes each segment URL. The decimal seconds drive PlaylistSegment.startTime and endTime.
  • Segment URLs can be relative (resolved against the playlist URL) or absolute.
  • #EXT-X-ENDLIST marks a finalized VOD playlist; omit for live.

Each view page in the views catalog includes a Python snippet that generates a matching chunk + playlist pair for that view's schema.

Mixing independent clocks

One <ClockProvider> covers the default case. For a preview timeline alongside the main one, pass clock explicitly:

<ClockProvider clock={mainClock}>
  <ImuView src="/imu.m3u8" />              {/* uses mainClock */}
  <ImuView src="/preview.m3u8" clock={previewClock} />
</ClockProvider>

Explicit clock always wins over context.