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

@cavegiant/cave-world-r3f

v1.1.0

Published

Web-based 3D virtual tour SDK — render interactive 3D scenes from JSON configuration

Downloads

91

Readme

@cavegiant/cave-world-r3f

Web-based 3D virtual tour SDK. Renders an interactive, walkable 3D scene from a single JSON description — including Gaussian-splat captures, collision, interactive objects, and seamless travel between connected scenes.

ESM-only. Consumers must use import (not require).

Install

npm install @cavegiant/cave-world-r3f

Peer dependencies (all required):

npm install react@">=18 <19.3" react-dom@">=18 <19.3" three @react-three/fiber @react-three/drei @react-three/viverse @sparkjsdev/spark@^0.1.10 zustand

@react-three/fiber currently requires React >=19 <19.3 (or React 18). Do not install React 19.3+ until fiber widens its peer range.

@sparkjsdev/spark is pinned to 0.1.x on purpose. Spark 2.x rebuilds its splat accumulator whenever the view changes, which injects frame-time jitter that the character integrator turns into visible stutter while walking. See doc/ARCHITECTURE.md.

If you hit @react-three/timeline issues with viverse, pin @react-three/[email protected] in the host app as well — this package's overrides only apply to its own install.

Quick start

The container needs a definite width and height — the viewer fills it. Omitting caveSpaceLoader uses DefaultCaveSpaceLoader (the public CaveGiant content API).

import { CaveExplore } from '@cavegiant/cave-world-r3f/explore'

export default function App() {
  return (
    <div style={{ width: '100vw', height: '100vh' }}>
      <CaveExplore spaceId="your-space-id" />
    </div>
  )
}

Loading scenes from your own backend

import { CaveExplore, createHttpCaveSpaceLoader } from '@cavegiant/cave-world-r3f/explore'

const loader = createHttpCaveSpaceLoader({
  buildUrl: (spaceId) => `/api/spaces/${spaceId}`,
  headers: { Authorization: `Bearer ${token}` }
})

<CaveExplore spaceId={id} caveSpaceLoader={loader} />

createHttpCaveSpaceLoader adds a request timeout, non-2xx detection, and payload validation on top of fetch, and reports failures as CaveWorldError with a stable code. Any (spaceId) => Promise<CaveSpace> function works too.

Features

  • JSON-driven — scene content is fully described by one config file
  • Gaussian splats — native 3DGS rendering with device-aware LOD selection
  • Cross-scene travel — seamless walk-through and portal teleport between scenes, with neighbor preloading
  • Extensible objects — register custom 3D object types through ObjectRegistry (unregistered types render nothing; enable setCaveWorldLogLevel('debug') to see skips)
  • Extensible behaviors — attach reusable components to any object through ComponentRegistry
  • Typed event bus — object:click, connector:enter, detail:open, custom:*, and more
  • Custom avatars — third-person GLB/VRM with VRM 1.0 bone mapping
  • Multiplayer — optional WebSocket character sync (requires explicit url + your avatar catalog)
  • Replaceable UI — every built-in overlay has a render* prop, and all copy is translatable
  • Load-failure hardening — automatic splat retry, stall watchdog, and a retry prompt instead of an infinite spinner

Wrap the viewer (or your own R3F canvas) in a React error boundary if you need host-level recovery from unexpected WebGL/R3F throws — the SDK's load-error overlay covers the hardened splat/config path only.

Entry points

| Import path | Contents | | -------------------------------------- | ------------------------------------------------------------------------------------- | | @cavegiant/cave-world-r3f | Common re-exports from all layers (CaveSpace is re-exported as CaveSpaceRenderer) | | @cavegiant/cave-world-r3f/types | Scene JSON types only — zero runtime | | @cavegiant/cave-world-r3f/core | Event bus, registries, provider, hooks, logger, i18n | | @cavegiant/cave-world-r3f/space | Scene rendering components (R3F), including CaveSpace | | @cavegiant/cave-world-r3f/explore | Viewers, overlays, character, multiplayer | | @cavegiant/cave-world-r3f/styles.css | Default overlay stylesheet |

