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

@needle-tools/usd

v1.1.2

Published

OpenUSD WebAssembly runtime and three.js Hydra render delegate — render real, composed USD stages (`.usd`, `.usda`, `.usdc`, `.usdz`) with MaterialX directly in the browser. The same technology powers the [Needle USD Viewer](https://usd-viewer.needle.tool

Readme

Needle USD

OpenUSD WebAssembly runtime and three.js Hydra render delegate — render real, composed USD stages (.usd, .usda, .usdc, .usdz) with MaterialX directly in the browser. The same technology powers the Needle USD Viewer and OpenUSD support on Needle Cloud.

📖 DocumentationOpenUSD & MaterialX with Needle

Developed & maintained by Needle.
For commercial use, please contact [email protected].

Features

Built on upstream OpenUSD 26.05 with Hydra imaging and MaterialX 1.39.5:

  • Composition — references, payloads, variants, and nested packages resolve exactly as they would in usdview.
  • Instancing — native instances and PointInstancer prims.
  • Visibility — prim visibility and purpose-based filtering (render, proxy, guide).
  • Cameras & lights — USD cameras and UsdLux lights.
  • Materials — UsdPreviewSurface and MaterialX via Hydra material documents, including environment lighting, real-time shadows, and vertex displacement.
  • Geometry — OpenSubdiv smooth subdivision surfaces and creases.
  • glTF-in-USD — Adobe usdGltf file format plugin loads glTF/GLB directly inside a USD stage, including Draco-compressed meshes.
  • CompressionusdDraco and usdGltfDraco compressed mesh payloads.

Install

npm install @needle-tools/[email protected] three

Runtime Requirements

This package ships a threaded Emscripten/OpenUSD wasm build. Browser pages that use it must be served in a cross-origin isolated context so SharedArrayBuffer and pthread workers are available:

res.setHeader("Cross-Origin-Embedder-Policy", "require-corp");
res.setHeader("Cross-Origin-Opener-Policy", "same-origin");

For Vite projects, use the package plugin to set these headers during local development:

import { needleUSD } from "@needle-tools/usd/vite";

export default {
  plugins: [needleUSD()],
};

The modern Emscripten output contains emHdBindings.js and emHdBindings.wasm. It does not ship a separate emHdBindings.worker.js; the pthread workers load the main generated JavaScript entrypoint directly.

Minimal Examples

All browser examples must be served with the COOP/COEP headers from "Runtime Requirements". The import-map examples use same-origin /vendor/... URLs so the threaded wasm worker can load the Emscripten JavaScript from the page origin; replace those URLs with your own served package paths.

Needle Engine With Package Install

package.json

{
  "type": "module",
  "scripts": {
    "dev": "vite --host 127.0.0.1"
  },
  "dependencies": {
    "@needle-tools/engine": "^5.1.2",
    "@needle-tools/usd": "1.1.1",
    "three": "npm:@needle-tools/three@^0.169.19",
    "vite": "^8.1.0"
  }
}

index.html

<!doctype html>
<html>
  <body style="margin:0">
    <script type="module">
      import "@needle-tools/engine";
      import { addPluginForNeedleEngine } from "@needle-tools/usd/plugins";

      await addPluginForNeedleEngine({
        // Needle Engine loadfinished waits for the initial Hydra draw and
        // asynchronous USD material generation, so engine auto-fit and screenshot
        // tools see a presentable scene.
        // Pass autoPlay: true when the host app should start USD timeline
        // playback automatically after loading.
        getFiles: () => []
      });

      document.body.insertAdjacentHTML(
        "beforeend",
        '<needle-engine src="./model.usdz" camera-controls contactshadows="0.7"></needle-engine>'
      );
    </script>
  </body>
</html>

Needle Engine With Import Map

index.html

<!doctype html>
<html>
  <body style="margin:0">
    <script type="importmap">
      {
        "imports": {
          "three": "/vendor/@needle-tools/engine/dist/three.min.js",
          "three/addons/": "/vendor/@needle-tools/three/examples/jsm/",
          "@needle-tools/engine": "/vendor/@needle-tools/engine/dist/needle-engine.min.js",
          "@needle-tools/materialx": "/vendor/@needle-tools/materialx/index.js",
          "@needle-tools/usd": "/vendor/@needle-tools/usd/src/index.js",
          "@needle-tools/usd/three": "/vendor/@needle-tools/usd/src/create.three.js",
          "@needle-tools/usd/plugins": "/vendor/@needle-tools/usd/src/plugins/index.js"
        }
      }
    </script>
    <script type="module">
      import "@needle-tools/engine";
      import { addPluginForNeedleEngine } from "@needle-tools/usd/plugins";

      await addPluginForNeedleEngine({
        // Needle Engine loadfinished waits for the initial Hydra draw and
        // asynchronous USD material generation, so engine auto-fit and screenshot
        // tools see a presentable scene.
        // Pass autoPlay: true when the host app should start USD timeline
        // playback automatically after loading.
        getFiles: () => []
      });

      document.body.insertAdjacentHTML(
        "beforeend",
        '<needle-engine src="./model.usdz" camera-controls contactshadows="0.7"></needle-engine>'
      );
    </script>
  </body>
</html>

For folder/drop workflows, return the active file set from getFiles(). The first file must be the root USD file, and each file should have a stable path property so USD references can resolve.

three.js With Package Install

package.json

{
  "type": "module",
  "scripts": {
    "dev": "vite --host 127.0.0.1"
  },
  "dependencies": {
    "@needle-tools/usd": "1.1.1",
    "three": "^0.185.0",
    "vite": "^8.1.0"
  }
}

index.html

<!doctype html>
<html>
  <body style="margin:0">
    <script type="module">
      import * as THREE from "three";
      import { getUsdModule } from "@needle-tools/usd";
      import { createThreeHydra } from "@needle-tools/usd/three";

      const scene = new THREE.Scene();
      const camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, 0.01, 1000);
      camera.position.set(0, 1.5, 4);

      const renderer = new THREE.WebGLRenderer({ antialias: true });
      renderer.setSize(innerWidth, innerHeight);
      document.body.append(renderer.domElement);

      const usd = await getUsdModule();
      const handle = await createThreeHydra({
        USD: usd,
        scene,
        url: "./model.usdz"
      });
      await handle.ready();

      let last = performance.now();
      renderer.setAnimationLoop((time) => {
        const dt = (time - last) / 1000;
        last = time;
        handle.update(dt);
        renderer.render(scene, camera);
      });
    </script>
  </body>
