Skip to content

Core: Time & State

A progress bar needs position, duration, and buffered range in one read; a status pill needs a typed enum, not a raw backend string. The kit provides both.

Time

time() reads the current position in seconds; time(seconds) seeks to a new one, there is no separate seek() method. Position is reported by two different events for two different reasons: ordinary playback ticks the time event (per frame) and the throttled progress event, while a deliberate jump fires the cancellable beforeSeekseekseeked cycle. It is the split the web platform draws between timeupdate and seeking/seeked, the tick versus the jump. buffered(), bufferedRanges(), and seekable() read the rest of the position picture straight from the backend, each returning a safe zero or empty range when no backend is registered yet. duration() returns the last value the backend reported through the duration event, or 0 before metadata has loaded.

timeData() bundles all of it into one TimeState snapshot: time (alias of position), position, duration, buffered, remaining, and percentage, computed together so the values are consistent at the moment of the call instead of drifting across four separate reads.

playbackRate() reads the current multiplier; playbackRate(rate) clamps it to [0.25, 2] and dispatches beforePlaybackRate before applying it, same cancellable shape as transport. It fires unconditionally, independent of setup({ mutationGuards }), since a speed change is cheap and every consumer expects it to always be interceptable. playbackRates() returns the fixed list of values a speed-selector UI should offer: [0.5, 0.75, 1, 1.25, 1.5, 2].

Coarse state

Four readers turn backend and platform detail into a typed enum:

  • bufferState(): BufferState.IDLE / LOADING / SEEKING / STALLED, derived from the active backend. IDLE when no backend is registered.
  • networkState(): NetworkState.ONLINE / OFFLINE / SLOW, from the platform’s network monitor. ONLINE when none is configured, SLOW below a 1.5 Mbps downlink.
  • streamState(): the backend’s raw state string ('idle', 'loading', 'playing', …). Prefer bufferState() for typed access.
  • visibilityState(): VisibilityState.VISIBLE / HIDDEN, from the platform’s visibility monitor. VISIBLE when none is configured.

Every one of these has a safe default for the no-backend, no-monitor case, which is exactly the state a kit composition like MinimalPlayer is in until you attach real infrastructure.

TypeScript
/**
* Time and coarse-state reads. `timeData()` bundles position, duration,
* buffered, remaining, and percentage into one snapshot instead of four
* separate calls. The state readers (`bufferState`, `networkState`, and
* their siblings `streamState` / `visibilityState` / `qualityMode` /
* `audioTrackMode`) return typed enum values instead of raw backend strings,
* with safe defaults when no backend or platform monitor is registered.
*/

import { BufferState, NetworkState } from '@nomercy-entertainment/nomercy-player-core';
import { tourPlayer } from './tour-player';

const player = tourPlayer('time-state-demo');
player.setup({ logLevel: 'info' });
await player.ready();

console.log(player.timeData());
// { position: 0, duration: 0, buffered: 0, remaining: 0, percentage: 0 } — no media loaded yet

console.log(player.bufferState() === BufferState.IDLE); // true — no backend registered
console.log(player.networkState() === NetworkState.ONLINE); // true — no monitor configured, safe default

// playbackRate() dispatches beforePlaybackRate before applying the clamped rate.
player.on('beforePlaybackRate', (event) => {
event.data.rate = Math.min(event.data.rate, 1.5); // clamp to a house limit below the kit's own [0.25, 2]
});

await player.playbackRate(2);
console.log(player.playbackRate()); // 1.5 — the listener's mutation won

await player.dispose();

Next steps

  • The Queue: the cursor-aware list every next() / previous() / item() call reads from.