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

@plasius/gpu-shared

v1.3.0

Published

Shared browser-safe demo runtime and asset helpers for the Plasius gpu-* package family.

Readme

@plasius/gpu-shared

npm version Build Status coverage License Code of Conduct Security Policy Changelog

Build browser scenes from generated geometry or your own glTF/GLB assets. Use gpu-shared to load materials, fit meshes into a studio, or add camera gestures and progressive inspection to an authored scene. @plasius/gpu-renderer supplies the WebGPU rendering; no Plasius website, account or service is required.

The shared helpers prepare assets, materials and camera interaction, while the renderer owns path tracing, accumulation and GPU resources. This separation lets you compose a scene in JavaScript or TypeScript with explicit rendering controls.

Apache-2.0 · ESM and CommonJS · TypeScript declarations included.

Install

npm install @plasius/gpu-shared @plasius/gpu-renderer

Use a browser bundler, such as the one in your existing application, and serve it over HTTPS or localhost in a WebGPU-capable browser. The renderer is an optional peer of gpu-shared (compatible range ^0.2.49) and is needed for this example. Installing the packages in Node does not provide a browser GPU.

Create a scene: a material gallery

Make three faceted sculptures with different finishes: rough terracotta, polished copper and blue ceramic. Generate the geometry locally, then let gpu-shared fit it into a lit studio. No downloaded models or site assets are needed.

Add a container and a live status message to your page:

<div id="gallery" style="max-width:960px"></div>
<p id="status" role="status">Preparing the material gallery…</p>

Run this complete JavaScript module through your bundler. It creates a tiny glTF asset in memory and passes its URL to the shared scene runtime:

import { mountGpuProductStudio } from "@plasius/gpu-shared";

// One octahedron, reused by three independently positioned nodes.
const positions = new Float32Array([
  0, 1.6, 0, 0, 0, 0,
  -0.5, 0.8, 0, 0, 0.8, 0.5, 0.5, 0.8, 0, 0, 0.8, -0.5,
]);
const indices = new Uint16Array([
  0, 2, 3, 0, 3, 4, 0, 4, 5, 0, 5, 2,
  1, 3, 2, 1, 4, 3, 1, 5, 4, 1, 2, 5,
]);
const bytes = new Uint8Array(positions.byteLength + indices.byteLength);
bytes.set(new Uint8Array(positions.buffer));
bytes.set(new Uint8Array(indices.buffer), positions.byteLength);
const finishes = [
  { name: "Terracotta", color: [0.6, 0.16, 0.07, 1], roughness: 0.85, metallic: 0 },
  { name: "Copper", color: [0.95, 0.64, 0.54, 1], roughness: 0.22, metallic: 1 },
  { name: "Ceramic", color: [0.04, 0.22, 0.48, 1], roughness: 0.32, metallic: 0 },
];
const gltf = {
  asset: { version: "2.0" }, scene: 0,
  scenes: [{ name: "Material gallery", nodes: [0, 1, 2] }],
  nodes: finishes.map((finish, i) => ({
    name: finish.name, mesh: i, translation: [(i - 1) * 1.1, 0, 0],
  })),
  meshes: finishes.map((_, material) => ({
    primitives: [{ attributes: { POSITION: 0 }, indices: 1, material }],
  })),
  materials: finishes.map(finish => ({
    name: finish.name,
    pbrMetallicRoughness: { baseColorFactor: finish.color,
      roughnessFactor: finish.roughness, metallicFactor: finish.metallic },
  })),
  buffers: [{ byteLength: bytes.length,
    uri: `data:application/octet-stream;base64,${btoa(String.fromCharCode(...bytes))}` }],
  bufferViews: [
    { buffer: 0, byteOffset: 0, byteLength: positions.byteLength },
    { buffer: 0, byteOffset: positions.byteLength, byteLength: indices.byteLength },
  ],
  accessors: [
    { bufferView: 0, componentType: 5126, count: 6, type: "VEC3",
      min: [-0.5, 0, -0.5], max: [0.5, 1.6, 0.5] },
    { bufferView: 1, componentType: 5123, count: 24, type: "SCALAR" },
  ],
};

