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

@refrain-lyre/render-webgl

v0.1.0

Published

WebGL2 renderer for Lyrical Refrain (Lyre) models

Readme

@refrain-lyre/render-webgl

WebGL2 renderer. Consumes the deformed geometry and draw order produced by @refrain-lyre/core and rasterizes into the canonical premultiplied-alpha model surface (§8.3), with the three blend modes (normal/additive/multiply) mapped to single blendFuncSeparate calls and mask clipping (§8.4). The offscreen surface preserves extended-premultiplied additive emission, including RGB at zero alpha; callers must not round-trip it through straight alpha.

Textures are premultiplied at load; all filtering and blending happen in premultiplied space (§3.2). The rendered surface is the conformance artifact compared against goldens (§12).

Usage

import { createWebGLRenderer, CONTEXT_ATTRIBUTES } from "@refrain-lyre/render-webgl";

const gl = canvas.getContext("webgl2", CONTEXT_ATTRIBUTES)!;
const renderer = createWebGLRenderer(gl, model.canvas.width, model.canvas.height);
renderer.setTexture(id, premultipliedImage /*, atlasRect */);
renderer.render(runtime.evaluate());
const surface = renderer.readSurface(); // premultiplied RGBA8, +y down

The context remains host-owned and may be shared with other WebGL code. The constructor, setTexture(), render(), readSurface(), and present() restore all caller-visible state they change, including separate draw/read framebuffer bindings, the default framebuffer draw buffer, texture and sampler units 0–1, pixel-transfer state, program/VAO/buffer bindings, blend state, capabilities, viewport, color mask, and clear color. dispose() invalidates renderer-owned objects (including a surfaceTexture the host may have bound), as expected for resource destruction.

WebGL's error queue is consumptive and cannot be snapshotted or restored. Enter renderer calls with a clean error queue; the renderer drains it so errors from its own operation can be attributed and reported precisely.

Implementation notes (why it matches the CPU reference within the §12 surface tolerance):

  • Renders both the model surface and reusable mask-coverage target as RGBA32F (no sRGB formats, no MSAA, no dither). Float32 preserves extended additive color and repeated low-alpha mask unions without intermediate float16 or RGBA8 precision loss; readSurface() performs the sole RGBA8 quantization. This requires WebGL2 EXT_color_buffer_float and EXT_float_blend; renderer construction fails explicitly when either extension is unavailable.
  • The projection flips y so canvas-space top/left edges stay top/left in window space and the GPU fill rule agrees with the CPU top-left rule; readSurface() flips rows back.
  • Triangles are de-indexed and normalized to positive winding on the CPU (float64) so opposite-winding neighbors stay watertight, and each triangle carries its exact affine canvas→uv map as flat attributes — the fragment shader reconstructs uv from gl_FragCoord, sidestepping the rasterizer's subpixel vertex snap (SwiftShader: 1/16 px).
  • Bilinear sampling is done manually with texelFetch + mix, clamped to the crop interior (§3.2) — hardware LINEAR has unspecified subtexel precision.
  • Mask coverage (§8.4) renders raw texture alpha into an offscreen target with normal alpha blending (equivalent to the union 1 − ∏(1 − aᵢ)). One target is reused across groups so mask-target memory remains bounded. The browser harness stress-checks both a 256-source union of 1/255-alpha masks and 9,998 low-intensity additive layers followed by multiply against the CPU reference.
  • Surface and texture creation checks both Lyre's static limits and the active device's texture/viewport limits. Allocation errors fail explicitly and partially created GL resources are released.

Conformance (e2e)

In this repository, run pnpm --filter @refrain-lyre/render-webgl exec playwright install chromium once, then pnpm --filter @refrain-lyre/render-webgl e2e. The command bundles an in-page harness, launches headless Chromium on SwiftShader, replays every corpus timeline, and compares against the committed CPU goldens at the §12 tolerance. LYRE_E2E_DUMP=<dir> writes actual/golden/diff PNGs for failures.

See the specification.