Canvases
A canvas is a picture you move around: a scene, a cloud of points, a network. Seven of TJ's apps have one in 3D, and in all of them you move it the same way.
The seven 3D views
Plane Displacement, AI Research's Lead 3D, Semantic Cartographer, the DDO demos' UMAP themes and permutohedron, GraphWise and Relatio. Each draws with three.js, the app's own library, which also does the moving. v2 doesn't move anything: it frames the view and sets the rules below, so the seven feel like one family.
TJ set the rules on October 30, 2026 (issue #46), after comparing the views side by side: what each already did well, and what none of them did yet.
The rules
- The app's library moves the view; v2 frames it. No v2 script turns or zooms anything.
- Up stays up. However far you turn, the view never rolls over: three.js's orbit camera, in every app. GraphWise and Relatio switch to it with one setting.
- The mouse: drag to rotate, right-drag (or Shift and drag) to pan, the wheel to zoom.
- The keys, once you Tab to the view: the arrow keys rotate, Shift and the arrow keys pan, Page Up and Page Down zoom. They work only while the view has the focus ring, so they never steal a key from the rest of the page.
- A screen reader hears what the view shows, then "Use the mouse or the arrow keys to move.", the way Google's model-viewer says it.
- One row along the bottom of the view: the help button at the left, the buttons at the right. The buttons come in one order, each only where it applies: Show axes or Hide axes, Stop orbit or Start orbit, Reset view, Full screen. Each says what a click will do. On an exhibit screen the row stays off the picture: a guest's comes back when it's reached for, and a kiosk or a wall draws none at all (Contexts › Exhibit). An art app's own Full screen, such as Plane Displacement's, is a guest screen. (TJ, October 31: "i dont like the controls being over the 'art' during 'exhibit'.")
- Help waits until it's wanted. A line of small instructions on the picture is either too faint to read or too loud to ignore, so the help is a button instead: the rotate-3d icon, named "How to move". Rest the pointer on it, Tab to it, or click or tap it, and a panel says how: Rotate, drag or the arrow keys; Pan, right-drag or Shift and the arrows; Zoom, scroll or Page Up and Page Down; Select, click a point (only where a point can be picked). The panel stays while the pointer is on it, Escape closes it, and it opens by itself once, on someone's first visit, until their first drag, scroll or key press. It takes the view's colors, dark over a dark view and light over a light one (a view that draws a dark picture on a light page says so with
data-ds-scene="dark"), a touch see-through with an opaque edge, and goes solid for anyone who has asked their computer for less transparency. (TJ changed this rule on October 30, from an always-visible hint line.) - Anything that moves on its own can be stopped: an orbit, dots flowing along links, a sliding pattern, each by a button that names it: Stop orbit, Stop flow, Stop animation. And it doesn't start by itself for anyone whose computer asks for less motion.
- Reset view takes the camera back to where it started and stops a running orbit.
- Click a point and its details show beside the view. A list, a table or a flat view of the same things stays wherever an app has one.
Try it
Twenty-four words in four groups. Drag it, scroll on it, or Tab to it and use the arrow keys. Click a word to see it beside the view. The guide draws this with a few lines of its own; an app would use three.js.
The markup, the rules and the roles are in Components › The frame › 3D view.
In an app
- The camera: three.js's OrbitControls, as they come. In react-force-graph-3d, add
controlType="orbit". - The keys: a keydown listener on the canvas, not on the window, that turns, pans and zooms the camera the way the mouse does. Give the canvas
tabindex="0",role="img", the label andaria-describedbynaming the "How to move" panel. - The help: the rotate-3d icon (Lucide's, at a 1.6 px line), on a button named "How to move", with a panel that opens on hover, focus and a click or tap, closes on Escape, and opens by itself once on a first visit. On v2, that is
.ds-view-helpandv2/view-help.js. - Motion: start an orbit or flowing dots only when
matchMedia('(prefers-reduced-motion: reduce)')doesn't match, and give it a Stop button in the row. - In a workbench's pane, add
ds-view--fill, so the drawing takes all the room the row leaves. - On an exhibit screen, load
/v2/exhibit.jsfirst in the<head>, readwindow.dsExhibit, and answerds-exhibit-resetby going back to the start. Forinteraction=noneturn the camera's input off; fororbit-no-panturn its pan off (in three.js,controls.enablePan = false).