TeachariumPlayer API
The TeachariumPlayer is a self-contained React component for embedding Teacharium lessons in your application. It handles all provider setup internally, making integration straightforward.
Installation
npm install @teacharium/player @teacharium/widget @measured/puck
# or
pnpm add @teacharium/player @teacharium/widget @measured/puckQuick Start
import { TeachariumPlayer } from "@teacharium/player";
import { getWidgets } from "@teacharium/widget";
import lessonData from "./lesson.json";
function LessonPage() {
return (
<TeachariumPlayer
lesson={lessonData}
widgets={getWidgets()}
onComplete={(result) => console.log("Lesson completed", result)}
/>
);
}Props Reference
Required Props
| Prop | Type | Description |
|---|---|---|
lesson | TeachariumLessonExport | The lesson data in export format |
You must provide either widgets or puckConfig:
| Prop | Type | Description |
|---|---|---|
widgets | TeachariumWidget[] | List of widgets (recommended for most cases) |
puckConfig | Config | Pre-built Puck config for advanced use cases |
Optional Props
| Prop | Type | Default | Description |
|---|---|---|---|
config | Partial<PlayerConfig> | {} | Player configuration options |
mode | "player" | "review" | "player" | Playback mode (review disables interactions) |
initialSessionState | SessionState | undefined | Resume from saved session state |
mediaResolvers | MediaResolverConfig | No-op | Hooks for resolving media URLs |
onStepChange | (state: SessionState) => void | undefined | Called at step boundaries for auto-saving |
onComplete | (result: CompletionResult) => void | undefined | Called when lesson completes |
additionalComponents | Record<string, ComponentConfig> | undefined | Extra Puck components (when using widgets) |
className | string | undefined | CSS class for container |
showStartButton | boolean | true | Show start button overlay |
startButtonText | string | "Start" | Custom start button text |
headerContent | React.ReactNode | undefined | Content above the player |
sideContent | React.ReactNode | undefined | Content alongside the player (e.g., debug panel) |
Session State
The player uses SessionState to track the learner’s progress through a lesson. This includes:
- Current position in the lesson
- History of visited steps with variable snapshots
- Widget states for each step (for resume/review)
SessionState Structure
interface SessionState {
version: 1;
lessonId: string;
currentHistoryIndex: number;
stepHistory: StepVisit[];
progress: LessonProgress;
currentVariables: Record<string, string | number | boolean>;
createdAt: string;
updatedAt: string;
}
interface StepVisit {
visitId: string;
stepId: string;
sectionIndex: number;
stepIndex: number;
variableSnapshot: Record<string, string | number | boolean>;
widgetStates: Record<string, unknown>;
itemStates: ItemState[];
visitedAt: string;
}CompletionResult
Sent via onComplete when the lesson finishes:
interface CompletionResult {
/** Final variable values at lesson completion */
finalVariables: Record<string, unknown>;
/** Final progress state */
progress: LessonProgress;
/** Total score achieved (if items had scores) */
score?: number;
/** Maximum possible score */
maxScore?: number;
/** All items from the lesson */
items?: ItemData[];
/** Full session state for review mode */
sessionState: SessionState;
}Player Configuration
The config prop accepts these options:
interface PlayerConfig {
showProgress?: boolean; // Show progress footer (default: true)
allowPreviousStep?: boolean; // Allow going back
allowSkipping?: boolean; // Allow skipping steps
autoAdvance?: boolean; // Auto-advance between steps
defaultStepDuration?: number; // Default step duration (ms)
showTimer?: boolean; // Show timer UI
debugMode?: boolean; // Enable debug logging
}Playback Modes
The mode prop controls how the player behaves:
"player"(default): Normal playback mode. Learners can interact with widgets and their progress is tracked."review": Read-only mode. Shows previous work with all interactions disabled. Use this when revisiting completed lessons.
<TeachariumPlayer
lesson={lessonData}
widgets={widgets}
mode="review"
initialSessionState={savedSessionState}
/>Media Resolution
Lessons may reference media files (images, videos, voiceovers) by ID. You provide resolver hooks that map these IDs to actual URLs.
import { TeachariumPlayer } from "@teacharium/player";
import { getWidgets } from "@teacharium/widget";
// Map media IDs to static file paths
const mediaFiles: Record<string, string> = {
"media:abc123": "/lessons/my-lesson/images/intro.png",
"media:def456": "/lessons/my-lesson/images/diagram.jpg",
};
// Hook that resolves media IDs to URLs
function useMediaUrl(mediaId: string | undefined) {
if (!mediaId) {
return { data: null, isLoading: false, error: null };
}
return { data: mediaFiles[mediaId] ?? null, isLoading: false, error: null };
}
// Hook that resolves voiceover content to audio URLs
function useVoiceoverUrl(
contentHash: string | undefined,
voice: string | undefined,
) {
if (!contentHash || !voice) {
return { data: null, isLoading: false, error: null };
}
return {
data: `/lessons/my-lesson/audio/${contentHash}.mp3`,
isLoading: false,
error: null,
};
}
function LessonPage() {
return (
<TeachariumPlayer
lesson={lessonData}
widgets={getWidgets()}
mediaResolvers={{
useMediaUrl,
useVoiceoverUrl,
}}
/>
);
}The resolver hooks must return this shape:
interface MediaUrlResult {
data: string | null | undefined;
isLoading?: boolean;
error?: Error | null;
}Saving and Resuming Progress
Saving Progress
Use the onStepChange callback to persist session state at each step boundary:
function LessonWithSaving({ lessonData }) {
const handleStepChange = async (sessionState: SessionState) => {
// Save to localStorage, server, etc.
localStorage.setItem(
`lesson-session-${lessonData.lesson.id}`,
JSON.stringify(sessionState),
);
};
return (
<TeachariumPlayer
lesson={lessonData}
widgets={getWidgets()}
onStepChange={handleStepChange}
/>
);
}Resuming Progress
Pass saved session state as initialSessionState:
function ResumableLesson({ lessonData }) {
const savedSession = JSON.parse(
localStorage.getItem(`lesson-session-${lessonData.lesson.id}`) || "null",
);
return (
<TeachariumPlayer
lesson={lessonData}
widgets={getWidgets()}
initialSessionState={savedSession}
/>
);
}Review Mode for Completed Lessons
When a lesson is completed, you can display it in review mode:
function ReviewLesson({ lessonData, completedSessionState }) {
return (
<TeachariumPlayer
lesson={lessonData}
widgets={getWidgets()}
mode="review"
initialSessionState={completedSessionState}
/>
);
}Complete Example
import { useState, useEffect } from "react";
import {
TeachariumPlayer,
type TeachariumLessonExport,
type SessionState,
type CompletionResult,
} from "@teacharium/player";
import { getWidgets } from "@teacharium/widget";
// Media resolution
const mediaFiles: Record<string, string> = {
"media:intro-image": "/lessons/intro/images/intro.png",
};
function useMediaUrl(mediaId: string | undefined) {
if (!mediaId) return { data: null };
return { data: mediaFiles[mediaId] ?? null };
}
function useVoiceoverUrl(
contentHash: string | undefined,
voice: string | undefined,
) {
if (!contentHash || !voice) return { data: null };
return { data: `/lessons/intro/audio/${contentHash}.mp3` };
}
export function LessonPage({
lessonData,
}: {
lessonData: TeachariumLessonExport;
}) {
const [initialSession, setInitialSession] = useState<
SessionState | undefined
>();
const [isReviewMode, setIsReviewMode] = useState(false);
// Load saved session on mount
useEffect(() => {
const saved = localStorage.getItem(`session-${lessonData.lesson.id}`);
if (saved) {
const session = JSON.parse(saved) as SessionState;
setInitialSession(session);
setIsReviewMode(session.progress.status === "completed");
}
}, [lessonData.lesson.id]);
// Save session state at step boundaries
const handleStepChange = (state: SessionState) => {
localStorage.setItem(
`session-${lessonData.lesson.id}`,
JSON.stringify(state),
);
};
// Handle completion
const handleComplete = (result: CompletionResult) => {
localStorage.setItem(
`session-${lessonData.lesson.id}`,
JSON.stringify(result.sessionState),
);
console.log("Lesson completed!", {
score: result.score,
maxScore: result.maxScore,
variables: result.finalVariables,
});
};
return (
<div className="h-screen">
<TeachariumPlayer
lesson={lessonData}
widgets={getWidgets()}
mediaResolvers={{ useMediaUrl, useVoiceoverUrl }}
initialSessionState={initialSession}
mode={isReviewMode ? "review" : "player"}
onStepChange={isReviewMode ? undefined : handleStepChange}
onComplete={handleComplete}
config={{
showProgress: true,
allowPreviousStep: true,
}}
showStartButton={true}
startButtonText="Begin Lesson"
/>
</div>
);
}TypeScript Types
Import types from the package:
import type {
TeachariumPlayerProps,
TeachariumLessonExport,
SessionState,
CompletionResult,
LessonProgress,
PlayerConfig,
MediaResolverConfig,
} from "@teacharium/player";