@carbonenginejs/runtime-resource 0.12.0 → 0.12.1

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.
Files changed (170) hide show
  1. package/dist/CjsResMan.js +4 -4
  2. package/dist/CjsResMan.js.map +1 -1
  3. package/dist/_virtual/_rollupPluginBabelHelpers.js +1 -4
  4. package/dist/_virtual/_rollupPluginBabelHelpers.js.map +1 -1
  5. package/dist/format/CjsByteReader.js +310 -0
  6. package/dist/format/CjsByteReader.js.map +1 -0
  7. package/dist/format/CjsByteWriter.js +242 -0
  8. package/dist/format/CjsByteWriter.js.map +1 -0
  9. package/dist/format/CjsFormatError.js +41 -0
  10. package/dist/format/CjsFormatError.js.map +1 -0
  11. package/dist/format/CjsStringTable.js +268 -0
  12. package/dist/format/CjsStringTable.js.map +1 -0
  13. package/dist/format/carbonEffect/CjsCarbonEffectReader.js +361 -0
  14. package/dist/format/carbonEffect/CjsCarbonEffectReader.js.map +1 -0
  15. package/dist/format/carbonEffect/CjsCarbonEffectWriter.js +373 -0
  16. package/dist/format/carbonEffect/CjsCarbonEffectWriter.js.map +1 -0
  17. package/dist/format/carbonEffect/carbonDescriptionFromPortable.js +372 -0
  18. package/dist/format/carbonEffect/carbonDescriptionFromPortable.js.map +1 -0
  19. package/dist/format/carbonEffect/carbonEffectBackendBlock.js +427 -0
  20. package/dist/format/carbonEffect/carbonEffectBackendBlock.js.map +1 -0
  21. package/dist/format/carbonEffect/carbonEffectRecords.js +955 -0
  22. package/dist/format/carbonEffect/carbonEffectRecords.js.map +1 -0
  23. package/dist/format/compareUtf8.js +36 -0
  24. package/dist/format/compareUtf8.js.map +1 -0
  25. package/dist/format/index.js +11 -0
  26. package/dist/format/index.js.map +1 -0
  27. package/dist/formats/bnk/CjsBnkFormat.js +10 -4
  28. package/dist/formats/bnk/CjsBnkFormat.js.map +1 -1
  29. package/dist/formats/bnk/core/eventAction.js +305 -0
  30. package/dist/formats/bnk/core/eventAction.js.map +1 -0
  31. package/dist/formats/bnk/core/helpers.js +11 -2
  32. package/dist/formats/bnk/core/helpers.js.map +1 -1
  33. package/dist/formats/bnk/core/nodeBase.js +532 -0
  34. package/dist/formats/bnk/core/nodeBase.js.map +1 -0
  35. package/dist/formats/bnk/core/sfxNodes.js +252 -152
  36. package/dist/formats/bnk/core/sfxNodes.js.map +1 -1
  37. package/dist/formats/hlsl/core/HlslReader.js +7 -257
  38. package/dist/formats/hlsl/core/HlslReader.js.map +1 -1
  39. package/dist/formats/hlsl/core/carbonDescriptionToRuntime.js +781 -0
  40. package/dist/formats/hlsl/core/carbonDescriptionToRuntime.js.map +1 -0
  41. package/dist/formats/hlsl/core/tr2/resources/HlslEffectRes.js +21 -1
  42. package/dist/formats/hlsl/core/tr2/resources/HlslEffectRes.js.map +1 -1
  43. package/dist/formats/index.js +1 -1
  44. package/dist/formats/webgl/core/cewg/CewgPackage.js +2 -1
  45. package/dist/formats/webgl/core/cewg/CewgPackage.js.map +1 -1
  46. package/dist/formats/webgl/core/cewg/binary.js +11 -93
  47. package/dist/formats/webgl/core/cewg/binary.js.map +1 -1
  48. package/dist/formats/webgl/core/effectPackage.js +1 -1
  49. package/dist/formats/webgpu/CjsWebgpuFormat.js +4 -23
  50. package/dist/formats/webgpu/CjsWebgpuFormat.js.map +1 -1
  51. package/dist/formats/webgpu/core/buildCarbonEffectContainer.js +197 -0
  52. package/dist/formats/webgpu/core/buildCarbonEffectContainer.js.map +1 -0
  53. package/dist/formats/webgpu/core/cewgpu/CewgpuContainer.js +368 -0
  54. package/dist/formats/webgpu/core/cewgpu/CewgpuContainer.js.map +1 -0
  55. package/dist/formats/webgpu/core/cewgpu/containerViews.js +355 -0
  56. package/dist/formats/webgpu/core/cewgpu/containerViews.js.map +1 -0
  57. package/dist/formats/webgpu/core/cewgpu/validateContainer.js +90 -0
  58. package/dist/formats/webgpu/core/cewgpu/validateContainer.js.map +1 -0
  59. package/dist/formats/webgpu/core/effectBackendBodySet.js +21 -20
  60. package/dist/formats/webgpu/core/effectBackendBodySet.js.map +1 -1
  61. package/dist/formats/webgpu/core/helpers.js +87 -92
  62. package/dist/formats/webgpu/core/helpers.js.map +1 -1
  63. package/dist/formats/webgpu/core/ir/analyzeRegisterValues.js +14 -13
  64. package/dist/formats/webgpu/core/ir/analyzeRegisterValues.js.map +1 -1
  65. package/dist/formats/webgpu/core/ir/inferValueTypes.js +10 -8
  66. package/dist/formats/webgpu/core/ir/inferValueTypes.js.map +1 -1
  67. package/dist/formats/webgpu/core/packageEffect.js +94 -9
  68. package/dist/formats/webgpu/core/packageEffect.js.map +1 -1
  69. package/dist/formats/webgpu/core/packageMetadata.js +10 -1
  70. package/dist/formats/webgpu/core/packageMetadata.js.map +1 -1
  71. package/dist/formats/webgpu/core/wgsl/buildResourceTransformPlan.js +17 -15
  72. package/dist/formats/webgpu/core/wgsl/buildResourceTransformPlan.js.map +1 -1
  73. package/dist/formats/webgpu/core/wgsl/buildWgslBindingPlan.js +13 -12
  74. package/dist/formats/webgpu/core/wgsl/buildWgslBindingPlan.js.map +1 -1
  75. package/dist/formats/webgpu/core/wgsl/buildWgslSet.js +9 -8
  76. package/dist/formats/webgpu/core/wgsl/buildWgslSet.js.map +1 -1
  77. package/dist/formats/webgpu/core/wgsl/lowerComputeProgram.js +23 -22
  78. package/dist/formats/webgpu/core/wgsl/lowerComputeProgram.js.map +1 -1
  79. package/dist/formats/webgpu/core/wgsl/selectionPlans.js +46 -44
  80. package/dist/formats/webgpu/core/wgsl/selectionPlans.js.map +1 -1
  81. package/dist/resource/CjsResource.js +700 -684
  82. package/dist/resource/CjsResource.js.map +1 -1
  83. package/dist/resource/Tr2LightProfileRes.js +18 -27
  84. package/dist/resource/Tr2LightProfileRes.js.map +1 -1
  85. package/dist/resource/audio/CjsAudioBufferRes.js +2 -2
  86. package/dist/resource/audio/CjsAudioBufferRes.js.map +1 -1
  87. package/dist/resource/audio/CjsAudioRes.js +2 -2
  88. package/dist/resource/audio/CjsAudioRes.js.map +1 -1
  89. package/dist/resource/geometry/TriGeometryRes.js +605 -586
  90. package/dist/resource/geometry/TriGeometryRes.js.map +1 -1
  91. package/dist/resource/geometry/granny/Tr2GrannyStateRes.js +21 -30
  92. package/dist/resource/geometry/granny/Tr2GrannyStateRes.js.map +1 -1
  93. package/dist/resource/geometry/granny/TriGrannyRes.js +21 -30
  94. package/dist/resource/geometry/granny/TriGrannyRes.js.map +1 -1
  95. package/dist/resource/shader/Tr2EffectRes.js +9 -7
  96. package/dist/resource/shader/Tr2EffectRes.js.map +1 -1
  97. package/dist/resource/shader/Tr2MaterialArea.js +5 -3
  98. package/dist/resource/shader/Tr2MaterialArea.js.map +1 -1
  99. package/dist/resource/shader/Tr2MaterialMesh.js +4 -2
  100. package/dist/resource/shader/Tr2MaterialMesh.js.map +1 -1
  101. package/dist/resource/shader/Tr2MaterialRes.js +5 -3
  102. package/dist/resource/shader/Tr2MaterialRes.js.map +1 -1
  103. package/dist/resource/shader/Tr2Shader.js +26 -21
  104. package/dist/resource/shader/Tr2Shader.js.map +1 -1
  105. package/dist/resource/shader/Tr2ShaderPermutation.js +8 -6
  106. package/dist/resource/shader/Tr2ShaderPermutation.js.map +1 -1
  107. package/dist/resource/shader/reflection/Tr2EffectDefine.js +5 -3
  108. package/dist/resource/shader/reflection/Tr2EffectDefine.js.map +1 -1
  109. package/dist/resource/shader/reflection/Tr2EffectDescription.js +5 -3
  110. package/dist/resource/shader/reflection/Tr2EffectDescription.js.map +1 -1
  111. package/dist/resource/shader/reflection/Tr2EffectLibrary.js +17 -15
  112. package/dist/resource/shader/reflection/Tr2EffectLibrary.js.map +1 -1
  113. package/dist/resource/shader/reflection/Tr2EffectParameterAnnotation.js +11 -9
  114. package/dist/resource/shader/reflection/Tr2EffectParameterAnnotation.js.map +1 -1
  115. package/dist/resource/shader/reflection/Tr2EffectResource.js +8 -6
  116. package/dist/resource/shader/reflection/Tr2EffectResource.js.map +1 -1
  117. package/dist/resource/shader/reflection/Tr2EffectStageInput.js +15 -13
  118. package/dist/resource/shader/reflection/Tr2EffectStageInput.js.map +1 -1
  119. package/dist/resource/shader/reflection/Tr2EffectTechnique.js +7 -5
  120. package/dist/resource/shader/reflection/Tr2EffectTechnique.js.map +1 -1
  121. package/dist/resource/shader/reflection/Tr2Pass.js +11 -9
  122. package/dist/resource/shader/reflection/Tr2Pass.js.map +1 -1
  123. package/dist/resource/shader/sampler/Tr2SamplerSetup.js +8 -6
  124. package/dist/resource/shader/sampler/Tr2SamplerSetup.js.map +1 -1
  125. package/dist/resource/texture/CjsTextureArrayRes.js +400 -411
  126. package/dist/resource/texture/CjsTextureArrayRes.js.map +1 -1
  127. package/dist/resource/texture/Tr2ImageRes.js +99 -95
  128. package/dist/resource/texture/Tr2ImageRes.js.map +1 -1
  129. package/dist/resource/texture/TriTextureRes.js +312 -273
  130. package/dist/resource/texture/TriTextureRes.js.map +1 -1
  131. package/docs/README.md +13 -1
  132. package/docs/architecture.md +3 -3
  133. package/docs/concepts/resource-lifecycle.md +9 -2
  134. package/docs/concepts/shader-resource-model.md +114 -0
  135. package/docs/concepts/writing-an-engine-adapter.md +115 -0
  136. package/docs/formats/README.md +24 -1
  137. package/docs/formats/carbon-effect-container.md +452 -0
  138. package/docs/formats/dxbc/reference/classes/README.md +5 -72
  139. package/docs/formats/hlsl/reference/api.md +5 -4
  140. package/docs/formats/hlsl/reference/classes/README.md +6 -11
  141. package/docs/formats/provenance.md +23 -13
  142. package/docs/formats/webgl/reference/classes/README.md +5 -92
  143. package/docs/formats/webgpu/README.md +19 -16
  144. package/docs/formats/webgpu/architecture.md +15 -12
  145. package/docs/formats/webgpu/formats/cewgpu.md +175 -438
  146. package/docs/formats/webgpu/guides/effect-packaging.md +132 -140
  147. package/docs/formats/webgpu/reference/api.md +131 -131
  148. package/docs/formats/webgpu/reference/classes/README.md +5 -62
  149. package/docs/formats/webgpu/reference/wgsl-compatibility.md +146 -45
  150. package/docs/formats/wwise.md +34 -8
  151. package/docs/reference/classes/core.md +80 -0
  152. package/docs/reference/classes/formats.md +18 -28
  153. package/docs/reference/events.md +25 -0
  154. package/docs/reference/motherlode-cache.md +22 -8
  155. package/docs/reference/workers.md +5 -5
  156. package/docs/roadmap.md +61 -41
  157. package/package.json +2 -1
  158. package/dist/formats/webgpu/core/cewgpu/CewgpuPackage.js +0 -415
  159. package/dist/formats/webgpu/core/cewgpu/CewgpuPackage.js.map +0 -1
  160. package/dist/formats/webgpu/core/cewgpu/CewgpuPackageBuilder.js +0 -100
  161. package/dist/formats/webgpu/core/cewgpu/CewgpuPackageBuilder.js.map +0 -1
  162. package/dist/formats/webgpu/core/cewgpu/binary.js +0 -93
  163. package/dist/formats/webgpu/core/cewgpu/binary.js.map +0 -1
  164. package/dist/formats/webgpu/core/cewgpu/tags.js +0 -17
  165. package/dist/formats/webgpu/core/cewgpu/tags.js.map +0 -1
  166. package/dist/formats/webgpu/core/effectPackageValidation.js +0 -1078
  167. package/dist/formats/webgpu/core/effectPackageValidation.js.map +0 -1
  168. package/docs/formats/hlsl/reference/classes/carbon-compatibility.md +0 -66
  169. package/docs/formats/hlsl/reference/classes/public-api.md +0 -26
  170. package/docs/formats/hlsl/reference/classes/tr2-effect-model.md +0 -150
