@plasius/gpu-renderer 0.2.43 → 0.2.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -23,6 +23,46 @@ All notable changes to this project will be documented in this file.
23
23
  - **Security**
24
24
  - (placeholder)
25
25
 
26
+ ## [0.2.45] - 2026-09-07
27
+
28
+ - **Added**
29
+ - (placeholder)
30
+
31
+ - **Changed**
32
+ - Refreshed compatible @plasius/* lockfile resolutions to the latest published releases.
33
+ - (placeholder)
34
+
35
+ - **Fixed**
36
+ - Documented verified locked-branch runner admission for trusted push checks,
37
+ including exact-commit verification and removal before branch updates.
38
+ - Restored trusted-push-only CI on explicit self-hosted runners, preserving
39
+ required check names and excluding external fork execution; bounded scheduled
40
+ dependency validation to self-hosted main runs.
41
+ - Preserved hosted pull-request isolation, bounded validation runtime, and
42
+ disabled package-manager cache finalization on self-hosted main validation.
43
+ - (placeholder)
44
+
45
+ - **Security**
46
+ - (placeholder)
47
+
48
+ ## [0.2.44] - 2026-08-31
49
+
50
+ - **Added**
51
+ - Added an explicit consent-, flag-, and capability-gated helper that converts
52
+ coarse renderer health observations into the closed shared feedback
53
+ diagnostics packet for approved generator and GPU demo surfaces.
54
+
55
+ - **Changed**
56
+ - Updated `@plasius/gpu-shared` to the protected-CD-published 1.1.1 release
57
+ that exposes the focused feedback-diagnostics contract, and revalidated
58
+ the renderer against the registry artifact.
59
+
60
+ - **Fixed**
61
+ - (placeholder)
62
+
63
+ - **Security**
64
+ - (placeholder)
65
+
26
66
  ## [0.2.43] - 2026-08-31
27
67
 
28
68
  - **Added**
@@ -90,11 +130,21 @@ All notable changes to this project will be documented in this file.
90
130
 
91
131
  - **Changed**
92
132
  - Updated internal GPU dependencies to their surviving clean lines and refreshed the esbuild resolution.
133
+ - Bound diagnostics to the focused shared-package subpath and canonical
134
+ contract-version export, and enabled complete declaration checking with the
135
+ published WebXR type definitions.
93
136
 
94
137
  - **Fixed**
95
- - (placeholder)
138
+ - Removed a duplicate public mesh `extensions` declaration and replaced
139
+ unresolved ambient XR session references with the `@plasius/gpu-xr` state
140
+ contract.
96
141
 
97
142
  - **Security**
143
+ - Updated the development-tool dependency graph to the patched
144
+ `brace-expansion` release after the feedback release audit.
145
+ - Kept feedback diagnostics separate from general renderer snapshots and
146
+ excluded user-captured pixels, DOM, player data, URLs, filenames, exact
147
+ measurements, adapter identity and raw warnings from the output contract.
98
148
  - Added permanent fail-closed Zero-Three validation for manifests, source,
99
149
  locks, installed dependency graphs, declarations, bundles, npm tarballs,
100
150
  CycloneDX SBOMs, and active documentation, with digest-bound evidence
@@ -657,6 +707,9 @@ All notable changes to this project will be documented in this file.
657
707
  contract used by the wavefront display-quality renderer.
658
708
 
659
709
  - **Fixed**
710
+ - Clamped wavefront tile capacity against the depth-scaled path-vertex
711
+ storage binding so supported high-depth reference renders stay within
712
+ `maxStorageBufferBindingSize`.
660
713
  - Raised the bounded wavefront `maxDepth` ceiling to 32 so offline/reference
661
714
  renders can request 20-bounce paths without being clamped by renderer
662
715
  configuration.
@@ -684,6 +737,9 @@ All notable changes to this project will be documented in this file.
684
737
  corruption and stalled validation captures on higher-SPP frames.
685
738
 
686
739
  - **Changed**
740
+ - Raised the bounded wavefront `maxDepth` ceiling to 32 so offline/reference
741
+ renders can request 20-bounce paths without being clamped by renderer
742
+ configuration.
687
743
  - Changed internal wavefront frame batching and dispatch-diagnostics plumbing
688
744
  to live in a dedicated runtime helper module so scheduling concerns stay
689
745
  separated from shader and pipeline assembly.
@@ -1069,3 +1125,5 @@ All notable changes to this project will be documented in this file.
1069
1125
  [0.2.41]: https://github.com/Plasius-LTD/gpu-renderer/releases/tag/v0.2.41
1070
1126
  [0.2.42]: https://github.com/Plasius-LTD/gpu-renderer/releases/tag/v0.2.42
1071
1127
  [0.2.43]: https://github.com/Plasius-LTD/gpu-renderer/releases/tag/v0.2.43
1128
+ [0.2.44]: https://github.com/Plasius-LTD/gpu-renderer/releases/tag/v0.2.44
1129
+ [0.2.45]: https://github.com/Plasius-LTD/gpu-renderer/releases/tag/v0.2.45
package/README.md CHANGED
@@ -8,19 +8,56 @@
8
8
  [![Security Policy](https://img.shields.io/badge/security%20policy-yes-orange.svg)](./SECURITY.md)
9
9
  [![Changelog](https://img.shields.io/badge/changelog-md-blue.svg)](./CHANGELOG.md)
10
10
 
11
- [![license](https://img.shields.io/github/license/Plasius-LTD/gpu-renderer)](./LICENSE)
12
-
13
11
  Framework-agnostic WebGPU renderer runtime for Plasius projects.
14
12
  This package is intended to replace Three.js-dependent render orchestration with
15
13
  an explicit WebGPU-first runtime that can be consumed from React, vanilla, or
16
14
  worker-driven app surfaces.
17
15
 
18
16
  The package targets Node.js 24, consumes the stable `@plasius/gpu-shared` 1.x
19
- runtime line (`^1.0.12`), and validates its development tooling against the
17
+ runtime line (`^1.1.1`), and validates its development tooling against the
20
18
  current ESLint 10 and TypeScript 7 baselines.
21
19
 
22
20
  Apache-2.0. ESM + CJS builds.
23
21
 
22
+ ## Privacy-Safe Feedback Diagnostics
23
+
24
+ Approved in-game viewers can explicitly convert a small set of current renderer
25
+ health observations into the closed
26
+ `@plasius/gpu-shared/feedback-diagnostics` packet:
27
+
28
+ ```js
29
+ import { createFeedbackGameDiagnosticSnapshot } from "@plasius/gpu-renderer";
30
+
31
+ const diagnostics = createFeedbackGameDiagnosticSnapshot({
32
+ featureEnabled,
33
+ capabilityGranted,
34
+ consentConfirmed: true,
35
+ surfaceId: "site.gpu-demo",
36
+ renderer: "webgpu",
37
+ backend: "worker",
38
+ viewportWidth: 1920,
39
+ viewportHeight: 1080,
40
+ frameRate: 59.9,
41
+ frameTimeMs: 16.7,
42
+ featureIds: ["renderer.frame-loop"],
43
+ counters: [{ code: "frame-drop", count: 2 }],
44
+ errorCodes: [],
45
+ });
46
+ ```
47
+
48
+ The helper returns `null` before reading renderer observations unless the
49
+ remotely evaluated `feedback.game-diagnostics.enabled` flag, the
50
+ `feedback.game-diagnostics.attach` capability, and explicit consent are all
51
+ present. It derives trusted provenance and returns only coarse buckets and
52
+ closed codes.
53
+
54
+ This API is deliberately separate from general renderer snapshots. It accepts
55
+ no canvas, user-captured pixels, DOM, player object, URL, filename,
56
+ adapter/device detail, coordinate or raw warning, performs no automatic
57
+ diagnostic capture or network/storage operation, and never registers
58
+ `/player-system`. Disabling the flag preserves ordinary structured-only bug
59
+ reporting.
60
+
24
61
  ## Install
25
62
 
26
63
  ```sh
@@ -654,9 +691,23 @@ npm run pack:check
654
691
  ## Release integrity
655
692
 
656
693
  CI keeps the administrative contributor registry outside Git and npm package
657
- artifacts using exact, case-normalised path checks. External fork heads are
658
- rejected; same-repository pull requests validate on GitHub-hosted runners and
659
- main pushes validate on approved self-hosted runners. Release preparation and
694
+ artifacts using exact, case-normalised path checks. CI runs only for pushes to
695
+ repository-owned branches on explicit `[self-hosted, Linux, X64]` runners.
696
+ External fork pull requests trigger no CI execution; a maintainer must review
697
+ and move a contribution to a repository-owned branch to produce required checks.
698
+ Before branch CI starts, an authorised maintainer reviews the exact commit and
699
+ locks its repository branch as read-only, enforcing the lock for administrators
700
+ and disabling force pushes, deletion, and fork syncing. After reading back the
701
+ lock and commit SHA, admit only that branch's fully qualified workflow ref for
702
+ `gpu-renderer/.github/workflows/ci.yml` in `Public CI - Quarantined`. Top-level
703
+ push jobs identify their workflow by branch ref; SHA-only admission did not
704
+ schedule the reviewed job. Remove the temporary workflow entry and verify its
705
+ removal before unlocking or updating the branch, and after delivery. Preserve all
706
+ other group restrictions. Never admit mutable branch or PR refs. See
707
+ [ADR-0028](docs/adrs/adr-0028-locked-branch-runner-admission.md) for the procedure.
708
+ The trusted admission, build-test, and artifact-integrity checks keep their
709
+ existing names for branch protection. Scheduled dependency validation also uses
710
+ bounded self-hosted capacity and accepts only `main`. Release preparation and
660
711
  publication use a two-run exact-main protocol on GitHub-hosted Node.js 24.18.0
661
712
  LTS. A read-only job seals the package tarball and SBOM before a dependency-free
662
713
  production job publishes that exact artifact through npm OIDC with provenance;
package/dist/index.cjs CHANGED
@@ -24,8 +24,12 @@ __export(index_exports, {
24
24
  applyMediumTransmittance: () => applyMediumTransmittance,
25
25
  beerLambertTransmittance: () => beerLambertTransmittance,
26
26
  bindRendererToXrManager: () => bindRendererToXrManager,
27
+ bucketFeedbackGameFrameRate: () => bucketFeedbackGameFrameRate,
28
+ bucketFeedbackGameFrameTime: () => bucketFeedbackGameFrameTime,
29
+ bucketFeedbackGameViewport: () => bucketFeedbackGameViewport,
27
30
  createAnimatedSceneRenderer: () => createAnimatedSceneRenderer,
28
31
  createDefaultWavefrontSceneObjects: () => createDefaultWavefrontSceneObjects,
32
+ createFeedbackGameDiagnosticSnapshot: () => createFeedbackGameDiagnosticSnapshot,
29
33
  createGpuRenderer: () => createGpuRenderer,
30
34
  createMediumStack: () => createMediumStack,
31
35
  createProfessionalAnimatedSceneRenderer: () => createProfessionalAnimatedSceneRenderer,
@@ -2294,6 +2298,140 @@ async function createProfessionalAnimatedSceneRenderer(options = {}) {
2294
2298
  };
2295
2299
  }
2296
2300
 
2301
+ // src/feedback-diagnostics.js
2302
+ var import_feedback_diagnostics = require("@plasius/gpu-shared/feedback-diagnostics");
2303
+ var inputKeys = Object.freeze([
2304
+ "featureEnabled",
2305
+ "capabilityGranted",
2306
+ "consentConfirmed",
2307
+ "surfaceId",
2308
+ "renderer",
2309
+ "backend",
2310
+ "viewportWidth",
2311
+ "viewportHeight",
2312
+ "frameRate",
2313
+ "frameTimeMs",
2314
+ "featureIds",
2315
+ "counters",
2316
+ "errorCodes"
2317
+ ]);
2318
+ function bucketFeedbackGameViewport(width, height) {
2319
+ if (typeof width !== "number" || typeof height !== "number" || !Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
2320
+ return "unknown";
2321
+ }
2322
+ const shorterEdge = Math.min(width, height);
2323
+ const longerEdge = Math.max(width, height);
2324
+ const size = shorterEdge < 600 ? "small" : shorterEdge < 900 || longerEdge < 1440 ? "medium" : "large";
2325
+ const orientation = width > height ? "landscape" : "portrait";
2326
+ return `${size}-${orientation}`;
2327
+ }
2328
+ function bucketFeedbackGameFrameRate(frameRate) {
2329
+ if (typeof frameRate !== "number" || !Number.isFinite(frameRate) || frameRate < 0) {
2330
+ return "unknown";
2331
+ }
2332
+ if (frameRate < 15) {
2333
+ return "under-15";
2334
+ }
2335
+ if (frameRate < 30) {
2336
+ return "15-29";
2337
+ }
2338
+ if (frameRate < 60) {
2339
+ return "30-59";
2340
+ }
2341
+ return "60-plus";
2342
+ }
2343
+ function bucketFeedbackGameFrameTime(frameTimeMs) {
2344
+ if (typeof frameTimeMs !== "number" || !Number.isFinite(frameTimeMs) || frameTimeMs < 0) {
2345
+ return "unknown";
2346
+ }
2347
+ if (frameTimeMs < 17) {
2348
+ return "under-17ms";
2349
+ }
2350
+ if (frameTimeMs < 34) {
2351
+ return "17-33ms";
2352
+ }
2353
+ if (frameTimeMs < 67) {
2354
+ return "34-66ms";
2355
+ }
2356
+ return "over-66ms";
2357
+ }
2358
+ function createFeedbackGameDiagnosticSnapshot(input) {
2359
+ try {
2360
+ return createFeedbackGameDiagnosticSnapshotInternal(input);
2361
+ } catch {
2362
+ throw new TypeError("Invalid privacy-safe renderer diagnostics input.");
2363
+ }
2364
+ }
2365
+ function createFeedbackGameDiagnosticSnapshotInternal(input) {
2366
+ const snapshot = snapshotInputIfEnabled(input);
2367
+ if (snapshot === null) {
2368
+ return null;
2369
+ }
2370
+ const registration = typeof snapshot.surfaceId === "string" && Object.hasOwn(
2371
+ import_feedback_diagnostics.feedbackGameDiagnosticSurfaceRegistrations,
2372
+ snapshot.surfaceId
2373
+ ) ? import_feedback_diagnostics.feedbackGameDiagnosticSurfaceRegistrations[snapshot.surfaceId] : void 0;
2374
+ return (0, import_feedback_diagnostics.parseFeedbackGameDiagnostics)({
2375
+ type: "feedback-game-diagnostics",
2376
+ version: import_feedback_diagnostics.FEEDBACK_GAME_DIAGNOSTICS_CONTRACT_VERSION,
2377
+ surfaceId: snapshot.surfaceId,
2378
+ consentConfirmed: true,
2379
+ provenanceContractId: registration?.provenanceContractId,
2380
+ renderer: snapshot.renderer,
2381
+ backend: snapshot.backend,
2382
+ viewportBucket: bucketFeedbackGameViewport(
2383
+ snapshot.viewportWidth,
2384
+ snapshot.viewportHeight
2385
+ ),
2386
+ frameRateBucket: bucketFeedbackGameFrameRate(snapshot.frameRate),
2387
+ frameTimeBucket: bucketFeedbackGameFrameTime(snapshot.frameTimeMs),
2388
+ featureIds: snapshot.featureIds,
2389
+ counters: snapshot.counters,
2390
+ errorCodes: snapshot.errorCodes
2391
+ });
2392
+ }
2393
+ function snapshotInputIfEnabled(input) {
2394
+ assertValid(
2395
+ input !== null && typeof input === "object" && !Array.isArray(input) && (Object.getPrototypeOf(input) === Object.prototype || Object.getPrototypeOf(input) === null)
2396
+ );
2397
+ const gateKeys = [
2398
+ "featureEnabled",
2399
+ "capabilityGranted",
2400
+ "consentConfirmed"
2401
+ ];
2402
+ const snapshot = /* @__PURE__ */ Object.create(null);
2403
+ for (const key of gateKeys) {
2404
+ const descriptor = Object.getOwnPropertyDescriptor(input, key);
2405
+ assertValid(
2406
+ descriptor !== void 0 && descriptor.enumerable === true && Object.hasOwn(descriptor, "value") && typeof descriptor.value === "boolean"
2407
+ );
2408
+ snapshot[key] = descriptor.value;
2409
+ }
2410
+ const { featureEnabled, capabilityGranted, consentConfirmed } = snapshot;
2411
+ if (!featureEnabled || !capabilityGranted || !consentConfirmed) {
2412
+ return null;
2413
+ }
2414
+ const actualKeys = Reflect.ownKeys(input);
2415
+ assertValid(
2416
+ actualKeys.length === inputKeys.length && inputKeys.every((key) => actualKeys.includes(key)) && actualKeys.every(
2417
+ (key) => typeof key === "string" && inputKeys.includes(key)
2418
+ )
2419
+ );
2420
+ for (const key of inputKeys.filter((key2) => !gateKeys.includes(key2))) {
2421
+ const descriptor = Object.getOwnPropertyDescriptor(input, key);
2422
+ assertValid(
2423
+ descriptor !== void 0 && descriptor.enumerable === true && Object.hasOwn(descriptor, "value")
2424
+ );
2425
+ snapshot[key] = descriptor.value;
2426
+ }
2427
+ return Object.freeze(snapshot);
2428
+ }
2429
+ function assertValid(condition) {
2430
+ if (!condition) {
2431
+ throw new TypeError("Invalid privacy-safe renderer diagnostics input.");
2432
+ }
2433
+ }
2434
+
2297
2435
  // src/wavefront-frame-runtime.js
