Skip to content

Decouple action toolbar state from entity selection (#1898) - #1900

Merged
kfarr merged 4 commits into
mainfrom
claude/editor-transform-stale-state-9f0j1b
Aug 1, 2026
Merged

Decouple action toolbar state from entity selection (#1898)#1900
kfarr merged 4 commits into
mainfrom
claude/editor-transform-stale-state-9f0j1b

Conversation

@kfarr

@kfarr kfarr commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator

Summary

Narrowed follow-up to #1898. Re-review of the original report showed the perceived selection-box misalignment in the 3D canvas was not a defect: the box correctly represented the bounds of the selected object including its hidden layers (ground/buildings), so it only appeared wrong. Earlier commits on this branch that speculatively changed OrientedBoxHelper, raycaster hover clearing, shortcut event ordering, and reselect behavior have been reverted — they could not be verified against a real error and current behavior is correct.

What remains is the confirmed improvement: selection never changes the action toolbar state. Mode is tool state, not per-object state.

Changes (ActionBar.component.jsx, ActionBar.module.scss only)

  • Hand button lights only when the hand tool is genuinely engaged. Previously, selecting any entity carrying data-no-transform (e.g. autocreated clones from street-generated-clones, which aren't listed in the layers panel) painted the hand button as active — reading as the editor being wedged in a phantom "hand" state.
  • Translate/rotate stay clickable, dimmed instead of disabled. Previously such a selection disabled both buttons, locking the user out of switching modes until they selected something else. They now keep the current mode's active highlight and remain clickable; while the selection can't be transformed they render dimmed (new .inapplicable style) to signal the tool won't act on this selection. Allowing the switch is safe because the gizmo layer independently refuses to attach to data-no-transform entities.

Behavior matrix (with a data-no-transform entity selected)

  • Current mode (e.g. translate) keeps its highlight, rendered dimmed; no gizmo attaches.
  • Clicking rotate still switches mode (also dimmed, still no gizmo on that entity).
  • Hand stays fully enabled and un-dimmed; clicking it engages hand mode normally.
  • Selecting any transformable entity restores full styling and the gizmo attaches per the active mode.

Manual test

Click a street-spawned car twice (first click selects the lane, second the car — an autocreated data-no-transform clone). Production: the hand button lights as if the hand tool were engaged and translate/rotate go dead-disabled. This branch: the toolbar keeps showing the user's chosen mode (dimmed), all mode switches still work, and selecting any movable object restores normal styling and the gizmo.

Testing

  • npm run test:modern — 756 passing; npm run test:core — 189 passing
  • eslint / prettier clean on changed files

🤖 Generated with Claude Code

https://claude.ai/code/session_019wjM3aCMUpQ4d78XihJtgw

claude added 2 commits August 1, 2026 13:51
Three interlocking editor selection/gizmo state fixes:

- viewport: remove the stale inspector.cursor.isPlaying read in the
  transformmodechange handler. When the mode change came from a keyboard
  shortcut, this handler ran before the ActionBar listener that re-emits
  showcursor, so the cursor still read as paused and the transform gizmo
  silently failed to attach — leaving the toolbar showing translate/rotate
  with no gizmo.

- inspector: re-emit objectselect when re-selecting the already-selected
  entity. select() dedupes on the same object3D, so once a selection got
  into a gizmo-less state, clicking the same entity could never repair it;
  only selecting a different object (or reloading) recovered. Reselect now
  rebuilds the selection box and transform-controls state.

- shortcuts: emit showcursor before transformmodechange for t/e/l (and
  their legacy w/s aliases), matching the ActionBar button path so no
  mode-change listener can observe a paused cursor.

- ActionBar: only light the hand-tool button when the hand tool is
  actually engaged. Selecting a data-no-transform entity (e.g. an
  autocreated clone from street-generated-clones) also painted the hand
  button active, which reads as the editor being wedged in a phantom
  "hand" state with no transform gizmo and no visible way out.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019wjM3aCMUpQ4d78XihJtgw
Core fix for the stale-canvas-state class of #1898, refocusing on the
selection box painted in the viewport:

- OrientedBoxHelper: union the cached _batchLocalBbox of EVERY descendant,
  not just the tracked root. Batching strips member mesh trees and stashes
  a per-member local AABB, but the helper only consulted the root's own
  cache — so containers of batched members (a managed street, a buildings
  container) sized their box from whatever unstripped geometry remained.
  Late repacking strips more meshes as a session goes on, so the same
  selection could compute a shrinking — eventually empty — box an hour in.

- OrientedBoxHelper: when the computed box is empty, collapse the vertex
  buffer to a degenerate point instead of returning early. The early
  return left the PREVIOUS selection's box vertices in the geometry while
  the helper was repositioned to the new object's transform and shown —
  painting a wrong-size, wrong-place selection box.

- viewport objectselect: the deferred model-loaded selection-box paint now
  checks the entity is still the current selection before drawing.

- raycaster: emit 'raycastermouseleave' when the raycaster is disabled
  (hand tool, viewer mode). The hover box was only cleared from the
  polling wrapper, which stops on disable, freezing the last hover
  highlight on screen.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019wjM3aCMUpQ4d78XihJtgw
@kfarr kfarr changed the title Fix stale/incorrect transform controls requiring page reload (#1898) Fix stale selection box painting in 3D canvas + decouple action toolbar from selection (#1898) Aug 1, 2026
claude added 2 commits August 1, 2026 14:51
Mode is tool state, not per-object state. Selecting a data-no-transform
entity previously disabled the translate/rotate buttons outright, locking
the user out of switching modes until they selected something else. The
buttons now stay clickable and keep showing the current mode's active
highlight; they render dimmed (new .inapplicable style) while the current
selection can't be transformed. The gizmo layer independently refuses to
attach to no-transform entities, so allowing the mode switch is safe.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019wjM3aCMUpQ4d78XihJtgw
…coupling (#1898)

Re-review of the original report showed the perceived selection-box
misalignment was not a defect: the box correctly represented the bounds of
the selected object's hidden layers (ground/buildings), so it only
appeared wrong. The speculative fixes to OrientedBoxHelper, the raycaster
hover clearing, the shortcut showcursor ordering, and the reselect
re-emit are reverted since they cannot be verified against a real error.

What remains is the confirmed pareto-superior toolbar behavior: selection
never changes the action bar state. The hand button lights only when the
hand tool is engaged, and translate/rotate stay clickable — dimmed, not
disabled — when the selected entity carries data-no-transform.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019wjM3aCMUpQ4d78XihJtgw
@kfarr kfarr changed the title Fix stale selection box painting in 3D canvas + decouple action toolbar from selection (#1898) Decouple action toolbar state from entity selection (#1898) Aug 1, 2026
@kfarr
kfarr marked this pull request as ready for review August 1, 2026 16:30
@kfarr
kfarr merged commit 88b7251 into main Aug 1, 2026
2 checks passed
@kfarr
kfarr deleted the claude/editor-transform-stale-state-9f0j1b branch August 1, 2026 16:30
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.

2 participants