Viewers

| Component | Use it for | | ----------------- | -------------------------------------------------------------------- | | CaveExplore | First/third-person walkable tour with physics and cross-scene travel | | CaveOrbitViewer | Orbit-camera overview of a single scene (no avatar, no physics) |

Styling

The built-in overlays ship a small stylesheet, namespaced under .cw-* and themed entirely through --cw-* custom properties. It is injected at runtime by default, so nothing is required to get a working UI.

The defaults are declared on :root, which means setting the same property on any ancestor of the viewer overrides them.

/* Re-theme without replacing any component */
:root {
  --cw-color-accent: #7c9cff;
  --cw-color-surface: rgb(20 20 28 / 88%);
  --cw-radius-md: 4px;
}

The properties you are most likely to want:

| Property | Themes | | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | | --cw-color-accent / --cw-color-accent-soft | Primary gold: eyebrow text, key caps, hairlines, hover rules | | --cw-color-accent-mint | Secondary accent: hover states and the action-panel status dot | | --cw-color-accent-warm | Load-error badge and its primary button | | --cw-color-text / --cw-color-text-muted | Overlay copy | | --cw-color-surface / --cw-color-surface-solid / --cw-color-scrim | Panel, dialog, and detail-window backgrounds | | --cw-color-label-surface / --cw-color-label-border | In-scene connector tags | | --cw-panel-fill / --cw-panel-rim / --cw-panel-clip / --cw-panel-grain | Action-panel HUD decoration (set --cw-panel-clip: none for square corners) | | --cw-radius-*, --cw-blur*, --cw-shadow-*, --cw-z-* | Shape, depth, stacking |

To bundle the CSS yourself instead, import it and turn the injector off:

import '@cavegiant/cave-world-r3f/styles.css'

;<CaveExplore spaceId={id} injectStyles={false} />

Localization

All built-in copy defaults to Chinese and is overridable per string. messages is deep-merged over the default locale, so partial overrides keep everything else intact.

import { messagesEn } from '@cavegiant/cave-world-r3f/core'

<CaveExplore spaceId={id} messages={messagesEn} />
<CaveExplore spaceId={id} messages={{ loadError: { retry: 'Try again' } }} />

Diagnostics

The SDK only logs warnings and errors by default, and never writes to the console outside that.

import { setCaveWorldLogLevel, setCaveWorldLogSink } from '@cavegiant/cave-world-r3f/core'

setCaveWorldLogLevel('debug') // while integrating (also logs unknown object types)
setCaveWorldLogLevel('silent') // mute entirely
setCaveWorldLogSink(myTelemetryAdapter) // forward to your own pipeline

Documentation

| Document | Audience | | ------------------------------------------------------------ | ----------------------------------------------------------------- | | doc/API.md | Integration guide, props reference, event list, extension recipes | | doc/ARCHITECTURE.md | Module design, data flow, dependency rules | | doc/scene-json-structure.md | Scene JSON schema | | doc/multiplayer-protocol.md | WebSocket message protocol | | AGENTS.md | Invariants and recipes for AI coding agents (repo only) | | examples/ | Runnable demos — npm run examples | | CONTRIBUTING.md | Setup, checks, PR expectations | | SECURITY.md | Vulnerability reporting |

Development

This repository is the standalone package. From the package root:

npm install
npm run check              # format:check + typecheck + lint + test
npm run build
npm run verify:package     # publint + attw
npm run verify:pack-size   # tarball must stay lean (no examples/)
npm run examples           # live playground at https://localhost:5173/

Nested under a host monorepo

If this tree lives inside a larger portal repo, do not run npm install here (nested node_modules duplicates React / Three.js). Use the host's sdk:* scripts instead (npm run sdk:examples, sdk:check, …). See AGENTS.md.

The playground mounts every examples/0N-*.tsx against the public demo scene id in examples/demo-space.ts. See examples/README.md.

License

MIT