@@ -36,7 +36,7 @@ operations (a previous compiler boundary for higher-quality shader profiles):
36
36
  crack/z-fight artifact `precise` protects against;
37
37
  - precise-mask metadata is still validated structurally (well-formed mask,
38
38
  lanes covered by a destination write) in
39
- `src/core/wgsl/precisionControls.js`.
39
+ `src/formats/webgpu/core/wgsl/precisionControls.js`.
40
40
 
41
41
  NOT promised: bit-exact arithmetic parity with native D3D11; differential
42
42
  tests against native output may differ in final ulps. Globally-non-refactorable
@@ -64,10 +64,10 @@ projections, and per-lane `movc` selects — in BOTH stages.
64
64
 
65
65
  SSA may resolve a post-join read to one arm's definition (the other path
66
66
  diverges via return/discard); structured WGSL scoping cannot express that
67
- directly. `src/core/wgsl/hoistEscapingValues.js` hoists escaping declarations
68
- to uninitialized function-top `var`s (WGSL zero-initializes) plus in-place
69
- assignments. The zero is unobservable — SSA proves the value is only read on
70
- assigning paths.
67
+ directly. `src/formats/webgpu/core/wgsl/hoistEscapingValues.js` hoists
68
+ escaping declarations to uninitialized function-top `var`s (WGSL
69
+ zero-initializes) plus in-place assignments. The zero is unobservable — SSA
70
+ proves the value is only read on assigning paths.
71
71
 