2298
2436
  function createGpuParallelismCounters() {
2299
2437
  return {
@@ -5139,7 +5277,13 @@ function clampTileSizeForDevice(config, device) {
5139
5277
  }
5140
5278
  const maxPixelsByRay = Math.floor(limit / RAY_RECORD_BYTES);
5141
5279
  const maxPixelsByHit = Math.floor(limit / HIT_RECORD_BYTES);
5142
- const maxPixels = Math.max(256, Math.min(maxPixelsByRay, maxPixelsByHit));
5280
+ const maxPixelsByPathVertex = Math.floor(
5281
+ limit / ((config.maxDepth + 1) * PATH_VERTEX_RECORD_BYTES)
5282
+ );
5283
+ const maxPixels = Math.max(
5284
+ 256,
5285
+ Math.min(maxPixelsByRay, maxPixelsByHit, maxPixelsByPathVertex)
5286
+ );
5143
5287
  if (config.tilePixelCapacity <= maxPixels) {
5144
5288
  return config.tileSize;
5145
5289
  }
@@ -11447,7 +11591,11 @@ async function createWavefrontPathTracingComputeRenderer(options = {}) {
11447
11591
  canvas,
11448
11592
  width: config.width,
11449
11593
  height: config.height,
11450
- tileSize: safeTileSize
11594
+ tileSize: safeTileSize,
11595
+ tilePixelCapacity: Math.min(
11596
+ config.tilePixelCapacity,
11597
+ safeTileSize * safeTileSize
11598
+ )
11451
11599
  });
11452
11600
  }
11453
11601
  config = Object.freeze({
@@ -13265,8 +13413,12 @@ function createRayTracingRenderPlan(options = {}) {
13265
13413
  applyMediumTransmittance,
13266
13414
  beerLambertTransmittance,
13267
13415
  bindRendererToXrManager,
13416
+ bucketFeedbackGameFrameRate,
13417
+ bucketFeedbackGameFrameTime,
13418
+ bucketFeedbackGameViewport,
13268
13419
  createAnimatedSceneRenderer,
13269
13420
  createDefaultWavefrontSceneObjects,
13421
+ createFeedbackGameDiagnosticSnapshot,
13270
13422
  createGpuRenderer,
13271
13423
  createMediumStack,
13272
13424
  createProfessionalAnimatedSceneRenderer,