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

@vctrl/viewer

v0.18.0

Published

vctrl/viewer is a React component library for rendering and interacting with 3D models. It's part of the vectreal ecosystem and is designed to work seamlessly with the vctrl/hooks package for model loading and management.

Downloads

644

Readme

@vctrl/viewer

NPM Downloads Storybook

A ready-to-use React component for rendering and interacting with 3D models. Built on top of Three.js and React Three Fiber.

This package is still in active development. Breaking changes may occur before the first major release.


Installation

npm install @vctrl/viewer
# or
pnpm add @vctrl/viewer

Quick start

import { useLoadModel } from '@vctrl/hooks/use-load-model'
import { VectrealViewer } from '@vctrl/viewer'
import '@vctrl/viewer/css'

function App() {
	const { file } = useLoadModel()
	return <VectrealViewer model={file?.model} />
}

You must import the CSS bundle (@vctrl/viewer/css) for the viewer to render correctly.


VectrealViewer props

| Prop | Type | Required | Description | | ------------------------------ | ------------------------------------------------------- | -------- | -------------------------------------------------------------------------------- | | model | Object3D | No* | The Three.js scene to display. Optional when using the use-load-model context. | | className | string | No | Additional CSS classes for the viewer container | | theme | 'light' \| 'dark' \| 'system' | No | Viewer theme, default is system | | enableViewportRendering | boolean | No | Render only while in viewport, default true | | enablePostProcessing | boolean | No | Toggle postprocessing effects, default true | | boundsOptions | BoundsProps | No | Scene bounds and framing behavior | | cameraOptions | CameraProps | No | Perspective camera configuration | | controlsOptions | ControlsProps | No | OrbitControls configuration | | envOptions | EnvironmentProps | No | Stage and Environment component configuration | | shadowsOptions | ShadowsProps | No | Shadow behavior configuration | | popover | React.ReactNode | No | Optional info popover slot | | loader | React.ReactNode | No | Custom loading UI | | loadingThumbnail | ViewerLoadingThumbnail | No | Optional blurred loading thumbnail | | onScreenshot | (dataUrl: string) => void | No | Called when a screenshot is captured | | onScreenshotCaptureReady | (capture: SceneScreenshotCapture \| null) => void | No | Receives a capture function for on-demand screenshots | | onCameraSnapshotCaptureReady | (capture: SceneCameraSnapshotCapture \| null) => void | No | Receives a capture function for the current camera pose | | onInteractionEvent | (event: ViewerInteractionEvent) => void | No | Receives viewer lifecycle and runtime interaction events | | onCommandExecutorReady | (executor: ViewerCommandExecutor \| null) => void | No | Receives a minimal imperative runtime command executor |

Notes on content source

  • model is optional because you can also render scene content via children.
  • Grid options are currently typed but not active in render output.

Camera options (CameraProps)

cameraOptions accepts:

type CameraProps = {
	cameras?: Array<
		PerspectiveCameraProps & {
			cameraId: string
			name: string
			initial?: boolean
			shouldAnimate?: boolean
			animationConfig?: {
				duration: number
				easing?: (t: number) => number
			}
		}
	>
}

Each camera entry extends PerspectiveCameraProps from Drei and adds viewer-specific camera switching metadata.

<VectrealViewer
	cameraOptions={{
		cameras: [
			{
				cameraId: 'default',
				name: 'Default',
				initial: true,
				shouldAnimate: true,
				animationConfig: { duration: 900 },
				position: [0, 5, 8],
				fov: 55,
				near: 0.1,
				far: 1000
			}
		]
	}}
/>

Controls options (ControlsProps)

Based on @react-three/drei OrbitControls.

controlsOptions extends OrbitControls props and adds:

| Option | Type | Description | | ----------------- | -------- | ------------------------------------------------------ | | controlsTimeout | number | Delay in milliseconds before controls behavior resumes |

<VectrealViewer
	controlsOptions={{
		maxPolarAngle: Math.PI / 2,
		autoRotate: true,
		controlsTimeout: 2000
	}}
/>

Camera snapshot callback

onCameraSnapshotCaptureReady(capture) gives you a function that captures the current viewer camera pose as { position, rotation, target, fov }.


Runtime commands and events

VectrealViewer exposes a small runtime interaction surface for surrounding app code.

Commands

onCommandExecutorReady(executor) gives you a ViewerCommandExecutor with execute(command).

Current commands:

| Command | Payload | Effect | | ---------------------- | ---------------------- | -------------------------------------------------- | | activate_camera | { cameraId: string } | Transitions to one of the configured scene cameras | | set_controls_enabled | { enabled: boolean } | Temporarily enables or disables orbit interaction |

Events

onInteractionEvent(event) emits the current viewer runtime events:

| Event | Payload | Meaning | | --------------------------- | ------------------------------ | ------------------------------------------- | | viewer_ready | none | Viewer runtime is ready to accept commands | | initial_framing_completed | { cameraId: string \| null } | Initial framing and stabilization completed | | camera_changed | { cameraId: string } | Active camera changed |

import { useRef } from 'react'
import { type ViewerCommandExecutor, VectrealViewer } from '@vctrl/viewer'

