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

@gum-jsx/png

v2.0.0

Published

Gum fragment rasterization with tiny-skia WebAssembly.

Readme

@gum-jsx/png

Render completed Gum fragments directly to PNG or RGBA through tiny-skia WebAssembly. The fragment renderer works in Bun, Node, and browsers without native addons, install scripts, host fonts, or a Rust installation.

CLI PNG/kitty output, Markdown figures/math, and MCP rasterization use fragments directly. This branch has no SVG-string rasterizer or native canvas dependency.

See the Gum project for getting started and the package overview.

Fragment rendering

import { LayoutPass, Text, px } from '@gum-jsx/core'
import { render_png, render_pixels } from '@gum-jsx/png'

const fragment = new LayoutPass().layout(
  new Text({ children: 'Hello, tiny-skia!', font_size: px(32) }),
)
const png = render_png(fragment, { ratio: 2 }) // Uint8Array
const rgba = render_pixels(fragment) // { width, height, data: Uint8ClampedArray }
await Bun.write('hello.png', png)

The package root selects the portable renderer in browsers and never imports Node modules. To display the PNG, use new Blob([png], { type: 'image/png' }) and an object URL.

The WASM payload is embedded in the published JavaScript. It is decoded and compiled on the first render, then reused. There is no fetch or asset-loader configuration, and both APIs remain synchronous. Sites using CSP must permit WebAssembly compilation, for example with script-src 'wasm-unsafe-eval' in addition to their existing script policy.

| Option | Behavior | |---|---| | ratio | Positive sampling multiplier, default 1. Output dimensions are rounded up; geometry is scaled by exactly this ratio. | | select: { x, y, width, height } | Crop in fragment coordinates before sampling; areas outside the original viewport remain transparent or show the background. | | background | Solid CSS color behind the fragment, transparent by default. | | encoding | PNG only: 'fast' (default) or 'standard', using the Rust PNG encoder's fast or balanced compression. Both encode identical pixels. |

Supported drawing features include rectangles and individually rounded corners, ellipses, M/L/Q/C/Z paths, nonzero fills, dashed strokes, caps and joins, affine transforms, nested rectangular/rounded/path clips, PNG images, color alpha, and drawing opacity. Text and math are rendered from their existing glyph outlines. Fill and stroke are composited together before applying drawing opacity. Shared path and image data are transferred to WASM once per render.

The current implementation has these limits:

  • Live text and emoji without outlines throw a descriptive error. Use outlined text, or export SVG for a browser with suitable fonts.
  • Colors support CSS names, hex, numeric RGB/HSL, transparent, and none. CSS variables, currentColor, gradients, and other paint expressions throw.
  • Images use bilinear sampling and 8-bit premultiplied RGBA internally. PNG output and render_pixels return straight alpha. Higher-depth input is reduced to 8 bits; color profiles and gamma metadata are not applied.
  • Each output and embedded image is limited to 16,777,216 pixels; nested clip masks are limited to 128 MiB. Transparent fill/stroke composites currently allocate a temporary surface the size of the output.
  • Debug overlays and fragment labels are not drawn. Path coordinates enter tiny-skia as float32; exceptionally large coordinates can lose precision.

See WASM implementation and measurements for the initial performance results and remaining portability and performance work.

SVG input

The former rasterize_svg, rasterize_pixels, and /svg entry point have been removed. Pass a completed Gum Fragment to render_png or render_pixels. Live text and emoji without outlines are unsupported. Export those figures as SVG for a browser or another renderer with suitable fonts.

For cropped PNG or RGBA output, pass select to the fragment renderer. The RasterSelection type is exported from the package root.

PNG requires positive dimensions, even though SVG and layout inspection support zero-sized viewports. Invalid image data and nonpositive or nonfinite dimensions throw errors.

Runtime requirements

The WASM backend has been checked with Bun 1.4.2, Node 26.9.0, and Chromium on Linux x64. Node 22+ is the supported Node baseline; other OSes still need release verification. The module uses the portable wasm32-unknown-unknown target and does not require WASI or SIMD.

Development

After bun install at the workspace root, run these commands in this package:

bun run build        # JS and declarations, using the checked-in WASM artifact
bun run test
bun run typecheck
bun run test:visual  # Ten comparisons with saved raster reference images
bun run test:package # Clean npm install with scripts and native addons disabled
bun run test:browser # Serve a browser check at http://127.0.0.1:4193
bun run perf        # Workspace text and Silk Road benchmarks

npm pack runs the JS build through prepack; it does not compile Rust. Build first when packing with --ignore-scripts. The npm tarball contains built JS, declarations, documentation, and licenses.

To rebuild the WASM artifact, install Rust and its wasm32-unknown-unknown target, then run bun run build:wasm followed by bun run build. The initial artifact was built with Rust 1.98.1. wasm/Cargo.lock pins Rust dependencies; the build script also refreshes their license notices. Commit the generated src/generated/wasm.ts so ordinary development and installation need no Rust.