npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@vixotic/vanatome-react

v0.1.6

Published

Embeddable React viewer for curated Vanatome human anatomy atlases.

Readme

@vixotic/vanatome-react

The embeddable Vanatome anatomy viewer for React. It renders curated Vanatome glTF atlases and exposes the interaction state needed to build search, hierarchy, layer, isolate, focus, and detail-panel experiences.

Install

npm install @vixotic/vanatome-react react react-dom three \
  @react-three/fiber @react-three/drei

React 19, React Three Fiber 9, Drei 10, and Three.js 0.180 or newer are peer dependencies. The package is ESM-only and includes TypeScript declarations.

Quick start

import { VanatomeViewer, useVanatomeController } from "@vixotic/vanatome-react";
import atlas from "./atlas";

export function Anatomy() {
  const viewer = useVanatomeController(["organs", "skeleton"]);

  return (
    <div style={{ height: 640 }}>
      <VanatomeViewer
        atlas={atlas}
        selectedId={viewer.selectedId}
        isolation={viewer.isolation}
        visibleLayers={viewer.visibleLayers}
        focusRequestKey={viewer.focusRequestKey}
        resetViewKey={viewer.resetViewKey}
        onSelect={viewer.select}
        onEscape={viewer.clear}
        enablePan
      />
    </div>
  );
}

The container must have a non-zero height. atlas is a VanatomeAtlas object whose modelUrl points to a GLB and whose structures map stable anatomy IDs to glTF nodes. The companion @vixotic/vanatome-atlas package loads the official hosted release and returns this object directly.

The host application owns its interface and state. VanatomeViewer owns only the 3D scene, so a product can compose its own sidebar, search, breadcrumbs, layer controls, and structure details without fighting a bundled UI.

The atlas contract

Every selectable glTF node needs extras.anatomyId; distributed system models also use extras.anatomySystem. Structure IDs must match the metadata and stay stable if applications persist selections in URLs or saved views.

import type { VanatomeAtlas } from "@vixotic/vanatome-react";

const atlas: VanatomeAtlas = {
  id: "example-human",
  name: "Example human atlas",
  version: "1.0.0",
  modelUrl: new URL("./human.glb", import.meta.url).href,
  attribution: "Example anatomy source",
  structures: [
    {
      id: "heart",
      name: "Heart",
      kind: "organ",
      system: "cardiovascular",
      layer: "cardiovascular",
      position: [0, 1.2, 0],
    },
  ],
};

position is a fallback focus point. When mapped geometry is present, focus uses the actual visible bounds. See the repository's atlas contract for hierarchy, validation, and glTF details.

Viewer behavior

The scene resolves interaction in a predictable order:

  1. visibleLayers filters atlas structures.
  2. isolation or legacy isolatedId chooses an isolation boundary.
  3. hiddenIds removes structures and their descendants.
  4. Hover and selection styles apply to the geometry that remains.

An empty visibleLayers array means “show every layer” for compatibility with the initial package releases. Structures with selectable: false, hidden structures, and filtered structures do not emit hover or selection events. Dragging rotates the model without committing a selection; click or tap selects, and clicking empty space clears selection. Use alwaysVisibleIds for non-interactive spatial context that should bypass layer filters; explicit hiding and isolation still take precedence.

<VanatomeViewer
  atlas={atlas}
  selectedId={selectedId}
  isolatedId={isolatedId}
  alwaysVisibleIds={["body-shell"]}
  hiddenIds={["body-shell"]}
  displayMode="xray"
  onHover={setHoveredId}
  onSelect={setSelectedId}
  onEscape={() => {
    setSelectedId(null);
    setIsolatedId(null);
  }}
/>

Display modes are normal, xray, and ghost. The official body shell and skeleton appearance remains the default; use appearance to change their IDs, opacities, highlight intensities, or selection pulse without reaching into the Three.js scene.

Layers and multi-system views

Pass all active system or layer IDs in visibleLayers. The viewer renders their union, so a host can implement single-select, multi-select, or presets without changing the scene component.

const viewer = useVanatomeController([
  "cardiovascular",
  "respiratory",
]);

viewer.toggleLayer("skeletal");
viewer.setVisibleLayers(["cardiovascular", "skeletal"]);

An empty array intentionally means “all layers” for compatibility. If the host needs a “none selected” state, do not mount the viewer or hide the canvas.

For separately delivered system GLBs, pass atlases instead of atlas. The viewer composes them into one scene with shared selection, isolation, camera, and layer behavior. Adding a source keeps already-ready models mounted while the new GLB loads; removing a source unloads only that model.

<VanatomeViewer
  atlases={[cardiovascular.atlas, respiratory.atlas]}
  visibleLayers={["cardiovascular", "respiratory"]}
  incrementalLoadingFallback={<span>Adding anatomy…</span>}
  onModelReady={(modelUrl) => console.info("Ready", modelUrl)}
/>

Use exactly one data prop: atlas for a single GLB or atlases for a composition. Every composed atlas must have the same release version and, when present, build ID. Structure IDs must remain unique across different model URLs. composeVanatomeAtlases() is exported for hosts that want to validate a collection before rendering it.

Isolation modes

useVanatomeController().isolate(id, mode) supports:

  • selected: only the selected structure and its descendants.
  • parent: the selected structure inside its complete direct-parent subtree.
  • parent-context: the selected subtree stays solid while the rest of its direct-parent subtree becomes translucent.

