Components / Organs
Organ viewer
The 3D stage every OrganUI explorer shares. Give it a GLB and a description of its structures; it handles loading, framing, picking and emphasis.
Installation
Most apps want a ready-made organ: adrenals, appendix, bladder, brain, breast, diaphragm, ear, esophagus, eye, gallbladder, hair, heart, intestines, joints, kidneys, larynx, liver, lungs, lymph node, muscles, nails, nerves, nose, pancreas, parathyroid, pharynx, pineal, pituitary, prostate, salivary glands, skeleton, skin, spinal cord, spleen, stomach, teeth, thymus, thyroid, tongue, uterus, vessels, vestibular system. To bring your own model, install the viewer alone.
bunx shadcn@4.22.1 add https://organui.com/r/organ-viewer.json
The source installs into your components directory and adds three.js, plus shadcn's alert, button, progress, select and tooltip for its controls. Its toolbar composes them with Base UI's render prop, so it needs one of shadcn's Base UI styles, such as base-nova; on a Radix style its buttons do nothing. It uses your theme tokens and installs no global styles.
Usage
import type { OrganModel } from "@/components/organ-viewer"
export const kidneyModel: OrganModel = {
name: "Kidney",
src: "/models/kidney.glb",
defaultView: "Anterior",
views: [
{ name: "Anterior", direction: [0, 0, 1] },
{ name: "Posterior", direction: [0, 0, -1] },
],
structures: [
// id is the mesh name, or userData.structureId, in the GLB.
{ id: "cortex", label: "Renal cortex", group: "Kidney", color: "#b5685f" },
],
attribution: {
credit: "Your model credit.",
license: "CC BY 4.0",
licenseUrl: "https://creativecommons.org/licenses/by/4.0/",
source: "https://example.com/model",
},
}Every structure must exist in the GLB, matched by mesh name or userData.structureId on the mesh or one of its parents; otherwise the viewer reports that the model is incomplete. View directions point from the model towards the camera, with +x the patient's left, +y superior and +z anterior. A view with structureIds frames only those structures.
Without Controls
Hide the built-in view, zoom, and reset controls while keeping camera interaction and attribution.
Controlled Selection
Connect selection to your application state with selectedId and onSelectionChange.
With Anatomy Panel
Pair this component with AnatomyTree for shared selection and visibility. For a complete layout with a mobile sheet, see the Explorer 01 block.
Behaviour
Selection and visibility are controlled, with the same contract as the anatomy tree: pass selectedId and a visibility map where missing IDs are visible, and update them from onSelectionChange. A selected structure glows in its own colour while everything else is ghosted, so it stays visible even inside other anatomy. Clicks on a ghost prefer the solid structure behind it.
Each named view fits the model to 80% of the stage from its direction. Rotating leaves the named view, and onViewChange reports null; zooming does not. Drag or the arrow keys rotate; scroll, pinch, plus and minus zoom. Motion damping is off when the user prefers reduced motion.
Control it from your UI
const viewer = useRef<OrganViewerHandle>(null)
// viewer.current?.setView("Posterior")
// viewer.current?.zoom(0.85) // below 1 zooms in
// viewer.current?.rotate(0.2) // radians around the target
// viewer.current?.reset()
<OrganViewer ref={viewer} model={kidneyModel} />Pass controls={false} to hide the built-in view menu, zoom and reset buttons. organAnatomyNodes(model) builds anatomy tree data from the model's groups, and organDefaultVisibility(model) returns its initial visibility.
WebGL is required. When it cannot start, or the model cannot load, the viewer shows a message with a retry button; keep a text alternative such as the anatomy tree alongside it.