Interactive 3D educational game for gifted program test preparation (Grade 2, Israel).
cp .env.example .env
# Edit .env with your API key
npm install
npm run devThe app auto-detects which AI provider to use based on your environment variables.
Environment Variables:
| Variable | Required | Description |
|---|---|---|
VITE_AI_API_KEY |
Yes | API key for any supported provider |
VITE_AI_BASE_URL |
No | Base URL for the AI endpoint |
VITE_AI_MODEL |
No | Override default model |
Auto-detection logic (3 tiers):
- Key starts with
sk-ant-→ Direct Anthropic API (default model:claude-sonnet-4-6) - Base URL contains "anthropic" → Anthropic-format proxy like z.ai (default model:
gpt-4o-mini) - Everything else → OpenAI-compatible (default model:
gpt-4o-mini)
Example configs:
Direct Anthropic:
VITE_AI_API_KEY=sk-ant-...OpenAI:
VITE_AI_API_KEY=sk-...z.ai or other Anthropic proxy:
VITE_AI_API_KEY=your-zai-key
VITE_AI_BASE_URL=https://api.z.ai/api/anthropic
VITE_AI_MODEL=GLM-4.7src/
├── types/ # TypeScript domain types
│ └── game.ts # Question, World, Character, SceneObject, etc.
├── config/ # Static configuration (no logic)
│ ├── characters.ts # 5 NPC characters with dialog trees
│ ├── worlds.ts # 5 worlds with 3D scene configs
│ └── prompts.ts # AI prompts for questions & scene generation
├── stores/ # Zustand state management
│ └── gameStore.ts # Single source of truth for all game state
├── services/ # External API calls
│ └── api.ts # Claude API — question gen + scene gen (parallel)
├── hooks/ # Custom React hooks
│ └── useWorldLoader.ts # Orchestrates loading questions + 3D scene
├── utils/ # Pure utility functions
│ └── helpers.ts
├── components/
│ ├── screens/ # UI screens (2D overlay)
│ │ ├── NameInputScreen.tsx
│ │ ├── StoryScreen.tsx
│ │ ├── MapScreen.tsx
│ │ ├── CharIntroScreen.tsx
│ │ ├── LoadingScreen.tsx
│ │ ├── QuestionScreen.tsx
│ │ ├── CompletionScreens.tsx
│ │ └── screens.module.css
│ └── 3d/ # Three.js / R3F components
│ ├── scenes/
│ │ └── WorldScene.tsx # Main 3D canvas — composes everything
│ ├── objects/
│ │ ├── SceneObjectMesh.tsx # Procedural object factory
│ │ └── Ground.tsx
│ └── effects/
│ ├── MagicFog.tsx # Volumetric fog (thins on correct answers)
│ └── FloatingParticles.tsx # Firefly particles
├── App.tsx # Root — screen router + 3D background toggle
├── main.tsx # Entry point
└── index.css # Global styles + font imports
- React 18 + TypeScript
- React Three Fiber (R3F) + drei — declarative 3D
- Zustand — lightweight state management
- Framer Motion — screen transitions + micro-animations
- Claude API (Sonnet) — dynamic question + scene generation
-
AI-Generated 3D Scenes: Each world sends a scene prompt to Claude, which returns a JSON array of typed
SceneObjects. These are rendered procedurally viaSceneObjectMesh— a factory that maps object types to Three.js geometries with animations. -
Fog as Progress Metaphor: The "Fog of Forgetfulness" (
MagicFog) is tied tofogStrengthin the store. Each correct answer reduces it — the 3D world literally clears up as the child succeeds. -
Parallel Loading:
useWorldLoaderfires question generation and scene generation simultaneously viaPromise.all. -
Character System: Each world has an NPC with personality-specific dialog for greetings, correct/wrong responses, loading messages, and story intros.
-
CSS Modules: All screen styles are scoped via
screens.module.cssto avoid global conflicts with R3F canvas.
- Add a world: Add entry to
config/worlds.ts+ character toconfig/characters.ts - New 3D object type: Add to
SceneObject["type"]union intypes/game.ts+ geometry case inSceneObjectMesh.tsx - New question category: Add to
CategoryIdtype +QUESTION_PROMPTS - Sound effects: Add a
services/audio.tsusing Web Audio API, hook intoanswerQuestionaction