function ViewerRuntimeExample({ model }: { model: object }) {
	const executorRef = useRef<null | ViewerCommandExecutor>(null)

	return (
		<>
			<button
				onClick={() =>
					executorRef.current?.execute({
						type: 'activate_camera',
						cameraId: 'overview'
					})
				}
			>
				Go to overview
			</button>
			<button
				onClick={() =>
					executorRef.current?.execute({
						type: 'set_controls_enabled',
						enabled: false
					})
				}
			>
				Lock controls
			</button>
			<VectrealViewer
				model={model as never}
				onCommandExecutorReady={(executor) => {
					executorRef.current = executor
				}}
				onInteractionEvent={(event) => {
					console.log('viewer event', event)
				}}
			/>
		</>
	)
}

Environment options (EnvironmentProps)

Configures the @react-three/drei Stage and @react-three/drei Environment components.

envOptions supports a typed preset system from @vctrl/core:

| Option | Type | Description | | ----------------------- | -------------------- | ------------------------------------------------------------- | | preset | EnvironmentKey | Preset key such as studio-key, outdoor-noon, night-city | | environmentResolution | '1k' \| '4k' | Resolution variant for environment assets | | background | boolean | Render environment as scene background | | backgroundBlurriness | number | Blur strength when background is enabled | | backgroundIntensity | number | Background intensity multiplier | | environmentIntensity | number | Lighting intensity multiplier | | files | string \| string[] | Custom environment files |

<VectrealViewer
	envOptions={{
		preset: 'studio-key',
		environmentResolution: '1k',
		background: true,
		backgroundBlurriness: 0.2,
		environmentIntensity: 1,
		backgroundIntensity: 1
	}}
/>

Bounds and shadows

| Prop | Type | Summary | | ---------------- | -------------- | ---------------------------------------------------- | | boundsOptions | BoundsProps | Pass-through to Drei Bounds behavior | | shadowsOptions | ShadowsProps | Union of accumulative and contact shadow configs |

boundsOptions (BoundsProps)

BoundsProps is forwarded to Drei Bounds. The viewer defaults are:

| Option | Default | | ------------- | ------- | | fit | true | | clip | true | | margin | 1.5 | | maxDuration | 0 |

<VectrealViewer
	boundsOptions={{
		fit: true,
		clip: true,
		margin: 1.25,
		maxDuration: 300
	}}
/>

shadowsOptions (ShadowsProps)

ShadowsProps is a discriminated union using type.

Contact shadows (type: 'contact')

Viewer defaults:

| Option | Default | | --------- | ----------- | | type | 'contact' | | opacity | 0.4 | | blur | 0.1 | | scale | 5 | | color | '#000000' | | smooth | true |

Commonly used ContactShadows fields:

| Option | Type | | ------------ | ---------------------------- | | opacity | number | | blur | number | | scale | number \| [number, number] | | far | number | | resolution | number | | color | string | | frames | number |

<VectrealViewer
	shadowsOptions={{
		type: 'contact',
		opacity: 0.45,
		blur: 1.8,
		scale: 6,
		far: 12,
		resolution: 1024,
		color: '#111111'
	}}
/>

Accumulative shadows (type: 'accumulative')

Viewer defaults:

| Option | Default | | ------------ | ---------------- | | type | 'accumulative' | | temporal | false | | frames | 30 | | alphaTest | 0.35 | | opacity | 1 | | scale | 10 | | resolution | 1024 | | colorBlend | 2 | | color | '#000000' |

Nested light defaults (shadowsOptions.light):

| Option | Default | | ----------- | ------------------------------------------------- | | intensity | 1 | | amount | 5 | | radius | 7.5 | | ambient | 0.5 | | position | [5, 10, 5] or auto-calculated from scene bounds |

<VectrealViewer
	shadowsOptions={{
		type: 'accumulative',
		temporal: true,
		frames: 40,
		alphaTest: 0.4,
		opacity: 0.95,
		scale: 12,
		resolution: 1024,
		colorBlend: 2,
		color: '#000000',
		light: {
			amount: 6,
			radius: 7,
			ambient: 0.5,
			intensity: 1,
			bias: 0.0001
		}
	}}
/>

Screenshot callbacks

VectrealViewer supports two screenshot-related callbacks:

  • onScreenshot(dataUrl) receives a data URL each time a screenshot is captured.
  • onScreenshotCaptureReady(capture) gives you a capture function that can be stored and called from external UI.

The callback types are exported from @vctrl/viewer as SceneScreenshotCapture and SceneScreenshotOptions.

SceneScreenshotOptions:

| Option | Type | Description | | ---------- | ------------------------------ | ----------------------------------- | | width | number | Output width in pixels | | height | number | Output height in pixels | | mimeType | 'image/jpeg' \| 'image/webp' | Output format | | quality | number | Image quality hint for lossy output | | mode | 'auto-fit' \| 'viewport' | Capture strategy |


Integration with @vctrl/hooks

The viewer is designed to be used alongside @vctrl/hooks. When you wrap your app with the ModelProvider context from @vctrl/hooks, the viewer can render with no explicit model prop:

import { ModelProvider } from '@vctrl/hooks/use-load-model'
import { VectrealViewer } from '@vctrl/viewer'
import '@vctrl/viewer/css'

function Scene() {
	return <VectrealViewer />
}

export default function App() {
	return (
		<ModelProvider>
			<Scene />
		</ModelProvider>
	)
}

Development

pnpm nx build vctrl/viewer
pnpm nx test vctrl/viewer
pnpm nx storybook vctrl/viewer

Notes

  • Grid configuration is not currently active in VectrealViewer render flow.

Related docs


Source

The full source and README live in packages/viewer.

License

AGPL-3.0-only. See LICENSE.md.