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

@forgeax/engine-rhi-webgpu

v0.1.25

Published

WebGPU thin shim implementation of @forgeax/engine-rhi — shape-aligned with @webgpu/types, opaque handle, math-free.

Readme

@forgeax/engine-rhi-webgpu

WebGPU thin shim implementation of @forgeax/engine-rhi; spec-aligned descriptors; 'x' in src guard; no field renaming.

Charter propositions (AI users read AGENTS.md §RHI / WebGPU first)

| Proposition | This package's contract | |:--|:--| | 1 Progressive disclosure | Single import { rhi } from '@forgeax/engine-rhi-webgpu' exposes 14 opaque handles plus the entire RHI surface; one read covers entry. | | 2 Industry practice | Descriptor mirroring uses Pick<GPUXxxDescriptor, ...>; tsconfig enables exactOptionalPropertyTypes; ts-morph drives the R12 lint mirror (S-2). | | 3 Machine-readable unions | Bounds-guard hints ('queue-write-buffer-out-of-bounds') carry concrete got X numbers, not prose; AI users parse .hint for self-recovery. | | 4 Explicit failure | Real-path surfaces return Result.err for every D-S3 trigger. The escape hatch is renamed to _internal_getRawDevice and confined to a four-path allow-list (D-S1). | | 5 Consistent abstraction | The shim never renames descriptor fields; BufferDescriptor.size maps byte-for-byte to GPUBufferDescriptor.size; descriptors use an 'x' in src guard to preserve missing versus explicit-undefined. | | 6 Real-GPU observation | src/__tests__/dawn-real-gpu.dawn.test.ts triggers the D-S3 codes against dawn.node GPU; silent-pass blind spots remain visible. |

AI users: read AGENTS.md §RHI / WebGPU first for the shape rules (spec alignment, capability gating, opaque handles, and math-free descriptors); this package is the WebGPU thin shim that realizes the contract.

API entries (mid-section method tables)

| Entry | Form | Purpose | |:--|:--|:--| | requestAdapter(opts?) | (RequestAdapterOptions?) => Promise<Result<RhiAdapter, RhiError>> | Browser-native adapter probe. A resolved null is adapter-unavailable; a rejection is webgpu-runtime-error and preserves the original cause in detail.error. | | requestDevice(opts?) | (RequestDeviceOptions) => Promise<Result<RhiDevice, RhiError>> | Entry 1: navigates navigator.gpu (default) or an injected gpu provider; error paths 1/2/3 originate here | | createShaderModule(device, desc) | (RhiDevice, { code, label? }) => Promise<Result<ShaderModule, RhiError>> | Entry 2: async shader compile; 'shader-compile-failed' forwards every GPUCompilationMessage field to RhiError.detail.compilerMessages | | rhi | { requestDevice, createShaderModule } const singleton | Progressive-disclosure entry (charter proposition 1); see Engine.create({ rhi, canvas }) and import { rhi } from '@forgeax/engine-rhi-webgpu' | | _internal_getRawDevice(device) | (RhiDevice) => GPUDevice \| undefined | D-S1 single-point escape hatch (whitelist: device.ts def + index.ts createShaderModule + apps/hello/triangle/src/main.ts:96 canvas context.configure + dawn-real-gpu.dawn.test.ts validation probe). getRawDevice (without prefix) was removed in M4 (AC-RSC-05). | | GpuLike / GpuAdapterLike / GpuDeviceLike | interface provider seam | Mock fixture's minimal GPU subset (research §F-6) | | RequestDeviceOptions | { gpu?, adapterOptions?, deviceDescriptor? } | Provider seam injection arguments | | re-export | RhiDevice / Result / RhiError / _internal_getRawDevice | Single-entry surface for downstream callers |

D-S3 real-path error coverage

adapter-unavailable is scoped to this browser-native backend. Runtime may continue through the separate rhi-wgpu WebGL2 lane, so consumers must not turn this one code into a whole-machine “WebGPU unsupported” verdict. Conversely, GPU.requestAdapter() throwing is not adapter absence: the shim emits webgpu-runtime-error and retains { code: 'request-adapter-threw', name?, message } in detail.error so permission-policy, security-context, and browser runtime failures remain distinguishable.

feat-20260508-rhi-surface-completion lands the real-path implementation for command recording + queue submit + queue.writeBuffer; the 4 D-S3 codes are observable through Result.err:

| Code | Wrapped at | Trigger | |:--|:--|:--| | 'command-encoder-finished' | device.ts:498-518 (finish() lifecycle) | Second encoder.finish() after a prior finish; void-recording APIs throw the structured error so AI users observe the failure | | 'render-pass-not-ended' | device.ts:507-512 (finish() activePass guard) | encoder.finish() while a pass has not been end()-ed; the guard tracks state.activePass per PASS_STATE weakmap | | 'queue-submit-failed' | device.ts:601-607 (submit() try/catch) | rawQueue.submit() throws (validation error / destroyed reference); message is forwarded into .hint | | 'queue-write-buffer-out-of-bounds' | device.ts:548-567 (writeBuffer() bounds guard) | bufferOffset % 4 !== 0 or bufferOffset + writeSize > buffer.size; .hint carries got X / got Y / got Z numbers for AI-user routing |

Real-GPU integration is in src/__tests__/dawn-real-gpu.dawn.test.ts (4 describes, 4 codes triggered).

Timestamp write contract

Timestamp capture uses the WebGPU pass descriptor timestampWrites field on beginRenderPass / beginComputePass. The shim maps the opaque ForgeaX QuerySet to the native GPUQuerySet at the pass boundary. The obsolete command-encoder writeTimestamp entry is intentionally not exposed: current Dawn rejects that method even when timestamp-query is advertised. A device without a usable timestamp period remains capability-negative and produces no synthetic ticks. When device.caps.timestampQuery is true, render and compute pass descriptors carry the mapped query set and timestamp indices. The WebGPU adapter does not expose the removed command-encoder timestamp entry; callers that need an encoder-position marker use an empty timestamp-enabled compute pass on the same encoder. A marker failure is a structured webgpu-runtime-error; the shim never treats it as a no-op or synthesizes timestamp ticks. Capability-disabled devices retain the existing refusal path.

Query forwarding contract

The shim forwards the query surface from @forgeax/engine-rhi:

| Operation | Runtime contract | Evidence | |:--|:--|:--| | createQuerySet / destroyQuerySet | Occlusion sets are available without an optional capability; count > 4096 returns limit-exceeded; timestamp sets require device.caps.timestampQuery | device.ts, Dawn create coverage | | occlusionQuerySet + beginOcclusionQuery / endOcclusionQuery | The pass owns the query-set state; missing set, out-of-range index, nested begin, and unmatched end produce structured errors | device.ts, Dawn state/round-trip coverage | | resolveQuerySet | Validates 256-byte destination alignment, QUERY_RESOLVE usage, range, and destination size before raw forwarding | device.ts, Dawn coverage | | Timestamp pass writes | timestampWrites maps opaque QuerySet handles to raw GPUQuerySet; a capability-negative device refuses creation and does not synthesize ticks | device.ts, Dawn admission/readback coverage | | Pass descriptor timestampWrites | Capability-positive devices map opaque query sets at the real render/compute pass boundary; unavailable periods remain fail-closed | device.ts, unit coverage | | executeBundles | Still unavailable: the public RHI has no constructible RenderBundle handle or creation path, so the shim returns rhi-not-available | device.ts |

[!NOTE] Dawn is the current real-GPU evidence owner for query behavior. This package does not claim a separate browser query artifact merely because the browser shim and interface compile; RhiNull remains structural-only.

Capabilities tri-layer

device.caps (hardware probe) / device.features (enabled set) / device.limits (numeric upper bounds) — three independent readonly fields (charter proposition 5); caps.X = false is an explicit signal, never an exception (proposition 4).

Deferred membership evidence closure

The full matrix closes only at acceptedGpu=16: five Dawn GPU records each for 32, 64, and 128 lights, one 256-light record, positive GPU ticks, variance, and the 256-light overflow fingerprint. acceptedGpu=0 is a fail-closed blocker. CPU control, WebKit WebGL2 refusal, RhiNull refusal, screenshots, and capability bits cannot be promoted to accepted GPU evidence.

The validator binds sourceHead, carrier, workload, profile, and artifactHashes. It requires the exact 20 top-level and 32 nested records and SHA-256 descriptors for record, profile, membership, and pixel. The formal budgets are Dawn 100000 events, WebKit 65536 events, nested frame limit 90, and settle time 25 ms. The 128-light / 90-frame / 40000 event configuration is a falsifier and must be incomplete with dropped events; it is not the formal WebKit budget.

