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

@plasius/gpu-lighting

v0.2.15

Published

Advanced lighting WGSL modules and planning profiles for @plasius/gpu-worker.

Downloads

420

Readme

@plasius/gpu-lighting

npm version Build Status coverage License Code of Conduct Security Policy Changelog

Advanced lighting WGSL modules and planning profiles for @plasius/gpu-worker. The package is structured around modern lighting tracks:

  • Lumen-inspired hybrid realtime GI/reflections.
  • Path-traced reference lighting.
  • Froxel-based volumetric lighting.
  • HDRI/IBL precomputation passes.

Apache-2.0. ESM + CJS builds. WGSL assets are published in dist/.

Install

npm install @plasius/gpu-lighting

Browser Demo

npm run demo

Then open http://localhost:8000/gpu-lighting/demo/.

The browser demo now mounts the shared 3D harbor validation scene from @plasius/gpu-shared instead of a catalog-only page, so lighting-band behavior is visible against GLTF ships, water, and cloth.

For browser-only serving, the demo resolves @plasius/gpu-shared through an import map so the page stays on the published package surface rather than a package-private source path.

Screenshot Capture

The repo also carries the Eames-chair environment validation harness under demo/eames-environments/ plus tracked Playwright helpers under scripts/eames-environments/. The referenced chair asset is tracked under data/models/eames-lounge-chair-ottoman/ so fresh repo checkouts can run the validation page without depending on a parent monorepo checkout. Build gpu-performance, gpu-renderer, and gpu-lighting first, then run:

node scripts/eames-environments/capture.mjs

Quick-mode captures now include the Eames matrix plus four synthetic reference scenes: furnace, all-material-direct-light, hdri-skybox, and dark-terminal-residual. The generated summary.md records which artifact classes each synthetic scene is intended to catch. To open a specific scene in the browser harness, pass validationScene=<scene-id> in the page query string.

For reverse-pass black-pixel diagnostics, run:

node scripts/eames-environments/path-debug-capture.mjs

If fresh Playwright Chromium bootstrap is unstable on macOS, start a WebGPU-capable Chrome separately with remote debugging enabled and set PLASIUS_CAPTURE_CDP_URL=http://127.0.0.1:<port> before running the capture script. The validation page now reports bootstrap step, detail, and WebGPU availability through window.__plasiusCaptureState and window.__plasiusCaptureError so capture failures stop at a named phase rather than hanging on the initial HUD. For long-running reference captures, browser boot readiness is considered complete once the page reaches frame rendering; the capture script then waits on the final render result with an offline timeout budget. This prevents a valid 4K/high-SPP render from being reported as a boot failure while GPU work is still making progress. The Eames validation page accepts maxDepth values up to 32 for reference-depth experiments.

For browser-controlled fallbacks, start node scripts/eames-environments/capture-bridge-server.mjs <port> and open the validation page with captureBitmap=1 plus captureUploadPath=output/playwright/eames-environments/<name>.png. If the page is being served by a plain static server such as python -m http.server, also pass captureUploadUrl=http://127.0.0.1:<port>/__plasius-capture. The page will freeze its own canvas and POST the PNG back to the bridge server once the render completes. The browser-side upload helper now rejects non-loopback capture endpoints so this fallback cannot be redirected at arbitrary remote origins.

The main capture and reverse-pass debug capture entry points now share the same server-selection helper, so local reuse, fresh static-server startup, and bridge fallback all follow the same port and readiness rules across macOS and Linux.

The capture scripts now pin deterministic validation settings unless explicitly overridden:

  • PLASIUS_CAPTURE_MAX_DEPTH=8
  • PLASIUS_CAPTURE_SPP=1
  • PLASIUS_CAPTURE_FRAMES=1
  • PLASIUS_CAPTURE_DENOISE=1
  • PLASIUS_CAPTURE_MOTION=0
  • PLASIUS_CAPTURE_FRAME_INDEX=777
  • PLASIUS_CAPTURE_PROBE=1

