# Control narrative playback — Vreo

Wire pause, resume, replay, visibility, events, and disposal to the public Player API.

Canonical: https://developer.realsee.ai/docs/vreo/playback-controls
Source: https://developer.realsee.ai/docs/vreo/playback-controls.md
Language: en

[Download examples](https://developer.realsee.ai/starters/react-five/1.3.0/starter.zip)

Use the player returned by the [quickstart](https://developer.realsee.ai/docs/vreo/quickstart). Keep one owner for its lifecycle so event listeners and the player are disposed together.

```ts title="examples/sdk-guides/src/vreo/controls.ts"
import type { Player } from '@realsee/vreo'
import type { VreoUnit } from '@realsee/vreo/typings'

export function bindNarrativeControls(player: Player, report: (status: string) => void) {
  const stops = [
    player.on('loaded', () => report('loaded')),
    player.on('playing', () => report('playing')),
    player.on('paused', (ended) => report(ended ? 'ended' : 'paused'))
  ]
  return {
    pause() { player.pause() },
    resume() { return player.play(player.getCurrentTime(), true) },
    // In 2.6.4 play(0) does not seek; load resets the timeline and keyframes, then starts playback.
    async replay(unit: VreoUnit) { return player.load(unit, 0, false, true, true) },
    hide() { player.hide() },
    show() { player.show() },
    dispose() { stops.forEach((stop) => stop()); player.dispose() }
  }
}
```

Connect the returned methods to user controls. Times are milliseconds. Resume passes `player.getCurrentTime()` explicitly. Retain the current `VreoUnit` and pass it to `await controls.replay(unit)` to restart the same narrative from zero, whether it is playing or paused. Disable repeated Replay clicks until the promise settles, handle rejection, and check the returned boolean before announcing playback.

In Vreo 2.6.4, `play(0)` does not seek: an already playing player returns immediately, and a paused player skips the zero-time assignment. The example instead calls the public `load(unit, 0, false, true, true)` method. This cancels the previous playback, resets the timeline and keyframe state, copies the script, and starts playback as a user action. Replay is asynchronous; Resume remains a synchronous `play()` call. A `false` result means the requested operation did not start.

## Keep UI state honest

`loaded`, `playing`, and `paused` are published events. The `paused` event may receive `true` when the narrative has ended. This example uses that signal because the published Player forwards completion through `paused`.

`hide()` changes interface visibility. It is not a substitute for `pause()`. If closing your panel should stop playback, call pause as well. On route or scene replacement, call the returned `dispose()` before disposing the owning Five instance. Do not use a disposed player for another script.

## Verify

Pause midway, resume near the saved time, then replay from zero. Hide and show the UI without claiming it pauses automatically. Leave and remount the route, and confirm the old narrative and callbacks no longer run.

[Published Player contract](https://unpkg.com/@realsee/vreo@2.6.4/lib/Player/index.d.ts) · [Player events](https://unpkg.com/@realsee/vreo@2.6.4/lib/typings/VreoUnit.d.ts)
