Skip to main content

Playback Integration

@wangyaoshen/locus-interaction integrates seamlessly with animation playback systems, allowing interactions to pause and resume animations.

InteractionManager

The InteractionManager is the main entry point for managing interactive components and sessions.

import { InteractionManager, createInteractionManager } from '@wangyaoshen/locus-interaction';

const manager = createInteractionManager({
canvas: canvasElement,
playbackController: myPlayer,
});

// Register components
manager.registerComponent(point);
manager.registerComponent(slider);

// Add interaction triggers
manager.addInteractionTrigger({
frame: 100,
session: {
id: 'quiz-1',
components: [point],
validation: { type: 'position', target: [200, 200], tolerance: 10 },
},
});

// Listen for events
manager.addEventListener((event) => {
console.log('Event:', event);
});

Configuration Options

interface InteractionManagerConfig {
canvas: HTMLCanvasElement;
playbackController?: PlaybackController;
autoRegisterTriggers?: boolean;
}

PlaybackIntegration

For more control over playback integration, use PlaybackIntegration directly.

import { PlaybackIntegration, PlaybackController } from '@wangyaoshen/locus-interaction';

// Implement the PlaybackController interface
const controller: PlaybackController = {
play: () => player.play(),
pause: () => player.pause(),
stop: () => player.stop(),
seekTo: (frame) => player.seekTo(frame),
getCurrentFrame: () => player.currentFrame,
getStatus: () => player.status,
onFrameChange: (callback) => {
player.on('frame', callback);
return () => player.off('frame', callback);
},
};

const integration = new PlaybackIntegration({
controller,
triggers: [
{
frame: 100,
session: {
id: 'quiz-1',
components: [point],
validation: { type: 'position', target: [200, 200], tolerance: 10 },
autoContinue: true,
autoContinueDelay: 2000,
},
},
{
frame: 200,
session: {
id: 'quiz-2',
components: [slider],
validation: { type: 'value', target: 75, tolerance: 5 },
},
},
],
});

PlaybackController Interface

interface PlaybackController {
play: () => void;
pause: () => void;
stop: () => void;
seekTo: (frame: number) => void;
getCurrentFrame: () => number;
getStatus: () => PlaybackStatus;
onFrameChange: (callback: (frame: number) => void) => () => void;
}

type PlaybackStatus = 'playing' | 'paused' | 'stopped';

Interaction Sessions

Sessions manage the lifecycle of an interaction.

import { InteractionSession } from '@wangyaoshen/locus-interaction';

const session = new InteractionSession({
id: 'quiz-1',
components: [point, slider],
timeout: 30, // 30 second timeout
validation: {
type: 'position',
target: [200, 200],
tolerance: 10,
},
onSuccess: () => console.log('Correct!'),
onFail: () => console.log('Incorrect'),
autoContinue: true, // Auto-continue after success
autoContinueDelay: 2000, // Delay before continuing (ms)
});

// Start the session
session.start();

// Listen for session events
session.addEventListener((event) => {
switch (event.type) {
case 'start':
console.log('Session started');
break;
case 'complete':
console.log('Session completed', event.success);
break;
case 'timeout':
console.log('Session timed out');
break;
}
});

// Manually complete the session
session.complete();

Session Configuration

interface InteractionSessionConfig {
id: string;
components: InteractiveComponent[];
validation?: ValidationConditionConfig;
timeout?: number; // Timeout in seconds
onSuccess?: () => void;
onFail?: () => void;
autoContinue?: boolean;
autoContinueDelay?: number;
}

Timeline Integration

For timeline-based interactions with visual markers.

import { TimelineIntegration } from '@wangyaoshen/locus-interaction';

const timeline = new TimelineIntegration({
totalFrames: 1000,
fps: 60,
markers: [
{
id: 'quiz-1',
frame: 100,
type: 'interaction',
label: 'Quiz 1',
session: { ... },
},
{
id: 'checkpoint',
frame: 500,
type: 'checkpoint',
label: 'Checkpoint',
},
],
});

// Get render info for timeline UI
const renderInfo = timeline.getRenderInfo();

// Check marker status
const status = timeline.getMarkerStatus('quiz-1');

Timeline Marker Types

type TimelineMarkerType = 'interaction' | 'checkpoint' | 'info';

interface TimelineMarker {
id: string;
frame: number;
type: TimelineMarkerType;
label?: string;
session?: InteractionSessionConfig;
}

type TimelineMarkerStatus = 'pending' | 'active' | 'completed' | 'skipped';

Scene Integration

For integrating with scene elements and transformations.

import { SceneIntegration } from '@wangyaoshen/locus-interaction';

const scene = new SceneIntegration({
elements: [
{
id: 'circle-1',
type: 'circle',
position: [100, 100],
interactive: true,
},
],
transform: {
scale: 1,
offset: [0, 0],
rotation: 0,
},
});

// Hit test for element at position
const result = scene.hitTest([105, 105]);
console.log(result.element); // 'circle-1'

// Update scene transform
scene.setTransform({ scale: 2 });

Events

All integration modules emit events for tracking interaction state.

type InteractionManagerEvent =
| { type: 'componentRegistered'; component: InteractiveComponent }
| { type: 'componentUnregistered'; component: InteractiveComponent }
| { type: 'sessionStart'; session: InteractionSession }
| { type: 'sessionComplete'; session: InteractionSession; success: boolean }
| { type: 'triggerActivated'; trigger: InteractionTrigger };

type PlaybackIntegrationEvent =
| { type: 'triggerActivated'; trigger: InteractionTrigger }
| { type: 'sessionComplete'; triggerId: string; success: boolean }
| { type: 'playbackResumed' };