From 71295f1c10568757f86095ad126ef2f5b2b0546f Mon Sep 17 00:00:00 2001 From: Devin C Date: Mon, 1 Jun 2026 16:59:09 -0400 Subject: [PATCH 1/7] Add docs page for the Gizmos plugin Documents the dashboard tool added in the previous PR: how to mount ``, the available gizmo modes, the public `useGizmos` hook, and the `gizmoTraits` namespace for queries against placed gizmos. Sidebar entry alphabetized between DrawService and SelectionTool. --- docs/astro.config.mjs | 1 + docs/src/content/docs/plugins/gizmos.mdx | 89 ++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 docs/src/content/docs/plugins/gizmos.mdx diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index 47eb3e9e3..23afc8b69 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -44,6 +44,7 @@ export default defineConfig({ items: [ { label: '', link: '/plugins/debug/' }, { label: '', link: '/plugins/draw-service/' }, + { label: '', link: '/plugins/gizmos/' }, { label: '', link: '/plugins/selection/' }, { label: '', link: '/plugins/skybox/' }, ], diff --git a/docs/src/content/docs/plugins/gizmos.mdx b/docs/src/content/docs/plugins/gizmos.mdx new file mode 100644 index 000000000..298f76517 --- /dev/null +++ b/docs/src/content/docs/plugins/gizmos.mdx @@ -0,0 +1,89 @@ +--- +title: +description: Add a toolset for placing editable reference geometry, lines, arrows, and normals inside a motion-tools visualizer. +--- + +`` adds a "Gizmos" dashboard toggle with a popover of tools for placing editable scene aids: a coordinate system, reference planes, reference geometries (box / sphere / capsule), polylines with optional measurement, arrows, and vertex or surface normals. + +Each tool places a Koota entity in the world, selects it, and renders a custom Details panel for editing its parameters in place. Switching the visualizer's interaction mode back to `navigate`, `measure`, or `select` exits gizmo mode automatically. + +## Usage + +```svelte + + +
+ + + +
+``` + +A new toggle appears in the top dashboard with the `shapes` icon. Clicking it opens a popover that lets you pick which gizmo to place; selecting one switches the visualizer into `'gizmo'` interaction mode and arms the chosen tool. Click in the scene to place the gizmo. The placed entity is auto-selected so its Details panel opens for further editing. + +`` takes no props. + +## Available gizmos + +| Gizmo | Mode key | Behavior | +| ------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------- | +| Coordinate system | `coordinate-system` | Place a labeled XYZ triad at a clicked surface point. | +| Reference plane | `reference-plane` | Place a `yz` / `xz` / `xy` plane either at a clicked point ("free") or at a numeric offset from world origin. | +| Reference geometry | `reference-geometry` | Drop a `box`, `sphere`, or `capsule` (solid or wireframe) at world origin or at a clicked point. | +| Polyline | `polyline` | Click to build a multi-segment line in world or screen space. Optional segment / total measurement labels. | +| Arrow | `arrow` | Place an arrow oriented to a chosen world axis or to the clicked surface normal. | +| Vertex normals | `vertex-normals` | Render the per-vertex normals of a clicked mesh. | +| Surface normals | `surface-normals` | Render the per-face normals of a clicked surface. | + +## Reading and driving plugin state + +Use `useGizmos` to read or mutate the plugin's state from anywhere inside ``. The hook is reactive (Svelte 5 runes), so reading its properties subscribes to changes: + +```svelte + + +

Active gizmo: {gizmos.mode}

+ +``` + +Mutable properties (read/write): + +| Property | Type | Description | +| ---------------------- | ----------------------------------- | ------------------------------------------------------ | +| `mode` | `GizmoMode` | Active tool (`'idle'` when no tool is armed). | +| `planeAxis` | `'yz' \| 'xz' \| 'xy'` | Axis-aligned plane for the reference-plane tool. | +| `planeConstruction` | `'free' \| 'offset'` | Placement strategy for the reference-plane tool. | +| `planeOffset` | `number` | Offset (mm) from world origin in `'offset'` mode. | +| `geometryShape` | `'box' \| 'sphere' \| 'capsule'` | Shape used by the reference-geometry tool. | +| `geometryConstruction` | `'at-origin' \| 'free'` | Placement strategy for reference geometries. | +| `isGeometryWireframe` | `boolean` | Render reference geometries as wireframe instead of solid. | +| `lineSpace` | `'world' \| 'screen'` | Coordinate space used by the polyline tool. | +| `lineMeasure` | `'none' \| 'segment' \| 'total'` | Measurement labels rendered on polylines. | +| `arrowAxis` | `'x' \| 'y' \| 'z' \| 'surface'` | Direction the arrow tool orients to. | +| `vertexNormalsLength` | `number` | Length (mm) of vertex-normals lines. | +| `surfaceNormalsLength` | `number` | Length (mm) of surface-normals lines. | + +Read-only: + +| Property | Description | +| ------------------- | -------------------------------------------------------------------------- | +| `planeAxisVector` | Cloned `THREE.Vector3` normal for the current `planeAxis`. | +| `geometryTrait` | Pre-configured size trait for the current `geometryShape`. | +| `exit()` | Switch the visualizer back to `'navigate'` and set `mode` to `'idle'`. | + +## Traits + +For lower-level access (e.g. iterating placed gizmos in your own queries), the plugin exports its Koota traits under the `gizmoTraits` namespace: + +```ts +import { gizmoTraits } from '@viamrobotics/motion-tools/plugins' +``` + +Every placed entity carries the generic `Gizmo` marker (with `PendingGizmo` added while the user is still placing it). Specific gizmos additionally carry a typed trait: `ReferencePlane`, `GizmoArrow`, `VertexNormals`, `SurfaceNormals`, or `PolylineMeasure`. Filter on these from your own queries to scope behavior to user-placed gizmos vs. robot frames. From c1dc3e9fcec20d093eb0d8ca96f02f87b98f3dd4 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Tue, 2 Jun 2026 14:12:06 +0000 Subject: [PATCH 2/7] docs: move exit() from Read-only table to Methods section Co-authored-by: Devin T. Currie --- docs/src/content/docs/plugins/gizmos.mdx | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/docs/src/content/docs/plugins/gizmos.mdx b/docs/src/content/docs/plugins/gizmos.mdx index 298f76517..84a2f664d 100644 --- a/docs/src/content/docs/plugins/gizmos.mdx +++ b/docs/src/content/docs/plugins/gizmos.mdx @@ -72,11 +72,16 @@ Mutable properties (read/write): Read-only: -| Property | Description | -| ------------------- | -------------------------------------------------------------------------- | -| `planeAxisVector` | Cloned `THREE.Vector3` normal for the current `planeAxis`. | -| `geometryTrait` | Pre-configured size trait for the current `geometryShape`. | -| `exit()` | Switch the visualizer back to `'navigate'` and set `mode` to `'idle'`. | +| Property | Description | +| ----------------- | -------------------------------------------------------------- | +| `planeAxisVector` | Cloned `THREE.Vector3` normal for the current `planeAxis`. | +| `geometryTrait` | Pre-configured size trait for the current `geometryShape`. | + +Methods: + +| Method | Description | +| --------- | ------------------------------------------------------------------------------ | +| `exit()` | Switch the visualizer back to `'navigate'` and set `mode` to `'idle'`. | ## Traits From d66e179332e58f474f209d7db167cc3c28c1a83e Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Tue, 2 Jun 2026 18:29:43 +0000 Subject: [PATCH 3/7] docs(gizmos): add Aside note for coordinate system and reference geometry traits Co-authored-by: Devin T. Currie --- docs/src/content/docs/plugins/gizmos.mdx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/src/content/docs/plugins/gizmos.mdx b/docs/src/content/docs/plugins/gizmos.mdx index 84a2f664d..b75d99060 100644 --- a/docs/src/content/docs/plugins/gizmos.mdx +++ b/docs/src/content/docs/plugins/gizmos.mdx @@ -3,6 +3,8 @@ title: description: Add a toolset for placing editable reference geometry, lines, arrows, and normals inside a motion-tools visualizer. --- +import { Aside } from '@astrojs/starlight/components' + `` adds a "Gizmos" dashboard toggle with a popover of tools for placing editable scene aids: a coordinate system, reference planes, reference geometries (box / sphere / capsule), polylines with optional measurement, arrows, and vertex or surface normals. Each tool places a Koota entity in the world, selects it, and renders a custom Details panel for editing its parameters in place. Switching the visualizer's interaction mode back to `navigate`, `measure`, or `select` exits gizmo mode automatically. @@ -92,3 +94,10 @@ import { gizmoTraits } from '@viamrobotics/motion-tools/plugins' ``` Every placed entity carries the generic `Gizmo` marker (with `PendingGizmo` added while the user is still placing it). Specific gizmos additionally carry a typed trait: `ReferencePlane`, `GizmoArrow`, `VertexNormals`, `SurfaceNormals`, or `PolylineMeasure`. Filter on these from your own queries to scope behavior to user-placed gizmos vs. robot frames. + + From b564fb57b4dd96aa2320681ae929e9570bd97f15 Mon Sep 17 00:00:00 2001 From: Devin C Date: Tue, 2 Jun 2026 14:35:06 -0400 Subject: [PATCH 4/7] format --- docs/src/content/docs/plugins/gizmos.mdx | 65 ++++++++++++------------ 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/docs/src/content/docs/plugins/gizmos.mdx b/docs/src/content/docs/plugins/gizmos.mdx index b75d99060..1099d9ada 100644 --- a/docs/src/content/docs/plugins/gizmos.mdx +++ b/docs/src/content/docs/plugins/gizmos.mdx @@ -30,15 +30,15 @@ A new toggle appears in the top dashboard with the `shapes` icon. Clicking it op ## Available gizmos -| Gizmo | Mode key | Behavior | -| ------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------- | -| Coordinate system | `coordinate-system` | Place a labeled XYZ triad at a clicked surface point. | -| Reference plane | `reference-plane` | Place a `yz` / `xz` / `xy` plane either at a clicked point ("free") or at a numeric offset from world origin. | -| Reference geometry | `reference-geometry` | Drop a `box`, `sphere`, or `capsule` (solid or wireframe) at world origin or at a clicked point. | -| Polyline | `polyline` | Click to build a multi-segment line in world or screen space. Optional segment / total measurement labels. | -| Arrow | `arrow` | Place an arrow oriented to a chosen world axis or to the clicked surface normal. | -| Vertex normals | `vertex-normals` | Render the per-vertex normals of a clicked mesh. | -| Surface normals | `surface-normals` | Render the per-face normals of a clicked surface. | +| Gizmo | Mode key | Behavior | +| ------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------- | +| Coordinate system | `coordinate-system` | Place a labeled XYZ triad at a clicked surface point. | +| Reference plane | `reference-plane` | Place a `yz` / `xz` / `xy` plane either at a clicked point ("free") or at a numeric offset from world origin. | +| Reference geometry | `reference-geometry` | Drop a `box`, `sphere`, or `capsule` (solid or wireframe) at world origin or at a clicked point. | +| Polyline | `polyline` | Click to build a multi-segment line in world or screen space. Optional segment / total measurement labels. | +| Arrow | `arrow` | Place an arrow oriented to a chosen world axis or to the clicked surface normal. | +| Vertex normals | `vertex-normals` | Render the per-vertex normals of a clicked mesh. | +| Surface normals | `surface-normals` | Render the per-face normals of a clicked surface. | ## Reading and driving plugin state @@ -57,33 +57,33 @@ Use `useGizmos` to read or mutate the plugin's state from anywhere inside ` **Coordinate system** and **reference geometry** gizmos have no dedicated `gizmoTraits` entry. To scope a query to those types specifically, combine the generic `Gizmo` marker with traits from the main `traits` module: - - **Coordinate system** — `Gizmo` + `traits.ReferenceFrame` (also carries `traits.ShowAxesHelper`) - - **Reference geometry** — `Gizmo` + `traits.Box`, `traits.Sphere`, or `traits.Capsule` + - **Coordinate system** — `Gizmo` + `traits.ReferenceFrame` (also carries `traits.ShowAxesHelper`) + - **Reference geometry** — `Gizmo` + `traits.Box`, `traits.Sphere`, or `traits.Capsule` + From 2d25161969e24b0cbc30dd18db180508fbbf874e Mon Sep 17 00:00:00 2001 From: Devin C Date: Tue, 2 Jun 2026 17:12:14 -0400 Subject: [PATCH 5/7] usage docs --- docs/src/content/docs/plugins/gizmos.mdx | 57 ++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/docs/src/content/docs/plugins/gizmos.mdx b/docs/src/content/docs/plugins/gizmos.mdx index 1099d9ada..f8610af38 100644 --- a/docs/src/content/docs/plugins/gizmos.mdx +++ b/docs/src/content/docs/plugins/gizmos.mdx @@ -40,6 +40,63 @@ A new toggle appears in the top dashboard with the `shapes` icon. Clicking it op | Vertex normals | `vertex-normals` | Render the per-vertex normals of a clicked mesh. | | Surface normals | `surface-normals` | Render the per-face normals of a clicked surface. | +## Tool reference + +Each tool lives behind an entry in the Gizmos dashboard popover. Picking a tool puts the visualizer into `'gizmo'` interaction mode and arms the placement gesture described below. After placement, the new entity is auto-selected and its Details panel renders the relevant editors (pose, color, geometry, line, opacity, axes helper) for the gizmo kind. + +### Coordinate system + +Click **Place coordinate system** in the popover, then click any surface to drop a labeled XYZ triad at the picked point. The placed entity carries `ShowAxesHelper` from the start. The Details panel exposes pose and parent only (no opacity, no axes-helper toggle, since the gizmo is itself an axes helper). + +### Reference plane + +Open the **Reference plane** folder. Pick an axis (`YZ`, `XZ`, `XY`) and a placement mode: + +- **Free (click to place)**: clicking **Place reference plane** arms a single-click gesture. Click anywhere in the scene to drop the plane at that point with the chosen normal. +- **Offset from coordinate plane**: drag the offset slider (in mm) to position the plane along its normal from world origin, then click **Place reference plane** to commit. + +Details for the placed plane: pose, opacity, color. + +### Reference geometry + +Open the **Reference geometry** folder. Pick a shape (`Box`, `Sphere`, `Capsule`), a placement mode (**At origin** or **Free (click to place)**), and toggle **Solid** / **Wireframe**: + +- **At origin** drops the geometry at world origin immediately on **Place reference geometry**. +- **Free** arms a single-click gesture; click a surface to drop it there. + +Details: pose, geometry size (per shape), opacity, axes helper toggle, color. + +### Polyline + +Open the **Polyline** folder. Pick a coordinate space (`World` / `Screen`) and a measurement mode (`Off` / `Per segment` / `Total length`). Click **Place polyline** to arm the tool. + +Each click adds a vertex. A floating confirm panel follows the cursor with these hotkeys: + +- `⌫` undo the last vertex +- `esc` cancel and discard +- `space` commit the current polyline and start a new one +- `↵` confirm and exit + +Details: pose, opacity, color. + +### Arrow + +Open the **Arrow** folder. Pick the orientation source: `Surface normal` (aligns with the clicked face's outward normal), or one of `X`, `Y`, `Z` (world axes). Click **Place arrow** to arm the tool, then click a surface to drop the arrow. + +Details: pose, opacity, axes helper toggle, color. + +### Vertex normals + +Open the **Vertex normals** folder. Adjust the length slider (in mm) for the helper lines, then click **Place vertex normals** to arm the tool. Click a mesh to attach a helper that renders one outward segment per vertex of the clicked surface. + +Details: helper length, opacity, color. + +### Surface normals + +Same flow as Vertex normals but the helper renders one segment per triangle face instead of per vertex. Open **Surface normals**, set length, click **Place surface normals**, then click a surface. + +Details: helper length, opacity, color. + ## Reading and driving plugin state Use `useGizmos` to read or mutate the plugin's state from anywhere inside ``. The hook is reactive (Svelte 5 runes), so reading its properties subscribes to changes: From a12178135c4289f95d06218d1e2daad2d026ae44 Mon Sep 17 00:00:00 2001 From: "Devin T. Currie" Date: Wed, 3 Jun 2026 10:08:43 -0400 Subject: [PATCH 6/7] Apply suggestions from code review Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> --- docs/src/content/docs/plugins/gizmos.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/src/content/docs/plugins/gizmos.mdx b/docs/src/content/docs/plugins/gizmos.mdx index f8610af38..ddf101453 100644 --- a/docs/src/content/docs/plugins/gizmos.mdx +++ b/docs/src/content/docs/plugins/gizmos.mdx @@ -50,7 +50,7 @@ Click **Place coordinate system** in the popover, then click any surface to drop ### Reference plane -Open the **Reference plane** folder. Pick an axis (`YZ`, `XZ`, `XY`) and a placement mode: +Open the **Reference plane** folder. Pick a placement mode (**Free (click to place)** or **Offset from coordinate plane**) and a normal axis (`YZ`, `XZ`, `XY`): - **Free (click to place)**: clicking **Place reference plane** arms a single-click gesture. Click anywhere in the scene to drop the plane at that point with the chosen normal. - **Offset from coordinate plane**: drag the offset slider (in mm) to position the plane along its normal from world origin, then click **Place reference plane** to commit. @@ -59,7 +59,7 @@ Details for the placed plane: pose, opacity, color. ### Reference geometry -Open the **Reference geometry** folder. Pick a shape (`Box`, `Sphere`, `Capsule`), a placement mode (**At origin** or **Free (click to place)**), and toggle **Solid** / **Wireframe**: +Open the **Reference geometry** folder. Pick a placement mode (**At origin** or **Free (click to place)**), a shape (`Box`, `Sphere`, `Capsule`), and toggle **Solid** / **Wireframe**: - **At origin** drops the geometry at world origin immediately on **Place reference geometry**. - **Free** arms a single-click gesture; click a surface to drop it there. From d9faeafb95db4f585ecc9412a93023a8aff768df Mon Sep 17 00:00:00 2001 From: Devin C Date: Wed, 3 Jun 2026 12:59:22 -0400 Subject: [PATCH 7/7] use tag --- src/lib/components/overlay/Details.svelte | 9 ++++----- src/lib/ecs/traits.ts | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/lib/components/overlay/Details.svelte b/src/lib/components/overlay/Details.svelte index 208debbe0..5c95f5886 100644 --- a/src/lib/components/overlay/Details.svelte +++ b/src/lib/components/overlay/Details.svelte @@ -41,7 +41,7 @@ import AddRelationship from '$lib/components/overlay/AddRelationship.svelte' import AxesHelperDetails from '$lib/components/overlay/details/AxesHelperDetails.svelte' import OpacityDetails from '$lib/components/overlay/details/OpacityDetails.svelte' - import { hierarchy, relations, traits, useParentName, useTrait, useWorld } from '$lib/ecs' + import { hierarchy, relations, traits, useParentName, useTag, useTrait, useWorld } from '$lib/ecs' import { FrameConfigUpdater } from '$lib/FrameConfigUpdater.svelte' import { useConfigFrames } from '$lib/hooks/useConfigFrames.svelte' import { useCameraControls } from '$lib/hooks/useControls.svelte' @@ -87,8 +87,7 @@ const arrows = useTrait(() => entity, traits.Arrows) const framesAPI = useTrait(() => entity, traits.FramesAPI) const geometriesAPI = useTrait(() => entity, traits.GeometriesAPI) - const customDetails = useTrait(() => entity, traits.CustomDetails) - const hasCustomDetails = $derived(customDetails.current === true) + const customDetails = useTag(() => entity, traits.CustomDetails) const localPose = $derived.by(() => { const source = editedMatrix.current ?? matrix.current @@ -461,7 +460,7 @@

Details

- {#if !hasCustomDetails} + {#if !customDetails.current}
world position (mm) @@ -749,7 +748,7 @@ - {#if !hasCustomDetails} + {#if !customDetails.current} {/if} diff --git a/src/lib/ecs/traits.ts b/src/lib/ecs/traits.ts index d48983c53..66a6790bc 100644 --- a/src/lib/ecs/traits.ts +++ b/src/lib/ecs/traits.ts @@ -81,7 +81,7 @@ export const Invisible = trait(() => true) * `details-extensions` portal target (e.g. gizmo plugin entities) opt in by * adding this trait. */ -export const CustomDetails = trait(() => true) +export const CustomDetails = trait() /** * True when the entity itself, or any of its parents up the `ChildOf`