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:
- Relies on 4 private fields:
_ticker, _lastFrameTime, _scheduler, _currTime
- Relies on the public-but-undocumented
handlerTick bound method
- Will break silently if internals are refactored
- 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:
pause() — Suspend playback at current position
resume() — Continue from paused position
state — Read-only property for current playback state
currentTime / totalTime — Allow progress tracking without private field access
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
Description
The
Playerclass currently has no publicpause()orresume()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
Current Workaround
Users must manipulate private fields directly:
This approach:
_ticker,_lastFrameTime,_scheduler,_currTimehandlerTickbound method_ticker.stop()/_ticker.start()because the ticker is globally shared (globalTickerStore.getGlobalTicker())Proposed API
Key additions:
pause()— Suspend playback at current positionresume()— Continue from paused positionstate— Read-only property for current playback statecurrentTime/totalTime— Allow progress tracking without private field accesson('end')— Event-based end detection instead of pollingUse Cases
Environment
@visactor/vstory-corePlayer class