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

@semio/scene

v0.1.0

Published

Higher-level visualization and interaction components for 3D models.

Readme

@semio/scene

3D scene primitives, gizmos, and React hooks built on react-three-fiber. Used standalone for embedded viewers (e.g. URDF preview) and as the rendering layer of @semio/studio.

Stores and contexts

The scene package separates two concerns:

  • Scene structure — what exists in the world: animatable definitions, the world tree, materials, namespaces. Lives in a Zustand store, accessed via SceneContext + useSceneStore.
  • Runtime values — the current value of every animatable. Lives in useValuesStore (re-exported from @semio/utils). Read it with useValuesStore and write to it with useValuesStore.getState().updateValues(...).

Scene render hooks (useFeatures, useAnimatableSubscription) subscribe to useValuesStore directly. The scene store does not own runtime values.

SceneValueWriterContext

Some scene primitives (e.g. joint gizmos) write back to runtime values when the user drags them. The default behavior writes straight to useValuesStore, which is what standalone consumers want.

When a host app needs to add semantics to those writes — for example, the Studio routes joint-gizmo writes through its animation system so that dragging a gizmo in animation mode produces a keypoint update instead of a transient direct write — the host overrides the writer via SceneValueWriterContext.

Standalone (default)

No setup required. Joint gizmos write directly to useValuesStore:

import { Scene, SceneContext, createSceneStore } from "@semio/scene";

const sceneStore = createSceneStore();

<SceneContext.Provider value={sceneStore}>
  <Scene />
</SceneContext.Provider>;

Dragging a joint gizmo calls useValuesStore.getState().updateValues(...) — no animation routing, no app coupling.

Override (host app)

Wrap the scene tree with SceneValueWriterContext.Provider and supply a writer that does whatever the host needs. Memoize the value object so consumers don't re-render unnecessarily.

import { useMemo } from "react";
import {
  SceneContext,
  SceneValueWriterContext,
  type SceneValueWriter,
} from "@semio/scene";

function HostProvider({ store, children }) {
  const valueWriter = useMemo<SceneValueWriter>(
    () => ({
      setValue: (animatableId, namespace, value) =>
        store.getState().setValue(animatableId, namespace, value),
    }),
    [store],
  );

  return (
    <SceneContext.Provider value={store}>
      <SceneValueWriterContext.Provider value={valueWriter}>
        {children}
      </SceneValueWriterContext.Provider>
    </SceneContext.Provider>
  );
}

The writer the host supplies is responsible for whatever semantics it wants — keypoint updates, telemetry, batching — and ultimately for ensuring the value reaches useValuesStore (so downstream readers like useFeatures see it).

Adding a new gizmo that writes values

Use the hook; do not import useValuesStore directly:

import { useSceneValueWriter } from "@semio/scene";

function MyGizmo({ animatableId, namespace }) {
  const { setValue } = useSceneValueWriter();
  return (
    <SomeDraggableThing
      onChange={(next) => setValue(animatableId, namespace, next)}
    />
  );
}

This keeps the gizmo agnostic to whether it's running in a standalone scene or under a host that wants to intercept writes. The default writer is provided automatically — no Provider is required for the hook to return a usable value.

Key APIs

| Export | Purpose | |---|---| | SceneContext | React context holding the scene Zustand store. | | useSceneStore(selector) | Subscribe to the scene store. | | createSceneStore(initial?) | Create an isolated scene store (e.g. for previews). | | useFeatures / useAnimatableSubscription | Subscribe to runtime values for a feature/animatable. | | SceneValueWriterContext | Override the gizmo value-write behavior. | | useSceneValueWriter() | Read the current writer (returns the default if no Provider). | | SceneValueWriter (type) | The writer interface: { setValue(id, namespace, value) }. |

Runtime values themselves (useValuesStore, mergeValueMaps) are re-exported from @semio/utils via @semio/animation for convenience; you can import either path.