Skip to content

Feature Request: Add pause() and resume() public API to Player #294

@xile611

Description

@xile611

Description

The Player class currently has no public pause() or resume() methods. Users who need to implement playback controls (pause/resume/restart) must access private internal fields, which is fragile and breaks on refactoring.

Current IPlayer Interface

// packages/vstory-core/src/interface/player.ts
export interface IPlayer extends IReleaseable {
  bindStory: (story: IStory) => void;
  tickTo: (t: number) => void;
  initActions: (acts: IActSpec[]) => void;
  setViewScale: (...) => void;
  play: (loop?: number) => void;   // ✅ exists
  reset: () => void;                // ✅ exists
  toDSL: () => IActSpec[];
  addAction: (...) => void;
  removeCharacterActions: (characterId: string) => void;
  // ❌ No pause()
  // ❌ No resume()
  // ❌ No way to query current playback state
}

Current Workaround

Users must manipulate private fields directly:

const player = new VStory.Player(story);
player.play(0);

// Pause — remove tick listener
player._ticker.removeListener('tick', player.handlerTick);

// Resume — reset frame time and re-add listener
player._lastFrameTime = -1;
player._ticker.addListener('tick', player.handlerTick);

// Detect playback end — poll private fields
setInterval(() => {
  if (player._currTime >= player._scheduler.getTotalTime()) {
    console.log('playback ended');
  }
}, 200);

This approach:

  1. Relies on 4 private fields: _ticker, _lastFrameTime, _scheduler, _currTime
  2. Relies on the public-but-undocumented handlerTick bound method
  3. Will break silently if internals are refactored
  4. Cannot use _ticker.stop() / _ticker.start() because the ticker is globally shared (globalTickerStore.getGlobalTicker())

Proposed API

export interface IPlayer extends IReleaseable {
  // ... existing methods ...

  play: (loop?: number) => void;
  pause: () => void;               // NEW: pause playback
  resume: () => void;              // NEW: resume from paused position
  reset: () => void;

  // Playback state
  readonly state: 'idle' | 'playing' | 'paused' | 'ended';
  readonly currentTime: number;     // current playback time in ms
  readonly totalTime: number;       // total duration in ms

  // Event support
  on: (event: 'stateChange' | 'end', callback: Function) => void;
  off: (event: string, callback: Function) => void;
}

Key additions:

  1. pause() — Suspend playback at current position
  2. resume() — Continue from paused position
  3. state — Read-only property for current playback state
  4. currentTime / totalTime — Allow progress tracking without private field access
  5. on('end') — Event-based end detection instead of polling

Use Cases

  • Interactive data stories with user-controlled pacing
  • Presentation mode with pause/resume controls
  • Progress bar / timeline scrubber
  • Embedding VStory in applications that need playback state management

Environment

  • VStory version: 0.0.25
  • Affected: @visactor/vstory-core Player class

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions