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

wgpu.js

v0.1.0

Published

WebGPU compute in pure JS, for Node and Browser!

Readme

wgpu.js

WebGPU compute from plain JavaScript functions.

Write a function that computes one output element, and wgpu.js compiles it to WGSL, runs it across every element in parallel, and hands back a Float32Array. It is gpu.js in spirit, targeting WebGPU instead of WebGL.

import { GPU } from "wgpu.js";

const gpu = await GPU.create();

const add = gpu.createKernel(
  function (a, b) {
    return a[this.thread.x] + b[this.thread.x];
  },
  { output: [1_000_000] },
);

const result = await add(left, right); // Float32Array(1000000)

Status: MVP, browser only. The API will change. Node support is not built yet — it needs a decision on which WebGPU implementation to bind to. You can already use wgpu.js anywhere navigator.gpu exists, and you can hand it a device you created yourself via GPU.create({ device }).

Demos

Live at https://playforge-coding.github.io/wgpu.js/ (needs a browser with WebGPU):

  • Benchmarks — vector add, matrix multiply against a CPU reference, mandelbrot, kernel chaining
  • Game of Life — one kernel per generation, with the grid held on the GPU in between
  • Self test — the numerical end-to-end suite, run against your own GPU

Install

npm install wgpu.js

Why this is not a drop-in gpu.js replacement

  • Kernel calls are async. WebGPU reads results back asynchronously, so await kernel(...) instead of kernel(...).
  • Results are flat by default. A [width, height] kernel returns a single Float32Array in row-major order. Pass returnNested: true if you want gpu.js-style rows.
  • Graphics output is not implemented. There is no graphical: true mode; a kernel produces numbers, and you decide what to do with them.

Writing kernels

Inside a kernel you get:

| Expression | Meaning | | ------------------------------- | ------------------------------------------------ | | this.thread.x, .y, .z | Index of the element this invocation computes | | this.output.x, .y, .z | The kernel's output size | | this.constants.NAME | A value from the constants option | | a[i], a[y][x], a[z][y][x] | Array arguments, indexed by their dimensionality | | a.length | The outermost dimension of an array argument |

The return value becomes the output element for that thread.

Supported JavaScript

const / let / var, assignment and compound assignment, ++ / --, arithmetic and comparison operators, && / || / !, the ternary operator, if / else, for, while, do..while, break, continue, early return, and most of Math (sqrt, pow, min, max, sin, log10, cbrt, hypot, the Math.PI family, and so on).

Anything else is a compile-time error with the offending line quoted, rather than silently wrong output.

Not supported yet

Helper functions, arrays declared inside a kernel, bitwise operators, strings, objects, closures over outer scope, Math.random, and integer types. Every value is a 32-bit float.

Arguments

An argument can be:

| You pass | The kernel sees | | ------------------------------------------------------- | ---------------------------------------- | | number / boolean | a scalar (s) | | Float32Array, Int32Array, Uint32Array, number[] | a 1D array (a[i]) | | number[][] / Float32Array[] | a 2D array (a[y][x]) | | number[][][] | a 3D array (a[z][y][x]) | | { data, size: [w, h] } | a flat buffer treated as 2D or 3D | | the result of kernel.pipe(...) | a 1D/2D/3D array that never left the GPU |

A kernel compiles lazily, once per distinct argument shape, and caches the pipeline. Changing argument values, the output shape, or constant values costs nothing; changing dimensionality compiles a second variant.

Chaining kernels

kernel.pipe(...) runs the kernel but leaves the result in GPU memory, so it can feed the next kernel without a round trip:

const doubled = await double.pipe(input);
const result = await addOne(doubled); // input never came back to the CPU
doubled.destroy();

API

GPU.isSupported()

true when navigator.gpu exists.

await GPU.create(options?)

Requests an adapter and device. Options: device, powerPreference, requiredFeatures, requiredLimits, label.

gpu.createKernel(fn, settings?)

Settings:

