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' };