Skip to content

Latest commit

 

History

History
481 lines (364 loc) · 15.4 KB

File metadata and controls

481 lines (364 loc) · 15.4 KB

Spark — Developer & Architecture Guide

This document is the single source of truth for anyone iterating on Spark outside of Lovable (VS Code, WebStorm, Cursor, etc.). Follow these conventions to keep the codebase consistent and mergeable with the Lovable-managed branch.


Table of Contents

  1. Quick Start
  2. MCP Context7 — Dependency Validation
  3. Tech Stack & Versions
  4. Project Structure
  5. Design System & Theming
  6. Component Architecture
  7. State Management & Data Flow
  8. Authentication & Backend
  9. Adding Content (Modules & Lessons)
  10. Animation & Motion
  11. Routing & Navigation
  12. Do's and Don'ts
  13. Testing
  14. Git & Lovable Sync

Quick Start

# Clone via GitHub (Lovable bi-directional sync is active)
git clone <YOUR_REPO_URL>
cd spark

# Install dependencies (Bun recommended, npm works too)
bun install        # or npm install

# Start dev server
bun run dev        # or npm run dev
# → http://localhost:8080

Environment Variables

The .env file is auto-generated by Lovable Cloud and must never be committed or edited manually. It provides:

Variable Purpose
VITE_SUPABASE_URL Backend API URL
VITE_SUPABASE_PUBLISHABLE_KEY Public anon key
VITE_SUPABASE_PROJECT_ID Project identifier

If developing locally, copy .env from the Lovable project settings or create your own pointing to a dev backend.


MCP Context7 — Dependency Validation

We use the Context7 MCP server to validate that every dependency we install matches the correct version and API surface. Before adding or upgrading any package:

  1. Query Context7 for the library's latest stable API and version constraints.
  2. Verify compatibility with our pinned versions (see Tech Stack).
  3. Never blindly upgrade — check for breaking changes against Context7's documentation index.

Workflow

# In your MCP-enabled IDE (Cursor, etc.)
# 1. Ask Context7: "What is the latest stable API for framer-motion v12?"
# 2. Cross-reference with our current usage in src/components/spark/
# 3. Only then: bun add framer-motion@^12.x

Pinned Dependency Rules

Package Constraint Reason
react ^18.3.x React 19 not yet adopted
react-router-dom ^6.x v7 has breaking loader/action API
framer-motion ^12.x Heavy use of motion component API
@supabase/supabase-js ^2.x v3 not yet released
tailwindcss ^3.4.x v4 has config migration
lucide-react ^0.462.x Icon set pinned for consistency

Tech Stack & Versions

Layer Technology Config File
Framework React 18 + TypeScript tsconfig.app.json
Build Vite 5 vite.config.ts
Styling Tailwind CSS 3 + shadcn/ui tailwind.config.ts, src/index.css
Animations Framer Motion 12
Routing React Router v6 (BrowserRouter) src/App.tsx
State / Server TanStack React Query v5 src/App.tsx
Backend Supabase (via Lovable Cloud) supabase/config.toml
Forms React Hook Form + Zod
Charts Recharts
Icons Lucide React
UI Primitives shadcn/ui (Radix-based) components.json

Project Structure

src/
├── assets/              # AI-generated illustrations (import as ES6 modules)
├── components/
│   ├── spark/           # App-specific components (13 files)
│   │   ├── BottomNav.tsx           # Mobile tab bar
│   │   ├── DashboardOrbitingWorlds.tsx
│   │   ├── Illustrations.tsx       # SVG illustration renderer
│   │   ├── IslandVisuals.tsx       # Progress island graphics
│   │   ├── ModuleCard.tsx          # Module list card
│   │   ├── ModuleGraphic.tsx       # Module hero graphic
│   │   ├── ModuleIcon.tsx          # Emoji/icon wrapper
│   │   ├── OrbitingWorlds.tsx      # Animated orbiting spheres
│   │   ├── SparkTypography.tsx     # Heading/body text components
│   │   ├── Starfield.tsx           # Background particle effect
│   │   ├── StatsBar.tsx            # Points/streak bar
│   │   ├── WelcomeAnimation.tsx    # Post-login welcome screen
│   │   └── WorldTransition.tsx     # Page transition overlay
│   └── ui/              # shadcn/ui primitives (DO NOT customise inline)
├── contexts/
│   └── TransitionContext.tsx  # Page transition state
├── data/
│   └── modules.ts       # All 13 modules + lessons + quiz content
├── hooks/
│   ├── useAuth.ts              # Auth state + sign in/up/out
│   ├── useProgress.ts          # Legacy local-storage progress (deprecated)
│   ├── useSupabaseProgress.ts  # Cloud-synced progress (primary)
│   └── use-mobile.tsx          # Viewport detection
├── integrations/
│   └── supabase/
│       ├── client.ts    # ⚠️  AUTO-GENERATED — never edit
│       └── types.ts     # ⚠️  AUTO-GENERATED — never edit
├── pages/               # Route-level components
│   ├── Landing.tsx      # Public landing page
│   ├── Auth.tsx         # Login / signup forms
│   ├── ResetPassword.tsx
│   ├── Onboarding.tsx   # Topic selection flow
│   ├── Dashboard.tsx    # Main hub (orbiting worlds)
│   ├── Explore.tsx      # Browse all modules
│   ├── ModuleView.tsx   # Module detail + lesson list
│   ├── LessonView.tsx   # Content/quiz/celebration screens
│   ├── ProgressIsland.tsx # Gamified progress map
│   ├── Profile.tsx      # User settings + stats
│   └── NotFound.tsx
├── types/
│   └── spark.ts         # Core domain types (Module, Lesson, UserProgress)
└── index.css            # 🎨  Design tokens (HSL variables)

