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

simple-compute-shaders

v0.3.1

Published

This library is a simplified wrapper around the WebGPU API, designed to make it easier to create and run compute shaders and simple 2D render shaders without dealing with the complex details of the WebGPU setup. It allows developers to initialize WebGPU,

Readme

Simple Compute Shaders

Installation

npm i simple-compute-shaders

Core Setup Pattern

// 1. Initialize once per app
await Shader.initialize();

// 2. Create buffers
const buffer = new StorageBuffer({
    dataType: "array<f32>",  // Required: specify WGSL type
    size: 1024,               // Required for arrays/textures
    initialValue: data,       // Optional: initial data
    canCopyDst: true,        // Optional: allow writing
    canCopySrc: true         // Optional: allow reading
});

// 3. Create shader with bindings
const shader = new ComputeShader({
    code: wgslCode,
    workgroupCount: [16, 1],  // 2D or 3D workgroup dispatch
    bindingLayouts: [{
        default: [
            {
                binding: buffer,
                name: "myBuffer",     // Name used in WGSL
                type: "storage"       // or "uniform", "read-only-storage"
            }
        ]
    }]
});

// 4. Execute
await buffer.write(data);
shader.dispatch();
const result = await buffer.read();

Buffer Types

Buffer Classes

  • StorageBuffer: Read/write data in shaders
  • UniformBuffer: Small constant data
  • IndirectBuffer: GPU-driven parameters

Supported Data Types

Primitives: u32, f32, i32 Vectors: vec2<T>, vec3<T>, vec4<T> where T is u32/f32/i32 Matrices: mat4x4<T> Arrays: array<T> (requires size parameter) Textures: texture_2d<T> (requires size parameter) Structs: Use dataType: "struct" with:

{
    structName: "MyStruct",
    fields: [
        { name: "field1", dataType: "f32" },
        { name: "field2", dataType: "vec3<f32>" }
    ]
}

Shader Types

ComputeShader

new ComputeShader({
    code: string,                    // WGSL with @compute fn main()
    workgroupCount: [x, y] | [x, y, z],
    bindingLayouts: BindingLayoutDef[],
    useExecutionCountBuffer?: boolean,  // Default: true, adds execution_count
    useTimeBuffer?: boolean             // Default: true, adds time
})

RenderShader2d

new RenderShader2d({
    code: string,                    // WGSL with @fragment fn main()
    canvas: HTMLCanvasElement,
    bindingLayouts: BindingLayoutDef[],
    sizeBufferStyle?: "floats" | "vector" | "none",  // Default: "floats"
    useExecutionCountBuffer?: boolean,
    useTimeBuffer?: boolean
})

Binding Layout Structure

bindingLayouts: [
    {
        default: [  // Group name (usually "default")
            {
                binding: bufferInstance,
                name: "bufferName",     // Name in WGSL
                type: "storage" | "uniform" | "read-only-storage" | "write-only-texture"
            }
        ]
    }
]

Buffer Swapping (Double Buffering)

For ping-pong patterns or double buffering, create multiple groups within a layout with swapped buffer assignments:

// Create two buffers for swapping
const bufferA = new StorageBuffer({ dataType: "array<f32>", size: 1024 });
const bufferB = new StorageBuffer({ dataType: "array<f32>", size: 1024 });

// Configure shader with swappable groups
const shader = new ComputeShader({
    code: wgslCode,
    workgroupCount: [16, 1],
    bindingLayouts: [{
        group1: [
            { binding: bufferA, name: "input", type: "storage" },
            { binding: bufferB, name: "output", type: "storage" }
        ],
        group2: [
            { binding: bufferB, name: "input", type: "storage" },
            { binding: bufferA, name: "output", type: "storage" }
        ]
    }]
});

// Execute with group swapping
let currentGroup = 0;
function compute() {
    shader.dispatch({
        bindGroups: {
            0: currentGroup === 0 ? "group1" : "group2"  // 0 is the layout index
        }
    });
    currentGroup = 1 - currentGroup;  // Toggle between 0 and 1
}

In WGSL, always use the same names (input and output). The library handles the actual buffer swapping based on the group you specify.

Buffer Operations

// Write data
await buffer.write(typedArray, offset?);

// Read data  
const data = await buffer.read(offset?, length?);

Execution

// Compute shader
computeShader.dispatch();

// Render shader (in animation loop)
function render() {
    renderShader.pass();
    requestAnimationFrame(render);
}

Key Notes

  • Don't declare bindings in WGSL - they're auto-injected
  • Entry point must be named main
  • Built-in uniforms available: execution_count, time, canvas_width, canvas_height (for render shaders)
  • Arrays use element count for size, not byte size
  • When using buffer swapping, all groups in a layout must have matching binding names and types in the same order