Technology Stack
- React 19: UI framework with concurrent rendering and automatic batching
- TypeScript 5.7: Type-safe development with strict mode
- Vite 6: Fast build tool and dev server with HMR
- Zustand: Lightweight state management (presentation store, lab store)
- TanStack Query: Server state caching for TTS audio and course data
- Motion: Animation library for scene transitions and effects
- Shiki: Syntax highlighting engine
- Monaco Editor: VS Code editor for labs
- Tailwind CSS 4: Utility-first styling
- Unified/Remark: Markdown AST parsing
Directory Structure
Parser
Location:src/parser/
The parser transforms markdown source into a typed intermediate representation (IR) that the presentation engine consumes.
Parsing Pipeline
Parse blocks
Within each step, separates narration (paragraphs) from visualization blocks (code fences).Visualization blocks are parsed based on their language tag:
code→ Code visualizationdata→ Data structurediagram→ Graph diagramchart→ Chart/graphmath→ LaTeX mathpreview→ HTML/React preview
Extract triggers
Parses inline triggers from narration text using Triggers are extracted and stored with their word positions for timing.
{{...}} syntax.Key Parser Files
parse-lesson.ts
Main orchestrator. Entry point is parseLesson(markdown: string): ParsedLesson.
Returns a ParsedLesson with:
title: stringsteps: LessonStep[]diagnostics: LessonDiagnostic[]
parse-data.ts
Parses data structure visualizations. Supports:
- Arrays:
[1, 2, 3] - Linked lists:
1 -> 2 -> 3 - Trees: Nested JSON-like syntax
- Graphs: Node and edge definitions
- Sequential animations:
seq { ... }DSL for multi-step transitions
parse-diagram.ts
Parses node-edge diagrams using a simple DSL:
parse-seq.ts
Parses the sequential animation DSL used in data blocks:
build-scenes.ts
Replays triggers to compute scene states. Output is a timeline of SceneState objects.
Presentation Engine
Location:src/presentation/
The presentation engine orchestrates lesson playback: audio synthesis, trigger execution, animation scheduling, and scene state management.
Presentation Store
File:src/presentation/store.ts
A Zustand store holds all presentation state:
loadLesson(opts)- Load a lessonplay()/pause()- Control playbacknextStep()/prevStep()- Navigate stepssetWordIndex(index)- Sync to audio positionadvanceScene()- Transition to next scene
Playback Orchestration
File:src/presentation/use-playback.ts
Manages audio playback and trigger execution:
- Fetch TTS audio for current narration block (cached via React Query)
- Play audio via Howler.js
- Listen for word boundary events
- Fire triggers when word index reaches trigger position
- Update scene state
- Schedule animations
src/presentation/event-scheduler.ts
Maps triggers to word positions and schedules execution.
Stage Rendering
File:src/presentation/Stage.tsx
The stage is the main rendering surface. It:
- Reads current scene state from the store
- Renders active visualization blocks
- Applies enter/exit animations via Motion
- Handles split-screen mode (multiple blocks side-by-side)
Animation System
File:src/presentation/animation-variants.ts
Defines Motion variants for enter/exit effects:
fade: Opacity transitionslide: Horizontal slideslide-up: Vertical slidegrow: Scale from 0typewriter: Character-by-character reveal
Visualization Primitives
Code Visualization
Location:src/code/
Renders syntax-highlighted code with animations:
- Syntax highlighting: Shiki tokenizer with customizable themes
- Line diffing: Compares two code states and highlights changes
- Animated transitions: Lines slide in/out, fade, or morph
- Focus regions: Highlight specific lines
- Annotations: Inline labels for explanations
Code.tsx- Main componentCodeLine.tsx- Individual line renderercode-diff.ts- Diffing algorithmuse-shiki.ts- Shiki highlighter hook
Data Structure Visualization
Location:src/data/
Renders data structures with automatic layout:
- Arrays: Horizontal cells with indices
- Linked lists: Nodes with arrows
- Trees: Hierarchical layout
- Graphs: Force-directed or hierarchical layout
- Pointers: Animated arrows between nodes
- State transitions: Sequential frames with animations
Data.tsx- Main componentlayouts/- Layout algorithms (array, list, tree, graph)DataNode.tsx- Individual node rendererDataPointer.tsx- Pointer arrow component
Diagram Visualization
Location:src/diagram/
Renders node-edge diagrams using ELK.js for auto-layout:
- Auto-layout: Hierarchical, force-directed, or custom algorithms
- Animated edges: Edge paths draw progressively
- Labels: Node and edge labels
- Styling: Color, shape, size customization
Diagram.tsx- Main componentuse-elk-layout.ts- ELK.js integration
Preview Visualization
Location:src/preview/
Renders live HTML or React components in an isolated iframe:
- HTML rendering: Direct HTML injection
- React rendering: Compiles JSX on-the-fly (via backend Babel transform)
- Isolated execution: Runs in sandboxed iframe
- Hot reload: Updates on content change
Preview.tsx- Main componentPreviewFrame.tsx- Iframe wrapper
Interactive Labs
Location:src/lab/
Labs provide a full IDE environment for hands-on exercises.
Lab Store
File:src/lab/store.ts
Manages lab state:
- File tree
- Open files
- Active file
- Editor content
- Terminal sessions
- Test results
- Service containers
Monaco Editor Integration
File:src/lab/Editor.tsx
Integrates Monaco Editor with:
- Language server protocol (LSP) for TypeScript, JavaScript
- Diagnostics (errors, warnings)
- Autocomplete
- Go-to-definition
- Vim mode (optional)
src/lab/lsp/ - Frontend side of LSP communication
Terminal Emulation
File:src/lab/TerminalPanel.tsx
Uses xterm.js for terminal rendering. Backend handles PTY process.
Container Orchestration
File:src/lab/use-containers.ts
Manages Docker Compose services:
- Start/stop containers
- View logs
- Check container status
Test Runner
File:src/lab/TestRunnerPanel.tsx
Runs tests and parses TAP output:
- Executes test command
- Parses TAP (Test Anything Protocol) results
- Displays pass/fail status
- Shows test output
TTS Integration
Location:src/tts/
Synthesis
File:src/tts/synthesize.ts
Invokes backend TTS command and returns audio + timing:
{ word, startMs, endMs, wordIndex }.
Audio Playback
File:src/tts/audio-player.ts
Wraps Howler.js for audio playback with callbacks:
Prefetching
File:src/tts/use-prefetch-tts.ts
Prefetches TTS audio for all narration blocks in a lesson using React Query:
State Management
Zustand Stores
-
Presentation Store (
src/presentation/store.ts)- Lesson playback state
- Current step, word index, scene index
- Playback controls
-
Lab Store (
src/lab/store.ts)- File tree, open files, active file
- Editor state
- Terminal sessions
- Test results
-
Diagnostics Store (
src/lab/diagnostics-store.ts)- LSP diagnostics (errors, warnings)
-
Settings Store (
src/lab/settings-store.ts)- Editor settings (theme, font size, Vim mode)
React Query
Used for server state caching:- TTS audio (keyed by narration text)
- Course list
- Course metadata
- Lesson content
- Lab files
Styling
Framework: Tailwind CSS 4 Theme:src/app/theme.ts - Color palette and design tokens
Components: Shadcn UI components in src/components/ui/
Routing
File:src/App.tsx
No external router. Simple state-based routing:
- Course browser →
<Browser /> - Lesson viewer →
<Presentation /> - Lab environment →
<Lab />
use-route.ts hook.
Build Configuration
File:vite.config.ts
Vite config with:
- React plugin for JSX
- Tailwind plugin
- Path aliases (
@/→src/) - Dependency pre-bundling for large libraries (Monaco, Shiki)
Development Workflow
- Edit files in
src/ - Vite HMR updates browser instantly
- TypeScript errors show in terminal and editor
- Test changes in dev app (
bun tauri dev)
Testing
Currently no automated tests. Manual testing:- Create test lessons in
data/lessons/ - Open in dev app
- Verify parsing, playback, animations
Next Steps
Parser
Deep dive into the markdown parser
Presentation Engine
Learn how playback works
Backend
Explore the Rust backend
Architecture
High-level system overview