</html>

For Vite projects, add the needleUSD() plugin shown in "Runtime Requirements" so dev serving uses the required COOP/COEP headers.

three.js With Import Map

index.html

<!doctype html>
<html>
  <body style="margin:0">
    <script type="importmap">
      {
        "imports": {
          "three": "/vendor/three/build/three.module.js",
          "three/addons/": "/vendor/three/examples/jsm/",
          "@needle-tools/materialx": "/vendor/@needle-tools/materialx/index.js",
          "@needle-tools/usd": "/vendor/@needle-tools/usd/src/index.js",
          "@needle-tools/usd/three": "/vendor/@needle-tools/usd/src/create.three.js"
        }
      }
    </script>
    <script type="module">
      import * as THREE from "three";
      import { getUsdModule } from "@needle-tools/usd";
      import { createThreeHydra } from "@needle-tools/usd/three";

      const scene = new THREE.Scene();
      const camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, 0.01, 1000);
      camera.position.set(0, 1.5, 4);

      const renderer = new THREE.WebGLRenderer({ antialias: true });
      renderer.setSize(innerWidth, innerHeight);
      document.body.append(renderer.domElement);

      const usd = await getUsdModule();
      const handle = await createThreeHydra({
        USD: usd,
        scene,
        url: "./model.usdz"
      });
      await handle.ready();
      // By default ready() waits for the stage and first Hydra draw, but not for
      // async material generation. Pass waitForMaterials: true when correctness
      // requires a material/texture barrier, or await handle.materialsReady().

      let last = performance.now();
      renderer.setAnimationLoop((time) => {
        const dt = (time - last) / 1000;
        last = time;
        handle.update(dt);
        renderer.render(scene, camera);
      });
    </script>
  </body>
</html>

Public Entrypoints

import { getUsdModule, loadOpenUsdBuildInfo } from "@needle-tools/usd";
import { createThreeHydra } from "@needle-tools/usd/three";
import { addPluginForNeedleEngine } from "@needle-tools/usd/plugins";
import { needleUSD } from "@needle-tools/usd/vite";

Low Level Usage

Import

import { getUsdModule } from '@needle-tools/usd';

Load the Module

getUsdModule({
  // We need to override where the initial module is loaded from, 
  // since after bundling we can't rely on paths anymore
  mainScriptUrlOrBlob: "/emHdBindings.js",
}).then(async (Usd: USD) => {
    // use Usd here
});

Load a file into the virtual file system

const blob = await fetch("test.usdz");
const arrayBuffer = await blob.arrayBuffer();
// Create a file in the virtual file system
Usd.FS_createDataFile("", "test.usdz", new Uint8Array(arrayBuffer), true, true, true);

Load file into USD

let driver = new Usd.HdWebSyncDriver(delegate, "test.usdz");
if (driver instanceof Promise) driver = await driver;

// This kicks off asynchronous tasks to look at everything that has changed – _SyncAll –
// which will then call into the delegate to create and update the scene graph.
driver.Draw();

Useful References

Uses Asyncify to handle async calls in emscripten.

A synchronous call in C that waits for an asynchronous operation in JS to complete. https://emscripten.org/docs/porting/asyncify.html

Contact ✒️

For commercial use, please contact [email protected].

🌵 NeedleGithubTwitterDiscordForumYoutube