The main screenshot harness now supports a scripted matrix:

  • PLASIUS_CAPTURE_MATRIX_MODE=quick keeps the default one-scenario-per-preset lane for faster local checks.
  • PLASIUS_CAPTURE_MATRIX_MODE=full expands into a cross-product over camera presets, SPP values, and denoise states for offline/reference validation.
  • PLASIUS_CAPTURE_CAMERA_PRESETS=reference,wide, PLASIUS_CAPTURE_SPP_MATRIX=1,4,8,32,128, and PLASIUS_CAPTURE_DENOISE_MATRIX=1,0 refine the matrix explicitly.

They save canvas-only PNGs plus per-scenario JSON under output/playwright/eames-environments/, including the capture URL, a repro command, renderer stats, exact-black/near-black counts, luminance spread, and quantized color-bucket metrics that act as lightweight texture-presence signals. The manifest and summary now also retain failure diagnostics instead of stopping with only terminal output. The validation page now decouples optional probe readback from the heavy render submission itself, which keeps higher-SPP screenshot validation more stable. The validation HUD/result also surfaces renderer transport guardrails, so completed jobs, dispatch/submission counts, frame time, tracked memory, queue-overflow, device-loss state, and adapter capability hints travel with the same JSON evidence used for release validation. For motion or realtime validation, the page also accepts frameTimeBudgetMs and will render at least one full-screen sample before adaptively spending the rest of the per-frame budget on additional SPP passes. The HUD reports rendered/target spp whenever the budgeted frame lands below the configured ceiling. When gpu-performance/dist/index.js is available, the Eames harness also routes that target through a @plasius/gpu-performance quality ladder fed by gpu-renderer's wavefront adaptive-sampling levels, so the requested SPP becomes a release-grade ceiling rather than an ungoverned demo-local heuristic. The Eames loader also preserves authored UVs, decoded base-colour, metallic-roughness, normal, occlusion, and emissive maps, plus authored glTF material factors such as clearcoat, sheen colour, specular colour, transmission, and IOR when present. That keeps the validation scene on the shared renderer path instead of relying on material-name-specific overrides for leather, wood, and chrome.

Usage (load one technique)

import {
  loadLightingTechniqueJobs,
  loadLightingTechniqueWorkerBundle,
  getLightingTechnique,
} from "@plasius/gpu-lighting";
import { assembleWorkerWgsl, loadWorkerWgsl } from "@plasius/gpu-worker";

const workerWgsl = await loadWorkerWgsl();
const { preludeWgsl, jobs } = await loadLightingTechniqueJobs("hybrid");

const shaderCode = await assembleWorkerWgsl(workerWgsl, {
  preludeWgsl,
  jobs,
});

console.log(getLightingTechnique("hybrid").description);

Usage (worker governance bundle)

import {
  getLightingProfileWorkerManifest,
  loadLightingTechniqueWorkerBundle,
} from "@plasius/gpu-lighting";

const bundle = await loadLightingTechniqueWorkerBundle("hybrid");

// WGSL for gpu-worker assembly
console.log(bundle.preludeWgsl, bundle.jobs);

// Contract-aligned metadata for gpu-performance and gpu-debug integrations
console.log(bundle.workerManifest.jobs[0].performance.levels);
console.log(bundle.workerManifest.jobs[0].debug);
console.log(bundle.workerManifest.schedulerMode);
console.log(bundle.workerManifest.jobs[0].worker.priority);
console.log(bundle.workerManifest.jobs[0].worker.dependencies);

const profileManifest = getLightingProfileWorkerManifest("realtime");
console.log(profileManifest.jobs.map((job) => job.worker.jobType));

Wavefront Lighting Contracts

@plasius/gpu-lighting now also publishes a renderer-aligned wavefront technique for the first active-ray lighting slice. It keeps the queue layout, buffer contract names, and terminal-hit policy aligned with @plasius/gpu-renderer while owning the lighting-specific WGSL for terminal radiance accumulation and continuation scattering.

import {
  createWavefrontLightingPlan,
  createWavefrontReferenceFixture,
  createWavefrontVisibilityProbeRay,
  evaluateWavefrontMaterialReference,
  evaluateWavefrontTerminalRadiance,
  evaluateWavefrontVisibilityProbe,
  loadLightingTechniqueWorkerBundle,
} from "@plasius/gpu-lighting";

