@carbonenginejs/runtime-resource 0.8.0 → 0.9.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 (297) hide show
  1. package/LICENSE +21 -21
  2. package/NOTICE +31 -29
  3. package/README.md +67 -548
  4. package/dist/CjsMotherLode.js +1271 -1271
  5. package/dist/CjsResMan.js +3005 -3005
  6. package/dist/CjsResManQueue.js +214 -214
  7. package/dist/CjsResource.js +566 -566
  8. package/dist/CjsResourceSource.js +68 -59
  9. package/dist/CjsResourceSource.js.map +1 -1
  10. package/dist/_virtual/_rollupPluginBabelHelpers.js +153 -153
  11. package/dist/format/CjsBlueReader.js +269 -269
  12. package/dist/format/CjsFormat.js +197 -192
  13. package/dist/format/CjsFormat.js.map +1 -1
  14. package/dist/format/CjsReader.js +18 -18
  15. package/dist/format/CjsResourceProbe.js +277 -277
  16. package/dist/format/payloadContract.js +173 -173
  17. package/dist/formats/black/CjsBlackFormat.js +278 -278
  18. package/dist/formats/black/core/CjsBlackBinaryReader.js +157 -153
  19. package/dist/formats/black/core/CjsBlackBinaryReader.js.map +1 -1
  20. package/dist/formats/black/core/CjsBlackPropertyReaders.js +387 -382
  21. package/dist/formats/black/core/CjsBlackPropertyReaders.js.map +1 -1
  22. package/dist/formats/black/core/CjsBlackReader.js +639 -639
  23. package/dist/formats/black/core/CjsBlackSchemaRegistry.js +437 -433
  24. package/dist/formats/black/core/CjsBlackSchemaRegistry.js.map +1 -1
  25. package/dist/formats/black/core/black-schema-v1-2026-07-23.json.js +4 -0
  26. package/dist/formats/black/core/black-schema-v1-2026-07-23.json.js.map +1 -0
  27. package/dist/formats/black/core/blackConstants.js +7 -7
  28. package/dist/formats/black/core/blackDefinitions.js +10 -10
  29. package/dist/formats/black/core/blackDefinitions.js.map +1 -1
  30. package/dist/formats/black/core/blackEnums.js +6 -6
  31. package/dist/formats/black/core/blackSchema.js +3 -3
  32. package/dist/formats/black/core/blackVersion.js +22 -22
  33. package/dist/formats/black/core/helpers.js +182 -182
  34. package/dist/formats/black/core/schema.js +4 -4
  35. package/dist/formats/black/index.js +2 -2
  36. package/dist/formats/bnk/CjsBnkFormat.js +125 -125
  37. package/dist/formats/bnk/core/graph.js +140 -140
  38. package/dist/formats/bnk/core/helpers.js +409 -409
  39. package/dist/formats/bnk/core/musicNodes.js +493 -489
  40. package/dist/formats/bnk/core/musicNodes.js.map +1 -1
  41. package/dist/formats/bnk/core/soundbanksInfo.js +246 -246
  42. package/dist/formats/bnk/index.js +2 -2
  43. package/dist/formats/cmf/CjsCmfFormat.js +497 -497
  44. package/dist/formats/cmf/core/binary.js +123 -118
  45. package/dist/formats/cmf/core/binary.js.map +1 -1
  46. package/dist/formats/cmf/core/buffers.js +233 -233
  47. package/dist/formats/cmf/core/constants.js +47 -47
  48. package/dist/formats/cmf/core/gr2Anim.js +453 -453
  49. package/dist/formats/cmf/core/helpers.js +287 -287
  50. package/dist/formats/cmf/core/pack.js +276 -276
  51. package/dist/formats/cmf/core/schema.js +364 -364
  52. package/dist/formats/cmf/core/shared.js +268 -268
  53. package/dist/formats/cmf/core/writer.js +517 -517
  54. package/dist/formats/cmf/index.js +2 -2
  55. package/dist/formats/dds/CjsDdsFormat.js +200 -193
  56. package/dist/formats/dds/CjsDdsFormat.js.map +1 -1
  57. package/dist/formats/dds/core/bc6h.js +288 -288
  58. package/dist/formats/dds/core/bc7.js +256 -251
  59. package/dist/formats/dds/core/bc7.js.map +1 -1
  60. package/dist/formats/dds/core/helpers.js +815 -815
  61. package/dist/formats/dds/index.js +2 -2
  62. package/dist/formats/fbx/CjsFbxFormat.js +266 -266
  63. package/dist/formats/fbx/core/helpers.js +3911 -3901
  64. package/dist/formats/fbx/core/helpers.js.map +1 -1
  65. package/dist/formats/fbx/index.js +2 -2
  66. package/dist/formats/flac/CjsFlacFormat.js +93 -87
  67. package/dist/formats/flac/CjsFlacFormat.js.map +1 -1
  68. package/dist/formats/flac/core/helpers.js +295 -295
  69. package/dist/formats/flac/index.js +2 -2
  70. package/dist/formats/gif/CjsGifFormat.js +92 -87
  71. package/dist/formats/gif/CjsGifFormat.js.map +1 -1
  72. package/dist/formats/gif/core/helpers.js +360 -360
  73. package/dist/formats/gif/index.js +2 -2
  74. package/dist/formats/gltf/CjsGltfFormat.js +290 -290
  75. package/dist/formats/gltf/core/helpers.js +292 -292
  76. package/dist/formats/gltf/core/json.js +79 -79
  77. package/dist/formats/gltf/core/parser.js +666 -666
  78. package/dist/formats/gltf/core/targets.js +163 -163
  79. package/dist/formats/gltf/index.js +2 -2
  80. package/dist/formats/gr2/CjsGr2Format.js +46 -0
  81. package/dist/formats/gr2/CjsGr2Format.js.map +1 -0
  82. package/dist/formats/gr2/core/CjsFormatGr2.js +273 -0
  83. package/dist/formats/gr2/core/CjsFormatGr2.js.map +1 -0
  84. package/dist/formats/gr2/core/bitknit2.js +280 -0
  85. package/dist/formats/gr2/core/bitknit2.js.map +1 -0
  86. package/dist/formats/gr2/core/curves.js +1047 -0
  87. package/dist/formats/gr2/core/curves.js.map +1 -0
  88. package/dist/formats/gr2/core/gsf.js +72 -0
  89. package/dist/formats/gr2/core/gsf.js.map +1 -0
  90. package/dist/formats/gr2/core/helpers.js +332 -0
  91. package/dist/formats/gr2/core/helpers.js.map +1 -0
  92. package/dist/formats/gr2/core/json.js +622 -0
  93. package/dist/formats/gr2/core/json.js.map +1 -0
  94. package/dist/formats/gr2/core/oodle1.js +388 -0
  95. package/dist/formats/gr2/core/oodle1.js.map +1 -0
  96. package/dist/formats/gr2/core/reader.js +617 -0
  97. package/dist/formats/gr2/core/reader.js.map +1 -0
  98. package/dist/formats/gr2/core/tangents.js +48 -0
  99. package/dist/formats/gr2/core/tangents.js.map +1 -0
  100. package/dist/formats/gr2/core/targets.js +351 -0
  101. package/dist/formats/gr2/core/targets.js.map +1 -0
  102. package/dist/formats/gr2/index.js +3 -0
  103. package/dist/formats/gr2/index.js.map +1 -0
  104. package/dist/formats/index.js +30 -23
  105. package/dist/formats/index.js.map +1 -1
  106. package/dist/formats/jpeg/CjsJpegFormat.js +212 -206
  107. package/dist/formats/jpeg/CjsJpegFormat.js.map +1 -1
  108. package/dist/formats/jpeg/core/helpers.js +350 -350
  109. package/dist/formats/jpeg/core/jpeg.js +387 -377
  110. package/dist/formats/jpeg/core/jpeg.js.map +1 -1
  111. package/dist/formats/jpeg/index.js +2 -2
  112. package/dist/formats/mp3/CjsMp3Format.js +197 -192
  113. package/dist/formats/mp3/CjsMp3Format.js.map +1 -1
  114. package/dist/formats/mp3/core/helpers.js +338 -338
  115. package/dist/formats/mp3/index.js +2 -2
  116. package/dist/formats/mp4/CjsMp4Format.js +197 -191
  117. package/dist/formats/mp4/CjsMp4Format.js.map +1 -1
  118. package/dist/formats/mp4/core/helpers.js +449 -449
  119. package/dist/formats/mp4/index.js +2 -2
  120. package/dist/formats/obj/CjsObjFormat.js +253 -253
  121. package/dist/formats/obj/core/helpers.js +573 -573
  122. package/dist/formats/obj/core/json.js +64 -64
  123. package/dist/formats/obj/core/parser.js +321 -321
  124. package/dist/formats/obj/index.js +2 -2
  125. package/dist/formats/ogg/CjsOggFormat.js +94 -88
  126. package/dist/formats/ogg/CjsOggFormat.js.map +1 -1
  127. package/dist/formats/ogg/core/helpers.js +387 -387
  128. package/dist/formats/ogg/core/imdct.js +178 -178
  129. package/dist/formats/ogg/core/vorbis.js +1004 -999
  130. package/dist/formats/ogg/core/vorbis.js.map +1 -1
  131. package/dist/formats/ogg/index.js +2 -2
  132. package/dist/formats/png/CjsPngFormat.js +201 -195
  133. package/dist/formats/png/CjsPngFormat.js.map +1 -1
  134. package/dist/formats/png/core/helpers.js +583 -583
  135. package/dist/formats/png/index.js +2 -2
  136. package/dist/formats/red/CjsRedFormat.js +261 -261
  137. package/dist/formats/red/core/CjsRedReader.js +194 -194
  138. package/dist/formats/red/core/blackDefinitions.js +3 -3
  139. package/dist/formats/red/core/helpers.js +139 -139
  140. package/dist/formats/red/core/redGraph.js +68 -68
  141. package/dist/formats/red/core/schema.js +4 -4
  142. package/dist/formats/red/index.js +2 -2
  143. package/dist/formats/stl/CjsStlFormat.js +365 -365
  144. package/dist/formats/stl/core/helpers.js +261 -261
  145. package/dist/formats/stl/core/json.js +51 -51
  146. package/dist/formats/stl/core/stl.js +634 -629
  147. package/dist/formats/stl/core/stl.js.map +1 -1
  148. package/dist/formats/stl/core/targets.js +163 -163
  149. package/dist/formats/stl/index.js +2 -2
  150. package/dist/formats/tga/CjsTgaFormat.js +197 -192
  151. package/dist/formats/tga/CjsTgaFormat.js.map +1 -1
  152. package/dist/formats/tga/core/helpers.js +446 -446
  153. package/dist/formats/tga/index.js +2 -2
  154. package/dist/formats/wav/CjsWavFormat.js +198 -192
  155. package/dist/formats/wav/CjsWavFormat.js.map +1 -1
  156. package/dist/formats/wav/core/helpers.js +328 -328
  157. package/dist/formats/wav/index.js +2 -2
  158. package/dist/formats/webm/CjsWebmFormat.js +197 -191
  159. package/dist/formats/webm/CjsWebmFormat.js.map +1 -1
  160. package/dist/formats/webm/core/helpers.js +537 -537
  161. package/dist/formats/webm/index.js +2 -2
  162. package/dist/formats/webp/CjsWebpFormat.js +91 -86
  163. package/dist/formats/webp/CjsWebpFormat.js.map +1 -1
  164. package/dist/formats/webp/core/helpers.js +214 -214
  165. package/dist/formats/webp/index.js +2 -2
  166. package/dist/formats/wem/CjsWemFormat.js +242 -241
  167. package/dist/formats/wem/CjsWemFormat.js.map +1 -1
  168. package/dist/formats/wem/core/bitStream.js +259 -259
  169. package/dist/formats/wem/core/codebookLibrary.js +164 -164
  170. package/dist/formats/wem/core/helpers.js +417 -417
  171. package/dist/formats/wem/core/packedCodebooksAotuv603.js +30 -30
  172. package/dist/formats/wem/core/ptadpcm.js +77 -77
  173. package/dist/formats/wem/core/resolve.js +121 -121
  174. package/dist/formats/wem/core/wemToOgg.js +485 -485
  175. package/dist/formats/wem/index.js +2 -2
  176. package/dist/formats/yaml/CjsYamlFormat.js +89 -83
  177. package/dist/formats/yaml/CjsYamlFormat.js.map +1 -1
  178. package/dist/formats/yaml/core/CjsYamlReader.js +311 -305
  179. package/dist/formats/yaml/core/CjsYamlReader.js.map +1 -1
  180. package/dist/formats/yaml/core/helpers.js +160 -160
  181. package/dist/formats/yaml/index.js +2 -2
  182. package/dist/index.js +49 -48
  183. package/dist/index.js.map +1 -1
  184. package/dist/resourcePath.js +18 -18
  185. package/dist/resourceStates.js +9 -9
  186. package/dist/resources/AudioGeometryResData.js +47 -47
  187. package/dist/resources/GStateBindingCallbackData.js +31 -31
  188. package/dist/resources/MeshDecalData.js +37 -37
  189. package/dist/resources/MeshDecalLodData.js +34 -34
  190. package/dist/resources/Tr2EffectRes.js +71 -71
  191. package/dist/resources/Tr2GrannyIntersectionResult.js +60 -60
  192. package/dist/resources/Tr2GrannyStateRes.js +44 -44
  193. package/dist/resources/Tr2ImageRes.js +114 -114
  194. package/dist/resources/Tr2LightProfileRes.js +40 -40
  195. package/dist/resources/Tr2MaterialArea.js +34 -34
  196. package/dist/resources/Tr2MaterialMesh.js +31 -31
  197. package/dist/resources/Tr2MaterialRes.js +34 -34
  198. package/dist/resources/Tr2ShaderPermutation.js +43 -43
  199. package/dist/resources/Tr2TextureLodManager.js +80 -80
  200. package/dist/resources/Tr2TextureLodUpdateRequest.js +37 -37
  201. package/dist/resources/Tr2TexturePackChannel.js +37 -37
  202. package/dist/resources/Tr2TexturePipeline.js +52 -52
  203. package/dist/resources/Tr2TexturePipelineParams.js +34 -34
  204. package/dist/resources/Tr2TexturePipelineStepCompress.js +40 -40
  205. package/dist/resources/Tr2TexturePipelineStepGenerateMips.js +22 -0
  206. package/dist/resources/Tr2TexturePipelineStepGenerateMips.js.map +1 -0
  207. package/dist/resources/Tr2TexturePipelineStepLimitSize.js +34 -34
  208. package/dist/resources/Tr2TexturePipelineStepLoad.js +31 -31
  209. package/dist/resources/Tr2TexturePipelineStepPack.js +43 -43
  210. package/dist/resources/TriGeometryRes.js +239 -239
  211. package/dist/resources/TriGeometryResAreaData.js +59 -59
  212. package/dist/resources/TriGeometryResJointData.js +38 -38
  213. package/dist/resources/TriGeometryResLodData.js +88 -88
  214. package/dist/resources/TriGeometryResMeshData.js +63 -63
  215. package/dist/resources/TriGeometryResSkeletonData.js +34 -34
  216. package/dist/resources/TriGrannyRes.js +43 -43
  217. package/dist/resources/TriJointBinding.js +38 -38
  218. package/dist/resources/TriMorphTargetGeometryConstants.js +46 -46
  219. package/dist/resources/TriRtGeometryConstants.js +88 -88
  220. package/dist/resources/TriTextureRes.js +304 -304
  221. package/dist/resources/enums.js +18 -18
  222. package/dist/resources/resourceBoundary.js +47 -47
  223. package/dist/resources/texturePipelineBehavior.js +308 -308
  224. package/dist/texture/CjsTextureArrayRes.js +406 -406
  225. package/dist/texture/CjsTextureParameterProxy.js +133 -133
  226. package/docs/README.md +73 -0
  227. package/docs/architecture.md +86 -0
  228. package/docs/concepts/resource-lifecycle.md +217 -0
  229. package/docs/formats/README.md +105 -0
  230. package/docs/formats/gr2.md +161 -0
  231. package/{FORMAT-PROVENANCE.md → docs/formats/provenance.md} +173 -155
  232. package/docs/formats/stl.md +37 -0
  233. package/docs/formats/wwise.md +44 -0
  234. package/docs/reference/classes/README.md +33 -0
  235. package/docs/reference/classes/core.md +106 -0
  236. package/docs/reference/classes/dropped.md +46 -0
  237. package/docs/reference/classes/formats.md +522 -0
  238. package/docs/reference/classes/resources.md +346 -0
  239. package/docs/reference/classes/texture.md +26 -0
  240. package/docs/reference/events.md +92 -0
  241. package/docs/reference/motherlode-cache.md +244 -0
  242. package/docs/reference/queues.md +102 -0
  243. package/docs/reference/reload.md +107 -0
  244. package/docs/reference/texture-arrays.md +113 -0
  245. package/docs/reference/texture-pipeline.md +53 -0
  246. package/docs/roadmap.md +104 -0
  247. package/format-notices/black/LICENSE +21 -21
  248. package/format-notices/black/NOTICE +47 -47
  249. package/format-notices/bnk/LICENSE +21 -21
  250. package/format-notices/bnk/NOTICE +20 -20
  251. package/format-notices/cmf/LICENSE +21 -21
  252. package/format-notices/cmf/NOTICE +36 -36
  253. package/format-notices/dds/LICENSE +21 -21
  254. package/format-notices/dds/NOTICE +14 -14
  255. package/format-notices/fbx/LICENSE +21 -21
  256. package/format-notices/fbx/NOTICE +14 -14
  257. package/format-notices/flac/LICENSE +21 -21
  258. package/format-notices/flac/NOTICE +14 -14
  259. package/format-notices/gif/LICENSE +21 -21
  260. package/format-notices/gif/NOTICE +14 -14
  261. package/format-notices/gltf/LICENSE +21 -21
  262. package/format-notices/gltf/NOTICE +27 -27
  263. package/format-notices/gr2/LICENSE +21 -0
  264. package/format-notices/gr2/NOTICE +60 -0
  265. package/format-notices/gr2/THIRD-PARTY-NOTICES.md +93 -0
  266. package/format-notices/jpeg/LICENSE +21 -21
  267. package/format-notices/jpeg/NOTICE +14 -14
  268. package/format-notices/mp3/LICENSE +21 -21
  269. package/format-notices/mp3/NOTICE +14 -14
  270. package/format-notices/mp4/LICENSE +21 -21
  271. package/format-notices/mp4/NOTICE +14 -14
  272. package/format-notices/obj/LICENSE +21 -21
  273. package/format-notices/obj/NOTICE +26 -26
  274. package/format-notices/ogg/LICENSE +21 -21
  275. package/format-notices/ogg/NOTICE +28 -28
  276. package/format-notices/png/LICENSE +21 -21
  277. package/format-notices/png/NOTICE +14 -14
  278. package/format-notices/red/LICENSE +21 -21
  279. package/format-notices/red/NOTICE +31 -31
  280. package/format-notices/stl/LICENSE +21 -21
  281. package/format-notices/stl/NOTICE +21 -21
  282. package/format-notices/tga/LICENSE +21 -21
  283. package/format-notices/tga/NOTICE +14 -14
  284. package/format-notices/wav/LICENSE +21 -21
  285. package/format-notices/wav/NOTICE +14 -14
  286. package/format-notices/webm/LICENSE +21 -21
  287. package/format-notices/webm/NOTICE +14 -14
  288. package/format-notices/webp/LICENSE +21 -21
  289. package/format-notices/webp/NOTICE +14 -14
  290. package/format-notices/wem/LICENSE +57 -57
  291. package/format-notices/wem/NOTICE +33 -33
  292. package/format-notices/yaml/LICENSE +21 -21
  293. package/format-notices/yaml/NOTICE +44 -44
  294. package/package.json +52 -51
  295. package/dist/formats/black/core/black-schema-v1-2026-07-11.json.js +0 -4
  296. package/dist/formats/black/core/black-schema-v1-2026-07-11.json.js.map +0 -1
  297. package/resource-lifecycle.md +0 -679
