synergi-course
This is a living vision for modernizing the Synergi course framework. It outlines goals, architecture, and migration direction to guide ongoing work. It is not a user guide and the API is subject to change during the migration.
Scope & Non‑Goals
Scope: Client‑side course playback (slides, transitions, media sync, quizzes), progress tracking, and backend persistence hooks.
Non‑Goals: Course authoring UI, content CMS, SCORM/xAPI packaging, routing/deep‑linking beyond slide index, analytics pipeline.
Target Stack & Removals
Target: React 19, Vite, MUI 7, valibot schemas, CSS files co‑located with components.
Remove/Replace: react‑redux (move to local state/hooks), legacy remark pipeline usage, ad‑hoc CSS‑in‑JS except small sx/Box tweaks.
Architecture Overview
Deck: Orchestrates navigation, transitions between slides, progress and persistence; renders outer slide shell.
Slide Types: Manual Slide vs media‑driven (AudioSlide, VideoSlide, VimeoSlide), plus QuizSlide; each manages its own inner transitions.
VideoSlideaccepts WebVTT subtitletracksin its slide props.Segment Model: Optional sub‑sections within a slide; only one visible; slide controls segment transitions.
Transition Engine: Ordered steps with triggers (manual next/prev or media timecodes), timing guarantees, and view‑transition CSS between slides.
Interfaces & Adapters
PersistenceAdapter: load/save progress (e.g., currentSlide, lastUnlockedSlide).
MediaSync: map media timecodes to transition triggers; pause/resume hooks.
AnalyticsAdapter: emit navigation/interaction events.
AssetLoader (optional): resolve media sources and preloading strategy.
State Model
Deck State: currentSlide, lastUnlockedSlide, direction, in‑flight slide transition.
Slide State: current transition index/segment, local timing; only one active transition at a time.
Event Flow: user/media → slide transition → deck (boundary events) → adapters (persistence/analytics).
Schema & Types (directional)
Course:
{ slides: Slide[]; currentSlide: number; lastUnlockedSlide: number }.Slide: discriminated by
type("Slide" | "AudioSlide" | "VideoSlide" | "QuizSlide" | "VimeoSlide"),props,transition, optionalchildren.Component:
{ type: string; props: Record<string, unknown>; transition: { type: "always" | "transition"; trigger: string }; children? }.Validation: valibot schemas in
packages/synergi-course/src/schemas.ts; schema remains flexible during migration.
Accessibility & i18n
Keyboard navigation parity for all actions; visible focus management.
Media captions/subtitles; ARIA labels for controls.
Text content and labels externalizable; RTL‑safe layouts where applicable.
Theming & Styling
Public theming via CSS classes/variables; prefer CSS files next to components.
Limit inline styling to minor layout tweaks; document stable class hooks as they emerge.
Performance Goals
Slide transition budget: ~300ms with CSS view transitions.
Media start latency minimized; lazy load off‑screen slides/assets.
Avoid unnecessary re‑renders on transition ticks.
Migration Plan (phased)
Replace redux stores with local component state and hooks.
Introduce valibot schemas; adapt slide/component props.
Implement transition engine and view‑transition CSS.
Add media‑driven triggers and segment model.
Wire Persistence/Analytics adapters; stabilize minimal public API.
Open Questions
Authoring source of truth: JSON vs JSX (or hybrid)?
Deep‑linking and shareable slide state (URL params)?
Analytics event schema (naming, payloads, sampling)?
Long‑term quiz model and scoring/persistence boundaries?
Last updated
Was this helpful?