Files You Must NEVER Edit

File Reason
src/integrations/supabase/client.ts Auto-generated by Lovable Cloud
src/integrations/supabase/types.ts Auto-generated from DB schema
supabase/config.toml Managed by Lovable Cloud
.env Auto-generated environment config

Design System & Theming

Colour Tokens (HSL only)

All colours are defined as HSL values in src/index.css under :root. Never use raw hex/rgb values in components.

/* Core semantic tokens */
--background: 218 58% 10%;     /* Deep navy */
--foreground: 210 40% 98%;     /* Near-white */
--primary: 187 100% 50%;       /* Cyan accent */
--secondary: 168 80% 50%;      /* Teal */
--accent: 265 70% 65%;         /* Purple */
--muted: 215 30% 20%;          /* Subdued panels */

/* Module colour palette */
--cyan: 187 100% 55%;
--teal: 168 80% 50%;
--purple: 265 70% 65%;
--orange: 25 95% 60%;
--pink: 320 90% 65%;
--gold: 45 100% 60%;

/* Glass morphism */
--glass-bg: 215 45% 14%;
--glass-border: 215 30% 28%;

Usage in Components

// ✅ Correct — use Tailwind semantic classes
<div className="bg-background text-foreground border-border" />
<button className="bg-primary text-primary-foreground" />

// ❌ Wrong — never hardcode colours
<div className="bg-[#0a1628] text-white" />

Typography

Role Font Tailwind Class
Body Inter font-sans (default)
Display / Headings Space Grotesk font-display

Extending the Design System

  1. Add new HSL variable to :root in src/index.css
  2. Map it in tailwind.config.tstheme.extend.colors
  3. Use the Tailwind class in components — never reference the CSS variable directly

Component Architecture

Naming Conventions

Type Convention Example
Page components PascalCase, in src/pages/ Dashboard.tsx
Spark components PascalCase, in src/components/spark/ ModuleCard.tsx
UI primitives lowercase, in src/components/ui/ button.tsx
Hooks camelCase with use prefix useSupabaseProgress.ts
Types PascalCase interfaces Module, Lesson, UserProgress

Component Rules

  1. Small, focused components — one responsibility per file
  2. Props over context for data that flows 1-2 levels
  3. Framer Motion for all animations (no CSS transitions for complex motion)
  4. shadcn/ui as the base for all form controls, dialogs, toasts — extend via variants, don't fork
  5. No inline styles — Tailwind classes only, using design tokens

Creating New Components

// src/components/spark/NewFeature.tsx
import { motion } from "framer-motion";

interface NewFeatureProps {
  title: string;
  isActive: boolean;
}

export function NewFeature({ title, isActive }: NewFeatureProps) {
  return (
    <motion.div
      className="bg-card rounded-lg p-4 border border-border"
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
    >
      <h3 className="font-display text-lg text-foreground">{title}</h3>
    </motion.div>
  );
}

State Management & Data Flow

Architecture

App.tsx
├── useAuth()                → User | null
├── useSupabaseProgress()    → UserProgress + mutation functions
│   ├── completeLesson()
│   ├── completeModule()
│   ├── setOnboardingComplete()
│   ├── setCurrentPosition()
│   └── resetProgress()
└── Props cascade to page components

Key Patterns

  • Auth state: Managed by useAuth() hook — listens to Supabase onAuthStateChange
  • Progress state: useSupabaseProgress(user) — reads/writes to user_progress and profiles tables
  • Server state: TanStack React Query QueryClient wraps the app (for future API calls)
  • Transition state: TransitionContext manages page-to-page world transitions

