Skip to main content

Interactive explainers

info

This page covers the interactive explainer system: canvas-based visual walkthroughs that open in a separate browser window so the student can study concepts alongside their code editor.

School Platform series

  1. School Platform
  2. Architecture
  3. AI features
  4. Calendar integration
  5. Programme
  6. Explainers - You are here
  7. Schedule
  8. Integrations
  9. Deployment

What explainers are

Explainers are multi-screen interactive visualisations that teach a specific programming or maths concept. Each one opens in a separate browser window via window.open() so the student can position it next to their IDE without overlaying the tracker page. If the popup is blocked, it falls back to an inline expandable panel.

How it works

  1. StepExplainer receives a taskCode and looks up the registry. If an explainer exists, it renders a clickable card on the task row.

  2. ExplainerShell is the generic canvas and navigation component. It handles responsive scaling (640x400 internal resolution), Back/Next buttons, progress text, pointer events, an animation loop for screens that set animate: true, and a pause/play toggle.

  3. Registry maps task codes to ExplainerConfig objects. Adding a new explainer requires one file and one registry entry.

  4. Explainers tab on each phase page collects all registered walkthroughs for that phase in a card grid. Each card shows its location in the programme (e.g. "Module 2, Part 2, Step 2") parsed from the task code.

Key interfaces

interface ExplainerScreen {
title: string
explain: React.ReactNode
draw: (ctx: CanvasRenderingContext2D, w: number, h: number, state: Record<string, number>) => void
onPointerMove?: (x: number, y: number, state: Record<string, number>) => void
animate?: boolean
initState?: () => Record<string, number>
}

interface ExplainerConfig {
cardTitle: string
cardDescription: string
screens: ExplainerScreen[]
}

Adding a new explainer

  1. Create a file under src/app/programme/_components/explainers/ (e.g. my-topic.tsx) that exports an ExplainerConfig.
  2. Import it in explainers/registry.ts and add a key matching the task's code field.
  3. Done. StepExplainer automatically renders the card for that step, and the Explainers tab lists it alongside other walkthroughs for the same phase.

Design decisions

DecisionRationale
Fixed 640x400 internal resolutionConsistent aspect ratio; CSS scales to fill container; pointer coordinates scaled accordingly
Colour palette: #378ADD, #EF9F27, #1D9E75, #D85A30, #7F77DDMatches the tracker's dark theme
Animation throttled to ~30 fpsValues are readable; achieved by incrementing state.frame every 2nd requestAnimationFrame call
Pause/play toggleLets the student freeze the canvas to study a particular frame
Self-contained filesNo shared mutable state between explainers; each file is independent
isDark() helper for SSR safetyGuards window.matchMedia calls that would fail during server rendering
Popup window route is anonymousRead-only and kid-facing; no auth gate needed

File layout

src/app/programme/_components/
├── explainer-shell.tsx # ExplainerShell component
├── step-explainer.tsx # StepExplainer entry card (inline in step)
├── explainer-grid.tsx # ExplainerGrid card grid (Explainers tab)
└── explainers/
├── registry.ts # Registry + getExplainersForPhase helper
├── distance-formula.tsx # Collision detection explainer
├── frame-counter.tsx # Frame % cycle mechanics explainer
└── sine-walking.tsx # Sin()-based walking explainer
src/app/programme/explainer/
└── [code]/page.tsx # Popup window page