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/hooks

v0.23.0

Published

vctrl/hooks is a React hooks package designed to simplify 3D model loading and management within React applications. It's part of the vectreal-core ecosystem and is primarily used in the vctrl/viewer React component and the official website application.

Readme

@vctrl/hooks

NPM Downloads

Browser-side React hooks for loading, optimizing, and exporting 3D models. The runtime counterpart to @vctrl/core, built for React apps that need to handle 3D files directly in the browser.


Installation

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

Hooks overview

| Hook | Import path | Description | | ------------------ | --------------------------------- | ------------------------------------------------------------------------------- | | useLoadModel | @vctrl/hooks/use-load-model | Load and parse GLTF, GLB, and USDZ files from file lists or dropped directories | | useOptimizeModel | @vctrl/hooks/use-optimize-model | Run glTF-Transform optimizations on loaded models | | useExportModel | @vctrl/hooks/use-export-model | Export the current scene to GLB or glTF |


useLoadModel

Loads 3D files and exposes the parsed Three.js Object3D scene.

import { ModelProvider, useLoadModel } from '@vctrl/hooks/use-load-model'

function Uploader() {
	const { load, file, isFileLoading } = useLoadModel()

	const handleDrop = (e: React.DragEvent) => {
		e.preventDefault()
		void load(Array.from(e.dataTransfer.files))
	}

	if (isFileLoading) return <p>Loading...</p>
	if (file?.model) return <p>Model loaded: {file.name}</p>

	return (
		<div onDrop={handleDrop} onDragOver={(e) => e.preventDefault()}>
			Drop a file
		</div>
	)
}

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

Context and direct usage

useLoadModel can be used in two ways:

  1. Context mode: wrap your app with ModelProvider, then consume with useModelContext() anywhere in that tree.
  2. Direct mode: call useLoadModel() outside a provider to manage a local model state.

Return values

| Value | Type | Description | | -------------------------- | ------------------------------------ | ----------------------------------------------------------- | | file | ModelFile \| null | Loaded file metadata and Three.js model | | isFileLoading | boolean | True while loading and parsing | | progress | number | Progress value from 0 to 100 | | load(filesOrDirectories) | Promise<void> | Load files or dropped FileSystemDirectoryHandle entries | | loadFromData(options) | Promise<SceneLoadResult> | Load already-resolved server scene payload | | loadFromServer(options) | Promise<SceneLoadResult> | Fetch and load scene from an API endpoint | | reset | () => void | Clear the current model | | on / off | Event helpers | Subscribe and unsubscribe to loader lifecycle events | | optimizer | OptimizerIntegrationReturn \| null | Populated when the hook is called with useOptimizeModel() |

useLoadModel events

on and off support these typed events:

| Event | Payload | | ---------------------- | ------------------- | | multiple-models | File[] | | not-loaded-files | File[] | | load-start | null | | load-progress | number | | load-complete | ModelFile \| null | | load-reset | null | | load-error | Error \| unknown | | server-load-start | string | | server-load-complete | SceneLoadResult | | server-load-error | Error \| unknown |

Scene loading option types

loadFromServer(options) uses:

| Field | Type | Description | | --------------- | --------------- | --------------------------------------------- | | sceneId | string | Scene identifier to fetch | | serverOptions | ServerOptions | Endpoint, auth, and header configuration | | applySettings | boolean | Whether scene settings are applied after load |

loadFromData(options) uses:

| Field | Type | Description | | --------------- | --------------------- | -------------------------------------------------------------- | | sceneId | string \| undefined | Optional scene identifier | | sceneData | ServerSceneData | Already-resolved payload containing glTF, settings, and assets | | applySettings | boolean | Whether scene settings are applied after load |


useOptimizeModel

Runs mesh simplification, deduplication, quantization, and normals optimization using glTF-Transform — geometry passes run in a Web Worker. Texture compression runs in the main thread via browser-native OffscreenCanvas encoding.

