update
This commit is contained in:
@@ -1,338 +0,0 @@
|
||||
# Animation & 3D Model System
|
||||
|
||||
This document describes how to use the 3D model components and animation system in La-Fabrik.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
1. [Model Types Overview](#model-types-overview)
|
||||
2. [SimpleModel - Static Models](#simplemodel---static-models)
|
||||
3. [AnimatedModel - Animated Models](#animatedmodel---animated-models)
|
||||
4. [Animation Control](#animation-control)
|
||||
5. [Other 3D Components](#other-3d-components)
|
||||
6. [Technical Notes](#technical-notes)
|
||||
|
||||
---
|
||||
|
||||
## Model Types Overview
|
||||
|
||||
The project provides three main types of model instantiation:
|
||||
|
||||
| Type | Component | Use Case |
|
||||
| ----------- | -------------------------------------------------------- | -------------------------------------------- |
|
||||
| Static | `SimpleModel` | Props, decoration, objects without animation |
|
||||
| Animated | `AnimatedModel` | Characters, animated objects with skeleton |
|
||||
| Interactive | `GrabbableObject`, `TriggerObject`, `InteractableObject` | Objects player can interact with |
|
||||
|
||||
---
|
||||
|
||||
## SimpleModel - Static Models
|
||||
|
||||
Use for GLTF models **without** skeleton/armature and no animations.
|
||||
|
||||
```tsx
|
||||
import { SimpleModel } from "@/components/3d";
|
||||
|
||||
<SimpleModel
|
||||
modelPath="/models/elecsimple/model.gltf"
|
||||
position={[0, 0, -5]}
|
||||
rotation={[0, 45, 0]}
|
||||
scale={1}
|
||||
castShadow={true}
|
||||
receiveShadow={true}
|
||||
/>;
|
||||
```
|
||||
|
||||
### Props
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| --------------- | ------------------------ | ----------- | --------------------------------- |
|
||||
| `modelPath` | `string` | required | Path to GLTF file in `/public` |
|
||||
| `position` | `Vector3Tuple` | `[0, 0, 0]` | World position [x, y, z] |
|
||||
| `rotation` | `Vector3Tuple` | `[0, 0, 0]` | Rotation in degrees [x, y, z] |
|
||||
| `scale` | `number \| Vector3Tuple` | `1` | Scale factor or [x, y, z] |
|
||||
| `castShadow` | `boolean` | `true` | Enable shadow casting |
|
||||
| `receiveShadow` | `boolean` | `true` | Enable shadow receiving |
|
||||
| `children` | `ReactNode` | - | Child components to render inside |
|
||||
|
||||
---
|
||||
|
||||
## AnimatedModel - Animated Models
|
||||
|
||||
Use for GLTF models **with** skeleton/armature and animations (like Mixamo characters).
|
||||
|
||||
```tsx
|
||||
import { AnimatedModel, useAnimatedModel } from "@/components/3d";
|
||||
|
||||
// Basic usage
|
||||
<AnimatedModel
|
||||
modelPath="/models/elec/model.gltf"
|
||||
defaultAnimation="Idle"
|
||||
position={[0, 0, -5]}
|
||||
rotation={[0, 0, 0]}
|
||||
scale={0.01}
|
||||
autoPlay={true}
|
||||
speed={1}
|
||||
fadeDuration={0.3}
|
||||
/>;
|
||||
```
|
||||
|
||||
### Props
|
||||
|
||||
| Prop | Type | Default | Description |
|
||||
| ------------------ | ------------------------ | ----------- | --------------------------------------------- |
|
||||
| `modelPath` | `string` | required | Path to GLTF file in `/public` |
|
||||
| `defaultAnimation` | `string` | `"Idle"` | Animation name to play by default |
|
||||
| `animations` | `string[]` | `[]` | List of animation names (optional) |
|
||||
| `position` | `Vector3Tuple` | `[0, 0, 0]` | World position [x, y, z] |
|
||||
| `rotation` | `Vector3Tuple` | `[0, 0, 0]` | Rotation in degrees [x, y, z] |
|
||||
| `scale` | `number \| Vector3Tuple` | `1` | Scale factor |
|
||||
| `autoPlay` | `boolean` | `true` | Auto-play default animation |
|
||||
| `speed` | `number` | `1` | Animation playback speed |
|
||||
| `fadeDuration` | `number` | `0.3` | Transition duration in seconds |
|
||||
| `onLoaded` | `() => void` | - | Callback when model loads |
|
||||
| `onAnimationEnd` | `(name: string) => void` | - | Callback when animation ends |
|
||||
| `children` | `ReactNode` | - | Child components (can use `useAnimatedModel`) |
|
||||
|
||||
### Important: Scale
|
||||
|
||||
Animated models (like Mixamo exports) often need a small scale (e.g., `0.01`) because they are exported in meters while Three.js uses different units. Adjust until the model appears at the right size.
|
||||
|
||||
---
|
||||
|
||||
## Animation Control
|
||||
|
||||
To control animations from inside or outside the `AnimatedModel`, use the `useAnimatedModel` hook.
|
||||
|
||||
### Basic Control
|
||||
|
||||
```tsx
|
||||
import { AnimatedModel, useAnimatedModel } from "@/components/3d";
|
||||
|
||||
// Create a controller component to use inside AnimatedModel
|
||||
function AnimationController() {
|
||||
const { play, stop, fadeTo, currentAnimation, names, setSpeed, isReady } =
|
||||
useAnimatedModel();
|
||||
|
||||
// names contains all available animation names
|
||||
// currentAnimation is the name of the currently playing animation
|
||||
// isReady is true when model and animations are loaded
|
||||
|
||||
return (
|
||||
<mesh onClick={() => play("Run", 0.5)}>
|
||||
<boxGeometry />
|
||||
</mesh>
|
||||
);
|
||||
}
|
||||
|
||||
// Usage
|
||||
<AnimatedModel
|
||||
modelPath="/models/elec/model.gltf"
|
||||
defaultAnimation="Idle"
|
||||
position={[0, 0, -5]}
|
||||
scale={0.01}
|
||||
>
|
||||
<AnimationController />
|
||||
</AnimatedModel>;
|
||||
```
|
||||
|
||||
### Available Methods
|
||||
|
||||
| Method | Signature | Description |
|
||||
| ------------------ | --------------------------------------- | ------------------------------------ |
|
||||
| `play` | `(name: string, fade?: number) => void` | Play animation with optional fade |
|
||||
| `fadeTo` | `(name: string, fade?: number) => void` | Fade to another animation |
|
||||
| `stop` | `(fade?: number) => void` | Stop and return to default animation |
|
||||
| `setSpeed` | `(speed: number) => void` | Set animation speed |
|
||||
| `currentAnimation` | `string` | Current animation name (getter) |
|
||||
| `names` | `string[]` | Available animation names |
|
||||
| `isReady` | `boolean` | Whether model is loaded |
|
||||
|
||||
### Transition Example
|
||||
|
||||
```tsx
|
||||
function Character() {
|
||||
const { play, fadeTo, currentAnimation } = useAnimatedModel();
|
||||
|
||||
const handleWalk = () => fadeTo("Walk", 0.5); // 0.5s fade
|
||||
const handleRun = () => play("Run", 0.3); // 0.3s fade
|
||||
const handleIdle = () => play("Idle", 0.5); // return to idle
|
||||
|
||||
return (
|
||||
<group>
|
||||
<mesh onClick={handleWalk} position={[-1, 0, 0]}>
|
||||
<boxGeometry />
|
||||
</mesh>
|
||||
<mesh onClick={handleRun} position={[0, 0, 0]}>
|
||||
<boxGeometry />
|
||||
</mesh>
|
||||
<mesh onClick={handleIdle} position={[1, 0, 0]}>
|
||||
<boxGeometry />
|
||||
</mesh>
|
||||
</group>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### Combined: GrabbableObject with Animation
|
||||
|
||||
You can combine `AnimatedModel` inside `GrabbableObject` to create animated objects that can be picked up:
|
||||
|
||||
```tsx
|
||||
import { AnimatedModel, GrabbableObject } from "@/components/3d";
|
||||
|
||||
// Animated weapon/tool that player can pick up
|
||||
<GrabbableObject position={[0, 1, 0]} colliders="cuboid">
|
||||
<AnimatedModel
|
||||
modelPath="/models/sword/model.gltf"
|
||||
defaultAnimation="Idle"
|
||||
position={[0, 0, 0]}
|
||||
scale={0.02}
|
||||
autoPlay={true}
|
||||
/>
|
||||
</GrabbableObject>;
|
||||
```
|
||||
|
||||
Or create an animated character that can be grabbed:
|
||||
|
||||
```tsx
|
||||
import {
|
||||
AnimatedModel,
|
||||
GrabbableObject,
|
||||
useAnimatedModel,
|
||||
} from "@/components/3d";
|
||||
|
||||
// Controller that triggers animations when grabbed
|
||||
function AnimatedGrabber() {
|
||||
const { play, fadeTo } = useAnimatedModel();
|
||||
|
||||
return (
|
||||
<AnimatedModel
|
||||
modelPath="/models/elec/model.gltf"
|
||||
defaultAnimation="Idle"
|
||||
position={[0, 0, 0]}
|
||||
scale={0.01}
|
||||
autoPlay={true}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
// When grabbed, play "Grab" animation
|
||||
<GrabbableObject
|
||||
position={[0, 1, 0]}
|
||||
colliders="cuboid"
|
||||
onGrab={() => {
|
||||
// This would require a context or store to trigger
|
||||
console.log("Object grabbed!");
|
||||
}}
|
||||
>
|
||||
<AnimatedGrabber />
|
||||
</GrabbableObject>;
|
||||
```
|
||||
|
||||
**Note:** For complex interactions (like playing specific animations when grabbing), you'll need to connect the grab events to animation controls via a state manager or context.
|
||||
|
||||
---
|
||||
|
||||
## Other 3D Components
|
||||
|
||||
### GrabbableObject
|
||||
|
||||
Objects that can be picked up by the player.
|
||||
|
||||
```tsx
|
||||
import { GrabbableObject } from "@/components/3d";
|
||||
|
||||
<GrabbableObject position={[0, 1, 0]} colliders="cuboid">
|
||||
<mesh>
|
||||
<boxGeometry args={[0.5, 0.5, 0.5]} />
|
||||
<meshStandardMaterial color="red" />
|
||||
</mesh>
|
||||
</GrabbableObject>;
|
||||
```
|
||||
|
||||
### TriggerObject
|
||||
|
||||
Objects that trigger events when interacted with.
|
||||
|
||||
```tsx
|
||||
import { TriggerObject } from "@/components/3d";
|
||||
|
||||
<TriggerObject
|
||||
position={[0, 1, 0]}
|
||||
soundPath="/sounds/click.mp3"
|
||||
onTrigger={() => console.log("Triggered!")}
|
||||
>
|
||||
<mesh>
|
||||
<sphereGeometry />
|
||||
<meshStandardMaterial color="blue" />
|
||||
</mesh>
|
||||
</TriggerObject>;
|
||||
```
|
||||
|
||||
### InteractableObject
|
||||
|
||||
Base object for interactions.
|
||||
|
||||
```tsx
|
||||
import { InteractableObject } from "@/components/3d";
|
||||
|
||||
<InteractableObject
|
||||
position={[0, 1, 0]}
|
||||
onInteract={() => console.log("Interacted!")}
|
||||
>
|
||||
<mesh>
|
||||
<cylinderGeometry />
|
||||
<meshStandardMaterial color="green" />
|
||||
</mesh>
|
||||
</InteractableObject>;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Technical Notes
|
||||
|
||||
### GLTF Models
|
||||
|
||||
- Models should be placed in `/public/models/`
|
||||
- Supported formats: `.gltf`, `.glb`
|
||||
- Animated models must have an Armature/skeleton for animations to work
|
||||
|
||||
### Model Scale Issue
|
||||
|
||||
If animated models don't appear, they may be too small or too large. Try:
|
||||
|
||||
- Scale `0.01` for Mixamo-exported models
|
||||
- Scale `1` for models in correct units
|
||||
|
||||
### Cloning
|
||||
|
||||
- `SimpleModel` uses `scene.clone()` for proper React lifecycle
|
||||
- `AnimatedModel` uses the original scene directly to preserve SkinnedMesh + Armature structure
|
||||
|
||||
### Animation System
|
||||
|
||||
The animation system uses:
|
||||
|
||||
- `@react-three/drei`: `useGLTF` for loading, `useAnimations` for animation control
|
||||
- Three.js: `AnimationMixer` for playback
|
||||
|
||||
### No State Machine
|
||||
|
||||
This system intentionally avoids complex state machines (like Unity's Animator). For simple animation transitions, use the `play`, `fadeTo`, and `stop` methods directly.
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
src/
|
||||
├── components/3d/
|
||||
│ ├── AnimatedModel.tsx # Animated model component + context
|
||||
│ ├── SimpleModel.tsx # Static model component
|
||||
│ ├── GrabbableObject.tsx # Pickable object
|
||||
│ ├── TriggerObject.tsx # Trigger event object
|
||||
│ ├── InteractableObject.tsx
|
||||
│ └── index.ts # Central exports
|
||||
└── hooks/
|
||||
└── useCharacterAnimation.ts # Animation hook (legacy)
|
||||
```
|
||||
@@ -4,16 +4,13 @@ This document describes the code that exists today in the repository.
|
||||
|
||||
## Runtime Structure
|
||||
|
||||
- `src/main.tsx` mounts React and wraps the app in `BrowserRouter`.
|
||||
- `src/App.tsx` declares the top-level routes:
|
||||
- `/` mounts the playable 3D scene, debug perf overlay, and HTML overlays.
|
||||
- `/editor` mounts the map editor page.
|
||||
- `src/App.tsx` mounts the `Canvas`, the 3D `World`, the debug perf overlay, and the HTML overlays.
|
||||
- `src/world/World.tsx` composes the active scene, including:
|
||||
- environment and lighting
|
||||
- debug helpers and debug camera mode
|
||||
- either the map scene or the debug physics test scene
|
||||
- the player rig when the active camera mode is `player`
|
||||
- `src/world/GameMap.tsx` loads map nodes from `public/map.json`, resolves available models, and builds the collision octree.
|
||||
- `src/world/Map.tsx` loads the main map model and builds the collision octree.
|
||||
- `src/world/debug/TestScene.tsx` provides a debug-oriented interaction and physics scene.
|
||||
- `src/world/player/PlayerComponent.tsx` mounts the camera and controller.
|
||||
- `src/world/player/PlayerController.tsx` owns pointer lock movement, jump handling, and interaction input.
|
||||
@@ -41,31 +38,10 @@ This document describes the code that exists today in the repository.
|
||||
- `src/utils/debug/scene/DebugHelpers.tsx` mounts debug helpers.
|
||||
- `src/utils/debug/scene/DebugCameraControls.tsx` mounts the free debug camera.
|
||||
|
||||
## Editor System
|
||||
|
||||
- `src/pages/editor/EditorPage.tsx` is the route-level editor page for `/editor`.
|
||||
- `src/components/editor/EditorControls.tsx` renders the HTML editor control panel.
|
||||
- `src/components/editor/scene/EditorScene.tsx` composes the editor canvas scene, camera controls, lights, shortcuts, and map rendering.
|
||||
- `src/components/editor/scene/EditorMap.tsx` renders map nodes, fallback cubes, selection highlighting, and transform controls.
|
||||
- `src/controls/editor/FlyController.tsx` provides player-style editor navigation.
|
||||
- `src/hooks/editor/useEditorSceneData.ts` loads scene data and handles folder upload fallback.
|
||||
- `src/hooks/editor/useEditorHistory.ts` owns editor undo and redo state.
|
||||
- `src/utils/editor/loadEditorScene.ts` handles editor-only folder upload parsing.
|
||||
- `src/utils/loadMapSceneData.ts` is shared by the game scene and editor to load `public/map.json` and resolve model URLs.
|
||||
- `src/types/editor.ts` contains the shared `MapNode`, `SceneData`, and `TransformMode` types.
|
||||
|
||||
## Map Data
|
||||
|
||||
- `public/map.json` is expected to be a `MapNode[]`.
|
||||
- Each map node `name` maps to `public/models/{name}/model.gltf`.
|
||||
- The editor renders a fallback cube for missing models.
|
||||
- The game scene filters out nodes whose model cannot be resolved.
|
||||
|
||||
## Current Limitations
|
||||
|
||||
- The repository is a prototype, not the full intended game runtime.
|
||||
- `src/world/debug/TestScene.tsx` is part of the active scene composition.
|
||||
- There is no central gameplay orchestrator such as `GameManager`.
|
||||
- The repository is still a prototype, not the full intended game runtime.
|
||||
- `src/world/debug/TestScene.tsx` is still part of the active scene composition.
|
||||
- There is no central gameplay orchestrator such as `GameManager` yet.
|
||||
- Missions, zones, cinematics, and dialogue systems are not implemented.
|
||||
- The player uses octree collision and simple movement rules, not a complete gameplay physics stack.
|
||||
- Editor save-to-server is implemented as a Vite dev-server plugin, not a production backend API.
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
# Editor Technical Notes
|
||||
|
||||
This document describes the map editor that exists in the current codebase.
|
||||
|
||||
## Purpose
|
||||
|
||||
The editor is a React route used to inspect and adjust the `public/map.json` scene data from inside the La-Fabrik app. It shares the same `MapNode` data format as the game scene and uses React Three Fiber for rendering.
|
||||
|
||||
## Routing
|
||||
|
||||
- `/` renders the playable La-Fabrik scene.
|
||||
- `/editor` renders the map editor.
|
||||
- `src/App.tsx` mounts TanStack Router through `RouterProvider`.
|
||||
- `src/router.tsx` defines the `/editor` route and imports `EditorPage` from `src/pages/editor/page.tsx`.
|
||||
|
||||
## File Structure
|
||||
|
||||
```txt
|
||||
src/
|
||||
├── pages/
|
||||
│ └── editor/
|
||||
│ └── page.tsx
|
||||
├── components/
|
||||
│ └── editor/
|
||||
│ ├── EditorControls.tsx
|
||||
│ └── scene/
|
||||
│ ├── EditorMap.tsx
|
||||
│ └── EditorScene.tsx
|
||||
├── controls/
|
||||
│ └── editor/
|
||||
│ └── FlyController.tsx
|
||||
├── hooks/
|
||||
│ └── editor/
|
||||
│ ├── useEditorHistory.ts
|
||||
│ └── useEditorSceneData.ts
|
||||
├── types/
|
||||
│ └── editor.ts
|
||||
└── utils/
|
||||
├── editor/
|
||||
│ └── loadEditorScene.ts
|
||||
└── loadMapSceneData.ts
|
||||
```
|
||||
|
||||
## Responsibilities
|
||||
|
||||
`src/pages/editor/page.tsx` is the route-level composition component. It owns route-specific state such as selected object, hovered object, transform mode, and player-mode toggle.
|
||||
|
||||
`src/hooks/editor/useEditorSceneData.ts` loads the default map data and handles folder uploads.
|
||||
|
||||
`src/hooks/editor/useEditorHistory.ts` owns editor undo and redo history.
|
||||
|
||||
`src/components/editor/scene/EditorScene.tsx` composes the editor canvas scene, camera controls, lights, keyboard shortcuts, and `EditorMap`.
|
||||
|
||||
`src/components/editor/scene/EditorMap.tsx` renders map nodes, fallback cubes, selection highlighting, and transform controls.
|
||||
|
||||
`src/components/editor/EditorControls.tsx` renders the HTML control panel outside the canvas.
|
||||
|
||||
`src/controls/editor/FlyController.tsx` provides editor movement controls for player-style navigation.
|
||||
|
||||
`src/utils/loadMapSceneData.ts` is shared by the game map and editor. It loads `/map.json` and resolves available `public/models/{name}/model.gltf` files.
|
||||
|
||||
`src/utils/editor/loadEditorScene.ts` contains editor-only upload handling for user-selected folders.
|
||||
|
||||
## Data Format
|
||||
|
||||
The shared editor type lives in `src/types/editor.ts`.
|
||||
|
||||
```ts
|
||||
interface MapNode {
|
||||
name: string;
|
||||
type: string;
|
||||
position: [number, number, number];
|
||||
rotation: [number, number, number];
|
||||
scale: [number, number, number];
|
||||
}
|
||||
```
|
||||
|
||||
`public/map.json` is expected to be a `MapNode[]`.
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"name": "pylone",
|
||||
"type": "Mesh",
|
||||
"position": [0, 5, 0],
|
||||
"rotation": [0, 1.57, 0],
|
||||
"scale": [1, 1, 1]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Each node `name` maps to a model folder:
|
||||
|
||||
```txt
|
||||
public/
|
||||
├── map.json
|
||||
└── models/
|
||||
└── pylone/
|
||||
└── model.gltf
|
||||
```
|
||||
|
||||
If a model is missing, the editor renders a fallback cube so the node can still be selected and transformed.
|
||||
|
||||
## Editor Flow
|
||||
|
||||
1. `EditorPage` mounts on `/editor`.
|
||||
2. `useEditorSceneData` calls `loadMapSceneData()`.
|
||||
3. `loadMapSceneData()` loads `/map.json` and available model URLs.
|
||||
4. If `/map.json` is missing, the page displays a folder-upload flow.
|
||||
5. `EditorScene` renders the grid, lights, camera controls, and map nodes.
|
||||
6. `EditorControls` exposes transform mode, history actions, export, save, and selection info.
|
||||
|
||||
## Controls
|
||||
|
||||
- Click: select a node.
|
||||
- `Esc`: clear selection.
|
||||
- `T`: translate mode.
|
||||
- `R`: rotate mode.
|
||||
- `S`: scale mode.
|
||||
- `Ctrl+Z` or `Cmd+Z`: undo.
|
||||
- `Ctrl+Y` or `Cmd+Y`: redo.
|
||||
- `WASD`, `ZQSD`, or arrow keys: move in player-controller mode.
|
||||
- `Space`: move upward in player-controller mode.
|
||||
- `Shift`: move downward in player-controller mode.
|
||||
|
||||
## Saving And Exporting
|
||||
|
||||
The editor supports two output paths:
|
||||
|
||||
- Export JSON downloads the current `MapNode[]` as `map.json`.
|
||||
- Save to Server posts the current `MapNode[]` to `/api/save-map`.
|
||||
|
||||
The dev-only `/api/save-map` endpoint is implemented by the Vite plugin in `vite.config.ts`. It writes to `public/map.json` and enforces a maximum payload size.
|
||||
|
||||
## Styling
|
||||
|
||||
Editor styles are in `src/index.css` under the `/* Editor page */` section. Classes are prefixed with `editor-` to avoid collisions with the game UI.
|
||||
|
||||
## Known Limitations
|
||||
|
||||
- Uploaded model object URLs are not currently revoked after replacement or unmount.
|
||||
- Large `map.json` files are not virtualized, culled, or LOD-managed.
|
||||
- There is no snap-to-grid, duplication, material editing, or object creation workflow.
|
||||
- Save to Server is a Vite dev-server helper, not a production backend API.
|
||||
@@ -5,7 +5,7 @@ This document describes the intended medium-term architecture for the project.
|
||||
## Relationship To The Current Code
|
||||
|
||||
- `docs/technical/architecture.md` is the source of truth for what exists now.
|
||||
- This document describes intended direction, not implemented behavior.
|
||||
- This document is intentionally aspirational.
|
||||
- If this document conflicts with the current implementation, the current implementation wins.
|
||||
|
||||
## Goals
|
||||
@@ -40,12 +40,12 @@ This document describes the intended medium-term architecture for the project.
|
||||
- performance overlay
|
||||
- scene helpers
|
||||
- free camera and calibration controls
|
||||
- debug test scenes used during development
|
||||
- temporary test scenes used during development
|
||||
|
||||
### UI Layer
|
||||
|
||||
- `src/components/ui/` should contain player-facing HTML overlays.
|
||||
- Candidate examples:
|
||||
- Expected future examples:
|
||||
- crosshair
|
||||
- loading flow
|
||||
- mission HUD
|
||||
@@ -54,7 +54,7 @@ This document describes the intended medium-term architecture for the project.
|
||||
### Gameplay Layer
|
||||
|
||||
- As the project grows, gameplay state can move toward a clearer orchestration layer.
|
||||
- Likely concerns:
|
||||
- Likely future concerns:
|
||||
- missions
|
||||
- zones
|
||||
- cinematics
|
||||
@@ -67,4 +67,4 @@ This document describes the intended medium-term architecture for the project.
|
||||
- Prefer direct, working code over speculative scaffolding.
|
||||
- Shared types should stay close to their domain until they have multiple real consumers.
|
||||
- Avoid creating new managers or service layers without an active runtime need.
|
||||
- Debug-only runtime paths should be clearly marked and easy to remove when obsolete.
|
||||
- Debug-only runtime paths should be clearly marked and easy to remove later.
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
# Editor User Guide
|
||||
|
||||
The map editor is available at `/editor`. It is a browser-based tool for inspecting and adjusting the objects listed in `public/map.json`.
|
||||
|
||||
## Purpose
|
||||
|
||||
Use the editor when you need to move, rotate, or scale existing map objects without editing JSON by hand.
|
||||
|
||||
The editor reads the same map data as the runtime scene:
|
||||
|
||||
- `public/map.json` contains the object list.
|
||||
- `public/models/{name}/model.gltf` contains the matching 3D model for each object name.
|
||||
- Missing models are displayed as gray fallback cubes, so incomplete maps remain editable.
|
||||
|
||||
## Map Node Format
|
||||
|
||||
Each entry in `public/map.json` represents one object:
|
||||
|
||||
| Field | Description |
|
||||
| ---------- | ------------------------------------------------- |
|
||||
| `name` | Model folder name in `public/models/{name}` |
|
||||
| `type` | Object category |
|
||||
| `position` | Object position as `[x, y, z]` |
|
||||
| `rotation` | Object rotation as `[x, y, z]`, expressed radians |
|
||||
| `scale` | Object scale as `[x, y, z]` |
|
||||
|
||||
## Editing Workflow
|
||||
|
||||
1. Open `/editor` in the local app.
|
||||
2. Click an object in the scene to select it.
|
||||
3. Choose a transform mode: translate, rotate, or scale.
|
||||
4. Drag the transform gizmo in the 3D view.
|
||||
5. Check the JSON inspector if you need exact values.
|
||||
6. Use undo or redo if the transform is not correct.
|
||||
7. Export the JSON or save it to the dev server.
|
||||
|
||||
## Controls
|
||||
|
||||
| Action | Input |
|
||||
| -------------------- | -------------------------- |
|
||||
| Select object | Click object |
|
||||
| Deselect | `Esc` or click empty space |
|
||||
| Translate mode | `T` |
|
||||
| Rotate mode | `R` |
|
||||
| Scale mode | `S` |
|
||||
| Undo | `Ctrl+Z` |
|
||||
| Redo | `Ctrl+Y` |
|
||||
| Locked view movement | `WASD`, `ZQSD`, arrows |
|
||||
| Move up | `Space` |
|
||||
| Move down | `Shift` |
|
||||
|
||||
## View Mode
|
||||
|
||||
The `Lock view` action switches the editor into a movement mode closer to the runtime player camera. Use it to navigate larger scenes while keeping the transform tools available.
|
||||
|
||||
## JSON Inspector
|
||||
|
||||
The side panel includes a raw JSON inspector:
|
||||
|
||||
- When no object is selected, it shows the full map node list.
|
||||
- When an object is selected, it highlights the JSON lines for that object.
|
||||
|
||||
This is useful for checking numeric transform values before saving or exporting.
|
||||
|
||||
## Saving Changes
|
||||
|
||||
### Export JSON
|
||||
|
||||
`Export JSON` downloads the current map node list as `map.json`. Use this when you want to manually replace `public/map.json`.
|
||||
|
||||
### Save To Server
|
||||
|
||||
`Save to server` is available only during local development. It writes the edited map back to `public/map.json` through the Vite dev-server endpoint.
|
||||
|
||||
The button is hidden in production builds because production persistence is not implemented.
|
||||
|
||||
## Current Limitations
|
||||
|
||||
- The editor only modifies existing nodes.
|
||||
- It does not create or delete objects.
|
||||
- It does not edit model files or textures.
|
||||
- It does not provide production persistence.
|
||||
- Fallback cubes indicate missing models; they are editor placeholders, not exported assets.
|
||||
+1
-16
@@ -5,7 +5,7 @@ This document lists features that are implemented in the current codebase.
|
||||
## Scene
|
||||
|
||||
- Fullscreen React Three Fiber scene
|
||||
- Main map scene loaded from `public/map.json` and matching `public/models/{name}/model.gltf` assets
|
||||
- Main map scene loaded from `public/models/map/model.gltf`
|
||||
- Debug physics test scene selectable from the debug panel
|
||||
- Ambient and directional lighting
|
||||
- Environment background setup
|
||||
@@ -38,20 +38,6 @@ This document lists features that are implemented in the current codebase.
|
||||
- Free debug camera
|
||||
- `r3f-perf` overlay
|
||||
|
||||
## Map Editor
|
||||
|
||||
- `/editor` route for inspecting and editing `public/map.json`
|
||||
- Automatic loading of `public/map.json` when available
|
||||
- Folder upload fallback when `map.json` is missing
|
||||
- Rendering of available `public/models/{name}/model.gltf` assets
|
||||
- Fallback cubes for nodes whose model is missing
|
||||
- Object selection by click
|
||||
- Transform modes for translate, rotate, and scale
|
||||
- Keyboard shortcuts for `T`, `R`, `S`, `Esc`, undo, and redo
|
||||
- Player-style navigation mode with `WASD`, `ZQSD`, arrow keys, `Space`, and `Shift`
|
||||
- JSON export for downloading the edited map
|
||||
- Dev-server save endpoint for writing changes back to `public/map.json`
|
||||
|
||||
## Not Implemented Yet
|
||||
|
||||
- mission system
|
||||
@@ -61,4 +47,3 @@ This document lists features that are implemented in the current codebase.
|
||||
- loading flow
|
||||
- minimap and mission HUD
|
||||
- full production separation between gameplay and debug scenes
|
||||
- production backend persistence for editor saves
|
||||
|
||||
Reference in New Issue
Block a user