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 🙏

© 2025 – Pkg Stats / Ryan Hefner

poppygl

v0.0.17

Published

Render GLTF files to PNG images in completely native JavaScript without WebGL/OpenGL.

Readme

poppygl

Render GLTF files to PNG images in completely native JavaScript without WebGL/OpenGL.

Quick start

Give poppygl a .gltf or .glb URL and it will fetch every referenced buffer/texture, rasterize the scene, and hand back a PNG buffer.

import { renderGLTFToPNGBufferFromURL } from "poppygl"
import { writeFile } from "node:fs/promises"

const png = await renderGLTFToPNGBufferFromURL(
  "https://models.babylonjs.com/DamagedHelmet.glb",
  {
    width: 800,
    height: 600,
    ambient: 0.15,
  },
)

await writeFile("DamagedHelmet.png", png)

The fetch helper relies on the global fetch API (present in Node 18+ and modern browsers). Pass a custom fetchImpl if you need different transport or caching behaviour.

Render from an in-memory GLB buffer

Already have the .glb bytes (for example, uploaded by a user or read from disk)? Send the buffer straight to renderGLTFToPNGBufferFromGLBBuffer and receive the PNG output.

import { readFile } from "node:fs/promises"
import { renderGLTFToPNGBufferFromGLBBuffer } from "poppygl"

const glb = await readFile("DamagedHelmet.glb")
const png = await renderGLTFToPNGBufferFromGLBBuffer(glb, {
  width: 1024,
  height: 768,
})

// write or return the PNG buffer

This helper expects every referenced buffer/image to be embedded in the GLB (the usual single-file package). If the asset links out to external resources, load it with renderGLTFToPNGBufferFromURL instead so poppygl can fetch the extras.

Render options

renderGLTFToPNGBufferFromURL accepts the same render options as the lower-level APIs:

  • width/height (default 512): output resolution in pixels.
  • fov: vertical field of view in degrees (defaults to 35).
  • camPos and lookAt: override the auto-framed camera position and target.
  • lightDir: normalized directional light vector (defaults to a top-right key light).
  • ambient: ambient lighting contribution (0–1, defaults to 0.2).
  • gamma: gamma correction applied to the output (defaults to 2.2).
  • cull: back-face culling mode ("back", "front", or "none").
  • fetchImpl: optional override for resource loading (must match the fetch signature).

You can inspect the defaults via getDefaultRenderOptions() or reuse the internal merge logic with resolveRenderOptions().

If you already have the GLTF JSON

When the GLTF JSON object is already in memory (for example, bundled with your app), skip the network loader and supply resources directly:

import {
  bufferFromDataURI,
  createSceneFromGLTF,
  decodeImageFromBuffer,
  encodePNGToBuffer,
  pureImageFactory,
  renderSceneFromGLTF,
} from "poppygl"
import gltfJson from "./CesiumMan.gltf.json" assert { type: "json" }
import { readFile } from "node:fs/promises"

const base = new URL("./CesiumMan/", import.meta.url)

const buffers = await Promise.all(
  (gltfJson.buffers ?? []).map(async (entry) => {
    if (!entry.uri) throw new Error("Buffers without URIs need custom handling.")
    return entry.uri.startsWith("data:")
      ? bufferFromDataURI(entry.uri)
      : await readFile(new URL(entry.uri, base))
  }),
)

const images = await Promise.all(
  (gltfJson.images ?? []).map(async (img) => {
    if (!img.uri) throw new Error("Only URI-backed images are shown in this example.")
    const data = img.uri.startsWith("data:")
      ? bufferFromDataURI(img.uri)
      : await readFile(new URL(img.uri, base))
    return decodeImageFromBuffer(data, img.mimeType)
  }),
)

const scene = createSceneFromGLTF(gltfJson, { buffers, images })
const { bitmap } = renderSceneFromGLTF(scene, { width: 512, height: 512 }, pureImageFactory)
const png = await encodePNGToBuffer(bitmap)

The only contract is that buffers is an array of Uint8Array instances and images is an array of BitmapLike textures (PNG and JPEG are supported out of the box via decodeImageFromBuffer).

Additional utilities

  • loadGLTFWithResourcesFromURL returns { gltf, resources } if you prefer to inspect or cache the parsed data before rendering.
  • createSceneFromGLTF builds draw calls ready for the software rasterizer.
  • computeSmoothNormals and computeWorldAABB expose useful preprocessing helpers.
  • pureImageFactory allocates the pureimage bitmap implementation used by the renderer.
  • encodePNGToBuffer packs any BitmapLike into a PNG buffer that can be written to disk or served over the network.

Happy rendering!