import { useOptimizeModel } from '@vctrl/hooks/use-optimize-model'
import { useLoadModel } from '@vctrl/hooks/use-load-model'

function Optimizer() {
	const optimizer = useOptimizeModel()
	const { file, optimizer: integrated } = useLoadModel(optimizer)

	const handleOptimize = async () => {
		if (!file?.model || !integrated) return
		await integrated.applyOptimization(integrated.simplifyOptimization, {
			ratio: 0.6,
			error: 0.001
		})
	}

	return (
		<button onClick={handleOptimize} disabled={optimizer.loading}>
			{optimizer.loading ? 'Optimizing...' : 'Optimize model'}
		</button>
	)
}

Key API surface

| Method / State | Type | Description | | ------------------------------------ | ------------------------------------------------------------------ | ---------------------------------------------------------------------- | | load(model) | (model: Object3D) => Promise<void> | Load a Three.js scene into the optimizer | | loadFromServerSceneData(sceneData) | Promise<void> | Initialize optimizer from a server scene payload | | applyOptimization(fn, opts?) | <T>(fn?: (opts?: T) => Promise<void>, opts?: T) => Promise<void> | Apply optimization and sync the optimized model back into loader state | | simplifyOptimization(options?) | Promise<void> | Simplify mesh geometry | | dedupOptimization(options?) | Promise<void> | Deduplicate model data | | quantizeOptimization(options?) | Promise<void> | Quantize vertex attributes | | normalsOptimization(options?) | Promise<void> | Recompute or normalize normals | | texturesOptimization(options?) | Promise<void> | Run texture compression flow | | getModel() | Promise<Uint8Array \| null> | Export the current optimized model as GLB binary | | report / info | Objects | Optimization metrics and derived stats | | loading / error | State | Optimization status |

Optimization option types

useOptimizeModel methods map directly to @vctrl/core/model-optimizer option types:

| Method | Option fields | | ---------------------- | ------------------------------------------------------------------------------------------------------------- | | simplifyOptimization | ratio?: number, error?: number | | dedupOptimization | textures?: boolean, materials?: boolean, meshes?: boolean, accessors?: boolean | | quantizeOptimization | quantizePosition?: number, quantizeNormal?: number, quantizeColor?: number, quantizeTexcoord?: number | | normalsOptimization | overwrite?: boolean | | texturesOptimization | resize?: [number, number], targetFormat?: 'webp' \| 'jpeg' \| 'png', quality?: number |

Texture compression runs browser-native via OffscreenCanvas. No server call is made.


useExportModel

Exports the current scene from ModelProvider context to a downloadable file.

import { useExportModel } from '@vctrl/hooks/use-export-model'
import type { ModelFile } from '@vctrl/hooks/use-load-model'

function ExportButton({ file }: { file: ModelFile | null }) {
	const { handleThreeGltfExport } = useExportModel()

	return (
		<button onClick={() => void handleThreeGltfExport(file, true)}>
			Download GLB
		</button>
	)
}

Methods

| Method | Description | | -------------------------------------------------------------- | ------------------------------------------------------------------- | | handleThreeGltfExport(file, binary) | Export a loaded Three.js model to .glb or a zipped .gltf bundle | | handleDocumentGltfExport(document, file, binary?, download?) | Export from a glTF-Transform Document |

binary = true writes .glb; binary = false writes a zipped .gltf package.


Additional exports

  • reconstructGltfFiles from @vctrl/hooks
  • ModelProvider and useModelContext from @vctrl/hooks/use-load-model
  • Shared types such as ModelFile, SceneLoadResult, and ServerSceneData

Peer dependencies

| Package | Version | | -------------------- | -------------- | | react | ^18 \|\| ^19 | | three | ^0.170 | | @react-three/fiber | ^9 |


Related docs


Source

The full source and README live in packages/hooks.

License

AGPL-3.0-only. See LICENSE.md.