Skip to content

Say which node a click selects, before and after the click - #122

Merged
kmatzen merged 1 commit into
mainfrom
worktree-selection-ux
Aug 3, 2026
Merged

Say which node a click selects, before and after the click#122
kmatzen merged 1 commit into
mainfrom
worktree-selection-ux

Conversation

@kmatzen

@kmatzen kmatzen commented Aug 3, 2026

Copy link
Copy Markdown
Owner

The problem

Selecting geometry was legible only to whoever wrote the picker. A click resolved to a leaf primitive somewhere deep in the tree, and the sole visible result was a row highlighting in a side panel — which on a narrow window or on mobile is not on screen at all. The model itself looked identical before and after. So "what did I just select, and why that?" had no answer in the viewport, and clicking was a guess you checked afterwards.

What changed

Hover preview — the node under the pointer is outlined and named before you commit to a click. Throttled to 50ms, skipped mid-drag, and it will not force a frame to answer: a stale preview beats a full sphere-march per pointer move. Clicks still force a frame, because a wrong selection is worse than a hitch.

Selection is visible in the 3D view — the bounding box used to belong to DimensionLabels and was gated on the Dimensions toggle, which is off by default. A new SelectionOverlay owns every wireframe in the scene and draws the selection in the accent colour whether or not dimensions are showing.

A breadcrumb naming the chain — clicking the flat face left by a subtract selects the cylinder that cut it. That is correct, and reads as arbitrary until something says Subtract › Move › Cylinder. Crumbs are clickable, which is also the only way to reach an ancestor, since picking can only ever land on a leaf. Alt+Click does the same one level up. Deep chains collapse to root + + last three.

Tree and viewport hover are the same state — pointing at a surface lights up its row, and pointing at a row lights up its geometry.

One real bug fixed

mesh was missing from the picker's leaf set, so a click on an imported STL matched no branch, fell through to the childless tail, and returned null — which the viewport reads as "the click missed the model". Clicking an imported mesh cleared the selection. That is the one node kind you cannot drag in from the palette, and so the one you most need to be able to find by clicking it.

Verification

  • tsc --noEmit clean
  • 19 new unit tests (sdfPicking, SelectionBreadcrumb, viewportStore)
  • 13/13 in viewport-frames.spec.ts against real WebGL, including 3 new ones covering hover preview, the breadcrumb, and alt-click
  • Golden image suite unchanged (setTree clears the selection, so no box is drawn in those scenes)
  • Full unit suite: 521 passed. One failure, fitPrimitive.test.ts timing out at 60s — passes in isolation, and was contending with a separate vitest run in the main checkout. Pre-existing load flake the vitest config comments already describe; unrelated to this change.

Notes

A design bug surfaced during testing and is fixed here: hovering a breadcrumb crumb flipped the chip into preview mode, which disabled the very button the pointer was reaching for. Hover now records its source (viewport vs ui), and only a hover over geometry counts as "a click here would select this".

🤖 Generated with Claude Code

Selecting geometry was legible only to whoever wrote the picker. A click
resolved to a leaf primitive somewhere deep in the tree, and the sole
visible result was a row highlighting in a side panel — which on a narrow
window or on mobile is not on screen at all. The model itself looked
identical before and after. So "what did I just select, and why that?"
had no answer in the viewport, and clicking was a guess you checked
afterwards.

Four parts, all aimed at that one gap:

- Hover preview. The node under the pointer is outlined and named before
  you commit to a click. Throttled to 50ms, skipped mid-drag, and it will
  not force a frame to answer — a stale preview beats a full sphere-march
  per pointer move.

- Selection is visible in the 3D view. The bounding box used to belong to
  DimensionLabels and was gated on the Dimensions toggle, which is off by
  default; SelectionOverlay now owns every wireframe and draws the
  selection in the accent colour whether or not dimensions are showing.

- A breadcrumb naming the chain. Clicking the flat face left by a
  subtract selects the cylinder that cut it — correct, and arbitrary
  until something says `Subtract > Move > Cylinder`. Crumbs are
  clickable, which is also the only way to reach an ancestor, since
  picking can only ever land on a leaf. Alt-click does the same one level
  up.

- Tree and viewport hover are the same state, so pointing at a surface
  lights its row and pointing at a row lights its geometry.

One real bug fell out of it: `mesh` was missing from the picker's leaf
set, so a click on an imported STL matched no branch, returned null, and
was read as a miss — clicking an imported mesh *cleared* the selection.
That is the one node kind you cannot drag in from the palette, and so the
one you most need to find by clicking it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown

🚀 Preview deployed: https://worktree-selection-ux.sinter.pages.dev

(updates on every push to this PR)

@kmatzen
kmatzen marked this pull request as ready for review August 3, 2026 00:51
@kmatzen
kmatzen merged commit 91ea417 into main Aug 3, 2026
6 checks passed
@kmatzen
kmatzen deleted the worktree-selection-ux branch August 3, 2026 00:51
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