72
72
  ### Switch clauses without a `default` → empty WGSL `default`
73
73
 
@@ -1054,11 +1054,12 @@ sample form and in both stages.
1054
1054
  495 qualified packages are byte-identical. Every changed package carries
1055
1055
  exactly one two- or three-layer Detail transform.
1056
1056
 
1057
- This closes the compiler-side sampled-texture binding limit only. WGSL-set
1058
- version 3 is not yet accepted by the committed engine reader, and raw module
1059
- compilation does not prove resource realization or rendering. Runtime
1060
- support must consume the recipe explicitly before these packages are
1061
- render-ready.
1057
+ This closes the compiler-side sampled-texture binding limit. Raw module
1058
+ compilation alone does not prove resource realization or rendering, but the
1059
+ current engine accepts WGSL-set version 3 and realizes the documented
1060
+ `texture-2d-array` transform recipe. The Detail and HeatDetail families have
1061
+ exact draw evidence; the Environment family remains unverified. See
1062
+ [Consumer boundary: resource transforms](#consumer-boundary-resource-transforms).
1062
1063
  - **Immediate 2D sample offsets** — `sample`, `sample_b`, `sample_d`, and
1063
1064
  `sample_l` lower their signed `_aoffimmi(u,v,w)` record to WGSL's final
1064
1065
  constant `vec2<i32>(u, v)` sampling argument. Both APIs apply that
@@ -1221,13 +1222,14 @@ WGSL forbids screen-space derivatives — the `dpdx*`/`dpdy*` family and the
1221
1222
  implicit-LOD samples that derive internally (`textureSample` /
1222
1223
  `textureSampleBias`) — inside **non-uniform** control flow (a branch whose
1223
1224
  condition can differ between the pixels of a 2x2 quad), because the derivative
1224
- compares neighbor pixels that may not all be present. `src/core/wgsl/
1225
- uniformity.js` tags each SSA value uniform or varying; when the fragment lowerer
1226
- finds one of these operations under a varying-conditioned branch it records
1227
- `requiresDerivativeUniformityOptOut` on the program, and `emitWgsl` prepends the
1228
- module-level filter `diagnostic(off, derivative_uniformity);` (a standard WGSL
1229
- opt-out that Dawn/Tint and Naga both honor — browser-gate confirmed) rather than
1230
- rejecting the shader.
1225
+ compares neighbor pixels that may not all be present.
1226
+ `src/formats/webgpu/core/wgsl/uniformity.js` tags each SSA value uniform or
1227
+ varying; when the fragment lowerer finds one of these operations under a
1228
+ varying-conditioned branch it records `requiresDerivativeUniformityOptOut` on
1229
+ the program, and `emitWgsl` prepends the module-level filter
1230
+ `diagnostic(off, derivative_uniformity);` (a standard WGSL opt-out that
1231
+ Dawn/Tint and Naga both honor — browser-gate confirmed) rather than rejecting
1232
+ the shader.
1231
1233
 
1232
1234
  Why the directive and not gradient hoisting: the DXBC came from HLSL that relied
1233
1235
  on **D3D11's permissive divergent-derivative behavior** (non-participating quad
@@ -1266,8 +1268,16 @@ is not emitted unnecessarily.
1266
1268
 
1267
1269
  ## Selected-effect package provenance
1268
1270
 
1269
- `BuildEffect` emits selected-effect INFO schema version 2 while the binary
1270
- CEWGPU container remains version 1. INFO v2 records the WebGPU target,
1271
+ The versioned checkpoints in this section describe the retired flat-chunk wire
1272
+ used before the Carbon-container switchover. Their corpus counts remain
1273
+ compiler and provenance evidence; `INFO`, `META`, `PGRF`, `RFLX`, `RBLB`,
1274
+ `ANLS`, and `WGSL` are no longer stored chunks. Current bytes are Carbon
1275
+ version-15 records with derived compatibility views. See
1276
+ [CEWGPU effect container](../formats/cewgpu.md).
1277
+
1278
+ At the 0.4.2 checkpoint, `BuildEffect` emitted selected-effect INFO schema
1279
+ version 2 while the binary CEWGPU container remained version 1. INFO v2
1280
+ recorded the WebGPU target,
1271
1281
  backend-package and translator semantic versions, and a lower-case SHA-256
1272
1282
  digest computed over the exact compiled-effect input byte view. A conflicting
1273
1283
  caller digest fails closed. The reader retains legacy selected-effect INFO v1
@@ -1370,36 +1380,44 @@ gates compile with zero WGSL warnings.
1370
1380
 
1371
1381
  ## All-body backend packaging
1372
1382
 
1373
- `mode: "all"` translates every unique source body and stores the result in a
1374
- `WGSB` `CJS_WGSL_BODY_SET` chunk. Selected mode remains the default and is
1375
- unchanged.
1383
+ `mode: "all"` attempts every unique source body after the resolved selection
1384
+ passes its initial translation gate. In the retired chunk wire, the result was
1385
+ stored as a `WGSB` `CJS_WGSL_BODY_SET` document. The current Carbon wire stores
1386
+ WGSL in stage program slots and bind-group/transform data in per-pass backend
1387
+ blocks; `backendBodySet` is now a derived compatibility view. Selected mode
1388
+ remains the default.
1376
1389
 
1377
1390
  The translation unit is deliberately one pass of one body rather than one
1378
1391
  stage. A pass owns its binding plan and resource-transform plan, so identical
1379
1392
  stage bytecode can legitimately translate differently when its pass-mates
1380
- differ; sharing at stage granularity would be unsound. Bodies whose pass
1381
- carries byte-identical stage bytecode, semantic bindings, and render states
1382
- therefore share exactly one stored unit. On real uber-shader ship families this
1383
- is the difference between storing every body's programs and storing a small
1384
- fraction of them, because most permutation axes change only one stage of one
1385
- pass.
1386
-
1387
- A body the compiler cannot lower is retained as an explicitly unsupported
1388
- record carrying its reason, and coverage degrades to `partial`. Its complete
1389
- source reflection is untouched, so a partial backend never silently reduces
1390
- source truth. This is the fail-closed alternative to dropping a body or
1391
- shrinking the reported shader count.
1393
+ differ; sharing at stage granularity would be unsound. The Carbon wire has no
1394
+ unit table. Exact emitted program and backend-block bytes share storage through
1395
+ the arena's bytewise deduplication.
1396
+
1397
+ All mode first requires the resolved selection to lower successfully. After
1398
+ that gate, a later body the compiler cannot lower is retained with empty
1399
+ program slots and coverage degrades to `partial`. The in-memory build result
1400
+ retains its specific reason; the wire does not. A reread can say only that the
1401
+ body carries no translated programs. Permutation topology and representable
1402
+ non-program description fields remain present, but source-stage programs are
1403
+ not stored. Non-dynamic sampler names are unrecoverable and stage order is
1404
+ canonicalized.
1392
1405
 
1393
1406
  Translating every body is deliberately **not** treated as backend completeness.
1394
1407
  `backendComplete` and `runtimeComplete` remain false, matching the sibling
1395
- WebGL package, because neither the engine's realization of these layouts and
1396
- resource transforms nor an exact draw of them has been gated. `INFO` carries
1397
- the honest scope in `backendBodyCoverage` instead.
1398
-
1399
- Evidence for the introducing change: the every-permutation reader join resolves
1408
+ WebGL package. The engine now realizes the documented layouts and
1409
+ `texture-2d-array` transforms and has exact draw evidence for representative
1410
+ Detail and HeatDetail families. That proof does not cover every required
1411
+ translated program, layout, and transform, and complete resource hydration and
1412
+ selection also remain open. The `BuildEffect` result carries the
1413
+ translated-body scope in `info.backendBodyCoverage`; the bytes express it
1414
+ structurally through which bodies carry programs.
1415
+
1416
+ Historical evidence for the retired WGSB implementation: its
1417
+ every-permutation reader join resolved
1400
1418
  every permutation of a real Quad family package to translated programs and
1401
- reaches every unique body; the selected body's shared units are byte-identical
1402
- to that package's own `WGSL` chunk; a full corpus rebuild leaves every
1419
+ reached every unique body; the selected body's shared units were byte-identical
1420
+ to that package's derived `WGSL` view; a full corpus rebuild leaves every
1403
1421
  selected-mode package byte-identical with unchanged statuses; every effect in
1404
1422
  the corpus builds in all-body mode with no build failures, the small number of
1405
1423
  partial results losing bodies only to already-documented compiler boundaries;
@@ -1418,16 +1436,99 @@ preflight. The synthetic fixtures cannot express either condition, so an
1418
1436
  all-body corpus sweep is part of this feature's verification, not an optional
1419
1437
  extra.
1420
1438
 
1439
+ ## Consumer boundary: resource transforms
1440
+
1441
+ `engine-webgpu` accepts `CJS_WGSL_SET` versions 1, 2 and 3, and realizes
1442
+ `texture-2d-array` resource transforms. The discriminator is the **feature**,
1443
+ never the document version and never `texture.viewDimension`:
1444
+
1445
+ - a **source-declared** `texture_2d_array` keeps every one of its bindings and
1446
+ needs no assembly. Gating on `viewDimension` would reject the very packages
1447
+ the exact draw gate renders — the selected Quad V5 body binds a plain
1448
+ `texture_2d_array<f32>` with no transform, and both Quad families carry
1449
+ `cube` bindings.
1450
+ - a **transformed** binding carries `transformId` and `arrayLayerCount`, and its
1451
+ merged-away inputs are absent from the layout. It cannot be fed from one
1452
+ source texture, so the consumer assembles the layers.
1453
+
1454
+ Only `kind: texture-2d-array`, `version: 1`,
1455
+ `representation: native-or-rgba8`, and `missingLayer: reject` are realized.
1456
+ Anything else throws a diagnostic naming the offending field, because the
1457
+ failure mode of guessing is WGSL a device accepts and pixels that are quietly
1458
+ wrong.
1459
+
1460
+ Both halves of the claim are validated, not just the record: exactly one binding
1461
+ must carry each declared transform, at the declared output identity, with a
1462
+ matching `arrayLayerCount`, a `texture_2d_array<f32>` type, visibility to the
1463
+ transform's stage, and **no surviving binding for any merged-away input**. A
1464
+ survivor would still be bindable and would silently receive a texture the shader
1465
+ never reads. Symmetrically, a binding claiming an undeclared transform, or
1466
+ declaring array layers without one, is rejected.
1467
+
1468
+ ### The analysis is pre-transform; the layout is post-transform
1469
+
1470
+ This asymmetry is the one thing a consumer must not get wrong. The reflection
1471
+ still lists every declared resource under its own register, including inputs the
1472
+ producer merged away; the layout is shorter by exactly those inputs. Checking
1473
+ one against the other reports the merge as drift. The merged array occupies the
1474
+ **layer-0 input's slot**, which is required rather than assumed, so the binding a
1475
+ consumer must fill is unambiguous.
1476
+
1477
+ Layers are written in declared order, layer *i* from `inputs[i]`, and must agree
1478
+ on size and format because one texture cannot hold layers that do not. A missing
1479
+ input is rejected rather than substituted: any stand-in layer would change the
1480
+ rendered result while still validating.
1481
+
1482
+ Realized and drawn, all with zero WGSL warnings:
1483
+
1484
+ | Family | Layers | Merged into | Evidence |
1485
+ | --- | --- | --- | --- |
1486
+ | `unpackedskinned_quadheatdetailv5` | 2 | `Detail1Map` slot | 22 over 22 bindings, 3 cases, detail changed 570/635 covered pixels |
1487
+ | `unpacked_quaddetailv5` | 3 | `Detail1Map` slot | both detail controls changed 1116/1116 covered pixels |
1488
+ | `unpackedskinned_quaddetailv5` | 3 | `Detail1Map` slot | 634/635 and 635/635, indexed non-identity bones observed |
1489
+
1490
+ The `Detail1` and `Detail2` delta maps were **distinct** in every case. That is
1491
+ the assertion that matters: a collapsed or misordered assembly would produce
1492
+ identical deltas while still rendering and still validating.
1493
+
1494
+ Source-declared array textures are now realized rather than merely accepted:
1495
+ the engine creates a layered 2D texture with a `2d-array` view and binds it
1496
+ through the same adapter, gated by a synthetic two-layer draw that asserts each
1497
+ layer's pixels exactly. A single-layer array view is legal and distinct from a
1498
+ plain 2D view, because a shader declaring `texture_2d_array<f32>` needs the
1499
+ array view whatever its layer count. A layout asking for the dimension the view
1500
+ was not created with fails closed, since a view's dimension is fixed at
1501
+ creation and cannot be reinterpreted.
1502
+
1503
+ This matters beyond the transform case: the High `.sm_depth` Quad V5 `Main`
1504
+ pass binds `LightProfileArray` as a plain `texture_2d_array<f32>` with no
1505
+ transform at all, so array-texture realization is a prerequisite for any
1506
+ High-tier draw gate, not a detail of transform support.
1507
+
1508
+ Array-texture realization is what made transform support possible: the engine
1509
+ allocates the array itself and fills layer *i* from `inputs[i]`, which is the
1510
+ only way a binding whose other inputs were removed can be filled at all. The
1511
+ Detail and HeatDetail family gates draw under this contract. The Environment
1512
+ family has not been exercised and should be treated as unverified rather than
1513
+ working.
1514
+
1515
+ Accepting version 3 also tightened three structural checks that were written
1516
+ `=== 2` and would otherwise have silently downgraded every version-3 package to
1517
+ version-1 semantics: shared binding identities must span at least two stages,
1518
+ and explicit D3D and scope identities are both required. That downgrade would
1519
+ have been invisible to the exact draw gate, because DX11 and DX12 downgrade
1520
+ identically and the bit-exact comparison would have stayed green.
1521
+
1421
1522
  ## Verification contract
1422
1523
 
1423
1524
  Every shader-emission, layout, or transform compatibility change requires the
1424
1525
  package suite and a representative `engine-webgpu` browser gate on a real
1425
1526
  WebGPU device with zero WGSL warnings. Format-level qualification cannot detect
1426
1527
  every WGSL scoping or validator failure, so browser validation remains part of
1427
- the compiler contract. A reviewed envelope-only schema change may omit a new
1428
- browser run when corpus comparison proves unchanged status/errors and
1429
- byte-identical runtime-consumed shader chunks, and downstream reader tolerance
1430
- is separately confirmed.
1528
+ the compiler contract. A reviewed record-layout or derived-view-only change
1529
+ may omit a new browser run when corpus comparison proves unchanged
1530
+ status/errors and byte-identical runtime-consumed programs/backend blocks, and
1531
+ downstream reader tolerance is separately confirmed.
1431
1532
 
1432
1533
  The browser gate proves the emitted WGSL is *valid and runs*; it does not by
1433
1534
  itself prove the translation is *semantically equivalent to D3D*. Semantic
@@ -16,22 +16,31 @@ manager behavior, or decoded-backend retention.
16
16
 
17
17
  `CjsBnkFormat.inspect()` decodes the chunk map, embedded media index, bank
18
18
  names, and the HIRC listing with version-stable typed fields (event action
19
- lists, action type/target, sound and music-track source ids; pinned against
20
- bank generator version 150). The Wwise-domain toolkit is grouped under the
21
- `CjsBnkFormat.wwise` static: the SoundbanksInfo catalog helpers, the FNV-1
22
- id hash, event-to-media resolution, and typed authored-SFX nodes:
19
+ lists, action type/target, sound and music-track source ids). For bank
20
+ generator version 150, recognized Event Actions additionally expose exact
21
+ scope/mode, property and range bundles, delay/transition/probability values,
22
+ fade and action flags, exceptions, and Play bank identities. The
23
+ Wwise-domain toolkit is grouped under the `CjsBnkFormat.wwise` static: the
24
+ SoundbanksInfo catalog helpers, the FNV-1 id hash, event-to-media resolution,
25
+ typed Event Actions, and typed authored-SFX nodes:
23
26
 
