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-ENDLISTRules:
#EXT-X-TARGETDURATIONis the maxEXTINFin the playlist. Required.#EXTINF:<seconds>,precedes each segment URL. The decimal seconds drivePlaylistSegment.startTimeandendTime.- Segment URLs can be relative (resolved against the playlist URL) or absolute.
#EXT-X-ENDLISTmarks 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.