feat: add the map

This commit is contained in:
2026-04-15 16:09:02 +02:00
parent f67799db30
commit d486f6f381
26 changed files with 391 additions and 587 deletions
+36 -3
View File
@@ -1,5 +1,7 @@
# Architecture Patterns
Coding conventions are maintained in `.agent/skills/best-practices.md`.
The project uses **two complementary patterns**:
- **Singleton service classes** for orchestration and side effects
@@ -332,17 +334,23 @@ useEffect(() => {
---
## 6. Debug Utility
## 6. Debug System
The debug panel can be activated by appending `?debug` to the URL:
`http://localhost:5173?debug`
All debug logic is centralized in `Debug.ts`.
All debug logic is centralized in `src/debug/`.
Do not scatter debug checks across the codebase.
- `src/debug/Debug.ts` owns the global lil-gui singleton
- `src/debug/DebugPerf.tsx` mounts the perf overlay
- `src/debug/scene/*` contains debug-only R3F helpers such as free camera controls and axes/grid helpers
`world/` stays focused on product scene components, while `debug/` contains developer tooling.
```ts
// utils/Debug.ts
// src/debug/Debug.ts
import GUI from "lil-gui";
export class Debug {
@@ -379,3 +387,28 @@ if (debug.active) {
debug.gui!.add(params, "bloomIntensity", 0, 3).name("Bloom");
}
```
Debug-only scene helpers should live outside `world/`:
```tsx
// src/debug/scene/DebugHelpers.tsx
import { Debug } from "@/debug/Debug";
export function DebugHelpers(): React.JSX.Element | null {
const debug = Debug.getInstance();
if (!debug.active) {
return null;
}
return (
<>
<gridHelper
args={[180, 36, "#1d4ed8", "#1e293b"]}
position={[0, 0.01, 0]}
/>
<axesHelper args={[10]} />
</>
);
}
```
-153
View File
@@ -1,153 +0,0 @@
# Best Practices
Generate code that is **simple**, **understandable**, **reviewable**, **scalable**, **optimized**, and **modern**. Follow W3C web standards and platform conventions.
## Naming Conventions
### Files
| Type | Convention | Example |
| ---------- | --------------------------- | -------------------- |
| Components | PascalCase | `WorkshopZone.tsx` |
| Hooks | camelCase with `use` prefix | `useGameState.ts` |
| Managers | PascalCase | `GameManager.ts` |
| Utils | PascalCase | `Dispose.ts` |
| Data | PascalCase | `missions.ts` |
| Shaders | kebab-case | `hologram.vert.glsl` |
### Variables & Functions
| Type | Convention | Example |
| ---------------- | -------------------- | ----------------------------------------- |
| Variables | camelCase | `activeZone`, `missionStep` |
| Functions | camelCase | `startMission()`, `setActiveZone()` |
| Constants | UPPER_SNAKE_CASE | `MAX_SPEED`, `DEFAULT_PHASE` |
| React components | PascalCase | `function WorkshopZone()` |
| React hooks | camelCase with `use` | `useGameState()`, `useFrame()` |
| Classes | PascalCase | `class GameManager` |
| Interfaces/Types | PascalCase | `type GameSnapshot`, `interface ZoneData` |
## Code Style
### Simplicity First
```ts
// Good — clear, direct
function getZoneRadius(zone: Zone): number {
return zone.radius;
}
// Bad — over-abstracted
function getZoneRadius(zone: Zone): number {
return zone[ZoneFields.RADIUS] ?? RADIUS_DEFAULTS[zone.type]?.default ?? 50;
}
```
### Early Return
```ts
// Good
if (!gltf) return null;
if (!visible) return null;
return <primitive object={gltf.scene} />;
```
### Avoid Nested Callbacks
```ts
// Good — flat structure
useEffect(() => {
const mixer = new THREE.AnimationMixer(model);
return () => mixer.stopAllAction();
}, [model]);
```
## TypeScript Rules
### Explicit Types for Exports
```ts
export function useGameState(): GameSnapshot { ... }
export function setPhase(phase: Phase): void { ... }
```
### Never use `any`
```ts
// Good
const ref = useRef<THREE.Group>(null);
// Bad
const ref = useRef<any>(null);
```
## Performance
### useRef for Mutable Values
```ts
// Good — no re-render
const position = useRef(new THREE.Vector3());
// Bad — triggers re-render every frame
const [position, setPosition] = useState(new THREE.Vector3());
```
### Memoize Expensive Computations
```ts
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
```
## Scalability
### Single Responsibility
```ts
// Good — focused component
export function WorkshopZone() {
// Only handles workshop zone logic
}
// Bad — does everything
export function WorkshopZone() {
// Handles zone logic + audio + cinematics + missions
}
```
### Constants for Magic Numbers
```ts
const DEFAULT_CAMERA_DISTANCE = 5;
const ZONE_DETECTION_RADIUS = 20;
```
## Accessibility (W3C)
### Semantic HTML
```tsx
// Good
<button onClick={handleInteract} aria-label="Interact with bike">
<Model />
</button>
// Bad
<div onClick={handleInteract}>
<Model />
</div>
```
## Rules
1. **Simplicity** — Every line of code must be justified.
2. **Readability** — Code is read 10x more than it's written.
3. **Reviewability** — PRs should be understandable in < 5 minutes.
4. **Scalability** — Architecture should support growth without refactoring.
5. **Performance** — Don't optimize prematurely, but don't introduce obvious bottlenecks.
6. **Modern** — Use ES2022+ features, TypeScript strict mode, React hooks.
7. **W3C** — Follow web standards: semantic HTML, ARIA, keyboard navigation.
8. **No Over-Engineering** — Avoid patterns that add complexity without benefit.