Skip to content

add base plugin with coordinate system tool - #1053

Open
Devin T. Currie (DTCurrie) wants to merge 5 commits into
mainfrom
gizmos/0-add-base-plugin
Open

add base plugin with coordinate system tool#1053
Devin T. Currie (DTCurrie) wants to merge 5 commits into
mainfrom
gizmos/0-add-base-plugin

Conversation

@DTCurrie

@DTCurrie Devin T. Currie (DTCurrie) commented Sep 4, 2026

Copy link
Copy Markdown
Member

Adds the Gizmos plugin: a dashboard tool picker for placing editable scene aids by clicking in the 3D view, with the coordinate-system tool as the first one. This is the base of a five-PR stack that revives #738 and #739 against the current plugin architecture.

Stack

  1. This PR: base plugin and coordinate system
  2. Reference geometry, plane, and arrow tools (add reference geometry, plane, and arrow gizmo tools #1054)
  3. Polyline and angle measures (add polyline and angle gizmos #1056)
  4. Opt-in persistence (allow persisting gizmos #1057)
  5. Docs (add gizmo plugin docs #1058)

Visualization

Core, because these are contribution points rather than plugin-local behavior:

  • traits.Gizmo marks a user-placed scene aid. It lives in core rather than the plugin because WorldTree's folder taxonomy is a static array there, and a folder keyed on a plugin-owned trait would invert the dependency.
  • treeFolders gains a Gizmos folder between drawn and imported-files, so placed gizmos group together instead of landing in Other.
  • HotkeyBinding gains an opt-in preventDefault, and KeyboardBindings applies it before dispatch for bindings whose when currently holds. A Space binding needs it so the page does not scroll, Backspace so the browser does not navigate back.
  • MeasurePoint moves from plugins/MeasureTool/ to components/, unchanged, so more than one plugin can use it as the placement cursor. Its x/y/z readout and MeasureTool's distance label now render in font-roboto-mono, the repo's convention for numeric text.

The plugin itself, under plugins/Gizmos/:

  • Gizmos.svelte mounts a dashboard DropdownPane holding the tool picker, claims interactionMode: 'gizmo' while a tool is armed, and disarms when another tool takes the mode away. The picker's shapes button opens the tool menu directly rather than arming the first tool, and a separate exit button appears beside it only while a tool is armed, so each control keeps one job. The interaction-mode claim is released on unmount too, not only on disarm, and only when this effect still owns it, so unmounting mid-tool never clobbers a mode another plugin has since taken.
  • DropdownPane gains an icon prop, which the picker uses for its shapes glyph, and a class prop for the trigger, both defaulting to today's chevron and rounding so MeasureTool and TransformDashboard are untouched.
  • useGizmos publishes the armed mode, the per-tool options, and exit().
  • spawn.ts owns the trait set every gizmo carries, so a placed gizmo and a restored one cannot drift.
  • cursor.ts and matrix.ts are pure helpers for resolving a usable raycast hit and composing placement transforms. arrowMatrix carries the arrow's direction on the local +Z axis, which is the axis BatchedArrows reads back through the orientation vector, and its spec decomposes each matrix the way the renderer does.
  • GizmoDetails contributes an editable pose section through useDetailsSection, gated on traits.Gizmo, so it appears in whichever mode's details card is showing.

Why?

Why does the plugin register no environment mode?

EnvironmentMode is a closed union of monitor, build, and move, and a plugin can only declare an existing mode reachable. Gizmos are viewing aids as much as authoring aids, so the plugin contributes no mode and works in all three. Editing works everywhere because every mode's details panel renders contributed sections for any selected entity.

Why does GizmoMenu take gizmos as a prop instead of calling useGizmos()?

The menu is rendered through DashboardPortal, which uses threlte's Portal to re-parent the component tree into the dashboard. A child there cannot read context the plugin provided, so useGizmos() returns undefined at runtime. Anything teleported into a portal has to take what it needs as props.

This is worth stating precisely because the first diagnosis was wrong. The tweakpane Pane also sat in the stack trace and took the blame, and removing it changed nothing. The tell is that a component reading the context during render throws and the popover opens empty, while one that only reads it in a click handler renders fine and fails on click.

Why is the tool picker the dashboard button rather than a chevron beside one?

MeasureTool puts a mode toggle next to a settings pane, which suits one tool with options. With six tools, choosing one is the primary action, so the picker owns the button and exiting is a separate control shown only while a tool is armed. Each control keeps one job, which also avoids layering popover semantics onto a button that already announces role="radio".

Testing

Ran pnpm exec svelte-check --tsconfig ./tsconfig.json and pnpm exec vitest --run. Added specs for the ported pure helpers (cursor, matrix, spawn), the preventDefault dispatch path in KeyboardBindings, the details-section trait gate in both directions, the plugin shell's interaction-mode handling including an external takeover and release on unmount, and DropdownPane's icon/class props. Opened the app and armed a tool end to end. That last step matters: every unit test passes with the context broken, because specs mount the menu directly rather than through the portal, and checking only that the menu renders is not enough either.

@changeset-bot

changeset-bot Bot commented Sep 4, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b1c4238

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@viamrobotics/visualization Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://viamrobotics.github.io/visualization/pr-preview/pr-1053/

Built to branch gh-pages at 2026-09-10 21:37 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

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