Adding New Persisted State

  1. Add column via Supabase migration (run in Lovable or use supabase migration new)
  2. Update the UserProgress type in src/types/spark.ts
  3. Update read/write logic in useSupabaseProgress.ts
  4. The types.ts file will auto-regenerate — never edit it manually

Authentication & Backend

Auth Flow

Landing → /auth (signup/login) → Email verification → /onboarding → /dashboard
  • Email + password auth via Supabase Auth
  • Email verification is required (no auto-confirm)
  • Password reset via /reset-password route
  • Session persisted in localStorage with auto-refresh

Database Schema

Table Purpose RLS
profiles Display name, avatar URL Users read/write own row
user_progress Lessons, modules, streaks, points Users read/write own row

Supabase Client Import

// Always import from the integration path
import { supabase } from "@/integrations/supabase/client";

Adding Content (Modules & Lessons)

All content lives in src/data/modules.ts. Each module follows the Module type from src/types/spark.ts.

Module Colour Palette

Each module must use one of the 5 defined colours: "cyan" | "teal" | "purple" | "orange" | "pink"

Lesson Screen Types

Type Required Fields Description
content title, text, illustration Teaching screen
quiz question, options, correctIndex, points Multiple-choice
celebration title, text, points Completion reward

Available Illustrations

See the illustration union type in src/types/spark.ts for the full list (30+ options including robot-happy, brain, gear, shield, atom, etc.).

Adding a New Module

{
  id: "unique_snake_case_id",
  title: "Module Title",
  description: "Short tagline",
  icon: "🔬",            // Emoji
  color: "teal",          // One of the 5 palette colours
  category: "Category Name",
  lessons: [
    {
      id: "unique_lesson_id",
      title: "Lesson Title",
      duration: "3 min",
      screens: [
        { type: "content", title: "...", text: "...", illustration: "brain" },
        { type: "quiz", question: "...", options: [...], correctIndex: 0, points: 10 },
        { type: "celebration", title: "...", text: "...", points: 10 },
      ],
    },
  ],
}

Animation & Motion

Library

All animations use Framer Motion v12. Use the motion component API.

Conventions

Animation Pattern
Page entry initial={{ opacity: 0, y: 20 }}animate={{ opacity: 1, y: 0 }}
Staggered lists transition={{ delay: index * 0.1 }}
Exit animations Use AnimatePresence with exit prop
World transitions Managed by WorldTransition.tsx + TransitionContext
Background effects Starfield.tsx, OrbitingWorlds.tsx (CSS + Framer hybrid)

Performance Rules

  • Use will-change sparingly
  • Prefer transform and opacity animations (GPU-accelerated)
  • Large particle effects (Starfield) should use requestAnimationFrame, not Framer

Routing & Navigation

Route Map

Path Component Auth Required
/ Landing (public) / Dashboard (authed) Conditional
/auth Auth No
/reset-password ResetPassword No
/explore Explore Yes
/progress ProgressIsland Yes
/profile Profile Yes
/module/:moduleId ModuleView Yes
/lesson/:moduleId/:lessonId LessonView Yes

Navigation Component

Mobile: BottomNav.tsx — fixed bottom tab bar (Home, Explore, Progress, Profile)


Do's and Don'ts

✅ Do

  • Use semantic design tokens (bg-card, text-muted-foreground, etc.)
  • Import assets as ES6 modules: import img from "@/assets/image.png"
  • Use font-display for headings, font-sans for body
  • Keep components under 200 lines — extract sub-components
  • Write all new animations with Framer Motion
  • Query Context7 before adding/upgrading any dependency
  • Use the @/ path alias for all imports

❌ Don't

  • Edit auto-generated files (client.ts, types.ts, config.toml, .env)
  • Use raw hex/rgb colours — always HSL via CSS variables
  • Install React 19 or React Router v7 (breaking changes)
  • Use localStorage for progress (deprecated — use useSupabaseProgress)
  • Create new Supabase client instances — import from @/integrations/supabase/client
  • Skip email verification on auth (no auto-confirm)
  • Use CSS transitions for complex motion — use Framer Motion

Testing

# Run all tests
bun run test

# Watch mode
bun run test:watch

Tests use Vitest + Testing Library. Test files go in src/test/ or co-located as *.test.ts(x).


Git & Lovable Sync

Lovable maintains bidirectional sync with GitHub:

  • Pushes from Lovable → GitHub (automatic)
  • Pushes from GitHub → Lovable (automatic)

Branch Strategy

  • main — production branch, synced with Lovable
  • Feature branches — create locally, merge via PR to main
  • Lovable picks up main changes automatically

Commit Conventions

Use clear, descriptive commits. Lovable auto-generates commits for its changes, so keep yours distinguishable:

feat: add quantum computing module content
fix: correct streak calculation for timezone edge case
style: update module card hover animation

Last updated: March 2026