package/README.md CHANGED
@@ -1,548 +1,67 @@
1
- # @carbonenginejs/runtime-resource
2
-
3
- CarbonEngineJS resource lifecycle, cache, format selection, source, and object
4
- loading contracts.
5
-
6
- This package owns the GPU-free resource layer:
7
-
8
- - `CjsResource` state and Carbon-style resource methods.
9
- - `CjsTextureArrayRes` and `CjsTextureParameterProxy` for material-facing,
10
- frame-coalesced texture-array inputs without changing ordinary texture
11
- parameter behavior.
12
- - `CjsMotherLode` canonical identity, explicit replacement results, activity
13
- and lock metadata, deterministic payload/adapter cleanup, and cache stats.
14
- - `CjsResMan` semantic resource construction, registered-format selection,
15
- concurrency-limited source loading, staged prepare queues, layered
16
- source/read/resource deduplication, object loader dispatch, and prefetch.
17
- - Raw `CjsEventEmitter` from `core-types/model` for manager/runtime events
18
- without requiring `CjsModel` inheritance. External listeners unregister
19
- directly with `OffEvent`; listener scopes, owner-side `ListenTo` helpers,
20
- and a separate resource notification layer are not part of the contract.
21
- - Path normalization and extension helpers.
22
- - Source adapters for memory and `fetch`.
23
- - Plain reader/converter payload objects with focused shared validators.
24
- - Canonical Carbon resource classes that validate and hold CPU payloads
25
- privately:
26
- `TriTextureRes`, `TriGeometryRes`, `Tr2EffectRes`, `Tr2ImageRes`,
27
- `TriGrannyRes`, `Tr2GrannyStateRes`, and `Tr2LightProfileRes`.
28
- - `Tr2TexturePipeline` for Carbon-shaped CPU-only load, limit-size, compress
29
- validation, and channel-pack steps, plus `Tr2TextureLodManager` for explicit
30
- texture-resource membership without device-memory policy.
31
- - Opaque engine-owned subobject slots for backend adapters.
32
- - Format policy, format class contracts, and load/prepare state mapping stay
33
- inside this package's implementation and public API rather than external
34
- workspace notes.
35
- - Non-shader format implementations are owned as explicit tree-shakeable
36
- subpaths under `@carbonenginejs/runtime-resource/formats/<name>`.
37
-
38
- It intentionally does not own WebGL/WebGPU realization. Engine packages should adapt prepared resources into backend objects.
39
-
40
- Authoring source is decorated JavaScript. Published/consumer output is built ESM in `npm/dist`.
41
-
42
- Completed Carbon data classes live with maintained source under
43
- `src/resources`; `src/generated` is reserved for unresolved active ports and is
44
- currently absent. Native shapes that JavaScript replaces or does not use are
45
- retained only under `src/dropped`, with their disposition documented there,
46
- and are never exported or bundled.
47
-
48
- ## Package relationships
49
-
50
- - `runtime-core` may configure and expose a `CjsResMan`, but does not own its
51
- implementation.
52
- - `runtime-trinity` and `runtime-sof` may request GPU-free objects and resources
53
- without selecting an engine.
54
- - `engine-webgpu` and future WebGL engines consume loaded resources and own all
55
- backend allocations, preparation, replacement, and destruction.
56
-
57
- Concrete formats are not imported or registered by the package root:
58
-
59
- ```js
60
- import { CjsResMan } from "@carbonenginejs/runtime-resource";
61
- import { CjsMp4Format } from "@carbonenginejs/runtime-resource/formats/mp4";
62
-
63
- const resMan = new CjsResMan().Register({
64
- source,
65
- formats: [ CjsMp4Format ]
66
- });
67
-
68
- const resource = resMan.GetResource("res:/video/intro.mp4");
69
- const video = await resource.Ready();
70
- ```
71
-
72
- Formats return plain payload objects. Semantic resource classes apply them
73
- through `SetPayload()`, validate their own required fields, and throw
74
- `CJS_RESOURCE_PAYLOAD_INVALID` before replacing a previously valid payload.
75
- `GetPayload()`, `HasPayload()`, and `ReleasePayload()` manage transient CPU
76
- retention without introducing a parallel DTO class hierarchy.
77
-
78
- Red payload output reserves configurable type, ID, reference, and sequence
79
- values markers (`_type`, `_id`, `_reference`, and `_values` by default).
80
- Repeated or cyclic sequences use an ID-bearing values envelope; unique
81
- sequences remain arrays. Authored fields may not collide with active markers,
82
- so remap the marker options when those names are real data. Disabling the
83
- reference marker preserves actual JavaScript identity; cyclic output in that
84
- mode is intentionally not JSON-serializable.
85
-
86
- ## Texture CPU pipeline and LOD membership
87
-
88
- `Tr2TexturePipeline` is the Carbon texture-specific CPU bitmap pipeline, not a
89
- general resource prepare stage. `GetResourceDependencies()` returns the sorted
90
- unique paths required by load and channel-pack steps. `Execute()` resolves
91
- those inputs from an explicit `inputs` map/object, an async `load(path)`
92
- callback, or an injected `CjsResMan`, then returns a canonical plain
93
- `rgba8unorm` payload:
94
-
95
- ```js
96
- import {
97
- Tr2TexturePipeline,
98
- Tr2TexturePipelineStepLoad,
99
- Tr2TexturePipelineStepLimitSize
100
- } from "@carbonenginejs/runtime-resource";
101
-
102
- const load = new Tr2TexturePipelineStepLoad();
103
- load.path = "res:/texture/source.png";
104
- const limit = new Tr2TexturePipelineStepLimitSize();
105
- limit.maxWidth = 512;
106
-
107
- const pipeline = new Tr2TexturePipeline();
108
- pipeline.steps = [ load, limit ];
109
- const rgba = await pipeline.Execute(0, 0, { resMan });
110
- ```
111
-
112
- The maintained runtime path currently accepts canonical `rgba8unorm` inputs.
113
- Load copies the source bitmap, limit-size repeatedly performs a 2x2 CPU
114
- downsample, pack builds logical RGBA channels from independent inputs, and
115
- Carbon's present compress step remains validation-only because the native
116
- method is itself a no-op. Unsupported step types fail explicitly.
117
-
118
- Decoded DDS fallback currently has a narrower contract than native DDS texture
119
- output. `emit: "rgba"` returns one canonical 2D surface decoded from the first
120
- DDS subresource; it does not preserve stored mip levels, cube faces, array
121
- layers, or volume slices. Consumers may use it for ordinary 2D fallback when
122
- the engine owns any required mip generation, but must not infer decoded
123
- multi-subresource support from a successful RGBA probe. A future richer
124
- decoded-texture contract must be introduced explicitly rather than overloading
125
- the current RGBA fields. The software path includes BC1-BC5 and BC7 as RGBA8,
126
- plus signed and unsigned BC6H as linear `Float32Array` RGBA without clamping HDR
127
- values. These block decoders are implemented in-project with no codec package.
128
-
129
- `Tr2TextureLodManager` owns only ordered resource membership through
130
- `RegisterTexture()`, `UnregisterTexture()`, and `GetManagedTextures()`. Engine
131
- packages continue to own GPU allocations, upload accounting, device budgets,
132
- capability limits, and device-loss recovery.
133
-
134
- ## Wwise soundbanks and media
135
-
136
- `formats/bnk` and `formats/wem` cover the Wwise audio pipeline end to end.
137
- `CjsBnkFormat.inspect()` decodes the chunk map, embedded media index, bank
138
- names, and the HIRC listing with version-stable typed fields (event action
139
- lists, action type/target, sound and music-track source ids; pinned against
140
- bank generator version 150). The Wwise-domain toolkit is grouped under the
141
- `CjsBnkFormat.wwise` static: the SoundbanksInfo catalog helpers, the FNV-1
142
- id hash, and event → media resolution:
143
-
144
- ```js
145
- import { CjsBnkFormat } from "@carbonenginejs/runtime-resource/formats/bnk";
146
- import { CjsWemFormat } from "@carbonenginejs/runtime-resource/formats/wem";
147
-
148
- const inspections = bankByteArrays.map(bytes => CjsBnkFormat.inspect(bytes));
149
- const { eventMedia } = CjsBnkFormat.wwise.eventMediaFromBanks(inspections);
150
- // eventMedia: Map<eventObjectId, Set<wemId>> - banks may split events from
151
- // their target sounds, so pass every related bank to one call.
152
-
153
- const ogg = CjsWemFormat.toOgg(wemBytes); // Wwise Vorbis -> Ogg (lossless)
154
- const pcm = CjsWemFormat.toPcm(wemBytes); // PTADPCM / 16-bit PCM -> float32
155
- ```
156
-
157
- The read/inspect path stays a pure container reader; `wwise.eventMediaFromBanks`
158
- is graph interpretation offered for consumers with their own engines — the
159
- resource lifecycle never calls it.
160
-
161
- ## STL export
162
-
163
- `CjsStlFormat` writes shared geometry directly to binary or ASCII STL. The
164
- writer consumes `mesh.vertex.position` and triangular `mesh.indices[].faces`;
165
- multiple meshes and index groups are flattened in encounter order because STL
166
- does not carry portable scene, material, skin, or animation structure.
167
-
168
- ```js
169
- import { CjsStlFormat } from "@carbonenginejs/runtime-resource/formats/stl";
170
-
171
- const bytes = CjsStlFormat.write(sharedGeometry, {
172
- binary: true,
173
- solidName: "ship_hull",
174
- scale: 1000,
175
- requireWatertight: true
176
- });
177
- ```
178
-
179
- Writes do not mutate the shared input. Facet normals are recalculated from
180
- winding by default; set `recalculateNormals: false` to average valid vertex
181
- normals. Degenerate triangles are skipped by default. Index values must be safe
182
- integers within the position channel, and binary output rejects coordinates
183
- outside float32 range instead of silently emitting infinities. The
184
- `requireWatertight` option rejects open, non-manifold, inconsistently wound, or
185
- degenerate output.
186
-
187
- ## MotherLode ownership
188
-
189
- `CjsResMan` resolves each normalized path and promised output to one canonical
190
- MotherLode key. `Insert(key, resource, options)` reports `{ inserted, replaced,
191
- displaced }`; replacement, deletion, clearing, and shutdown destroy attached
192
- adapter allocations and release the complete CPU payload by default. Callers
193
- that deliberately retain ownership may pass `{ cleanup: false }` and keep the
194
- returned displaced resource. If replacement cleanup fails, insertion throws a
195
- contextual error and leaves the existing owner registered. These ordinary
196
- ownership removals preserve the handle's last resource state; `PURGED` is
197
- reserved for successful policy eviction through inactivity or byte pressure.
198
-
199
- Canonical resource identity is the normalized source path plus its promised
200
- output tag. `variant` is the explicit tag; otherwise `emit`, `requirement`, or
201
- `payload` supplies it. Human-readable identities are written as
202
- `res:/ship.gr2@cmf`, although MotherLode uses an internal delimiter. Reader,
203
- constructor, and format-option implementations never enter the key. CjsLibrary
204
- chooses the promised output and ResMan executes the current setup-time format
205
- registration for it.
206
-
207
- Output selection is case-insensitive for identity and matching, but format
208
- readers receive the canonical declared spelling (for example `cmfJson`). A
209
- legacy direct object loader exposes only its unforced default; named output
210
- variants belong on a format class. Unsupported `@output` requests fail before
211
- cache lookup, so a resident handle cannot bypass the declaration.
212
-
213
- A released CPU payload retains only the small request needed to reconstruct
214
- that same path/output from its source and `sourceRevision`. The retained
215
- promised-output fields and source provenance win over later
216
- `Ready()`/`GetObject()` overrides, while cache/reload policy remains per-call.
217
- Payload leases protect active consumers; an engine may release its own backend
218
- adapter without destroying shared CPU data. Change setup-time registrations
219
- only with an explicit resource reset (`Delete`/`Clear`) or a new manager. A
220
- changed output contract must use a new tag such as `@cmf2`.
221
-
222
- `Startup()` and `Shutdown()` are idempotent. `HasKey`, `Lookup`, `Delete`,
223
- `GetKeys`, `GetValues`, `GetSize`, `SetCacheSize`, `GetCacheSize`, `GetStats`,
224
- `TrimCache`, `ReplaceExpected`, `Clear`, and `ClearCached` provide the
225
- Carbon-shaped cache vocabulary plus the exact-owner compare-and-swap required
226
- by staged JavaScript reload. The old `Has`, `GetCount`, and `DeleteAll` names
227
- remain temporary compatibility aliases.
228
-
229
- Byte budgeting applies only to records explicitly admitted with
230
- `{ cached: true, bytes }`; JavaScript reachability is never inferred. The byte
231
- value is a caller-supplied safe-integer eviction weight, not a heuristic walk of
232
- the resource graph. `TrimCache()` removes positive-byte cached identities in
233
- oldest-admission order until `cacheBytes <= cacheSize`. Live, locked,
234
- `cacheable: false`, and zero-byte entries do not create pressure. With default
235
- cleanup, successful pressure eviction performs the same deterministic
236
- payload/adapter cleanup as inactivity eviction and marks detached compatible
237
- handles `PURGED`.
238
-
239
- `SetCacheSize()` installs and immediately enforces a new budget. `Update()` and
240
- `Tick()` retry cache housekeeping after pumping queues; `{ cache: false }`
241
- skips it for one update. Cleanup failure leaves that candidate canonical,
242
- continues through later candidates, and throws
243
- `CJS_MOTHERLODE_CACHE_TRIM_FAILED` with a partial result.
244
-
245
- `CjsResMan` binds resource-facing `KeepAlive`, `KeepPayloadAlive`, `Lock`, and
246
- `Unlock` operations to the canonical key. Publishing a non-null payload renews
247
- its independent lease; `GetPayload()`, `HasPayload()`, `IsGood()`, and other
248
- queries remain pure. `PurgeInactive(options)` performs an explicit deterministic
249
- sweep using independent identity and payload frame/time limits. Locks skip both
250
- forms of eviction. Identity expiry cleans adapters and payloads, detaches the
251
- handle, marks it `PURGED`, and removes it; payload expiry releases only the CPU
252
- payload. A sweep never fetches, prepares, or reloads a resource.
253
-
254
- Generic/base reader results participate in the same payload ownership: the
255
- manager stores the complete result through `SetPayload()` and mirrors it on the
256
- compatibility `object` property. Payload release clears that alias only while
257
- it still identifies the released value. Concurrent object/readiness calls
258
- share only their in-flight operation; settled promises are removed so evicted
259
- graphs are collectible and failed operations can be explicitly retried. A
260
- resident payload returns without rereading, while a released payload is rebuilt
261
- only by an explicit `GetObject()` or `Ready()` call.
262
-
263
- Source and parsed-format caches use explicit provenance. `sourceRevision` is an
264
- opaque caller/source-supplied string or finite number identifying source
265
- content for one source object and normalized path. It scopes read caches only;
266
- it does not alter MotherLode resource identity, and changing it does not replace a
267
- resident payload without `reload: true`.
268
-
269
- `cacheSource` and `cacheFormat` are tri-state per-call policies:
270
-
271
- - omitted: share in-flight or explicitly retained work, then drop a newly
272
- completed record;
273
- - `true`: share and retain success; a joining caller upgrades the record;
274
- - `false`: bypass sharing and retention.
275
-
276
- Failures are never retained. Format records are additionally isolated by
277
- selected source object, frozen registration descriptor, revision, and effective
278
- format options. Re-registering a format with new defaults therefore cannot
279
- reuse an old descriptor's parse. Registered defaults are copied into deeply
280
- frozen plain-object/array snapshots. Material format options that cannot be
281
- represented safely (for example class instances with hidden mutable state)
282
- bypass format-cache sharing instead of risking a false match; functions and
283
- byte views use cache-local identity plus visible byte content where applicable.
284
-
285
- `reload: true` synchronously detaches every queued/source/format read record for
286
- the selected source/path before fresh work starts. Existing consumers keep
287
- their detached promises; reload does not abort them. Fresh success repopulates
288
- only caches explicitly requested with `cacheSource: true` or
289
- `cacheFormat: true`. `InvalidateReadCache(path, { source, sourceRevision })`
290
- provides the same no-abort invalidation explicitly; omitting `sourceRevision`
291
- removes all revisions for that source/path. `Delete()` remains canonical
292
- resource-identity-only, while `Clear()` resets all read ledgers.
293
-
294
- A resource loader retains the effective selected source and `sourceRevision`
295
- for reconstruction, including the manager default selected at creation, but
296
- not cache flags or one-shot reload.
297
-
298
- Reload is candidate-first. When an owner already exists,
299
- `GetResource(path, { reload: true })` returns a distinct off-registry candidate
300
- without changing ordinary lookup. `Ready()` on that candidate, `GetObject()` /
301
- `FetchResource()` with `reload: true`, and the explicit `ReloadObject()` /
302
- `ReloadResource()` helpers all run the same queued contract:
303
-
304
- 1. purge-lock the exact former owner and invalidate reusable reads once;
305
- 2. read, convert through the selected format, and publish payload state only on the detached candidate;
306
- 3. require the newest per-key reload token and exact former ownership;
307
- 4. compare-and-swap the fully loaded CPU candidate into MotherLode;
308
- 5. invalidate and clean the displaced handle after the lookup switch.
309
-
310
- Source, format, or publication failure therefore leaves the former handle, state,
311
- payload, and adapters canonical; the failed candidate's attached payload and
312
- adapters are cleaned and its original error is retained. An otherwise-
313
- successful candidate that was superseded, deleted, cleared, or replaced rejects
314
- with `CJS_RESMAN_STALE_RELOAD_CANDIDATE` and cannot resurrect the key. Failed
315
- freshness attempts still invalidate reusable source/format records when their
316
- work begins; the already-published canonical payload is not dependent on those
317
- records. If displaced-owner cleanup fails after the swap,
318
- the promise rejects with `CJS_MOTHERLODE_REPLACE_CLEANUP_FAILED`, whose result
319
- explicitly reports `committed: true`; the good candidate remains canonical.
320
-
321
- This deliberately differs from Carbon's `BlueAsyncRes::Reload`, which reloads
322
- one stable handle in place and releases its old data before success. Existing
323
- JavaScript references likewise are never silently retargeted: they keep the
324
- displaced handle, while fresh lookup sees the committed candidate.
325
-
326
- Every queued, direct, standalone, and candidate resource preparation captures the exact
327
- MotherLode, canonical key, resource handle, and manager-local ownership
328
- generation. Delete, Clear, reload replacement, or handle reinsertion makes old
329
- work stale before it can enter another state or publish. Otherwise-
330
- successful obsolete work rejects with `CJS_RESMAN_STALE_RESOURCE_OPERATION`;
331
- an obsolete source/format failure preserves its original rejection while
332
- suppressing `SetError()` on the detached handle.
333
-
334
- Candidate work is a normal `Wait()` root and blocks synchronous MotherLode
335
- replacement while active. MotherLode replacement otherwise remains synchronous
336
- configuration and rejects with
337
- `CJS_RESMAN_ACTIVE_RESOURCE_OPERATIONS` while queued or direct mutations are
338
- active. `Wait()` drains queued roots; callers must separately await direct load
339
- or direct prepare promises before retrying replacement. Started source or
340
- format work is not yet aborted; deterministic cleanup applies to the staged
341
- candidate resource itself.
342
-
343
- Automatic scheduling is available only when a caller supplies
344
- `autoPurgePolicy` to the constructor/`Register()` or calls
345
- `SetAutoPurgePolicy()`. It is disabled by default and deliberately accepts only
346
- millisecond limits: MotherLode activity frames count explicit observations and
347
- are not renderer frames. `Update()`/`Tick()` run a due sweep after queue pumps;
348
- `{ purge: false }` skips it for one call. The first pump after configuration is
349
- due immediately, then `intervalMilliseconds` limits cadence. Manager-owned
350
- queued and direct resource work holds a balanced purge lock until completion.
351
-
352
- ```js
353
- const resMan = new CjsResMan({
354
- source,
355
- autoPurgePolicy: {
356
- intervalMilliseconds: 1000,
357
- maxIdleMilliseconds: 60_000,
358
- payloadMaxIdleMilliseconds: 10_000
359
- }
360
- });
361
-
362
- resMan.Update();
363
- ```
364
-
365
- Cache trimming and automatic inactivity sweeps retain the strict no-reload
366
- rule. Application retention defaults, automatic resource/payload byte
367
- estimation, separate CPU/adapter budgets, and purged-resource/device-loss
368
- recovery policy remain later work.
369
-
370
- ## Queued CPU load and publication
371
-
372
- `GetObject()`, `LoadObject()`, and resource `Ready()` use two manager-owned
373
- queues:
374
-
375
- ```text
376
- BACKGROUND: deduplicated source load, limited by maxConcurrentLoads
377
- MAIN: reader/format conversion -> resource publication
378
- ```
379
-
380
- The main reader/format operation and publication are separate queue items.
381
- `maxPrepareTime` is a per-pump budget in seconds, and
382
- `maxPrepareItemsPerTick` can add an item-count limit. The default scheduler
383
- keeps promise-based calls working; a `CjsLibrary` or direct caller can provide
384
- its frame scheduler:
385
-
386
- ```js
387
- const resMan = new CjsResMan({
388
- source,
389
- maxConcurrentLoads: 8,
390
- maxPrepareTime: 0.005,
391
- queueScheduler: callback => requestAnimationFrame(callback)
392
- });
393
-
394
- await resMan.FetchResource("res:/model/ship.gr2", {
395
- requirement: "geometry",
396
- emit: "cmf"
397
- });
398
- ```
399
-
400
- The selected format class owns conversion to the promised CPU output.
401
- `CjsResMan` does not inspect WebGL, WebGPU, texture, geometry, or codec support,
402
- and it does not run backend realization. An engine consumes the published CPU
403
- resource afterward through its own explicit operation.
404
-
405
- Blue-compatible queue controls are exposed directly on `CjsResMan`:
406
- `AddToQueue`, `CancelFromQueue`, `GetNextIdForQueue`,
407
- `PumpMainThreadQueue`, `PauseQueue`, `ResumeQueue`, `GetPendingLoads`, and
408
- `GetPendingPrepares`. `Update()`/`Tick()` pump work. `Wait()` synchronously
409
- captures queued resource-operation roots and low-level queue tasks that already
410
- exist when it is called. Captured resource roots include publication work
411
- enqueued after an asynchronous read; unrelated later roots/tasks do not
412
- postpone the fence. Failure and queued cancellation count as settlement and remain
413
- observable through their original operation promises.
414
-
415
- By default `Wait()` pumps the two queues directly within their ordinary budgets
416
- and never runs automatic purge housekeeping. It preserves pause state;
417
- `{ pump: false }` leaves all progress to an external driver. A standalone
418
- canonical `PrepareResourceObjectQueued()` call is a queued root. Direct
419
- `LoadResourceObject()`, direct `PrepareResourceObject()`, standalone
420
- `ReadResource()`, and standalone `ReadFormatOnce()` calls bypass both queues
421
- and are outside this fence unless they own a captured queue task, although
422
- direct resource mutations are still tracked for safe MotherLode replacement.
423
- `WaitUrgent()` remains deferred until the queue has real per-item priority and
424
- urgent-membership semantics.
425
-
426
- Format classes own input extensions. Resource classes are registered by a
427
- semantic requirement, never by file extension:
428
-
429
- ```js
430
- const resMan = new CjsResMan().Register({
431
- source,
432
- formats: [ CjsDdsFormat, CjsPngFormat ],
433
- resourceTypes: [ TriTextureRes, Tr2ImageRes ]
434
- });
435
-
436
- const texture = resMan.GetResource("res:/image/ship.png", {
437
- requirement: "texture",
438
- emit: "image"
439
- });
440
- const image = resMan.GetResource("res:/image/ship.png", {
441
- requirement: "image",
442
- emit: "image"
443
- });
444
- ```
445
-
446
- Those are distinct resource identities but share the normalized source-byte
447
- operation. The manager does not expose an extension-to-resource compatibility
448
- registry.
449
-
450
- Texture-array resources expose one ordinary-looking proxy per ordered layer:
451
-
452
- ```js
453
- const textureArray = new CjsTextureArrayRes({
454
- paths: [
455
- "res:/detail1.dds",
456
- "res:/detail2.dds",
457
- "res:/detail3.dds"
458
- ],
459
- layerNames: [ "Detail1Map", "Detail2Map", "Detail3Map" ],
460
- updateScheduler: resource => frameQueue.add(resource)
461
- });
462
-
463
- const detail2 = textureArray.GetLayerParameter(1);
464
- detail2.SetValue("res:/replacement.dds");
465
-
466
- detail2.textureRes === textureArray; // true
467
- ```
468
-
469
- Proxy setters only update their source path and invalidate the parent. The
470
- parent is scheduled once even if several proxies change in the same frame.
471
- The next-frame consumer calls `Update()` or `ConsumeUpdateRequest()` to obtain
472
- one immutable ordered snapshot. Runtime-resource does not know which shader
473
- metadata caused the aggregate request; shader packages and engine adapters map
474
- public parameter names to layer indices.
475
-
476
- Public effect parameters remain separate from these internal proxies. Their
477
- authored paths and individual 2D source resources are not replaced by the
478
- aggregate. An engine-owned, non-persisted bridge mirrors public changes into
479
- the fixed internal layers.
480
-
481
- Consumed snapshots are explicit in-flight generations. An adapter either
482
- publishes the current candidate atomically, requeues retryable work, or records
483
- failure:
484
-
485
- ```js
486
- const request = textureArray.ConsumeUpdateRequest();
487
-
488
- try {
489
- const candidate = await adapter.PrepareTextureArray(request);
490
- const result = textureArray.CommitPreparedAdapterRevision(
491
- request.revision,
492
- "webgpu",
493
- candidate
494
- );
495
-
496
- // A rejected/stale candidate is destroyed by the commit method by default.
497
- // The adapter owns disposal of a successfully displaced allocation.
498
- result.displaced?.destroy();
499
- } catch (error) {
500
- textureArray.FailUpdateRequest(request.revision, error, { retry: true });
501
- }
502
-
503
- await textureArray.Ready(); // the generation requested at call time
504
- ```
505
-
506
- `SetLayerResource()` attaches a resolved source without rewriting the logical
507
- requested path. `TouchLayer()` invalidates an in-place source revision.
508
- `RetryUpdateRequest()` restores consumed work, and `HandleAdapterLoss()` drops
509
- an unusable adapter allocation and schedules a complete topology rebuild.
510
- Topology-changing snapshots set `topologyChanged: true` and report only valid
511
- current layer indices in `dirtyLayers`.
512
-
513
- ## Development
514
-
515
- Install dependencies and run the non-interactive baseline checks from the
516
- repository root:
517
-
518
- ```sh
519
- npm install
520
- npm run lint
521
- npm run check
522
- npm test
523
- ```
524
-
525
- `npm run check` builds the consumer package and proves that decorator metadata
526
- matches between authoring source and built output. `npm test` additionally runs
527
- the complete GPU-free unit suite; it requires no private assets, credentials,
528
- network access, browser, or GPU after dependencies are installed.
529
-
530
- See [Runtime Resource Lifecycle](resource-lifecycle.md) for state, retention,
531
- and texture-array generation contracts. See
532
- [Format ownership and fork provenance](FORMAT-PROVENANCE.md) for copied-reader
533
- ownership, licenses, exclusions, and the deferred GR2 migration. Both documents
534
- ship with the published package.
535
-
536
- ## Provenance
537
-
538
- CarbonEngine and Fenris Creations (CCP Games) are named for interoperability
539
- and provenance context. This package contains CarbonEngineJS original resource
540
- infrastructure, CarbonEngine-shaped resource ports, and maintained copies of
541
- the non-shader readers identified in `FORMAT-PROVENANCE.md`. It does not copy
542
- Fenris Creations game assets, proprietary documentation, or shader source.
543
- CarbonEngine and historical JavaScript implementations were used as the
544
- behavioral references described in the package notices.
545
-
546
- This project is not affiliated with, endorsed by, or sponsored by CCP Games or
547
- CCP ehf. EVE Online and related marks remain the property of their respective
548
- owners.
1
+ # @carbonenginejs/runtime-resource
2
+
3
+ CarbonEngineJS resource lifecycle, cache, format selection, source, and object
4
+ loading contracts — the GPU-free resource layer.
5
+
6
+ Use this package when you need Carbon-shaped resource loading (`res:/` paths,
7
+ requirement/emit selection, `Ready()`/`GetObject()`) or one of the non-shader
8
+ format readers, without choosing a GPU backend. It sits between source
9
+ adapters and the engine packages that realize prepared resources. It does not
10
+ own WebGL/WebGPU realization, device budgets, or shader formats.
11
+
12
+ ## Install
13
+
14
+ ```sh
15
+ npm install @carbonenginejs/runtime-resource
16
+ ```
17
+
18
+ ## Quick start
19
+
20
+ Concrete formats are explicit tree-shakeable subpaths, never imported by the
21
+ package root:
22
+
23
+ ```js
24
+ import { CjsResMan } from "@carbonenginejs/runtime-resource";
25
+ import { CjsMp4Format } from "@carbonenginejs/runtime-resource/formats/mp4";
26
+
27
+ const resMan = new CjsResMan().Register({
28
+ source,
29
+ formats: [ CjsMp4Format ]
30
+ });
31
+
32
+ const resource = resMan.GetResource("res:/video/intro.mp4");
33
+ const video = await resource.Ready();
34
+ ```
35
+
36
+ ## Documentation
37
+
38
+ - [Package documentation](docs/README.md)
39
+ - [Architecture and boundaries](docs/architecture.md)
40
+ - [Resource lifecycle concepts](docs/concepts/resource-lifecycle.md)
41
+ - [Format subpaths](docs/formats/README.md)
42
+ - [Format ownership and fork provenance](docs/formats/provenance.md)
43
+
44
+ ## Development
45
+
46
+ Non-interactive baseline checks run from the repository root:
47
+
48
+ ```sh
49
+ npm install
50
+ npm run lint
51
+ npm run check
52
+ npm test
53
+ ```
54
+
55
+ `npm run check` builds the consumer package and proves that decorator metadata
56
+ matches between authoring source and built output. `npm test` additionally
57
+ runs the complete GPU-free unit suite; it requires no private assets,
58
+ credentials, network access, browser, or GPU after dependencies are installed.
59
+
60
+ ## License
61
+
62
+ MIT. See [LICENSE](LICENSE) and [NOTICE](NOTICE). CarbonEngine and Fenris
63
+ Creations (CCP Games) are named for interoperability and provenance context;
64
+ copied-reader ownership, licenses, and retained snapshots are recorded in
65
+ [docs/formats/provenance.md](docs/formats/provenance.md). This project is not
66
+ affiliated with, endorsed by, or sponsored by CCP Games or CCP ehf. EVE
67
+ Online and related marks remain the property of their respective owners.