Interactive Elements
Use interactive: true when a scene should react to pointer hover and click,
for example showing a tooltip on hover and zooming the camera in on click.
Runtime API
import { mountScene } from '@sebastianwessel/isostate';
import sceneBundle from './scene.isostate.js';
const target = document.querySelector<HTMLElement>('#scene');
if (!target) throw new Error('Missing scene target');
const tooltip = document.querySelector<HTMLElement>('#tooltip');
if (!tooltip) throw new Error('Missing tooltip target');
const mounted = mountScene(target, sceneBundle, {
label: 'Deployment scene',
interactive: true,
controller: {
transitionDuration: 500,
transitionEasing: 'ease-out'
}
});
mounted.on('element-enter', (event) => {
tooltip.textContent = event.id;
tooltip.style.display = 'block';
});
mounted.on('element-leave', () => {
tooltip.style.display = 'none';
});
mounted.on('element-click', (event) => {
mounted.controller?.zoomToElement(event.id, { padding: 48 });
});
element-enter/element-leave fire once per element group crossing, so a
tooltip driven this way does not flicker while the pointer moves between child
nodes of the same element. element-click combined with
controller.zoomToElement() gives click-to-zoom navigation without any
per-element listeners: mountScene() attaches exactly three delegated
listeners (click, pointerover, pointerout) to the root SVG.
Hover Styling
The runtime toggles the iso-hover class on the hovered element group and
scopes cursor: pointer to interactive scenes automatically. Add custom hover
styling with a CSS rule targeting the same class:
.iso-interactive g[data-id].iso-hover {
filter: brightness(1.1);
}
Notes
interactivedefaults tofalse. Without it,mounted.on()still registers listeners but they never fire, and the SVG never gains theiso-interactiveclass.- Floor, connectors,
<defs>, and the diagnostics overlay never produce events. An element whose current presence isremovednever produces events either. mounted.on()throwsMOUNT_DESTROYEDif called aftermounted.destroy(). Unsubscribe with the functionon()returns instead of leaking closures past destroy.