const plan = createWavefrontLightingPlan({
  maxDepth: 6,
  queueCapacity: 4096,
  explicitLightSampling: true,
  visibilityProbeMode: "mis-balanced",
});

const bundle = await loadLightingTechniqueWorkerBundle("wavefront");
const emissive = evaluateWavefrontTerminalRadiance({
  hitType: "emissive",
  throughput: [0.5, 0.5, 0.5],
  emission: [8, 6, 4],
});
const material = evaluateWavefrontMaterialReference({
  hitType: "surface",
  eventKind: "refraction",
  throughput: [1, 1, 1],
  transmission: [0.92, 0.95, 0.98],
  ior: 1.45,
  shadingNormal: [0, 1, 0],
  viewDirection: [0, 1, 0],
  currentMediumRefId: 0,
  surfaceMediumRefId: 7,
});
const probeRay = createWavefrontVisibilityProbeRay({
  rayId: 12,
  parentRayId: 4,
  sourcePixelId: 9,
  sampleId: 2,
  bounce: 1,
  origin: [0, 1, 0],
  direction: [0.25, -1, 0.15],
  throughput: [0.8, 0.7, 0.6],
  mediumRefId: 7,
  mediumStack: [7],
});
const probe = evaluateWavefrontVisibilityProbe({
  probeRay,
  probeMode: "exclusive-emissive",
  activeEmissiveRadiance: [4, 3, 2],
  emissiveRadiance: [4, 3, 2],
  transparentSegments: [[0.8, 0.8, 0.8]],
});
const fixture = createWavefrontReferenceFixture({
  hitType: "emissive",
  throughput: [0.8, 0.7, 0.6],
  emission: [4, 3, 2],
  visibilityProbe: {
    probeMode: "mis-balanced",
    emissiveRadiance: [0.6, 0.3, 0.1],
    transparentSegments: [[0.7, 0.8, 0.9]],
  },
});

console.log(plan.requiredRendererPassOrder);
console.log(plan.visibilityProbeMode);
console.log(bundle.jobs.map((job) => job.label));
console.log(emissive.radiance);
console.log(material.continuation.mediumState);
console.log(probe.doubleCountPrevented);
console.log(fixture.tolerance);

This slice keeps emissive hits, environment hits, and environment-miss dark fallbacks on the lighting package surface without reintroducing a depth-first shader dependency into the renderer-owned wavefront queue model.

The continuation/reference surface now also exposes:

  • compact medium-state carry for refraction/transparency events, including total-internal-reflection fallback reporting
  • shared-ray payload helpers where visibility probes reuse the base ray layout and encode their kind through the low bits of flags
  • optional probe contribution helpers with mis-balanced and exclusive-emissive modes so active emissive hits remain correct even when explicit light sampling is enabled
  • deterministic reference fixtures that publish buffer-like accumulation outputs with a documented default tolerance of 0.0005 for CPU-vs-GPU comparisons

Distance-Banded Lighting

import { createLightingBandPlan } from "@plasius/gpu-lighting";

const bandPlan = createLightingBandPlan({
  profile: "realtime",
  importance: "high",
});

console.log(bandPlan.bands.map((band) => band.primaryShadowSource));
console.log(bandPlan.bands.find((band) => band.band === "near").rtParticipation);

Band plans make near, mid, far, and horizon shadow sources explicit, keep RT shadow/reflection/GI participation independent, and publish temporal reuse plus update cadence expectations for downstream renderer and performance packages.

Environment Lighting Presets

import {
  createEnvironmentLightingConfig,
  createWavefrontEnvironmentLightingOptions,
} from "@plasius/gpu-lighting";

const lighting = createEnvironmentLightingConfig({
  scene: "forest",
  timeOfDay: "dusk",
  intensity: 1.05,
  environmentPortals: [
    {
      id: "north-window",
      position: [0, 1.2, -2.4],
      normal: [0, 0, 1],
      tangent: [1, 0, 0],
      width: 1.8,
      height: 1.1,
      intensity: 1.4,
    },
  ],
});

const wavefrontLighting = createWavefrontEnvironmentLightingOptions({
  preset: "cavern-night",
});

console.log(lighting.environmentLightSources.map((source) => source.kind));
console.log(wavefrontLighting.environmentMissLighting.startingPoint);

createEnvironmentLightingConfig(...) owns the reusable sky/environment semantics: horizon and zenith colours, key-light direction, key-light colour, environment intensity, exposure, ambient residual colour, and optional environment-light portals. The grass-field, forest, warehouse, and cavern families use restrained ambient residual scaling so low-sample renderers keep some final-bounce colour without washing dark materials toward white. They also publish sunlitBaseline, a scene-scaled time-of-day daylight floor that renderers can use at terminal path collisions without raising the global ambient colour.

Preset families now cover:

  • grass-field-{dawn,midday,dusk,night}
  • forest-{dawn,midday,dusk,night}
  • warehouse-{dawn,midday,dusk,night}
  • cavern-{dawn,midday,dusk,night}

Callers can pass the combined preset name directly or pass scene plus timeOfDay; scene-only aliases default to midday.

Each preset publishes scene, timeOfDay, normalized sunlitBaseline, environmentLightSources, a dominantLightSource, and environmentMissLighting. Source metadata includes source kind, role, direction, position, colour, intensity, radiance, luminance, reach, and angular radius. Renderers can use environmentMissLighting when a path ray misses scene geometry: the miss has an inferred source colour/brightness and a stable startingPoint of environment-miss instead of an unbounded null/negative sky sample. Emissive material hits remain explicit light-source hits and should not be double-counted by environment inference. Callers can also pass an environmentMap/hdri descriptor; the lighting config preserves it in createWavefrontEnvironmentLightingOptions(...) so the wavefront renderer can sample an equirectangular radiance map for environment misses and ambient residuals instead of relying primarily on static ambient values.

Portals describe physical openings such as windows where outside radiance can enter an interior. They are normalized as rectangle apertures with position, normal, tangent, dimensions, colour, and radiance scale. createWavefrontEnvironmentLightingOptions(...) projects that contract into the current @plasius/gpu-renderer wavefront renderer options without making the renderer depend on this package directly.

DAG Scheduling

Lighting worker manifests now publish schedulerMode: "dag" plus per-job priority and dependencies so downstream runtimes can preserve stage order.

  • hybrid: directLighting and screenTrace are roots; radianceCache, finalGather, and reflectionResolve unlock as upstream work finishes.
  • pathtracer: pathTrace -> accumulate -> denoise
  • volumetrics: volumetricShadow -> froxelIntegrate
  • hdri: irradianceConvolution and specularPrefilter are roots; brdfLut joins after both finish.

Usage (profile planning)

import {
  createLightingProfileModeLadder,
  getLightingProfile,
  loadLightingProfile,
} from "@plasius/gpu-lighting";

const profile = getLightingProfile("realtime");
// profile.techniques -> ["hybrid", "volumetrics", "hdri"]

const plan = await loadLightingProfile("realtime");
// plan.techniques is an array of loaded prelude+job WGSL bundles.

const modeLadder = createLightingProfileModeLadder();
// modeLadder exposes reference -> hybrid -> realtime ordering for gpu-performance.

Usage (reference-first performance ladder)

import {
  createGpuPerformanceGovernor,
  createQualityLadderAdapter,
} from "@plasius/gpu-performance";
import {
  createLightingProfileModeLadder,
} from "@plasius/gpu-lighting";

const lightingModePlan = createLightingProfileModeLadder({
  initialProfile: "reference",
});
const lightingMode = createQualityLadderAdapter(lightingModePlan);

const governor = createGpuPerformanceGovernor({
  device,
  modules: [lightingMode],
  target: lightingModePlan.target,
  adaptation: lightingModePlan.adaptation,
});

createLightingProfileModeLadder() publishes the policy contract for the reference-first mode you described:

  • start from reference
  • keep a 4-frame adaptation window
  • hold the premium mode while the negotiated average remains at or above 30 FPS
  • degrade the whole lighting profile to hybrid, then realtime, only when that window can no longer sustain the budget

