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

@contensu/directus-extension-model-viewer-interface

v1.0.1

Published

A Directus interface that renders 3D model files (glTF/GLB, STL, OBJ, PLY) from a file field in an interactive three.js viewer with orbit controls.

Readme

@contensu/directus-extension-model-viewer-interface

A Directus interface for file fields that renders 3D model files in an interactive three.js viewer.

A textured GLB rendered in the field, with the toolbar, ground shadow, grid, and model info panel

Install

Open Settings → Marketplace in Directus, search for @contensu/directus-extension-model-viewer-interface, and press Install. Directus unpacks the extension and reloads on its own — no restart required.

If a self-hosted instance refuses the install, it is running the default MARKETPLACE_TRUST=sandbox; set MARKETPLACE_TRUST=all to allow it.

Then create or edit a field and pick 3D Model Viewer under Interface.

Supported formats

| Format | Loader | Notes | | --- | --- | --- | | .glb | GLTFLoader | Full support: materials, textures, scenes, animations | | .gltf | GLTFLoader | Self-contained files only (embedded buffers/textures) — external .bin and texture references cannot be resolved from a single Directus asset | | .stl | STLLoader | Rendered with the configured model colour | | .obj | OBJLoader | Geometry only; .mtl materials are not fetched | | .ply | PLYLoader | Vertex colours respected when present |

Compression: EXT_meshopt_compression works out of the box (the decoder is bundled). Draco needs a decoder path — set Draco Decoder Path (e.g. https://www.gstatic.com/draco/versioned/decoders/1.5.7/); the viewer says so explicitly when it meets a Draco file without one. KTX2/Basis textures are not supported.

A file whose extension lies is still detected correctly — the binary glTF magic number wins over the name.

Features

Camera — orbit with damping, seven view presets (isometric, front, back, left, right, top, bottom), perspective or orthographic projection, configurable field of view, auto-framing that fits any model regardless of size or origin, and a one-key reset.

Lighting — three environments: Studio (neutral product lighting), Daylight (sky/ground gradient), and Lights only. Intensity and tone-mapping exposure are adjustable, live, from the toolbar.

Display — wireframe, flat shading, ground grid, axes helper, bounding box, and a soft ground shadow, each toggleable at runtime.

Animation — glTF clips are detected automatically: play/pause, clip selector, scrubber, and a speed control. Optional auto-play.

Model info — meshes, triangles, vertices, materials, textures, bounding-box dimensions, animation count, file size, and detected format.

Output — full screen (button or F) and a one-click PNG screenshot of the current view, transparent where the background is.

Keyboard — F full screen, R reset view, Space play/pause the animation (or auto-rotate when there is none). Keys are ignored while a control is focused.

Performance — rendering stops entirely when the field scrolls out of view or the tab is hidden; the pixel ratio is capped at 2; WebGL context loss is reported rather than failing silently. Every geometry, material, texture, and the renderer itself are disposed on unmount.

In the editor

Every display setting is a live control, so editors can inspect a model without touching the field configuration.

The display options panel: wireframe, flat shading, grid, axes, shadow, bounding box, lighting, brightness, rotation speed, and projection

The same model in wireframe, showing mesh density

glTF animation clips are detected automatically and get a play/pause button, a clip selector, a scrubber, and a speed control.

An animated glTF playing, with the animation bar and three detected clips

Formats that carry no materials — STL, OBJ, PLY — are shaded with the configured model colour.

An STL rendered with the default model colour

Options

| Option | Default | Description | | --- | --- | --- | | Viewer Height | 420 px | Canvas height outside full screen | | Background Color | theme | Stage background; empty keeps the canvas transparent | | Lighting | studio | studio, sky (daylight), or none | | Lighting Intensity | 0.9 | Environment map contribution | | Brightness | 0.85 | Tone-mapping exposure | | Model Color | #9aa7bd | Applied to STL, OBJ, and PLY, which carry no materials | | Projection | perspective | perspective or orthographic | | Initial View | iso | Camera preset applied on load | | Field of View | 45 | Perspective only | | Rotation Speed | 1.5 | Auto-rotate speed | | Auto Rotate | true | Slowly orbit the model | | Ground Shadow | true | Soft shadow under the model | | Ground Grid | false | Grid at the model's base | | Axes Helper | false | Red X, green Y, blue Z | | Bounding Box | false | Wireframe box around the extents | | Wireframe | false | Render edges only | | Flat Shading | false | Facets instead of smoothed normals | | Show Model Info | false | Opens the statistics panel by default | | Enable Full Screen | true | Full-screen button and F | | Enable Screenshot | true | PNG export button | | Auto-play Animations | true | Start the first clip on load | | Draco Decoder Path | — | Required only for Draco-compressed glTF; a trailing slash is added if missing |

Every display option is also a live toolbar control, so editors can change the view without touching the field configuration.

CSP note: Directus's default Content-Security-Policy allows blob: URLs in img-src but not in connect-src. three.js's preferred ImageBitmapLoader fetches embedded glTF textures from blob: URLs, which that CSP silently blocks — models would render untextured white. This extension therefore forces GLTFLoader onto the <img>-based TextureLoader path, which works under the default CSP with no server configuration.

Versions

Every dependency is pinned to an exact version — no ^ ranges. Two of them are load-bearing:

  • vue must match the copy @directus/extensions-sdk resolves internally (3.5.24 for SDK 18.0.2). A caret lets a newer vue in alongside it, and vue-tsc then compares component types across the two instances and crashes mid-elaboration instead of reporting an error. pnpm why vue must say Found 1 version.
  • typescript stays on 5.x — vue-tsc 3.x cannot drive TS 6 (internal tsc crash) or TS 7 (no ./lib/tsc export). The extension build itself uses esbuild and does not care; only pnpm typecheck does.

The directus:extension.host field is deliberately still a range: it declares which Directus versions this extension supports, not a dependency to install.

Development

A Docker Compose stack runs the extension inside a real Directus while you build it:

pnpm install
pnpm dev            # rebuilds dist/ on every save
docker compose up   # http://localhost:8055 — [email protected] / d1r3ctu5

dist/ and package.json are mounted into the container's extensions folder and EXTENSIONS_AUTO_RELOAD is on, so saving a file rebuilds the bundle and Directus reloads it — refresh the browser to see the change.

Then create a field using the 3D Model Viewer interface to try it out.

pnpm typecheck      # vue-tsc
pnpm validate       # directus-extension validate
pnpm test           # vitest

CI & Releases

Every push runs typecheck, build, and extension validation via GitHub Actions. Releases are published to npm manually:

pnpm build
npm publish --access public

Contributing

Pull requests are welcome. Please open an issue first to discuss what you would like to change.


License

MIT © Contensu