24
27
  ```js
25
28
  import { CjsBnkFormat } from "@carbonenginejs/runtime-resource/formats/bnk";
26
29
  import { CjsWemFormat } from "@carbonenginejs/runtime-resource/formats/wem";
27
30
 
28
31
  const inspections = bankByteArrays.map(bytes => CjsBnkFormat.inspect(bytes));
32
+ const action = CjsBnkFormat.wwise.parseEventAction(actionPayload, {
33
+ bankVersion: 150
34
+ });
29
35
  const { eventMedia } = CjsBnkFormat.wwise.eventMediaFromBanks(inspections);
30
36
  // eventMedia: Map<eventObjectId, Set<wemId>> - banks may split events from
31
37
  // their target sounds, so pass every related bank to one call.
32
38
 
33
39
  const {
34
40
  nodes,
41
+ nodeBases,
42
+ actorMixers,
43
+ attenuations,
35
44
  events,
36
45
  actions,
37
46
  diagnostics
@@ -45,11 +54,28 @@ The read/inspect path stays a pure container reader;
45
54
  `wwise.eventMediaFromBanks` is graph interpretation offered for consumers
46
55
  with their own engines — the resource lifecycle never calls it.
47
56
 
57
+ The undecoded-container ID scan used by `eventMediaFromBanks` is diagnostic
58
+ reachability, not an authoritative playback program. Consumers requiring
59
+ audible correctness should use the typed `sfxNodesFromBanks` graph and fail
60
+ closed for unsupported events.
61
+
48
62
  Typed authored-SFX tail decoding is deliberately pinned to bank generator
49
- version 150. It preserves Random/Sequence, Switch/State, and Layer fields
50
- without deciding how an audio runtime should lower them. Unsupported versions,
51
- failed exact-end anchors, ambiguities, and duplicate object identities are
52
- reported through `diagnostics` instead of being guessed. Like
63
+ version 150. Recognized Event Actions are accepted only when the whole body
64
+ is consumed; unknown, truncated, other-version, or trailing-byte bodies retain
65
+ their shallow action type/target and raw payload, with `action: null`.
66
+ `nodes` contains playable Sound, Random/Sequence, Switch/State, and Layer
67
+ objects. The separate `nodeBases` map preserves common authored properties
68
+ and positioning facts for playable nodes and Actor-Mixers.
69
+ `actorMixers` contains HIRC type 7 hierarchy objects; they are inheritance
70
+ parents, not playable parallel containers. `attenuations` contains raw HIRC
71
+ type 14 cone data, signed curve-slot assignments, graph points, and RTPCs
72
+ without assigning application meaning to a curve.
73
+
74
+ Unsupported versions, failed exact-end anchors, ambiguities, NodeBase
75
+ failures, and duplicate object identities are reported through `diagnostics`
76
+ instead of being guessed. Consumers may resolve hierarchy and project
77
+ runtime-specific metadata from these raw facts. In particular, this format
78
+ layer does not infer a numeric maximum radius from an attenuation curve. Like
53
79
  `eventMediaFromBanks`, `sfxNodesFromBanks` is consumer-facing graph
54
80
  interpretation; the resource lifecycle never calls it.
55
81
 
@@ -115,6 +115,86 @@ Internal base for construction-bound readers that are created for one source and
115
115
  - Visibility: Internal
116
116
  - Kind: Internal implementation class
117
117
 
118
+ <!-- class:CjsFormatReadError -->
119
+ ## `CjsFormatReadError`
120
+
121
+ Error raised when shared binary format bytes cannot be decoded safely.
122
+
123
+ - Export: `@carbonenginejs/runtime-resource/format`
124
+ - Source: `src/format/CjsFormatError.js`
125
+ - Visibility: Public
126
+ - Kind: Original CarbonEngineJS class
127
+
128
+ <!-- class:CjsFormatWriteError -->
129
+ ## `CjsFormatWriteError`
130
+
131
+ Error raised when shared binary format bytes cannot be encoded safely.
132
+
133
+ - Export: `@carbonenginejs/runtime-resource/format`
134
+ - Source: `src/format/CjsFormatError.js`
135
+ - Visibility: Public
136
+ - Kind: Original CarbonEngineJS class
137
+
138
+ <!-- class:CjsByteReader -->
139
+ ## `CjsByteReader`
140
+
141
+ Little-endian cursor over resource bytes, with optional string-table arena resolution.
142
+
143
+ - Export: `@carbonenginejs/runtime-resource/format`
144
+ - Source: `src/format/CjsByteReader.js`
145
+ - Visibility: Public
146
+ - Kind: Original CarbonEngineJS class
147
+
148
+ <!-- class:CjsByteWriter -->
149
+ ## `CjsByteWriter`
150
+
151
+ Growable little-endian append cursor with reserve-and-patch support.
152
+
153
+ - Export: `@carbonenginejs/runtime-resource/format`
154
+ - Source: `src/format/CjsByteWriter.js`
155
+ - Visibility: Public
156
+ - Kind: Original CarbonEngineJS class
157
+
158
+ <!-- class:CjsStringTable -->
159
+ ## `CjsStringTable`
160
+
161
+ Carbon's compiled-effect string table: a deduplicated blob arena whose offsets are assigned by a bytewise sort rather than by insertion order.
162
+
163
+ - Export: `@carbonenginejs/runtime-resource/format`
164
+ - Source: `src/format/CjsStringTable.js`
165
+ - Visibility: Public
166
+ - Kind: Adapted Carbon concept
167
+
168
+ <!-- class:CjsCarbonEffectBodyReader -->
169
+ ## `CjsCarbonEffectBodyReader`
170
+
171
+ Plain byte cursor over one description blob, carrying the Carbon effect error class and message.
172
+
173
+ - Export: `@carbonenginejs/runtime-resource/format`
174
+ - Source: `src/format/carbonEffect/CjsCarbonEffectReader.js`
175
+ - Visibility: Public
176
+ - Kind: Adapted Carbon concept
177
+
178
+ <!-- class:CjsCarbonEffectReader -->
179
+ ## `CjsCarbonEffectReader`
180
+
181
+ Reader for Carbon's compiled-effect container at version 15.
182
+
183
+ - Export: `@carbonenginejs/runtime-resource/format`
184
+ - Source: `src/format/carbonEffect/CjsCarbonEffectReader.js`
185
+ - Visibility: Public
186
+ - Kind: Adapted Carbon concept
187
+
188
+ <!-- class:CjsCarbonEffectWriter -->
189
+ ## `CjsCarbonEffectWriter`
190
+
191
+ Builder for a Carbon compiled-effect container.
192
+
193
+ - Export: `@carbonenginejs/runtime-resource/format`
194
+ - Source: `src/format/carbonEffect/CjsCarbonEffectWriter.js`
195
+ - Visibility: Public
196
+ - Kind: Adapted Carbon concept
197
+
118
198
  <!-- class:CjsResourceProbe -->
119
199
  ## `CjsResourceProbe`
120
200
 
@@ -79,13 +79,23 @@ Little-endian byte cursor over HIRC payload bytes used to decode Wwise interacti
79
79
  - Visibility: Internal
80
80
  - Kind: Internal implementation class
81
81
 
82
- <!-- class:SfxCursor -->
83
- ## `SfxCursor`
82
+ <!-- class:WwiseCursor -->
83
+ ## `WwiseCursor`
84
84
 
85
- Bounds-aware little-endian cursor used for exact-end Wwise SFX-tail validation.
85
+ Bounds-aware little-endian cursor used for exact Wwise v150 NodeBase, authored-SFX, and attenuation decoding.
86
86
 
87
87
  - Export: `None`
88
- - Source: `src/formats/bnk/core/sfxNodes.js`
88
+ - Source: `src/formats/bnk/core/nodeBase.js`
89
+ - Visibility: Internal
90
+ - Kind: Internal implementation class
91
+
92
+ <!-- class:ActionCursor -->
93
+ ## `ActionCursor`
94
+
95
+ Bounds-aware byte cursor used for exact Wwise v150 Event Action decoding.
96
+
97
+ - Export: `None`
98
+ - Source: `src/formats/bnk/core/eventAction.js`
89
99
  - Visibility: Internal
90
100
  - Kind: Internal implementation class
91
101
 
@@ -843,33 +853,13 @@ WebGPU shader format profile that translates compiled Carbon effects into CEWGPU
843
853
  - Visibility: Public
844
854
  - Kind: Original CarbonEngineJS class
845
855
 
846
- <!-- class:CewgpuPackage -->
847
- ## `CewgpuPackage`
848
-
849
- Reader for the flat CEWGPU container: chunk lookup, cached JSON decoding, and gated portable reflection and backend program access.
850
-
851
- - Export: `None`
852
- - Source: `src/formats/webgpu/core/cewgpu/CewgpuPackage.js`
853
- - Visibility: Internal
854
- - Kind: Internal implementation class
855
-
856
- <!-- class:CewgpuPackageBuilder -->
857
- ## `CewgpuPackageBuilder`
858
-
859
- Builds a CEWGPU container from ordered, uniquely tagged chunks.
860
-
861
- - Export: `None`
862
- - Source: `src/formats/webgpu/core/cewgpu/CewgpuPackageBuilder.js`
863
- - Visibility: Internal
864
- - Kind: Internal implementation class
865
-
866
- <!-- class:WebgpuReader -->
867
- ## `WebgpuReader`
856
+ <!-- class:CewgpuContainer -->
857
+ ## `CewgpuContainer`
868
858
 
869
- Bounded little-endian byte cursor over CEWGPU container bytes.
859
+ Reader over one WebGPU effect container.
870
860
 
871
861
  - Export: `None`
872
- - Source: `src/formats/webgpu/core/cewgpu/binary.js`
862
+ - Source: `src/formats/webgpu/core/cewgpu/CewgpuContainer.js`
873
863
  - Visibility: Internal
874
864
  - Kind: Internal implementation class
875
865
 
@@ -34,6 +34,31 @@ wildcard listener dispatch, no `family.event` or ancestor routing, and no
34
34
  event payload history. Resource classes may emit their own state or domain
35
35
  events, but the emitter does not invent a resource lifecycle contract.
36
36
 
37
+ ## Resource lifecycle events
38
+
39
+ `CjsResource.SetState()` supplies the resource-specific lifecycle contract. A
40
+ state transition emits, in order:
41
+
42
+ 1. the lowercase state name with `(resource, ...details)`;
43
+ 2. `statechange` with `(resource, nextState, previousState)`; and
44
+ 3. `completed` with `(resource, ...details)` when the new state is
45
+ `prepared` or `failed`.
46
+
47
+ `purged` is deliberately not completion. A purged handle may re-register and
48
+ reload itself into the same identity, and listeners are not cleared by purge.
49
+ A listener that remains registered for `completed` can therefore observe the
50
+ initial outcome and a later purge/reload outcome.
51
+
52
+ Raw `OnEvent()` and `OnceEvent()` never replay event history. The one
53
+ state-aware registration helper is `CjsResource.OnCompleted(listener,
54
+ source?)`: it calls the listener synchronously and stores nothing when the
55
+ resource is already complete; otherwise it registers a persistent
56
+ `completed` listener. This is the canonical check-then-subscribe operation for
57
+ late consumers. A listener satisfied synchronously will not observe a later
58
+ reload unless it explicitly subscribes again. Use `Ready()`/`GetObject()` when
59
+ the caller needs a promise for the current load operation rather than a
60
+ re-enterable lifecycle observer.
61
+
37
62
  ## Memory rules
38
63
 
39
64
  Event storage is the optional `events` member of the emitter's non-enumerable
@@ -27,6 +27,12 @@ create a hidden second resource; reset the affected identity
27
27
  (`Delete`/`Clear`) or create a new manager. A changed output contract must use
28
28
  a new tag such as `@cmf2`.
29
29
 
30
+ Do not restore a hidden execution-plan identity through function fingerprints,
31
+ arbitrary option serialization, `buildKey`, or `buildVersion`. Those details
32
+ cannot create a second canonical resource behind the same public path/output
33
+ promise. A materially different promised result requires an explicit output
34
+ tag.
35
+
30
36
  ## Ownership and replacement
31
37
 
32
38
  `CjsResMan` resolves each normalized path and promised output to one canonical
@@ -117,10 +123,16 @@ resource.ReleasePayload()
117
123
  `CjsResMan` binds resource-facing `KeepAlive()`, `KeepPayloadAlive()`,
118
124
  `Lock()`, and `Unlock()` to the resource's canonical MotherLode key.
119
125
  `SetPayload()` renews both identity and payload activity when it publishes a
120
- non-null payload. `GetPayload()`, `HasPayload()`, `IsGood()`, and other
121
- queries are pure; reading the payload does not implicitly renew its lease.
122
- Detached and purged handles retain deterministic no-op liveness methods rather
123
- than silently starting work.
126
+ non-null payload. `GetPayload()`, `HasPayload()`, `IsPrepared()`, and other
127
+ state/payload queries are pure; reading the payload does not implicitly renew
128
+ its lease. `IsGood()` is the deliberate exception: it calls `KeepAlive()`,
129
+ renewing this handle and starting its bounded reload path when it is `PURGED`.
130
+ It does not recursively traverse or renew child resources.
131
+
132
+ A handle detached by ordinary ownership removal has no live MotherLode
133
+ controller. A purged handle retains the reload hook needed to re-register and
134
+ refill that exact handle, so `IsGood()`/`KeepAlive()` can recover it as
135
+ described under [Ownership and replacement](#ownership-and-replacement).
124
136
 
125
137
  A released CPU payload retains only the small request needed to reconstruct
126
138
  that same path/output from its source and `sourceRevision`. The retained
@@ -249,10 +261,12 @@ operation is still active. Lock release is conditional on the same captured
249
261
  ownership generation, so stale work cannot decrement a newly rebound handle's
250
262
  lock. Scheduling and active-work protection do not fetch or reload data.
251
263
 
252
- Cache trimming and automatic inactivity sweeps retain the strict no-reload
253
- rule. Application retention defaults, automatic resource/payload byte
254
- estimation, separate CPU/adapter budgets, and purged-resource/device-loss
255
- recovery policy are future work; see the [roadmap](../roadmap.md).
264
+ Cache trimming and automatic inactivity sweeps never fetch or reload as part
265
+ of the sweep itself. A later `IsGood()`/`KeepAlive()` call may recover the
266
+ purged handle through its bounded reload path. Application retention defaults,
267
+ automatic resource/payload byte estimation, and separate CPU/adapter budgets
268
+ remain future work; backend device-loss recovery belongs to the engine
269
+ realization contract. See the [roadmap](../roadmap.md).
256
270
 
257
271
  ## Related documentation
258
272
 
@@ -82,10 +82,10 @@ invent offset semantics.
82
82
  A clone-safe format opts in with a static worker declaration:
83
83
 
84
84
  ```js
85
- static worker = Object.freeze({
85
+ static worker = {
86
86
  module: import.meta.url,
87
87
  exportName: "CjsExampleFormat"
88
- });
88
+ };
89
89
  ```
90
90
 
91
91
  The worker dynamically imports that exact module and invokes its static
@@ -98,12 +98,12 @@ their class identity.
98
98
  A declaration may restrict clone-safe outputs:
99
99
 
100
100
  ```js
101
- static worker = Object.freeze({
101
+ static worker = {
102
102
  module: import.meta.url,
103
103
  exportName: "CjsExampleFormat",
104
- outputTypes: Object.freeze([ "json", "payload" ]),
104
+ outputTypes: [ "json", "payload" ],
105
105
  defaultOutput: "json"
106
- });
106
+ };
107
107
  ```
108
108
 
109
109
  Format options containing functions, symbols, non-plain instances, cycles, or