Docs
/

@leumas/body-viewer

The generic 3D body viewer — a React/r3f surface that renders ANY species' model manifest, with the layer system, the selection model, isolate/ghost/clip, camera presets and the closed visual-command...

@leumas/body-viewer

The generic 3D body surface. It takes a loaded body and a model manifest and draws whatever they describe — grep it for human, heart, skeletal or bone and you find none of them.

const Viewer = lazy(() => import('@leumas/body-viewer'));   // three + fiber + drei: ALWAYS lazy

const store = createViewerStore({ species: 'human', variant: 'adult-female' });
<BodyViewer body={body} manifest={body.manifests[body.variant.modelManifest]} store={store} />
<LayerPanel body={body} store={store} />

The two rules

1. A THREE.Mesh is never application truth. Selection, visibility, opacity and isolation are sets of canonical structure ids. The scene is a function of them. That is what makes the tree, the graph, the 3D and an agent's command interchangeable — all four read and write the same ids — and it is why a variant switch cannot leave a highlight pointing at geometry that is no longer the structure it names.

2. The command list is closed. applyCommand is a trust boundary: the command is generated by a model, relayed through a tool result, and executed in a browser. Anything outside VISUAL_ACTIONS is refused by name, no command in this package reads or writes anything but view state, and an id that does not exist in the body is reported rather than silently dropped.

Import it lazily

three, @react-three/fiber and @react-three/drei are peers, and both Leumas products' eager JS is budgeted at ~300 KB. ./store and ./commands are three-free subpaths, so a panel that only reads the selection — or an agent bridge that only applies a command — never touches WebGL.

What is in it

store.jsthe canonical viewer state, as an external store (useSyncExternalStore)
commands.jsthe closed visual-action executor + lesson-step → command mapping
BodyViewer.jsxthe r3f scene, selection, hover, clipping, the camera-nonce driver
LayerPanel.jsxlayers, colour mode, peel, ghost, cross-section, camera presets
palette.jssix colour schemes, keyed by slug so an unknown species is still legible
geometry.jsplacements → drawable instances, the primitive vocabulary, the shared geometry cache, explode offsets
batches.jspure — grouping into InstancedMeshes, slot assignment, the confidence fade. No three, no React
InstancedBody.jsxthe InstancedMeshes, the per-frame pick loop, the colour/alpha/matrix writes

It draws the WHOLE body, in about sixty draw calls

One React component and one THREE.Mesh per structure is fine for the ~100 a body plan places by hand and ruinous for the ~6,500 a species slice contains. Every distinct shape is now two InstancedMeshes — opaque and transparent — and an instance moves between them with a zero-scale matrix rather than a scene-graph rebuild.

The slot-to-structure mapping lives in batches.js, away from the renderer, because getting it wrong by one renders a complete, plausible body at sixty frames a second in which clicking the liver selects the spleen. test/instancing.test.js shuffles the input and asserts every slot still resolves.

Only an authored placement gets a rich primitive. A derived one gets a generic proxy sized from its category, because we know roughly where it is and nothing at all about its shape — and a convincingly-shaped organ nobody has evidence for is the exact failure the schematic approach exists to refuse. It is also the performance answer: the cache holds ~100 rich buffers plus a couple of dozen proxies rather than 6,500 distinct meshes.

Three traps it already handles

  • visibleSystems: null means ALL, not none. The first "hide one layer" click resolves it against

the full system list; treating null as empty turns one click into a blank viewer.

  • The camera moves on a NONCE, not on a value. Reacting to view or focusIds directly means

every unrelated re-render re-applies the last camera intent, and the user's orbit snaps back to the front whenever anything else updates.

  • Shared geometry must not be disposed by a component teardown. Same rule as @leumas/body-3d:

disposeShapeCache() is process-wide and is the only sanctioned way to free it.

Plus three more that arrived with instancing, all guarded by check:body:

  • Never vertexColors on an instanced material. setColorAt already defines

USE_INSTANCING_COLOR; adding USE_COLOR makes the shader multiply by a per-vertex attribute the geometry lacks and every instance renders black — with a correct palette and a correct buffer.

  • Null boundingSphere after every matrix write. three computes an InstancedMesh's sphere lazily

on the first raycast and never again, so a stale one culls the whole mesh and picking silently stops working for everything.

  • Inject per-instance alpha AFTER #include <clipping_planes_fragment>. The cross-section discards

there; patching earlier multiplies alpha into pixels about to be thrown away.

Prove it

pnpm --filter @leumas/body-viewer test   # 13 tests, no browser, no WebGL

The store and the executor are plain JavaScript, and every viewer failure a user actually notices lives in one of them.

What it exports

72 exports: 22 components, 4 hooks, 46 helpers. Import from @leumas/body-viewer.

BodyViewerBundleLoaderCATEGORY_COLORSCOLOR_MODESCOLOR_MODESDEFAULT_HIDDEN_SLUGSDEFAULT_HIDDEN_SLUGSDETAIL_LEVELSDETAIL_LEVELSEMPTY_SETInstancedBodyLayerPanelLayerPanelMATERIAL_IDSMOUNT_CHUNKMOUNT_FIRST_CHUNKREALISTIC_COLORSREVEAL_MODESREVEAL_MODESSYSTEM_COLORSVIEWSVIEWSuseViewerSelectoruseViewerSelectoruseViewerStateuseViewerStateapplyCommandapplyCommandapplyCommandsapplyCommandsbundleGeometrybundleGeometrybundleReportbundleReportbundleRevisionbundleRevisionbundlesInbundlesIncolorForcommandsForStepcommandsForStepconfidenceFadecreateViewerStorecreateViewerStoredisposeBundlesdisposeBundlesdisposeShapeCacheexplodedPositionfailBundlefailBundlegeometriesFromgeometriesFromhasBundleMeshhasBundleMeshinstancesForisVisibleisVisiblematerialFormaterialPropsmountOrderopacityForopacityForplanBatchesquantizeRadiusregisterBundleregisterBundleresolveInstanceshapeExtentshapeGeometryshapeKeysimplifysystemColor
Source shared/packages/body-viewer/README.md (no-git)markdownjson
Generated from the Leumas repository. Every page cites the file it came from.leumas.techllms.txt