| Option | Default | Meaning | | --------------- | -------- | ----------------------------------------------------------------------------- | | output | — | Output shape, [x], [x, y] or [x, y, z]. Required before the first call. | | constants | {} | Numbers exposed as this.constants.* | | returnNested | false | Reshape 2D/3D results into arrays of row views | | name | "main" | Entry point name, used in errors and debug output | | workgroupSize | 64 | Threads per workgroup | | debug | false | Log the generated WGSL when a variant compiles |

The returned kernel is callable and also has pipe(), setOutput(), setConstants(), compile(), destroy(), and a wgsl property holding the most recently generated shader.

gpu.destroy()

Destroys every kernel created by this instance and then the device.

transpile(input)

The JS → WGSL translator on its own, with no GPU involved. Useful for tests, tooling, or generating shaders ahead of time.

Notes and limits

  • Every value is f32. Indices are computed in floats too, except when you index directly by this.thread.*, which uses the integer thread id — so arrays larger than 2²⁴ elements are safe as long as you index them by thread.
  • 1D outputs larger than the per-dimension workgroup limit are dispatched across a 2D grid automatically; the self test covers 5,000,000 threads.
  • A kernel serialises its own calls, so Promise.all([k(a), k(b)]) is safe but will not overlap. Use separate kernels for real concurrency.
  • Math.round is emitted as floor(x + 0.5) to match JavaScript, which differs from WGSL's round-half-to-even.

Development

vp install
vp test           # unit tests for the transpiler (no GPU needed)
vp check          # format, lint, type check
vpr demo          # dev server on /examples/index.html
vpr life          # dev server on /examples/life.html
vpr selftest      # dev server on /examples/selftest.html

The pages are:

  • examples/index.html — vector add, matrix multiply vs CPU, mandelbrot, kernel chaining
  • examples/life.html — Conway's Game of Life, one kernel per generation, with the grid held on the GPU between generations
  • examples/selftest.html — numerical end-to-end checks against a real device, also readable headlessly from globalThis.__selftest

vp test runs everywhere; the pages above are how the GPU path gets verified, since Node has no WebGPU.

Releasing

.github/workflows/publish.yml publishes to npm with trusted publishing — OIDC, so no npm token is stored anywhere. It runs on a v* tag, gates on vp check and vp test, refuses to publish if the tag and package.json version disagree or the version already exists, checks the tarball contents, and attaches build provenance.

To cut a release:

vpr release      # bumpp: bumps the version, commits, tags and pushes

Prereleases (0.2.0-beta.1) go to the next dist-tag automatically, so they never take over latest.

One-time setup

  1. Publish 0.1.0 manually with a token. npm cannot configure a trusted publisher for a package that does not exist yet (npm/cli#8544), so the first version has to go up the old way. Revoke the token afterwards.
  2. On npmjs.com, go to the package → Settings → Trusted Publisher and enter the GitHub org/user, the repository, and the workflow filename publish.yml, then select npm publish under allowed actions.
  3. Every later release publishes with no credentials at all.

Two things to know if you change any of this:

  • The workflow filename is part of the npm configuration. Renaming publish.yml breaks publishing until npmjs.com is updated to match.
  • Trusted publishing does not work on self-hosted runners, and needs id-token: write plus Node ≥ 22.14. Publishing goes through pnpm publish rather than npm publish, because devEngines pins pnpm and npm refuses to run in that case; pnpm has supported OIDC properly since 11.1.3.

For an approval gate before a release goes out, add an environment: to the publish job and set the matching environment name on npmjs.com.

Publishing the demos

.github/workflows/deploy-demos.yml runs vp check and vp test, builds the demo site, and publishes it to GitHub Pages on every push to main. Pull requests build but do not deploy.

It needs Settings → Pages → Source = GitHub Actions enabled once on the repository. The base path is derived from the repository name, so forks deploy to their own URL without editing anything.

To build the site locally:

vpr build:demos          # -> dist-demos/
vp preview examples

Note that the deployed site is minified, and kernels reach wgpu.js through Function.prototype.toString. The transpiler handles the statement shapes minifiers produce (comma sequences, a && (x = 1), and conditionals used as statements) — see the minified source tests.

License

BSD-3-Clause