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

@bitruvius/render-runtime

v0.3.1

Published

Bitruvius SDK WebGL2 render runtime: GL context, programs, buffers, data textures, blend and depth presets, splat depth sorting, and the shadow, clip and drape contracts every Bitruvius renderer shares

Downloads

354

Readme

@bitruvius/render-runtime

The WebGL2 layer every Bitruvius renderer stands on, so that none of them has to stand on another.

Internal building block. This package exists so that @bitruvius/sdk-maplibre and the Bitruvius codecs can resolve their dependencies on npm. It has no standalone product story. Unless you are deliberately building against it, install the SDK instead.

Why it is a separate package

Bitruvius ships several renderers: mesh, point cloud, Gaussian splat, point symbol and terrain. They are separate packages on purpose, because a map that draws only LiDAR should not pull in a splat renderer.

But the interesting features cut across all of them. One sun casts into one shadow atlas that a mesh, a point cloud and a splat cloud all write into and read back. One slice plane cuts every dataset at exactly the same place. One vector drape composites over every surface in the scene. Those features only work if the renderers agree, to the sign bit, on the state they share.

If that shared state lived in any one renderer, the others would have to depend on it, and rendering a point cloud would drag in the mesh renderer. So it lives here instead, in the common leaf below all of them, and the renderers stay independent of each other.

The rule holds throughout the package. The shadow coordinator stays in @bitruvius/mesh; only the contract every caster implements lives here. The clip test is a single GLSL string that mesh (fragment discard), points and splats (vertex cull) all interpolate into their shaders, so a slice plane cannot drift between datasets. The drape contract sits here so the MapLibre-side coordinator that produces the atlas never has to know about renderers, and the renderers never have to know about MapLibre.

Every shared block is also off by default and a strict no-op when off. Uniform defaults of zero disable clipping, shadows and draping, so a program that never touches them renders byte-identically.

What is in it

GL plumbing. getWebGL2 for standalone viewers that do not already own a context, compileShader / createProgram / uniformLocations (compile and link failures arrive as the GL info log, not a silent black screen), createBuffer and updateBuffer, and createDataTexture with texDimsFor for the integer data textures that splats read with texelFetch.

const gl = getWebGL2(canvas, { antialias: false, premultipliedAlpha: true });
const prog = createProgram(gl, vertexSrc, fragmentSrc);
const u = uniformLocations(gl, prog, ['uMVP'] as const);

Blend and depth presets. setPremultipliedBlend, disableBlend, setSplatDepthState (depth test on, depth write off, because sorted transparent splats would otherwise corrupt each other) and setOpaqueDepthState. Viewer adapters call these and then restore the host's expected state.

Splat depth sort. radixSortIndices and cameraSpaceZ, the pure core of the back-to-front ordering splats need for correct premultiplied "over" blending. A comparison sort is too slow at millions of splats, so this is a stable O(n) LSD radix sort; the f32 keys are reinterpreted as order-preserving unsigned ints so a single unsigned pass handles negative depths correctly. Runs off the main thread in the splat worker.

const depth = cameraSpaceZ(positions, count, viewModel);
const drawOrder = radixSortIndices(depth); // ascending z = back-to-front

Shared shadow contract. SharedShadow (one cascade atlas plus its matrices) and ShadowCastRenderer, discriminated into MeshShadowCaster (triangle VAOs drawn with the coordinator's depth program) and FootprintShadowCaster (points and splats drawn as depth discs with their own). The GLSL comes with it: FOOTPRINT_SIZE_GLSL, ROUND_POINT_DEPTH_FRAG, SAMPLE_SUN_SHADOW_GLSL and a cheaper one-tap variant for high-overdraw receivers.

Shared clip state. ClipState, clipStateFromPlanes, MAX_CLIP_PLANES and bindClipUniforms, with CLIP_UNIFORMS_GLSL and CLIP_TEST_GLSL as the one copy of the plane test. Planes arrive already resolved into the renderer's anchor-ENU frame in metres; converting from geographic coordinates is the layer's job.

Shared drape contract. SharedDrape, DrapeReceiver, bindDrapeUniforms and DRAPE_UNIFORMS_GLSL / DRAPE_BLEND_GLSL, the single premultiplied over-blend that keeps a draped road looking the same on a mesh, a point cloud and a splat.

Debug. Tiles3DBoundsRenderer, a small line renderer for tile bounding volumes, shared by the mesh, splat and point-cloud tile layers for the same reason as everything else here.

Who should depend on it

Almost nobody directly. @bitruvius/mesh, @bitruvius/ptcloud, @bitruvius/splats, @bitruvius/point-symbols, @bitruvius/raster and @bitruvius/sdk-maplibre depend on it, and installing the SDK brings it along.

Take a direct dependency only if you are writing your own renderer that has to join the shared passes: implement ShadowCastRenderer to cast into the same atlas, include the clip and drape GLSL so your geometry slices and drapes with everyone else's, and use the GL helpers so your programs report failures the same way.

npm i @bitruvius/render-runtime

Requires WebGL2. The math (sort, texture sizing, clip test) is unit-tested under bun test; the thin GL glue is exercised by the SDK examples.

Trademarks

Cesium and 3D Tiles are trademarks of Cesium GS, Inc. MapLibre is a trademark of the MapLibre organization. All other marks are the property of their respective owners.

These names are used solely to describe the data formats this software interoperates with. Bitruvius is not affiliated with, sponsored by, or endorsed by any of them, and no such relationship is implied.

License

Proprietary. The full terms ship as LICENSE inside this package, and are readable before installing at cdn.bitruvius.com/legal/sdk-license-v1.txt.

© Bitruvius, Inc.