The controller exposes the resulting isolation object and retains isolatedId as a compatibility alias. Passing only isolatedId to the viewer continues to use selected mode.

The published VanatomeController contract remains compatible with 0.1.3. useVanatomeController returns the additive VanatomeControllerState type, which includes isolation, multi-mode isolate, and clear.

The package remains headless. Use onStructureContextMenu to render product actions without coupling a menu design to the canvas:

<VanatomeViewer
  atlas={atlas}
  isolation={controls.isolation}
  onStructureContextMenu={({ id, clientX, clientY }) => {
    openStructureMenu({ id, clientX, clientY });
  }}
/>

Right-clicking without dragging emits the event. A right-drag remains available for panning when enablePan is set; two-finger touch gestures provide the corresponding pan/zoom behavior. Shift+F10 or the Context Menu key opens the host menu for the current selection.

Camera behavior

Focus requests frame the visible geometry for the selected structure and its descendants. The viewer preserves the current viewing direction, accounts for the canvas aspect ratio, and cancels its animation as soon as the user starts orbiting.

<VanatomeViewer
  atlas={atlas}
  selectedId={selectedId}
  focusRequestKey={focusRequestKey}
  focusPadding={1.3}
  focusDistance={2}
  cameraAnimationDuration={550}
  enablePan
  onFocusRejected={(id, reason) => {
    console.warn(`Could not focus ${id}: ${reason}`);
  }}
  onCameraChange={(view) => saveView(view)}
/>

focusDistance is the minimum focus distance retained for compatibility; large structures automatically move the camera farther away. Set cameraAnimationDuration={0} for immediate movement. Animated focus and reset automatically become immediate when the user prefers reduced motion unless respectReducedMotion={false} is supplied.

Loading and recovery

The atlas loader resolves catalog metadata. The viewer separately owns the GLB request and reports its lifecycle:

<VanatomeViewer
  atlases={atlases}
  loadingFallback={<p>Loading geometry…</p>}
  incrementalLoadingFallback={<p>Adding selected systems…</p>}
  errorFallback={(error) => <p>{error.message}</p>}
  onLoadStart={(modelUrl) => console.info("Loading", modelUrl)}
  onModelReady={(modelUrl) => console.info("Ready", modelUrl)}
  onLoadProgress={({ percentage }) => setProgress(percentage)}
  onReady={() => setSceneReady(true)}
  onError={(error) => reportViewerError(error)}
/>

loadingFallback is shown while no active model is ready. incrementalLoadingFallback is shown after at least one model is ready, so the host can use a compact nonblocking status instead of replacing the scene. onModelReady fires per GLB; the existing onReady callback fires when every currently active GLB is ready.

Model failures and WebGL context loss use stable error codes. Replacing a model URL resets that model's lifecycle and prevents its previous state from being presented as the new scene. A failed added model reports its error without blanking models that are already ready.

The focusable viewer wrapper is labelled “Interactive 3D anatomy viewer” by default; override ariaLabel for a more specific host context. Mouse orbit, wheel zoom, one-finger orbit, pinch zoom, Escape, and reduced-motion behavior are built in. Hierarchy keyboard navigation remains the host application's responsibility.

Controller actions

useVanatomeController(initialLayers?) returns controlled viewer state plus these actions:

| Action | Effect | | --- | --- | | select(id) | Selects a structure and requests focus. Pass null to clear selection. | | focus(id?) | Requests another focus animation, optionally changing selection. | | isolate(id?, mode?) | Applies selected, parent, or parent-context isolation. | | clear() | Clears selection and isolation without changing the camera or layers. | | reset() | Clears selection/isolation, restores initial layers, and resets the camera. | | setVisibleLayers(ids) | Replaces the visible layer union. | | toggleLayer(id) | Adds or removes one layer. |

Viewer props

The main prop groups are:

| Group | Props | | --- | --- | | Data | atlas or atlases | | Selection | selectedId, hoveredId, onSelect, onHover | | Visibility | visibleLayers, alwaysVisibleIds, hiddenIds, displayMode | | Isolation | isolation, compatibility alias isolatedId | | Camera | focusRequestKey, resetViewKey, focusPadding, focusDistance, cameraAnimationDuration, enablePan, minDistance, maxDistance | | Lifecycle | onLoadStart, onLoadProgress, onModelReady, onReady, onError, loadingFallback, incrementalLoadingFallback, errorFallback | | Interaction | onStructureContextMenu, onEscape, onCameraChange, onInteractionStart, onInteractionEnd | | Presentation | appearance, className, style, ariaLabel, modelScale, modelPosition |

All callbacks and props are optional; exactly one of atlas or atlases is required at runtime. Existing atlas={atlas} consumers remain source-compatible. Import VanatomeViewerProps, VanatomeViewerAppearance, and the event/state types from the package for exact signatures.

Upgrading from 0.1.3

Version 0.1.6 is backward compatible with the 0.1.3 public contract. isolatedId continues to isolate a selected subtree, the original VanatomeController type remains unchanged, and an empty visibleLayers array still displays all layers. Pan, context-menu events, multi-mode isolation, appearance controls, camera events, and VanatomeControllerState are additive. Multi-atlas composition and its per-model lifecycle callbacks are also additive; existing single-atlas applications do not need to change.

Licensing

Viewer code is MIT-licensed. Atlas files are distributed separately and may carry different attribution and ShareAlike obligations. Preserve the attribution supplied by the loaded atlas.