From 874df17b39469d9dc4ee47c6e29f3f909c1f29e3 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 26 Jan 2026 02:44:37 +0000 Subject: [PATCH] fix(editor): correct model scale and move selected panel to tabs Model Scale Fix: - Normalize models to unit height first, then multiply by target scale - This matches the game's AssetManager behavior for consistent sizing UI Improvements: - Move SelectedObjectPanel into main tab panel as "Edit" tab - Add empty state with helpful message when nothing selected - Make tabs more compact (smaller padding, flex-1 for even distribution) - Add hasContent indicator dot for Edit tab when object is selected - Reorder panels: Paint first, AI moved to near end - Shorten tab names for better fit (Objects->Obj, Settings->Set, etc.) Panel order now: Paint, Bases, Obj, Decor, Edit, Set, AI, Val --- src/editor/configs/voidstrike.ts | 11 +-- src/editor/core/EditorPanels.tsx | 96 +++++++++++++++------ src/editor/rendering3d/EditorModelLoader.ts | 9 +- 3 files changed, 82 insertions(+), 34 deletions(-) diff --git a/src/editor/configs/voidstrike.ts b/src/editor/configs/voidstrike.ts index fcb75de3..2bc5f367 100644 --- a/src/editor/configs/voidstrike.ts +++ b/src/editor/configs/voidstrike.ts @@ -644,13 +644,14 @@ export const VOIDSTRIKE_THEME: UIThemeConfig = { // ============================================ export const VOIDSTRIKE_PANELS: PanelConfig[] = [ - { id: 'ai', name: 'AI', icon: '🪄', type: 'ai' }, - { id: 'paint', name: 'Paint', icon: '🖌', type: 'paint' }, + { id: 'paint', name: 'Paint', icon: '🎨', type: 'paint' }, { id: 'bases', name: 'Bases', icon: '🏠', type: 'objects' }, - { id: 'objects', name: 'Objects', icon: '🪨', type: 'objects' }, + { id: 'objects', name: 'Obj', icon: '📦', type: 'objects' }, { id: 'decorations', name: 'Decor', icon: '🌲', type: 'objects' }, - { id: 'settings', name: 'Settings', icon: '⚙', type: 'settings' }, - { id: 'validate', name: 'Validate', icon: '✓', type: 'validate' }, + { id: 'selected', name: 'Edit', icon: '✎', type: 'selected' }, + { id: 'settings', name: 'Set', icon: '⚙', type: 'settings' }, + { id: 'ai', name: 'AI', icon: '✨', type: 'ai' }, + { id: 'validate', name: 'Val', icon: '✓', type: 'validate' }, ]; // ============================================ diff --git a/src/editor/core/EditorPanels.tsx b/src/editor/core/EditorPanels.tsx index 25e83d14..4c2a1e04 100644 --- a/src/editor/core/EditorPanels.tsx +++ b/src/editor/core/EditorPanels.tsx @@ -155,36 +155,40 @@ function Section({ ); } -// Modern panel tab with animated indicator +// Modern panel tab with animated indicator - compact design function PanelTab({ active, onClick, icon, name, theme, + hasContent, }: { active: boolean; onClick: () => void; icon?: string; name: string; theme: EditorConfig['theme']; + hasContent?: boolean; }) { return ( ); } @@ -1530,8 +1533,51 @@ function ScaleControl({ ); } +// Selected panel - wrapper with empty state +function SelectedPanel({ + config, + state, + onPropertyUpdate, + onRemove, +}: { + config: EditorConfig; + state: EditorState; + onPropertyUpdate: (id: string, key: string, value: unknown) => void; + onRemove: (id: string) => void; +}) { + const theme = config.theme; + + if (state.selectedObjects.length === 0 || !state.mapData) { + return ( +
+
+ ✎ +
+
+ No Object Selected +
+
+ Click on an object in the map to select it and edit its properties here +
+
+ ); + } + + return ( + + ); +} + // Selected object properties panel with enhanced UI -function SelectedObjectPanel({ +function SelectedObjectPanelContent({ config, state, onPropertyUpdate, @@ -1564,10 +1610,7 @@ function SelectedObjectPanel({ const currentScale = (selectedObj.properties?.scale as number) ?? scaleProp?.defaultValue ?? 1; return ( -
+
{/* Header */}
@@ -1848,6 +1891,7 @@ export function EditorPanels({ icon={panel.icon} name={panel.name} theme={theme} + hasContent={panel.id === 'selected' ? state.selectedObjects.length > 0 : undefined} /> ))}
@@ -1900,6 +1944,14 @@ export function EditorPanels({ onObjectRemove={onObjectRemove} /> + + +
- {/* Selected object properties */} - - {/* Keyboard shortcuts footer */}
diff --git a/src/editor/rendering3d/EditorModelLoader.ts b/src/editor/rendering3d/EditorModelLoader.ts index 02cff4c9..9127c750 100644 --- a/src/editor/rendering3d/EditorModelLoader.ts +++ b/src/editor/rendering3d/EditorModelLoader.ts @@ -103,8 +103,9 @@ let initPromise: Promise | null = null; /** * Normalize a model: scale to target height and ground to y=0 + * This matches how the game's AssetManager handles model scaling. */ -function normalizeModel(root: THREE.Object3D, scale: number, rotationY: number = 0): void { +function normalizeModel(root: THREE.Object3D, targetScale: number, rotationY: number = 0): void { root.updateMatrixWorld(true); const box = new THREE.Box3().setFromObject(root); @@ -112,9 +113,11 @@ function normalizeModel(root: THREE.Object3D, scale: number, rotationY: number = const size = box.getSize(new THREE.Vector3()); - // Apply scale + // Normalize to unit height first, then multiply by target scale + // This ensures model height equals targetScale in world units if (size.y > 0.001) { - root.scale.setScalar(scale); + const normalizeScale = targetScale / size.y; + root.scale.setScalar(normalizeScale); } // Apply base rotation