diff --git a/docs/technical/editor.md b/docs/technical/editor.md index 0587e12..08c1084 100644 --- a/docs/technical/editor.md +++ b/docs/technical/editor.md @@ -52,7 +52,7 @@ src/ ## 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, selection lock, player-mode toggle, cinematic preview requests, and editor scene loading state. +`src/pages/editor/page.tsx` is the route-level composition component. It owns route-specific state such as primary selected object, selected object indexes, hovered object, transform mode, selection lock, player-mode toggle, cinematic preview requests, and editor scene loading state. `src/hooks/editor/useEditorSceneData.ts` loads the default map data and handles folder uploads. @@ -60,7 +60,7 @@ src/ `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/scene/EditorMap.tsx` renders map nodes, fallback cubes, selection highlighting, and transform controls. For multi-selection, it attaches `TransformControls` to a temporary group centered on the selected nodes, then decomposes the group delta back into each selected node transform. `src/components/editor/EditorControls.tsx` renders the HTML control panel outside the canvas. The panel is organized into top-level `details` groups: `Editor`, `Cinematics`, `Dialogues`, and `SRT`. @@ -115,11 +115,12 @@ If `model.glb` and `model.gltf` are both missing, the editor renders a fallback 4. If `/map.json` is missing, the page displays a folder-upload flow. 5. `EditorSceneLoadingTracker` uses drei `useProgress()` to update the fullscreen editor loading overlay while models load. 6. `EditorScene` renders the grid, lights, camera controls, and map nodes inside `Suspense`. -7. `EditorControls` exposes transform mode, terrain snap, terrain-selection lock, add/delete node, precise scale inputs, history actions, camera focus/reset, export, save, JSON preview, selection lock, and the cinematic/dialogue/SRT editors. +7. `EditorControls` exposes transform mode, terrain snap, terrain-selection lock, add/delete node, precise scale inputs, history actions, camera focus/reset, export, save, JSON preview, selection lock, multi-selection status, and the cinematic/dialogue/SRT editors. ## Controls - Click: select a node. +- `Shift` + right click: add or remove a node from the multi-selection. - `Esc`: clear selection. - Click empty space: clear selection. - Selection lock button: prevent object clicks, empty-space clicks, and `Esc` from changing the current selection. @@ -128,6 +129,7 @@ If `model.glb` and `model.gltf` are both missing, the editor renders a fallback - `R`: rotate mode. - `S`: scale mode. - Snap terrain on move: enabled by default and applied while translating an object. +- Multi-selection transforms use a temporary centered group and write the resulting position, rotation, and scale back to every selected map node. - Lock terrain: enabled by default so terrain remains visible but ignores selection clicks. - Camera action: centers on the selected object or resets to the editor home view. - Add node: creates a fallback cube under `blocking` using the requested model folder name. diff --git a/docs/user/editor.md b/docs/user/editor.md index 0c1a230..67ee333 100644 --- a/docs/user/editor.md +++ b/docs/user/editor.md @@ -45,14 +45,15 @@ Only the `Editor` group is open by default. Open the other groups when you need 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. Keep `Snap terrain on move` enabled when placing objects on the terrain. -6. Use `Center on object` or `Reset camera` from the `View` section when navigating large maps. -7. Adjust scale numerically from the `Selection` section if the gizmo is not precise enough. -8. Check the JSON inspector if you need exact values. -9. Use undo or redo if the transform is not correct. -10. Export the JSON or save it to the dev server. +3. Use `Shift + right click` on other objects to add or remove them from the current multi-selection. +4. Choose a transform mode: translate, rotate, or scale. +5. Drag the transform gizmo in the 3D view. With multiple objects selected, the gizmo transforms the selected group and writes each object transform back to `map.json`. +6. Keep `Snap terrain on move` enabled when placing objects on the terrain. +7. Use `Center on object` or `Reset camera` from the `View` section when navigating large maps. +8. Adjust scale numerically from the `Selection` section if the gizmo is not precise enough. +9. Check the JSON inspector if you need exact values. +10. Use undo or redo if the transform is not correct. +11. Export the JSON or save it to the dev server. ## Adding And Deleting Nodes @@ -70,6 +71,7 @@ Use the trash button in `Selection` to delete the selected node from the map tre | Action | Input | | -------------------- | -------------------------- | | Select object | Click object | +| Toggle multi-select | `Shift` + right click | | Deselect | `Esc` or click empty space | | Lock selection | `Lock` button in Selection | | Clear selection | `X` button in Selection | @@ -87,6 +89,8 @@ Use the trash button in `Selection` to delete the selected node from the map tre The `Selection` section shows the selected object name and its index in `public/map.json`. - Click an object to select it. +- Use `Shift + right click` on objects to add or remove them from a multi-selection. +- When several objects are selected, the gizmo appears on the selection group and applies translate, rotate, or scale to each selected node. - Click empty space or press `Esc` to clear the selection. - Use the `X` button to clear the selection explicitly. - Use the `Lock` button to protect the current selection while editing. diff --git a/src/components/editor/EditorControls.tsx b/src/components/editor/EditorControls.tsx index 8d1e090..7080eec 100644 --- a/src/components/editor/EditorControls.tsx +++ b/src/components/editor/EditorControls.tsx @@ -29,6 +29,7 @@ interface EditorControlsProps { transformMode: TransformMode; onTransformModeChange: (mode: TransformMode) => void; selectedNodeIndex: number | null; + selectedNodeIndexes: number[]; mapNodes: MapNode[]; nodesCount: number; selectedNodeName: string | null; @@ -66,6 +67,7 @@ const TRANSFORM_OPTIONS = [ const EDITOR_SHORTCUTS = [ ["Click", "Select object"], + ["Shift + Right click", "Toggle multi-selection"], ["T / R / S", "Transform mode"], ["Ctrl Z / Y", "Undo / redo"], ["Esc", "Deselect"], @@ -103,6 +105,7 @@ export function EditorControls({ transformMode, onTransformModeChange, selectedNodeIndex, + selectedNodeIndexes, mapNodes, nodesCount, selectedNodeName, @@ -135,6 +138,7 @@ export function EditorControls({ const jsonPreview = getJsonPreview(mapNodes, selectedNodeIndex); const selectedNode = selectedNodeIndex !== null ? mapNodes[selectedNodeIndex] : null; + const selectionCount = selectedNodeIndexes.length; const transformValues = getTransformValues(selectedNode ?? null); return ( @@ -240,10 +244,14 @@ export function EditorControls({