Skip to content

Plugin dependencies

Every plugin mounts independently inside <Visualizer />, and none requires another plugin to function. A few, though, rely on optional npm packages, a live machine connection, or coordinate with a sibling plugin at runtime. This page audits those relationships so you know what to install and mount together.

Most plugins need nothing beyond @viamrobotics/visualization. Several use optional peer dependencies — install them only when you use the plugin:

PluginInstall
<SelectionTool />earcut
<DrawService />@connectrpc/connect @connectrpc/connect-web
<Debug />@tanstack/svelte-query-devtools
<MoveFrame />@dimforge/rapier3d-compat @threlte/rapier
<Settings />@zag-js/tabs
<WorldTree />@zag-js/tree-view svelte-virtuallists
<XR />@threlte/xr

Two more build on packages that ship as required peers of @viamrobotics/visualization — already installed with it, and listed here only for completeness:

PluginRequired peers
<ControlWidgets />@viamrobotics/test-widgets, @viamrobotics/svelte-sdk
<XR />@viamrobotics/svelte-sdk

No plugin imports another as a hard requirement, but several pairs coordinate at runtime. Each is soft: the dependent plugin still works alone, just with reduced behavior.

PluginCoordinates withWhat happens
<ControlWidgets /><XR />Registry widget panels are hidden while an immersive XR session is active.
<DrawService /><Logs />Connection status and errors are written to the Logs panel. Without Logs, they’re dropped silently.
mode pluginseach otherButtons portal into the mode toggle in mount order, which is also fallback priority. Mount Monitor first.
<FramePov /><XR />POV panels hide while an immersive session owns the canvas.
any SettingsPortal user<Settings />The contributed tab is registered either way, but only renders when Settings is mounted.
ControlWidgets ──► XR         panels hide during an immersive session
DrawService ──► Logs          draw-server diagnostics, if Logs is mounted
Monitor ──► BuildFrames ──► MoveFrame   mount order is button order and priority
FramePov ──► XR               POV panels hide during an immersive session
SettingsPortal ──► Settings   contributed tabs need a popover to live in

The <ControlWidgets /> ──► <XR /> link only observes the session state XR publishes to useEnvironment().current.isImmersive, not the other plugin’s internals — which is what lets @threlte/xr stay an optional peer. Which cameras appear in a headset is chosen independently in the <XR /> plugin’s own AR settings panel.

Plugins are the visualizer’s own chrome, split out so an embedded viewer doesn’t inherit UI it has no use for: <Monitor />, <WorldTree />, <Settings />, <BuildFrames />, <FileDrop />, and <FramePov />. Mount all six — Monitor first, so it is the default mode — for the full standalone app; mount none for a bare scene with camera controls.

One of them reaches beyond the visualizer element: <FileDrop /> listens for drags on window, so it swallows drag-and-drop for the whole page. Keyboard shortcuts are dispatched by core but exist only when the feature contributing them is mounted, and inputBindingsEnabled={false} disables keyboard input wholesale.

Some plugins need more than a mounted <Visualizer />:

PluginAlso needs
<ControlWidgets />, <XR />, <FramePov />a live machine connection (resources resolved per part)
<BuildFrames />a partID and edit permissions on that part
<XR />a WebXR-capable device to enter a session
<Focus />an active selection — click an entity first
<DrawService />a running draw server (see its page)
<TopDownLock />orbit-style camera controls (the default); no effect under trackball controls
<FramePov />a POV panel opened from a frame’s details card