The package now ships concrete WGSL contracts for:

  • hybrid.directLighting: direct sun/sky resolve with roughness-aware specular shaping
  • hybrid.screenTrace: first-hit reflection tracing over the shared hybrid scene contracts
  • hybrid.radianceCache: irradiance history updates for cache-backed indirect reuse
  • hybrid.finalGather: cache + trace composition with temporal reuse for the hybrid GI path
  • volumetrics.volumetricShadow: slice-aware Beer-Lambert shadow history for fog and shafts
  • volumetrics.froxelIntegrate: froxel scattering/extinction integration with temporal stability
  • hdri.irradianceConvolution: cosine-weighted diffuse environment convolution
  • hdri.specularPrefilter: roughness-aware environment prefiltering for glossy IBL
  • hdri.brdfLut: split-sum BRDF LUT integration for image-based lighting
  • pathtracer.pathTrace: analytic scene tracing, bounce integration, and sky fallback
  • pathtracer.accumulate: progressive history resolve with reset handling
  • pathtracer.denoise: spatial-temporal bilateral filtering for reference previews
  • hybrid.reflectionResolve: surface-aware reflection shading with roughness/fresnel shaping

This is still a catalog/planning package rather than proof of a finished end-to-end renderer. Downstream runtimes such as @plasius/gpu-renderer still need to bind real scene buffers and execute these kernels on the live frame graph.

Profiles

  • realtime: Lumen-inspired hybrid GI/reflections + volumetrics + HDRI/IBL.
  • hybrid: hybrid GI/reflections with HDRI/IBL support.
  • reference: path tracing + volumetrics + HDRI/IBL for validation and lookdev.

Techniques

  • hybrid
    • directLighting
    • screenTrace
    • radianceCache
    • finalGather
    • reflectionResolve
  • pathtracer
    • pathTrace
    • accumulate
    • denoise
  • volumetrics
    • froxelIntegrate: accumulates participating-media scattering/extinction per froxel
    • volumetricShadow: resolves directional shadow transmittance history per froxel
  • hdri
    • irradianceConvolution: builds diffuse irradiance from the environment source
    • specularPrefilter: builds roughness-aware glossy environment mip data
    • brdfLut: integrates the split-sum BRDF lookup surface for IBL

Demo

Run the demo server from the repo root:

cd gpu-lighting
npm run demo

Then open http://localhost:8000/gpu-lighting/demo/. The mounted 3D scene keeps the lighting profile, band-policy, and worker-state catalog visible while rendering the shared harbor validation surface.

Development Checks

npm run lint
npm run typecheck
npm run test:coverage
npm run build
npm run pack:check
npm run zero-three
npm run zero-three:test

Zero-Three architecture invariant

This GPU-native package permanently prohibits Three.js and every package whose dependency, peer, or optional graph reaches it. The prohibition covers source, public declarations, tests, tooling, manifests, lockfiles, installed graphs, bundles, npm tarballs, SBOMs, and active documentation. There is no compatibility mode, waiver, or renderer fallback.

Run npm run zero-three:source before installation and npm run zero-three after building to generate the immutable package evidence consumed by site release-integrity validation. npm run zero-three:test exercises the fail-closed negative fixtures. The system-wide decision is recorded in ADR 0168.

Files

  • src/index.js: technique/profile catalogs, loader APIs, validation.
  • src/techniques/hybrid/*: realtime hybrid GI/reflections WGSL modules.
  • src/techniques/pathtracer/*: path tracing reference WGSL modules.
  • src/techniques/volumetrics/*: volumetric lighting WGSL modules.
  • src/techniques/hdri/*: HDRI/IBL precompute WGSL modules.
  • docs/adrs/*: architecture decisions for the lighting stack.
  • docs/tdrs/*: technical design records for worker manifests and debug hooks.
  • docs/design/*: integration guidance for worker budgets, DAG metadata, and debug instrumentation.

Release integrity

CI keeps the administrative contributor registry outside Git and npm package artifacts using exact, case-normalised path checks. CI runs on approved GitHub-hosted runners. Release preparation and publication use a two-run exact-main protocol on GitHub-hosted Node.js 24.18.0 LTS with a pinned npm 11.6.2 release client. A read-only job seals the package tarball, SBOM, and Zero-Three evidence before a dependency-free production job publishes that exact artifact through npm OIDC with provenance; there is no npm write-token fallback.