const root = document.querySelector("#gallery");
const status = document.querySelector("#status");
if (!(root instanceof HTMLElement) || !status) {
  throw new Error("Add the gallery and status markup first.");
}
const assetUrl = URL.createObjectURL(new Blob([JSON.stringify(gltf)], {
  type: "model/gltf+json",
}));
/** @type {Awaited<ReturnType<typeof mountGpuProductStudio>> | undefined} */
let gallery;
try {
  gallery = await mountGpuProductStudio({
    root, productAssetUrl: assetUrl,
    width: 640, height: 360, samplesPerPixel: 64, maxDepth: 4, denoise: true,
  });
  gallery.canvas.setAttribute("role", "img");
  gallery.canvas.setAttribute("aria-label",
    "Three faceted sculptures: terracotta, copper and blue ceramic, in a lit studio");
  status.textContent = "Gallery submitted. The image appears when the GPU finishes.";
} catch (error) {
  dispose();
  root.replaceChildren();
  status.textContent = error instanceof Error ? error.message : "Unable to render the gallery.";
} finally {
  URL.revokeObjectURL(assetUrl);
}

// Call this when leaving the page or unmounting the component.
export function dispose() {
  gallery?.destroy();
  gallery = undefined;
}

You authored the geometry, layout and materials. mountGpuProductStudio loads that glTF, applies its node transforms and material factors, fits the complete model, adds a floor, two walls and an emissive light, and delegates rendering to @plasius/gpu-renderer. Despite the API's name, it accepts your own scene; the provided URL prevents the default product asset from being loaded.

This entry submits one bounded render with a fixed studio camera. It does not attach camera controls or progressively refine. Its promise resolves after submission, so the status deliberately does not claim GPU completion. The Blob URL is released after loading, and dispose() releases the scene when unmounted. For larger scenes, export a glTF/GLB file instead of building a base64 buffer in JavaScript. The small in-memory geometry above is just a self-contained starting point. Normals are omitted to use flat facets.

Adopt the glTF adapter

Existing loadGltfModel(url) calls keep their compatibility behaviour. Pass the host's remotely evaluated gpu.model.conversion.enabled decision as conversionEnabled to use the lazy @plasius/gpu-model-gltf importer. The adapter validates JSON/GLB and nested resources; the shared renderer projection preserves source coordinates, materials, textures and physics. timeoutMs and maxInputBytes can tighten its 30-second deadline and 16 MiB entry ceiling.

The showcase and Product Studio consume the same decision from their existing feature-flag snapshot. Their gltfLoadOptions option forwards cancellation, integrity and tighter budgets; the remote snapshot owns the conversion decision. Disabling the remote flag selects the existing loader on the next load. There is no persistent conversion cache; each load reacquires external resource revisions.

Adapter results expose importProfile: "gltf-static-resources-v1". Explicitly unsupported features such as WebP retain the bounded compatibility projection and report importProfile: "legacy" with compatibilityReason. The existing approved brigantine network fallback also reports its reason. Malformed input, validation, byte budgets, cancellation and integrity failures never downgrade to another scene. An integrity manifest must list every external resource; embedded normalized resources retain the admitted source identity.

See the migration contract for limits, source/canonical coordinate differences, fallback and release guidance.

Make the scene yours

| Change | Where to edit | | --- | --- | | Sculpture shape | positions and indices; update accessor counts, bounds and buffer offsets if the geometry size changes | | Placement or scale | glTF nodes: translation, rotation (quaternion) and scale; the studio fits the complete group | | Colour and finish | finishes: RGB values are linear; roughness runs from smooth 0 to rough 1, metallic from dielectric 0 to metal 1 | | Image quality | samplesPerPixel, maxDepth, denoise, width and height; retain the studio's 16:9 presentation ratio | | Your own environment and interactive camera | Use the inspection entry, which does not add the studio environment |

To use an authored scene, replace assetUrl with new URL("/models/my-scene.glb", location.href) and omit the geometry/Blob creation. Serve your model at that URL and keep any external buffers/textures beside it. The loader decodes glTF/GLB, shares authored materials within each load, and honours EXT_texture_webp sources. The mesh adapter carries UVs and supported material maps/factors to the renderer. Source licences and attribution remain your responsibility.

You can also reuse loading and mesh conversion independently:

import { loadGltfModel, createProductStudioMeshes } from "@plasius/gpu-shared";

const controller = new AbortController();
const modelUrl = new URL("/models/my-scene.glb", location.href);
const model = await loadGltfModel(modelUrl, { signal: controller.signal });
const studioMeshes = createProductStudioMeshes(model, {
  targetCenter: [0, 0.85, 0], targetSize: 3.2,
});

createProductStudioMeshes fits the longest model dimension to targetSize and includes the four studio environment meshes. loadGltfModel(url, options?) accepts an optional AbortSignal and integrity map from absolute resource URLs to browser Subresource Integrity digests. Supply a digest for the model and every external buffer/image; an unlisted resource is rejected before its request. The same signal and each declared digest reach the corresponding fetch. Call controller.abort() to cancel acquisition. This does not interrupt synchronous mesh processing or image decoding already underway.

One-argument calls retain the existing showcase fallback. Aborted loads and loads with an integrity manifest never substitute the inline showcase model. ESM and CommonJS exports apply the same policy. See the request policy for a manifest example and the inspection entry's separate lifecycle controls.

Add interaction and explore other features

  • Camera and progressive refinement: inspect your own scene
  • Several models together: arrange a composite study with explicit placement, shared lighting and one progressive camera using createSceneInspection. with mouse, touch and keyboard controls, SHA-256 asset verification, samples, bounces, denoising and native render sizes up to 3840 × 2160. The shared runtime refines while the camera is still; your application supplies UI and handles visibility and cleanup. It currently renders static poses with fixed-SPP batches.
  • Material ageing: the isolated material study demonstrates varnish wear and rope fraying on its supplied crate. These effects are specific to that study, not automatically applied to arbitrary models.
  • Voxel assets, animation, translations and ready-made scenes: see the integration guide. The harbour remains available through mountGpuShowcase; it is a separate prebuilt example. PVOX loading needs the optional @plasius/gpu-model-voxel peer.
  • Structured diagnostics: validate consented diagnostic packets before passing them to your application's delivery service.

Import @plasius/gpu-shared/model-inspection or @plasius/gpu-shared/material-study only when their view is needed. Hosts own access policy, visible errors and resource disposal. The package consumes caller-supplied decisions; it does not connect to Plasius account or feature services.

Public declarations: root helpers, inspection, material study.

Development

For checkout setup and required validation, start with the development guide.

npm run demo also requires Python 3. It serves the parent directory; with the checkout named gpu-shared, open http://localhost:8000/gpu-shared/demo/. See contributing and release operations.

Release integrity

CI keeps the administrative contributor registry outside Git and npm package artifacts using exact, case-normalised path checks. CI validates repository-owned branch pushes on explicit [self-hosted, Linux, X64] runners. Pull-request and pull_request_target events do not execute CI code. Maintainers review fork contributions before moving accepted commits to repository-owned branches. Release preparation and publication use a two-run exact-main protocol on GitHub-hosted Node.js 24.18.0 LTS. A read-only job seals the package tarball and SBOM before a dependency-free production job publishes that exact artifact through npm OIDC with provenance; there is no npm write-token fallback. Production publication remains gated by the npm trusted-publisher binding and the protected-branch-only GitHub production environment.