# Agent — La Fabrik You are working on **La Fabrik**, an interactive 3D web experience built with React Three Fiber. The player steps into the role of a technician in Altera (2050) and completes missions: repairing an e-bike, fixing a power grid, upgrading a vertical farm. ## Project Identity - **Stack:** React 19, Three.js, @react-three/fiber 9, @react-three/drei, @react-three/rapier, GSAP, TypeScript, Vite - **No external state lib.** State is managed by a custom `GameManager` singleton with a subscribe/getState pattern. - **No Zustand, no Redux, no Context for global state.** - **Versions are pinned** (no `^` in dependencies). Do not upgrade packages without explicit request. ## Architecture Rules ### Two patterns coexist 1. **Singleton manager classes** — for orchestration, audio, cinematics, zone detection, debug 2. **Declarative React components** — for all 3D scene objects (map, zones, lights, player, postprocessing) Scene objects are **never** singleton classes. Managers are **never** React components. ### State ownership - `GameManager` is the single source of truth for durable gameplay state (phase, zone, mission, input lock, dialogue) - Other managers (`CinematicManager`, `AudioManager`, `ZoneManager`) handle side effects only — they read from GameManager but do not duplicate its state - React components subscribe to GameManager through `useGameState()` hook - **High-frequency values** (movement, camera interpolation, physics) stay in `useRef` + `useFrame` — never in React state ### File conventions - Every file starts with a comment: `# route path ` (e.g. `# route path src/world/Map.tsx`) - Scene components live in `src/world/` and `src/components/3d/` - UI overlays live in `src/components/ui/` - Managers live in `src/stateManager/` - Hooks live in `src/hooks/` - Static data lives in `src/data/` - Shaders live in `src/shaders/` - Utilities live in `src/utils/` ### Import paths Use `@/` alias for imports from `src/`: ```ts import { GameManager } from "@/stateManager/GameManager"; import { useGameState } from "@/hooks/useGameState"; ``` ### Memory management - Dispose only what you own (custom materials, render targets, manual clones) - Never blindly deep-dispose shared/cached assets (drei loaders cache models) - Use `Dispose.material()`, `Dispose.mesh()`, `Dispose.renderTarget()` from `src/utils/Dispose.ts` ### Debug - Debug panel activates with `?debug` in URL - All debug logic goes through `Debug.getInstance()` from `src/utils/Debug.ts` - Never scatter `if (isDev)` blocks across files - `r3f-perf` is lazy-loaded only in debug mode via `src/components/3d/DebugPerf.tsx` ## Managers (4 max) | Manager | Responsibility | | ------------------ | ------------------------------------------------------------------- | | `GameManager` | Phase, zone, mission, input lock, dialogue — single source of truth | | `CinematicManager` | GSAP timelines, camera lock/unlock | | `AudioManager` | Music, SFX, spatial audio | | `ZoneManager` | Zone detection, LOD triggers | ## Do NOT - Create new manager classes without explicit request - Use Zustand, Redux, or React Context for global state - Put high-frequency values in React state (`useState`) - Import `CinematicManager`/`AudioManager`/`ZoneManager` directly from components — always go through `GameManager` - Upgrade pinned dependency versions - Create files outside the documented architecture without explicit request ## Skills See `.agent/skills/` for detailed patterns per technology: - `r3f.md` — React Three Fiber component patterns - `three.md` — Three.js conventions and AnimationMixer - `gsap.md` — GSAP timeline and cinematic patterns - `managers.md` — Singleton manager implementation - `memory.md` — GPU memory and disposal rules - `debug.md` — Debug utility and r3f-perf setup