Skip to content

feat(editor): wave-7 polish -- undo UI + toolbar + asset browser (#20)#213

Merged
havokentity merged 1 commit into
integration/parallel-batch-1from
feat/wave7-editor-polish
May 19, 2026
Merged

feat(editor): wave-7 polish -- undo UI + toolbar + asset browser (#20)#213
havokentity merged 1 commit into
integration/parallel-batch-1from
feat/wave7-editor-polish

Conversation

@havokentity
Copy link
Copy Markdown
Owner

Summary

Wave-7 editor polish drop. Three sub-features in one PR:

1. Global keyboard shortcuts

  • Cmd/Ctrl+Z dispatches scene_undo
  • Cmd/Ctrl+Shift+Z and Ctrl+Y dispatch scene_redo
  • G / R / S flip gizmo_mode translate / rotate / scale

Installed by <Shell> so every editor panel gets them automatically. Listener
gates on the focused element: a number-field that wants the user to type s
still works because typing into <input>/<textarea>/contenteditable skips
dispatch.

2. Toolbar panel rebuild (panels/toolbar)

Thin top-bar (~32 px) modeled after Blender / Unity headers:

  • Translate / Rotate / Scale -- dispatch gizmo_mode <mode>
  • Undo / Redo -- scene_undo / scene_redo (also flash when the matching
    Cmd+Z keyboard shortcut fires)
  • Snap toggle (cvar gizmo_snap, new) + Transform-space selector
    (cvar gizmo_space, new; world / local)

Toolbar polls the three cvars every 1 s so external changes (GLFW G/R/S
handler, console, other panels) stay reflected without a manual refresh.

3. Asset Browser panel (panels/asset-browser)

Four tabs, file-path filter, click-to-load:

Tab Source Click dispatches
Scenes tests/goldens/scenes/*.cfg exec <path>
HDRIs assets/hdri/*.hdr r_env_map <path>
glTF assets/gltf/*.gltf / *.glb mesh_load_gltf <path>
Meshes assets/meshes/*.obj / .ply mesh_load_gltf <path> (stub; no .obj importer yet)

Rows are draggable: drag-start writes the dispatch line into both
application/x-demont-asset (custom MIME) and text/plain so a future
native-viewport drop handler can pick either off the DataTransfer.

Engine additions

  • new cvars gizmo_snap (default 0) + gizmo_space (default "world"),
    both CVAR_ARCHIVE so they survive across runs
  • new command list_assets <subdir>: directory walk over
    tests/goldens/scenes (.cfg/.toml), assets/hdri (.hdr/.exr),
    assets/gltf (.glb/.gltf), assets/meshes (.obj/.ply/.stl). Emits one
    workspace-relative path per line plus a trailing
    (list_assets: N entries under '<dir>') summary the React client splits on
    \n and drops.

Existing engine commands consumed:

Test plan

  • npm run typecheck -- clean (web/editor/)
  • npm test -- 41 tests pass (24 hierarchy, 11 keyboard, 6 asset-browser)
  • npm run build -- 18 embedded files emitted
  • cmake --build build/mac-release --target demont -j 8 -- clean Mac/Metal build
  • Smoke: spawn demont, line-TCP probe list_assets scenes -- 29 entries
  • Smoke: WS get_cvar gizmo_snap returns {value: "0", default: "0"}; gizmo_space same shape
  • Smoke: HTTP GET /editor/{toolbar,asset-browser,inspector,scene-hierarchy} -- 200, <div id="app"> present
  • Smoke: WS exec scene_undo on a fresh engine returns scene_undo: history is empty (round-trips properly)

Notes for the integrator

  • Test runner now uses happy-dom for the DOM-dependent keyboard handler tests; added as a devDependency in web/editor/package.json
  • The Meshes tab is informational only; the engine currently only imports
    glTF. Empty-state hint says so
  • gizmo_space local is currently a metadata cvar -- the analytic-prim gizmo
    drag dispatch is world-space only. Wired now so the rotation-aware gizmo
    follow-up (fix(shaders): per-ray underwater medium tracking (Phase 4 #134) #206 -- light / per-prim orientation) can read it without
    another cvar-add roundtrip

Three editor-side features in one drop:

1. Global keyboard shortcuts (shared/src/keyboard.ts):
   - Cmd/Ctrl+Z dispatches scene_undo
   - Cmd/Ctrl+Shift+Z (and Ctrl+Y) dispatches scene_redo
   - G / R / S flip gizmo_mode translate / rotate / scale
   - Handler installed by <Shell>, opt-out via installShortcuts={false},
     and skips dispatch when focus is inside <input>/<textarea>/
     contenteditable so number-field typing still works

2. Toolbar panel rebuild (panels/toolbar):
   - Thin header strip with three groups: gizmo mode, undo/redo,
     snap toggle + transform-space selector
   - Reads gizmo_mode / gizmo_snap / gizmo_space cvars at mount and
     re-polls every 1s so external changes (GLFW G/R/S, console) stay
     reflected
   - Buttons highlight on matching shortcut press so the user gets
     visual feedback when Cmd+Z fires

3. Asset Browser panel (panels/asset-browser):
   - Four tabs (Scenes, HDRIs, glTF, Meshes) with file-path filter
   - Click-to-load via engine console commands:
       Scenes  -> exec <path>
       HDRIs   -> r_env_map <path>
       glTF    -> mesh_load_gltf <path>
   - Drag-start stuffs the dispatch line into
     application/x-demont-asset + text/plain so a future native
     viewport drop handler can read either MIME and run the line

Engine additions:
- new cvars gizmo_snap (default 0) + gizmo_space (default "world"),
  archived so they survive across runs
- new command list_assets <subdir> -- directory_iterator over
  tests/goldens/scenes (.cfg/.toml), assets/hdri (.hdr/.exr),
  assets/gltf (.glb/.gltf), assets/meshes (.obj/.ply/.stl); emits one
  workspace-relative path per line plus a trailing summary; React
  client splits on '\n' and drops the parenthesised summary

Tests:
- shared/__tests__/keyboard.test.ts -- 11 tests for the shortcut
  dispatcher (jsdom via happy-dom)
- panels/asset-browser/__tests__/helpers.test.ts -- 6 tests for the
  list_assets output parser

Smoke-tested on Mac/Metal: the four panel HTMLs serve on
/editor/<name>, the WS protocol returns the new cvars correctly, and
list_assets enumerates the workspace asset tree as expected.
@havokentity havokentity merged commit ba26c82 into integration/parallel-batch-1 May 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant