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

bbmodel-viewer

v0.1.1

Published

Render and view Blockbench .bbmodel files (cubes + meshes, textures, bones) in the browser with three.js.

Readme

bbmodel-viewer

Render and view Blockbench .bbmodel files in the browser with three.js. Drop a container element in, point it at a file (URL, File, or parsed object) and get an orbit-controlled 3D preview — cubes and meshes, per-face UVs, textures, and the full bone (outliner) hierarchy with correct pivots and rotations.

Built for exactly this kind of use case: previewing model files stored on a drive / CDN without opening Blockbench.

Features

  • ✅ Cube elements with per-face UVs, inflate, per-face UV rotation
  • ✅ Mesh (poly) elements (triangles + quads)
  • ✅ Embedded textures (data: sources) with crisp nearest-neighbour filtering
  • ✅ Full outliner hierarchy: groups/bones with pivots and ZYX Euler rotation
  • ✅ Transparent textures (alpha cutout)
  • ✅ Orbit / zoom / pan controls, optional auto-rotate and ground grid
  • ✅ Auto camera framing, container resize handling, clean dispose()
  • ✅ TypeScript types, ESM + CJS builds, three.js as a peer dependency

Install

npm install bbmodel-viewer three

three is a peer dependency (>=0.150.0) so your app controls the version.

Quick start

import { BBModelViewer } from "bbmodel-viewer";

const container = document.getElementById("viewer")!; // give it a size in CSS
const viewer = new BBModelViewer(container, {
  background: "#20232a",
  autoRotate: true,
});

await viewer.load("/models/creeper.bbmodel");

The container should have a non-zero size (e.g. width: 100%; height: 480px). The viewer fills it and follows resizes automatically.

From a file input or drag & drop (drive viewer)

input.addEventListener("change", (e) => {
  const file = (e.target as HTMLInputElement).files?.[0];
  if (file) viewer.loadFile(file);
});

From an already-parsed object

const data = await fetch(url).then((r) => r.json());
await viewer.loadModel(data);

Options

All options are optional.

| Option | Type | Default | Description | | ----------------------- | --------------------------- | -------------- | ------------------------------------------------------- | | background | string \| number \| null | "#20232a" | Scene background. null/"transparent" for see-through | | grid | boolean | true | Ground grid aligned to the model base | | controls | boolean | true | Orbit / zoom / pan | | autoRotate | boolean | false | Spin the model | | autoRotateSpeed | number | 1.0 | Spin speed | | fov | number | 45 | Camera field of view (degrees) | | ambientIntensity | number | 0.8 | Ambient light | | directionalIntensity | number | 0.55 | Key light | | doubleSided | boolean | true | Render both sides of every polygon | | alphaTest | number | 0.02 | Alpha cutoff for transparent texels | | showUntexturedFaces | boolean | false | Draw faces with no texture as flat color instead of hiding them | | antialias | boolean | true | MSAA | | pixelRatio | number | min(dpr, 2) | Device pixel ratio cap | | onLoad | (model, object) => void | — | Fires after a model is added to the scene | | onError | (error) => void | — | Fires on load/parse failure |

API

const viewer = new BBModelViewer(container, options);

await viewer.load(url, init?);   // fetch + render a .bbmodel URL
await viewer.loadFile(file);     // render a File/Blob
await viewer.loadModel(data);    // render a parsed bbmodel object
viewer.frameModel();             // re-frame the camera on the model
viewer.resize();                 // re-measure the container (also automatic)
viewer.clear();                  // remove the model + free GPU memory
viewer.dispose();                // tear everything down

// Escape hatches for advanced use:
viewer.scene;      // THREE.Scene
viewer.camera;     // THREE.PerspectiveCamera
viewer.renderer;   // THREE.WebGLRenderer
viewer.controls;   // OrbitControls | undefined

Lower-level building blocks

If you just want the geometry (e.g. to drop into your own scene):

import { MaterialLibrary, buildModelObject } from "bbmodel-viewer";

const materials = new MaterialLibrary(model, { alphaTest: 0.02, side: THREE.DoubleSide });
await materials.load();
const object3d = buildModelObject(model, materials); // THREE.Group
myScene.add(object3d);

Coordinate system & conventions

  • Units are Blockbench units (16 = one Minecraft block); the grid draws one cell per block.
  • Rotations use Euler order ZYX (matching Blockbench's Rz·Ry·Rx).
  • Per-face UVs are read as [u_min, v_min, u_max, v_max] in texture pixels and normalized by each texture's uv_width/uv_height (falling back to the project resolution).
  • Textures use NearestFilter and no mipmaps for pixel-perfect art.

Notes & limitations

  • Animations are not played yet (static pose only). The bone hierarchy is built, so this is a planned addition.
  • Untextured faces are hidden (treated as transparent), matching how they look in-game. Set showUntexturedFaces: true to draw them as flat color instead. Models with no textures at all are always drawn colored.
  • box_uv: files store computed per-face UVs, which are used directly; a best-effort standard unwrap is used only if a face's uv is missing.
  • Cross-origin textures/URLs need appropriate CORS headers when loaded from a remote drive.

Development

npm install
npm run build       # bundle to dist/ (ESM + CJS + d.ts)
npm run typecheck
npm run example     # serve examples/ with Vite

License

MIT