The producer report is the recovery entry point. Read blocker.code, blocker.expected, blocker.hint, and blocker.acceptedGpu, then inspect the per-attempt identity, profile, timing, membership, pixel, and artifact hash records. The Render reason union remains closed: timestamp-query refusal uses timestamp-query-unsupported, while a raw timestamp write failure is webgpu-runtime-error at the RHI layer and timestamp-write-unavailable in the Render owner contract. Neither produces synthetic ticks.

Test infrastructure

  • Hand-rolled minimal mock GPU device (decision S-2 path (b)) at src/__tests__/__mocks__/gpu-device.ts; zero-native dependency, pure TS.
  • Provider seam injection via gpu?: GPU parameter (research §F-6 webgpu-utils + CTS consensus); default routes through globalThis.navigator.gpu.
  • dawn.node real-GPU coverage: src/__tests__/dawn-real-gpu.dawn.test.ts (4 D-S3 triggers, candidate proposition 6 monitoring).

Intentional differences (vs spec / wgpu)

  • 'x' in src guard transit: spec ?: T vs forgeax ?: T | undefined differ under exactOptionalPropertyTypes:true; the shim guards each field per F-3 anti-pattern 2.
  • device.lost single source: this package only forwards the spec Promise; fan-out is the engine's job (LostListenerRegistry).
  • Error message keyword classification: requestDevice failure routes via feature / limit keyword detection; mock and real-GPU formats may differ.
  • Real-path implementation (M4-M5 + query closure): command recording + queue submit + queue.writeBuffer landed; query-set creation/destruction, occlusion begin/end, resolve, and timestamp pass writes are forwarded or capability-gated. The only remaining public placeholder is executeBundles, which returns Result.err({ code: 'rhi-not-available', hint: 'see feat-future-rhi-render-bundle' }) until a RenderBundle handle and creation owner exist.
  • Escape hatch tear-down: getRawDevice (no prefix) removed in feat-20260508-rhi-surface-completion M4 (AC-RSC-05); the single sanctioned hatch is _internal_getRawDevice confined to the AC-08 (h) allow-list.
  • destroyBuffer / destroyTexture (feat-20260612): per-handle destroyed-state bookkeeping in shim layer (WeakMap<Handle, { destroyed: boolean }>) on top of the spec's idempotent-void GPUBuffer.destroy() / GPUTexture.destroy(). Dual-backend behavior is symmetric: both shims track destroyed boolean per handle, fail-fast on second destroy with 'destroy-after-destroy' error code, and never depend on wasm panic interception (plan-strategy D-6). Implementation at packages/rhi-webgpu/src/device.ts.

FAQ

Q: Why not directly implements GPUDevice for the full interface?

A: charter proposition 1 — progressive disclosure: the shim only touches descriptors actually used (createX + features / limits / lost / queue + command recording). Mock fixtures need not implement wgslLanguageFeatures / getPreferredCanvasFormat.

Q: Are real GPUDevice and mock semantics aligned for device.lost.reason / message?

A: No — spec and wgpu impl format are not interchangeable (research §F-4). This package forwards the Promise without classification; consumers should switch over 'destroyed' | 'unknown'.

Q: Why does _internal_getRawDevice exist if escape hatches are forbidden?

A: D-S1 single-point exemption — apps/hello/triangle/src/main.ts:96 context.configure({device: rawDevice}) requires raw GPUDevice because RhiCanvasContext is owned by feat-future-rhi-adapter-surface. The hatch is renamed (no bare getRawDevice), confined to a 4-path allow-list (AC-08 (h)), and grep-fenced.

Upgrade path

  • @webgpu/types ^0.1.69: caret range tracks v0.1.x patches; v0.2.x triggers major-upgrade markers (S-4).
  • After upstream spec migrates to ?: T | undefined, the ExplicitUndefined<> mapped type can be removed and the mirror simplifies (L-P4 widening contract).

Dependencies

  • @forgeax/engine-rhi (workspace) — interface contract SSOT.
  • @forgeax/engine-types (workspace) — POD types / union aliases SSOT.
  • @webgpu/types ^0.1.69 — spec types; lock-version policy is in repo-root AGENTS.md.

Related packages