@plasius/gpu-model-renderer 0.1.5 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,35 +1,130 @@
1
1
  # @plasius/gpu-model-renderer
2
2
 
3
- Canonical model to renderer-ready buffers, bounds, materials, skinning, and animation bridge.
3
+ Prepare verified canonical GPU models as renderer-ready geometry, material slots,
4
+ texture resources, joint palettes, skin influences, animation tracks and bounds.
5
+ The package follows site ADR 0094. It does not parse file formats, fetch URLs,
6
+ decode images, evaluate animation, or upload GPU resources.
4
7
 
5
- This repository is the dedicated package boundary defined by ADR 0094.
8
+ ## Usage
6
9
 
7
- ## Bootstrap status
10
+ ```ts
11
+ import { prepareGpuModelRendererInput } from "@plasius/gpu-model-renderer";
8
12
 
9
- This initial repository contains the approved schema baseline, legal and governance files, and a package smoke-test surface. Functional model conversion work is tracked in the repository's [TASK] issues and must flow through the canonical GPU model boundary.
13
+ // document is factory output from the same @plasius/gpu-model-core instance.
14
+ // The source adapter/runtime owns loading, hashing and resource verification.
15
+ const prepared = await prepareGpuModelRendererInput(document, {
16
+ conversionEnabled: remotelyEvaluatedConversionFlag,
17
+ signal: abortController.signal,
18
+ timeoutMs: 30_000,
19
+ maxDecodedBytes: 64 * 1024 * 1024,
20
+ });
10
21
 
11
- ## Rollout
22
+ // Load the renderer only when needed. Image decoding is owned by the host.
23
+ const { createCanonicalWavefrontMeshInputs } = await import("@plasius/gpu-renderer");
24
+ const meshes = createCanonicalWavefrontMeshInputs({
25
+ document: prepared.document,
26
+ geometry: prepared.geometry,
27
+ textures: decodedTextureSamplesByCanonicalTextureId,
28
+ });
29
+ ```
30
+
31
+ The renderer is a consumer dependency, not a runtime dependency of this bridge.
32
+ The example maps **mesh-local geometry**. Before rendering a scene, the host must
33
+ apply `nodes`/`roots` transforms and instancing, and handle skins, morph targets
34
+ and animation. `bounds` retains the validated **world-space** canonical bounds.
35
+ The current Wavefront canonical adapter supports triangle primitives and a
36
+ subset of canonical materials. It rejects unsupported topology/workflows;
37
+ callers must preserve that failure or select another renderer. Passing geometry
38
+ alone does not bake a scene or implement animation.
39
+
40
+ `primitives` retains every attribute semantic and a zero-based `materialSlot`
41
+ (`null` for the default material). `accessors` contains tightly packed,
42
+ little-endian-decoded buffers, including animation and morph accessors.
43
+ Non-normalized unsigned integers use `Uint32Array`; other components use
44
+ `Float32Array`, including normalized integer attributes. Indices never pass
45
+ through floating-point conversion. Missing normals remain absent so the
46
+ renderer owns its existing normal fallback.
47
+
48
+ `skins` contains ordered joint IDs, packed inverse bind matrices, joint indices
49
+ and weights. `animations` contains channels, interpolation and decoded sampler
50
+ inputs/outputs. The full immutable `document` retains clip names, source
51
+ metadata, material extensions, texture binding transforms, colour spaces,
52
+ samplers, analytic source references, and diagnostics. Texture entries pair
53
+ canonical metadata with verified encoded image resources. Image decoders must
54
+ apply their own output limits; the bridge makes no image/network requests.
55
+
56
+ ## Validation and failure handling
57
+
58
+ Only privately verified `GpuModelDocument` factory output is accepted. Plain
59
+ objects and structured clones fail closed; verify clones through
60
+ `createAndVerifyGpuModelDocument` in the receiving core instance. Keep core
61
+ versions/module instances consistent across adapters and bridge consumers.
62
+ The deprecated `packageBootstrap` identity export remains compatible.
12
63
 
13
- - Feature flag: gpu.model.conversion.enabled
14
- - Capability: none for this package-only layer
15
- - Rollback: disable the feature flag and keep the published package version pinned to the last validated release
64
+ Optional `diagnostics` uses the core `GpuModelDiagnosticInput` contract. Core
65
+ owns strict/tolerant/forensic evaluation and bounded repair/loss/evidence
66
+ ledgers. Strict is the default. Tolerant reports describe repairs already
67
+ performed by a source adapter; the bridge performs no repairs. Rejected reports
68
+ or canonical error diagnostics prevent preparation in every mode. Forensic raw
69
+ evidence is returned only in its explicit report and is never logged here.
16
70
 
17
- ## Development
71
+ `GpuModelRendererError.code` distinguishes `feature-disabled`,
72
+ `unverified-document`, `invalid-options`, `budget-exceeded`, `aborted`,
73
+ `diagnostics-rejected`, and `resource-read-failed`. Core may also throw its
74
+ bounded diagnostics error for malformed reports. Errors contain no payloads,
75
+ source URLs or identifiers. No partial output is returned.
18
76
 
19
- Requires Node.js 24 and npm.
77
+ The default/fixed ceiling is 64 MiB for encoded buffer copies plus decoded
78
+ accessors and skin buffers, preflighted before allocation. The timeout defaults
79
+ to 30 seconds and can only be tightened. Resource acquisition is sequential,
80
+ with no retries or shared mutable cache. Cancellation/deadline failures discard
81
+ partial output. CPU loops check the deadline; run large models in a host worker
82
+ so cancellation and main-thread responsiveness remain under host control.
83
+ Output containers are frozen; typed arrays are intentionally consumer-owned
84
+ and mutable for GPU upload. Accessor views within one result may share a buffer.
85
+ Mutations never affect the canonical document or a subsequent preparation.
86
+
87
+ ## Rollout and rollback
88
+
89
+ - Parent Feature: [site #1153](https://github.com/Plasius-LTD/plasius-ltd-site/issues/1153).
90
+ - Feature flag: `gpu.model.conversion.enabled`.
91
+ - Source-of-truth evaluator: the host's remote feature-flag service; pass its
92
+ decision as `conversionEnabled` on every preparation. Omission/false rejects.
93
+ - Capability: none for this data-only package layer.
94
+ - Rollback: disable the remote flag, cancel outstanding preparation via its
95
+ signal, and retain the previous consumer loader and validated package pin.
96
+ No local environment value is used as the normal control plane.
97
+
98
+ ## Development and release
99
+
100
+ Requires the Node.js 24 version pinned in `.nvmrc` and npm.
20
101
 
21
102
  ```bash
22
103
  npm ci
23
104
  npm run typecheck
24
105
  npm test
106
+ npm run test:coverage
25
107
  npm run lint
26
108
  npm run build
109
+ npm run pack:check
27
110
  npm pack --dry-run
28
111
  ```
29
112
 
30
- ## License
113
+ Tests cover canonical geometry/accessor fidelity, scene/rig/animation retention,
114
+ rollout and error paths, and the published runtime -> bridge -> published
115
+ renderer material-atlas/mesh-acceleration boundary. The runtime test adapter is
116
+ a deterministic canonical fixture, **not** a glTF parser. These tests do not
117
+ prove the full format conformance matrix in site Story #1160: the current
118
+ published GLB canonical importer supports a narrower texture-free static
119
+ profile. Actual format-adapter support must be verified separately.
120
+
121
+ Dependencies added for this API: runtime core `0.4.6` (canonical validation and
122
+ diagnostics); test-only runtime `0.2.4` and renderer `0.2.51` (published consumer
123
+ contract checks). No local package references or format SDKs are introduced.
124
+ See [ADR 0006](docs/adrs/adr-0006-canonical-renderer-preparation.md) and the
125
+ [design and NFR evidence](docs/design/canonical-renderer-preparation.md).
31
126
 
32
- Apache-2.0. See LICENSE, SECURITY.md, and the files under legal/.
127
+ Apache-2.0. See LICENSE, SECURITY.md, and legal/.
33
128
 
34
129
  <!-- BEGIN PLASIUS RELEASE INTEGRITY -->
35
130
  ## Release integrity
package/dist/index.cjs CHANGED
@@ -20,10 +20,204 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ GPU_MODEL_RENDERER_FEATURE_FLAG: () => GPU_MODEL_RENDERER_FEATURE_FLAG,
24
+ GPU_MODEL_RENDERER_MAX_DECODED_BYTES: () => GPU_MODEL_RENDERER_MAX_DECODED_BYTES,
25
+ GpuModelRendererError: () => GpuModelRendererError,
23
26
  packageBootstrap: () => packageBootstrap,
24
- packageName: () => packageName
27
+ packageName: () => packageName,
28
+ prepareGpuModelRendererInput: () => prepareGpuModelRendererInput
25
29
  });
26
30
  module.exports = __toCommonJS(index_exports);
31
+
32
+ // src/renderer-input.ts
33
+ var import_gpu_model_core = require("@plasius/gpu-model-core");
34
+ var GPU_MODEL_RENDERER_MAX_DECODED_BYTES = 64 * 1024 * 1024;
35
+ var GPU_MODEL_RENDERER_FEATURE_FLAG = "gpu.model.conversion.enabled";
36
+ var GpuModelRendererError = class extends Error {
37
+ constructor(code) {
38
+ super(`GPU model renderer preparation failed: ${code}`);
39
+ this.code = code;
40
+ this.name = "GpuModelRendererError";
41
+ }
42
+ code;
43
+ };
44
+ var COMPONENT_BYTES = { i8: 1, u8: 1, i16: 2, u16: 2, u32: 4, f32: 4 };
45
+ var COMPONENTS = { scalar: 1, vec2: 2, vec3: 3, vec4: 4, mat2: 4, mat3: 9, mat4: 16 };
46
+ var readBlob = Blob.prototype.arrayBuffer;
47
+ function decode(accessor, view, check) {
48
+ const size = COMPONENT_BYTES[accessor.componentType];
49
+ const width = COMPONENTS[accessor.elementType];
50
+ const stride = accessor.byteStride ?? size * width;
51
+ const output = ["u8", "u16", "u32"].includes(accessor.componentType) && !accessor.normalized ? new Uint32Array(accessor.count * width) : new Float32Array(accessor.count * width);
52
+ for (let index = 0; index < output.length; index += 1) {
53
+ if (index % 4096 === 0) check();
54
+ const offset = accessor.byteOffset + Math.floor(index / width) * stride + index % width * size;
55
+ let value;
56
+ switch (accessor.componentType) {
57
+ case "i8":
58
+ value = view.getInt8(offset);
59
+ break;
60
+ case "u8":
61
+ value = view.getUint8(offset);
62
+ break;
63
+ case "i16":
64
+ value = view.getInt16(offset, true);
65
+ break;
66
+ case "u16":
67
+ value = view.getUint16(offset, true);
68
+ break;
69
+ case "u32":
70
+ value = view.getUint32(offset, true);
71
+ break;
72
+ case "f32":
73
+ value = view.getFloat32(offset, true);
74
+ break;
75
+ }
76
+ if (accessor.normalized) {
77
+ const divisor = { i8: 127, u8: 255, i16: 32767, u16: 65535, u32: 4294967295, f32: 1 }[accessor.componentType];
78
+ value = Math.max(-1, value / divisor);
79
+ }
80
+ output[index] = value;
81
+ }
82
+ return output;
83
+ }
84
+ async function prepareGpuModelRendererInput(value, options) {
85
+ if (options?.conversionEnabled !== true) throw new GpuModelRendererError("feature-disabled");
86
+ if (!(0, import_gpu_model_core.isGpuModelDocument)(value)) throw new GpuModelRendererError("unverified-document");
87
+ const document = value;
88
+ const maxBytes = options.maxDecodedBytes ?? GPU_MODEL_RENDERER_MAX_DECODED_BYTES;
89
+ const timeoutMs = options.timeoutMs ?? 3e4;
90
+ if (!Number.isSafeInteger(maxBytes) || maxBytes < 1 || maxBytes > GPU_MODEL_RENDERER_MAX_DECODED_BYTES || !Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 3e4) {
91
+ throw new GpuModelRendererError("invalid-options");
92
+ }
93
+ const diagnosticReport = options.diagnostics === void 0 ? void 0 : (0, import_gpu_model_core.evaluateGpuModelDiagnostics)(options.diagnostics);
94
+ if (diagnosticReport?.accepted === false || document.diagnostics.some(({ severity }) => severity === "error")) {
95
+ throw new GpuModelRendererError("diagnostics-rejected");
96
+ }
97
+ let allocation = 0;
98
+ for (const accessor of document.accessors) allocation += accessor.count * COMPONENTS[accessor.elementType] * 4;
99
+ for (const skin of document.skins) {
100
+ allocation += skin.inverseBindMatrices.length * 16 * 4;
101
+ for (const weights of skin.weightSets) allocation += weights.joints.length * weights.influencesPerVertex * 8;
102
+ }
103
+ for (const resource of document.resources) if (resource.kind === "buffer") allocation += resource.byteLength;
104
+ if (allocation > maxBytes) throw new GpuModelRendererError("budget-exceeded");
105
+ const deadline = performance.now() + timeoutMs;
106
+ const check = () => {
107
+ if (options.signal?.aborted || performance.now() >= deadline) throw new GpuModelRendererError("aborted");
108
+ };
109
+ check();
110
+ const accessors = /* @__PURE__ */ Object.create(null);
111
+ const accessorsByResource = /* @__PURE__ */ new Map();
112
+ for (const accessor of document.accessors) {
113
+ const entries = accessorsByResource.get(accessor.resourceId) ?? [];
114
+ entries.push(accessor);
115
+ accessorsByResource.set(accessor.resourceId, entries);
116
+ }
117
+ for (const resource of document.resources) {
118
+ const entries = accessorsByResource.get(resource.id);
119
+ if (!entries) continue;
120
+ let timer;
121
+ let abort;
122
+ try {
123
+ const buffer = await new Promise((resolve, reject) => {
124
+ abort = () => reject(new GpuModelRendererError("aborted"));
125
+ options.signal?.addEventListener("abort", abort, { once: true });
126
+ timer = setTimeout(abort, Math.max(1, deadline - performance.now()));
127
+ readBlob.call(resource.payload).then(resolve, () => reject(new GpuModelRendererError("resource-read-failed")));
128
+ });
129
+ check();
130
+ const view = new DataView(buffer);
131
+ for (const accessor of entries) {
132
+ check();
133
+ accessors[accessor.id] = decode(accessor, view, check);
134
+ }
135
+ } finally {
136
+ clearTimeout(timer);
137
+ if (abort) options.signal?.removeEventListener("abort", abort);
138
+ }
139
+ }
140
+ const primitives = [];
141
+ const geometry = [];
142
+ const materialSlots = new Map(document.materials.map((material, index) => [material.id, index]));
143
+ for (const mesh of document.meshes) for (const primitive of mesh.primitives) {
144
+ check();
145
+ const attributes = /* @__PURE__ */ Object.create(null);
146
+ for (const attribute of primitive.attributes) attributes[attribute.semantic] = accessors[attribute.accessorId];
147
+ primitives.push(Object.freeze({
148
+ meshId: mesh.id,
149
+ primitiveId: primitive.id,
150
+ topology: primitive.topology,
151
+ materialSlot: primitive.materialId === void 0 ? null : materialSlots.get(primitive.materialId),
152
+ attributes: Object.freeze(attributes)
153
+ }));
154
+ geometry.push(Object.freeze({
155
+ primitiveId: primitive.id,
156
+ positions: attributes.POSITION,
157
+ ...primitive.indicesAccessorId === void 0 ? {} : { indices: accessors[primitive.indicesAccessorId] },
158
+ ...attributes.NORMAL === void 0 ? {} : { normals: attributes.NORMAL },
159
+ ...attributes.TEXCOORD_0 === void 0 ? {} : { texcoords: attributes.TEXCOORD_0 }
160
+ }));
161
+ }
162
+ const pack = (rows, output) => {
163
+ let offset = 0;
164
+ for (const row of rows) {
165
+ check();
166
+ output.set(row, offset);
167
+ offset += row.length;
168
+ }
169
+ return output;
170
+ };
171
+ const skins = document.skins.map((skin) => {
172
+ check();
173
+ return Object.freeze({
174
+ id: skin.id,
175
+ skeletonId: skin.skeletonId,
176
+ jointIds: skin.jointIds,
177
+ inverseBindMatrices: pack(skin.inverseBindMatrices, new Float32Array(skin.inverseBindMatrices.length * 16)),
178
+ weightSets: Object.freeze(skin.weightSets.map((weights) => Object.freeze({
179
+ primitiveId: weights.primitiveId,
180
+ influencesPerVertex: weights.influencesPerVertex,
181
+ joints: pack(weights.joints, new Uint32Array(weights.joints.length * weights.influencesPerVertex)),
182
+ weights: pack(weights.weights, new Float32Array(weights.weights.length * weights.influencesPerVertex))
183
+ })))
184
+ });
185
+ });
186
+ const animations = document.animations.map((animation) => Object.freeze({
187
+ id: animation.id,
188
+ durationSeconds: animation.durationSeconds,
189
+ channels: animation.channels,
190
+ samplers: Object.freeze(animation.samplers.map((sampler) => Object.freeze({
191
+ id: sampler.id,
192
+ interpolation: sampler.interpolation,
193
+ input: accessors[sampler.inputAccessorId],
194
+ output: accessors[sampler.outputAccessorId]
195
+ })))
196
+ }));
197
+ const resources = new Map(document.resources.map((resource) => [resource.id, resource]));
198
+ check();
199
+ return Object.freeze({
200
+ document,
201
+ bounds: document.bounds,
202
+ roots: document.roots,
203
+ nodes: document.nodes,
204
+ materials: document.materials,
205
+ skeletons: document.skeletons,
206
+ joints: document.joints,
207
+ blendShapes: document.blendShapes,
208
+ analyticGeometry: document.analyticGeometry,
209
+ diagnostics: document.diagnostics,
210
+ ...diagnosticReport === void 0 ? {} : { diagnosticReport },
211
+ accessors: Object.freeze(accessors),
212
+ primitives: Object.freeze(primitives),
213
+ geometry: Object.freeze(geometry),
214
+ skins: Object.freeze(skins),
215
+ animations: Object.freeze(animations),
216
+ textures: Object.freeze(document.textures.map((texture) => Object.freeze({ texture, resource: resources.get(texture.imageResourceId) })))
217
+ });
218
+ }
219
+
220
+ // src/index.ts
27
221
  var packageName = "@plasius/gpu-model-renderer";
28
222
  var packageBootstrap = Object.freeze({
29
223
  packageName,
@@ -32,7 +226,11 @@ var packageBootstrap = Object.freeze({
32
226
  });
33
227
  // Annotate the CommonJS export names for ESM import in node:
34
228
  0 && (module.exports = {
229
+ GPU_MODEL_RENDERER_FEATURE_FLAG,
230
+ GPU_MODEL_RENDERER_MAX_DECODED_BYTES,
231
+ GpuModelRendererError,
35
232
  packageBootstrap,
36
- packageName
233
+ packageName,
234
+ prepareGpuModelRendererInput
37
235
  });
38
236
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/** Package identity and rollout metadata for the initial repository baseline. */\nexport const packageName = \"@plasius/gpu-model-renderer\" as const;\n\nexport const packageBootstrap = Object.freeze({\n packageName,\n featureFlag: \"gpu.model.conversion.enabled\",\n status: \"bootstrap\",\n} as const);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACO,IAAM,cAAc;AAEpB,IAAM,mBAAmB,OAAO,OAAO;AAAA,EAC5C;AAAA,EACA,aAAa;AAAA,EACb,QAAQ;AACV,CAAU;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/renderer-input.ts"],"sourcesContent":["/** Package identity and rollout metadata for the initial repository baseline. */\nexport const packageName = \"@plasius/gpu-model-renderer\" as const;\n\n/** @deprecated Retained for compatibility with the bootstrap package identity. */\nexport const packageBootstrap = Object.freeze({\n packageName,\n featureFlag: \"gpu.model.conversion.enabled\",\n status: \"bootstrap\",\n} as const);\n\nexport * from \"./renderer-input.js\";\n","import {\n evaluateGpuModelDiagnostics, isGpuModelDocument,\n type GpuModelAccessor, type GpuModelDiagnosticInput, type GpuModelDiagnosticReport,\n type GpuModelDocument, type GpuModelResource, type GpuModelTexture,\n} from \"@plasius/gpu-model-core\";\n\n/** Fixed allocation ceiling; callers may tighten it, never raise it. */\nexport const GPU_MODEL_RENDERER_MAX_DECODED_BYTES = 64 * 1024 * 1024;\n/** Remotely evaluated parent Feature flag. No environment override is read here. */\nexport const GPU_MODEL_RENDERER_FEATURE_FLAG = \"gpu.model.conversion.enabled\";\n\n/** Stable, payload-free failure categories for callers and worker boundaries. */\nexport type GpuModelRendererErrorCode = \"feature-disabled\" | \"unverified-document\" | \"invalid-options\" | \"budget-exceeded\" | \"aborted\" | \"diagnostics-rejected\" | \"resource-read-failed\";\n/** Bounded errors deliberately omit source paths, URIs and payload content. */\nexport class GpuModelRendererError extends Error {\n public constructor(public readonly code: GpuModelRendererErrorCode) {\n super(`GPU model renderer preparation failed: ${code}`);\n this.name = \"GpuModelRendererError\";\n }\n}\n\n/** Consumer-owned buffers; changing them never changes the canonical document. */\nexport type GpuModelRendererBuffer = Float32Array | Uint32Array;\n/** Decode policy. Gate decisions must come from the host's remote flag evaluator. */\nexport interface GpuModelRendererOptions {\n readonly conversionEnabled: boolean;\n readonly signal?: AbortSignal;\n readonly timeoutMs?: number;\n readonly maxDecodedBytes?: number;\n readonly diagnostics?: GpuModelDiagnosticInput;\n}\n/** Geometry in mesh-local coordinates, directly usable by the canonical renderer adapter. */\nexport interface GpuModelRendererGeometry {\n readonly primitiveId: string;\n readonly positions: Float32Array;\n readonly indices?: Uint32Array;\n readonly normals?: Float32Array;\n readonly texcoords?: Float32Array;\n}\n/** All attributes are retained, including UV sets, colours, joints and custom semantics. */\nexport interface GpuModelRendererPrimitive {\n readonly meshId: string;\n readonly primitiveId: string;\n readonly topology: GpuModelDocument[\"meshes\"][number][\"primitives\"][number][\"topology\"];\n /** Zero-based canonical material index; null denotes the renderer's default material. */\n readonly materialSlot: number | null;\n readonly attributes: Readonly<Record<string, GpuModelRendererBuffer>>;\n}\n/** Ordered joint palette and packed vertex influences; no animation is evaluated or baked. */\nexport interface GpuModelRendererSkin {\n readonly id: string;\n readonly skeletonId: string;\n readonly jointIds: readonly string[];\n readonly inverseBindMatrices: Float32Array;\n readonly weightSets: readonly {\n readonly primitiveId: string;\n readonly influencesPerVertex: number;\n readonly joints: Uint32Array;\n readonly weights: Float32Array;\n }[];\n}\n/** Canonical clip semantics with decoded, tightly packed sampler buffers. */\nexport interface GpuModelRendererAnimation {\n readonly id: string;\n readonly durationSeconds: number;\n readonly channels: GpuModelDocument[\"animations\"][number][\"channels\"];\n readonly samplers: readonly {\n readonly id: string;\n readonly interpolation: GpuModelDocument[\"animations\"][number][\"samplers\"][number][\"interpolation\"];\n readonly input: GpuModelRendererBuffer;\n readonly output: GpuModelRendererBuffer;\n }[];\n}\n/** Verified images remain encoded; the caller chooses its decoder/upload strategy. */\nexport interface GpuModelRendererTexture {\n readonly texture: GpuModelTexture;\n readonly resource: GpuModelResource;\n}\n/** Scene-aware preparation result. Geometry alone is not a baked world-space scene. */\nexport interface GpuModelRendererInput {\n readonly document: GpuModelDocument;\n readonly bounds: GpuModelDocument[\"bounds\"];\n readonly roots: GpuModelDocument[\"roots\"];\n readonly nodes: GpuModelDocument[\"nodes\"];\n readonly materials: GpuModelDocument[\"materials\"];\n readonly skeletons: GpuModelDocument[\"skeletons\"];\n readonly joints: GpuModelDocument[\"joints\"];\n readonly blendShapes: GpuModelDocument[\"blendShapes\"];\n readonly analyticGeometry: GpuModelDocument[\"analyticGeometry\"];\n readonly diagnostics: GpuModelDocument[\"diagnostics\"];\n readonly diagnosticReport?: GpuModelDiagnosticReport;\n readonly accessors: Readonly<Record<string, GpuModelRendererBuffer>>;\n readonly geometry: readonly GpuModelRendererGeometry[];\n readonly primitives: readonly GpuModelRendererPrimitive[];\n readonly textures: readonly GpuModelRendererTexture[];\n readonly skins: readonly GpuModelRendererSkin[];\n readonly animations: readonly GpuModelRendererAnimation[];\n}\n\nconst COMPONENT_BYTES = { i8: 1, u8: 1, i16: 2, u16: 2, u32: 4, f32: 4 } as const;\nconst COMPONENTS = { scalar: 1, vec2: 2, vec3: 3, vec4: 4, mat2: 4, mat3: 9, mat4: 16 } as const;\n\nconst readBlob = Blob.prototype.arrayBuffer;\n\nfunction decode(accessor: GpuModelAccessor, view: DataView, check: () => void): GpuModelRendererBuffer {\n const size = COMPONENT_BYTES[accessor.componentType];\n const width = COMPONENTS[accessor.elementType];\n const stride = accessor.byteStride ?? size * width;\n const output = [\"u8\", \"u16\", \"u32\"].includes(accessor.componentType) && !accessor.normalized\n ? new Uint32Array(accessor.count * width)\n : new Float32Array(accessor.count * width);\n for (let index = 0; index < output.length; index += 1) {\n if (index % 4096 === 0) check();\n const offset = accessor.byteOffset + Math.floor(index / width) * stride + (index % width) * size;\n let value: number;\n switch (accessor.componentType) {\n case \"i8\": value = view.getInt8(offset); break;\n case \"u8\": value = view.getUint8(offset); break;\n case \"i16\": value = view.getInt16(offset, true); break;\n case \"u16\": value = view.getUint16(offset, true); break;\n case \"u32\": value = view.getUint32(offset, true); break;\n case \"f32\": value = view.getFloat32(offset, true); break;\n }\n if (accessor.normalized) {\n const divisor = { i8: 127, u8: 255, i16: 32767, u16: 65535, u32: 4294967295, f32: 1 }[accessor.componentType];\n value = Math.max(-1, value / divisor);\n }\n output[index] = value;\n }\n return output;\n}\n\n/**\n * Prepares privately verified core output without parsing source formats, fetching\n * resources or importing a renderer. Structured clones must be reverified by core.\n * Run on a host worker for large inputs. Operations are sequential, bounded and\n * have no retries. The host owns scene transforms and animation evaluation.\n */\nexport async function prepareGpuModelRendererInput(\n value: unknown,\n options?: GpuModelRendererOptions,\n): Promise<GpuModelRendererInput> {\n if (options?.conversionEnabled !== true) throw new GpuModelRendererError(\"feature-disabled\");\n if (!isGpuModelDocument(value)) throw new GpuModelRendererError(\"unverified-document\");\n const document = value;\n const maxBytes = options.maxDecodedBytes ?? GPU_MODEL_RENDERER_MAX_DECODED_BYTES;\n const timeoutMs = options.timeoutMs ?? 30_000;\n if (!Number.isSafeInteger(maxBytes) || maxBytes < 1 || maxBytes > GPU_MODEL_RENDERER_MAX_DECODED_BYTES\n || !Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 30_000) {\n throw new GpuModelRendererError(\"invalid-options\");\n }\n const diagnosticReport = options.diagnostics === undefined ? undefined : evaluateGpuModelDiagnostics(options.diagnostics);\n if (diagnosticReport?.accepted === false || document.diagnostics.some(({ severity }) => severity === \"error\")) {\n throw new GpuModelRendererError(\"diagnostics-rejected\");\n }\n let allocation = 0;\n for (const accessor of document.accessors) allocation += accessor.count * COMPONENTS[accessor.elementType] * 4;\n for (const skin of document.skins) {\n allocation += skin.inverseBindMatrices.length * 16 * 4;\n for (const weights of skin.weightSets) allocation += weights.joints.length * weights.influencesPerVertex * 8;\n }\n // Include copies of encoded buffers in the peak budget; image bytes are not decoded here.\n for (const resource of document.resources) if (resource.kind === \"buffer\") allocation += resource.byteLength;\n if (allocation > maxBytes) throw new GpuModelRendererError(\"budget-exceeded\");\n const deadline = performance.now() + timeoutMs;\n const check = () => {\n if (options.signal?.aborted || performance.now() >= deadline) throw new GpuModelRendererError(\"aborted\");\n };\n check();\n const accessors: Record<string, GpuModelRendererBuffer> = Object.create(null);\n // One bounded read at a time. Abort/deadline rejects even if a host read stalls.\n const accessorsByResource = new Map<string, GpuModelAccessor[]>();\n for (const accessor of document.accessors) {\n const entries = accessorsByResource.get(accessor.resourceId) ?? [];\n entries.push(accessor);\n accessorsByResource.set(accessor.resourceId, entries);\n }\n for (const resource of document.resources) {\n const entries = accessorsByResource.get(resource.id);\n if (!entries) continue;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let abort: (() => void) | undefined;\n try {\n const buffer = await new Promise<ArrayBuffer>((resolve, reject) => {\n abort = () => reject(new GpuModelRendererError(\"aborted\"));\n options.signal?.addEventListener(\"abort\", abort, { once: true });\n timer = setTimeout(abort, Math.max(1, deadline - performance.now()));\n readBlob.call(resource.payload).then(resolve, () => reject(new GpuModelRendererError(\"resource-read-failed\")));\n });\n check();\n const view = new DataView(buffer);\n for (const accessor of entries) {\n check();\n accessors[accessor.id] = decode(accessor, view, check);\n }\n } finally {\n clearTimeout(timer);\n if (abort) options.signal?.removeEventListener(\"abort\", abort);\n }\n }\n const primitives: GpuModelRendererPrimitive[] = [];\n const geometry: GpuModelRendererGeometry[] = [];\n const materialSlots = new Map(document.materials.map((material, index) => [material.id, index]));\n for (const mesh of document.meshes) for (const primitive of mesh.primitives) {\n check();\n const attributes: Record<string, GpuModelRendererBuffer> = Object.create(null);\n for (const attribute of primitive.attributes) attributes[attribute.semantic] = accessors[attribute.accessorId]!;\n primitives.push(Object.freeze({ meshId: mesh.id, primitiveId: primitive.id, topology: primitive.topology,\n materialSlot: primitive.materialId === undefined ? null : materialSlots.get(primitive.materialId)!, attributes: Object.freeze(attributes) }));\n geometry.push(Object.freeze({ primitiveId: primitive.id, positions: attributes.POSITION! as Float32Array,\n ...(primitive.indicesAccessorId === undefined ? {} : { indices: accessors[primitive.indicesAccessorId]! as Uint32Array }),\n ...(attributes.NORMAL === undefined ? {} : { normals: attributes.NORMAL as Float32Array }),\n ...(attributes.TEXCOORD_0 === undefined ? {} : { texcoords: attributes.TEXCOORD_0 as Float32Array }) }));\n }\n const pack = <T extends Float32Array | Uint32Array>(rows: readonly (readonly number[])[], output: T): T => {\n let offset = 0;\n for (const row of rows) { check(); output.set(row, offset); offset += row.length; }\n return output;\n };\n const skins = document.skins.map(skin => {\n check();\n return Object.freeze({ id: skin.id, skeletonId: skin.skeletonId, jointIds: skin.jointIds,\n inverseBindMatrices: pack(skin.inverseBindMatrices, new Float32Array(skin.inverseBindMatrices.length * 16)),\n weightSets: Object.freeze(skin.weightSets.map(weights => Object.freeze({ primitiveId: weights.primitiveId,\n influencesPerVertex: weights.influencesPerVertex, joints: pack(weights.joints, new Uint32Array(weights.joints.length * weights.influencesPerVertex)), weights: pack(weights.weights, new Float32Array(weights.weights.length * weights.influencesPerVertex)) }))) });\n });\n const animations = document.animations.map(animation => Object.freeze({ id: animation.id, durationSeconds: animation.durationSeconds,\n channels: animation.channels, samplers: Object.freeze(animation.samplers.map(sampler => Object.freeze({ id: sampler.id,\n interpolation: sampler.interpolation, input: accessors[sampler.inputAccessorId]!, output: accessors[sampler.outputAccessorId]! }))) }));\n const resources = new Map(document.resources.map(resource => [resource.id, resource]));\n check();\n return Object.freeze({ document, bounds: document.bounds, roots: document.roots, nodes: document.nodes, materials: document.materials,\n skeletons: document.skeletons, joints: document.joints, blendShapes: document.blendShapes, analyticGeometry: document.analyticGeometry,\n diagnostics: document.diagnostics, ...(diagnosticReport === undefined ? {} : { diagnosticReport }), accessors: Object.freeze(accessors),\n primitives: Object.freeze(primitives), geometry: Object.freeze(geometry), skins: Object.freeze(skins), animations: Object.freeze(animations),\n textures: Object.freeze(document.textures.map(texture => Object.freeze({ texture, resource: resources.get(texture.imageResourceId)! }))) });\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.cts CHANGED
@@ -1,9 +1,108 @@
1
+ import { GpuModelDocument, GpuModelDiagnosticReport, GpuModelTexture, GpuModelResource, GpuModelDiagnosticInput } from '@plasius/gpu-model-core';
2
+
3
+ /** Fixed allocation ceiling; callers may tighten it, never raise it. */
4
+ declare const GPU_MODEL_RENDERER_MAX_DECODED_BYTES: number;
5
+ /** Remotely evaluated parent Feature flag. No environment override is read here. */
6
+ declare const GPU_MODEL_RENDERER_FEATURE_FLAG = "gpu.model.conversion.enabled";
7
+ /** Stable, payload-free failure categories for callers and worker boundaries. */
8
+ type GpuModelRendererErrorCode = "feature-disabled" | "unverified-document" | "invalid-options" | "budget-exceeded" | "aborted" | "diagnostics-rejected" | "resource-read-failed";
9
+ /** Bounded errors deliberately omit source paths, URIs and payload content. */
10
+ declare class GpuModelRendererError extends Error {
11
+ readonly code: GpuModelRendererErrorCode;
12
+ constructor(code: GpuModelRendererErrorCode);
13
+ }
14
+ /** Consumer-owned buffers; changing them never changes the canonical document. */
15
+ type GpuModelRendererBuffer = Float32Array | Uint32Array;
16
+ /** Decode policy. Gate decisions must come from the host's remote flag evaluator. */
17
+ interface GpuModelRendererOptions {
18
+ readonly conversionEnabled: boolean;
19
+ readonly signal?: AbortSignal;
20
+ readonly timeoutMs?: number;
21
+ readonly maxDecodedBytes?: number;
22
+ readonly diagnostics?: GpuModelDiagnosticInput;
23
+ }
24
+ /** Geometry in mesh-local coordinates, directly usable by the canonical renderer adapter. */
25
+ interface GpuModelRendererGeometry {
26
+ readonly primitiveId: string;
27
+ readonly positions: Float32Array;
28
+ readonly indices?: Uint32Array;
29
+ readonly normals?: Float32Array;
30
+ readonly texcoords?: Float32Array;
31
+ }
32
+ /** All attributes are retained, including UV sets, colours, joints and custom semantics. */
33
+ interface GpuModelRendererPrimitive {
34
+ readonly meshId: string;
35
+ readonly primitiveId: string;
36
+ readonly topology: GpuModelDocument["meshes"][number]["primitives"][number]["topology"];
37
+ /** Zero-based canonical material index; null denotes the renderer's default material. */
38
+ readonly materialSlot: number | null;
39
+ readonly attributes: Readonly<Record<string, GpuModelRendererBuffer>>;
40
+ }
41
+ /** Ordered joint palette and packed vertex influences; no animation is evaluated or baked. */
42
+ interface GpuModelRendererSkin {
43
+ readonly id: string;
44
+ readonly skeletonId: string;
45
+ readonly jointIds: readonly string[];
46
+ readonly inverseBindMatrices: Float32Array;
47
+ readonly weightSets: readonly {
48
+ readonly primitiveId: string;
49
+ readonly influencesPerVertex: number;
50
+ readonly joints: Uint32Array;
51
+ readonly weights: Float32Array;
52
+ }[];
53
+ }
54
+ /** Canonical clip semantics with decoded, tightly packed sampler buffers. */
55
+ interface GpuModelRendererAnimation {
56
+ readonly id: string;
57
+ readonly durationSeconds: number;
58
+ readonly channels: GpuModelDocument["animations"][number]["channels"];
59
+ readonly samplers: readonly {
60
+ readonly id: string;
61
+ readonly interpolation: GpuModelDocument["animations"][number]["samplers"][number]["interpolation"];
62
+ readonly input: GpuModelRendererBuffer;
63
+ readonly output: GpuModelRendererBuffer;
64
+ }[];
65
+ }
66
+ /** Verified images remain encoded; the caller chooses its decoder/upload strategy. */
67
+ interface GpuModelRendererTexture {
68
+ readonly texture: GpuModelTexture;
69
+ readonly resource: GpuModelResource;
70
+ }
71
+ /** Scene-aware preparation result. Geometry alone is not a baked world-space scene. */
72
+ interface GpuModelRendererInput {
73
+ readonly document: GpuModelDocument;
74
+ readonly bounds: GpuModelDocument["bounds"];
75
+ readonly roots: GpuModelDocument["roots"];
76
+ readonly nodes: GpuModelDocument["nodes"];
77
+ readonly materials: GpuModelDocument["materials"];
78
+ readonly skeletons: GpuModelDocument["skeletons"];
79
+ readonly joints: GpuModelDocument["joints"];
80
+ readonly blendShapes: GpuModelDocument["blendShapes"];
81
+ readonly analyticGeometry: GpuModelDocument["analyticGeometry"];
82
+ readonly diagnostics: GpuModelDocument["diagnostics"];
83
+ readonly diagnosticReport?: GpuModelDiagnosticReport;
84
+ readonly accessors: Readonly<Record<string, GpuModelRendererBuffer>>;
85
+ readonly geometry: readonly GpuModelRendererGeometry[];
86
+ readonly primitives: readonly GpuModelRendererPrimitive[];
87
+ readonly textures: readonly GpuModelRendererTexture[];
88
+ readonly skins: readonly GpuModelRendererSkin[];
89
+ readonly animations: readonly GpuModelRendererAnimation[];
90
+ }
91
+ /**
92
+ * Prepares privately verified core output without parsing source formats, fetching
93
+ * resources or importing a renderer. Structured clones must be reverified by core.
94
+ * Run on a host worker for large inputs. Operations are sequential, bounded and
95
+ * have no retries. The host owns scene transforms and animation evaluation.
96
+ */
97
+ declare function prepareGpuModelRendererInput(value: unknown, options?: GpuModelRendererOptions): Promise<GpuModelRendererInput>;
98
+
1
99
  /** Package identity and rollout metadata for the initial repository baseline. */
2
100
  declare const packageName: "@plasius/gpu-model-renderer";
101
+ /** @deprecated Retained for compatibility with the bootstrap package identity. */
3
102
  declare const packageBootstrap: Readonly<{
4
103
  readonly packageName: "@plasius/gpu-model-renderer";
5
104
  readonly featureFlag: "gpu.model.conversion.enabled";
6
105
  readonly status: "bootstrap";
7
106
  }>;
8
107
 
9
- export { packageBootstrap, packageName };
108
+ export { GPU_MODEL_RENDERER_FEATURE_FLAG, GPU_MODEL_RENDERER_MAX_DECODED_BYTES, type GpuModelRendererAnimation, type GpuModelRendererBuffer, GpuModelRendererError, type GpuModelRendererErrorCode, type GpuModelRendererGeometry, type GpuModelRendererInput, type GpuModelRendererOptions, type GpuModelRendererPrimitive, type GpuModelRendererSkin, type GpuModelRendererTexture, packageBootstrap, packageName, prepareGpuModelRendererInput };
package/dist/index.d.ts CHANGED
@@ -1,9 +1,108 @@
1
+ import { GpuModelDocument, GpuModelDiagnosticReport, GpuModelTexture, GpuModelResource, GpuModelDiagnosticInput } from '@plasius/gpu-model-core';
2
+
3
+ /** Fixed allocation ceiling; callers may tighten it, never raise it. */
4
+ declare const GPU_MODEL_RENDERER_MAX_DECODED_BYTES: number;
5
+ /** Remotely evaluated parent Feature flag. No environment override is read here. */
6
+ declare const GPU_MODEL_RENDERER_FEATURE_FLAG = "gpu.model.conversion.enabled";
7
+ /** Stable, payload-free failure categories for callers and worker boundaries. */
8
+ type GpuModelRendererErrorCode = "feature-disabled" | "unverified-document" | "invalid-options" | "budget-exceeded" | "aborted" | "diagnostics-rejected" | "resource-read-failed";
9
+ /** Bounded errors deliberately omit source paths, URIs and payload content. */
10
+ declare class GpuModelRendererError extends Error {
11
+ readonly code: GpuModelRendererErrorCode;
12
+ constructor(code: GpuModelRendererErrorCode);
13
+ }
14
+ /** Consumer-owned buffers; changing them never changes the canonical document. */
15
+ type GpuModelRendererBuffer = Float32Array | Uint32Array;
16
+ /** Decode policy. Gate decisions must come from the host's remote flag evaluator. */
17
+ interface GpuModelRendererOptions {
18
+ readonly conversionEnabled: boolean;
19
+ readonly signal?: AbortSignal;
20
+ readonly timeoutMs?: number;
21
+ readonly maxDecodedBytes?: number;
22
+ readonly diagnostics?: GpuModelDiagnosticInput;
23
+ }
24
+ /** Geometry in mesh-local coordinates, directly usable by the canonical renderer adapter. */
25
+ interface GpuModelRendererGeometry {
26
+ readonly primitiveId: string;
27
+ readonly positions: Float32Array;
28
+ readonly indices?: Uint32Array;
29
+ readonly normals?: Float32Array;
30
+ readonly texcoords?: Float32Array;
31
+ }
32
+ /** All attributes are retained, including UV sets, colours, joints and custom semantics. */
33
+ interface GpuModelRendererPrimitive {
34
+ readonly meshId: string;
35
+ readonly primitiveId: string;
36
+ readonly topology: GpuModelDocument["meshes"][number]["primitives"][number]["topology"];
37
+ /** Zero-based canonical material index; null denotes the renderer's default material. */
38
+ readonly materialSlot: number | null;
39
+ readonly attributes: Readonly<Record<string, GpuModelRendererBuffer>>;
40
+ }
41
+ /** Ordered joint palette and packed vertex influences; no animation is evaluated or baked. */
42
+ interface GpuModelRendererSkin {
43
+ readonly id: string;
44
+ readonly skeletonId: string;
45
+ readonly jointIds: readonly string[];
46
+ readonly inverseBindMatrices: Float32Array;
47
+ readonly weightSets: readonly {
48
+ readonly primitiveId: string;
49
+ readonly influencesPerVertex: number;
50
+ readonly joints: Uint32Array;
51
+ readonly weights: Float32Array;
52
+ }[];
53
+ }
54
+ /** Canonical clip semantics with decoded, tightly packed sampler buffers. */
55
+ interface GpuModelRendererAnimation {
56
+ readonly id: string;
57
+ readonly durationSeconds: number;
58
+ readonly channels: GpuModelDocument["animations"][number]["channels"];
59
+ readonly samplers: readonly {
60
+ readonly id: string;
61
+ readonly interpolation: GpuModelDocument["animations"][number]["samplers"][number]["interpolation"];
62
+ readonly input: GpuModelRendererBuffer;
63
+ readonly output: GpuModelRendererBuffer;
64
+ }[];
65
+ }
66
+ /** Verified images remain encoded; the caller chooses its decoder/upload strategy. */
67
+ interface GpuModelRendererTexture {
68
+ readonly texture: GpuModelTexture;
69
+ readonly resource: GpuModelResource;
70
+ }
71
+ /** Scene-aware preparation result. Geometry alone is not a baked world-space scene. */
72
+ interface GpuModelRendererInput {
73
+ readonly document: GpuModelDocument;
74
+ readonly bounds: GpuModelDocument["bounds"];
75
+ readonly roots: GpuModelDocument["roots"];
76
+ readonly nodes: GpuModelDocument["nodes"];
77
+ readonly materials: GpuModelDocument["materials"];
78
+ readonly skeletons: GpuModelDocument["skeletons"];
79
+ readonly joints: GpuModelDocument["joints"];
80
+ readonly blendShapes: GpuModelDocument["blendShapes"];
81
+ readonly analyticGeometry: GpuModelDocument["analyticGeometry"];
82
+ readonly diagnostics: GpuModelDocument["diagnostics"];
83
+ readonly diagnosticReport?: GpuModelDiagnosticReport;
84
+ readonly accessors: Readonly<Record<string, GpuModelRendererBuffer>>;
85
+ readonly geometry: readonly GpuModelRendererGeometry[];
86
+ readonly primitives: readonly GpuModelRendererPrimitive[];
87
+ readonly textures: readonly GpuModelRendererTexture[];
88
+ readonly skins: readonly GpuModelRendererSkin[];
89
+ readonly animations: readonly GpuModelRendererAnimation[];
90
+ }
91
+ /**
92
+ * Prepares privately verified core output without parsing source formats, fetching
93
+ * resources or importing a renderer. Structured clones must be reverified by core.
94
+ * Run on a host worker for large inputs. Operations are sequential, bounded and
95
+ * have no retries. The host owns scene transforms and animation evaluation.
96
+ */
97
+ declare function prepareGpuModelRendererInput(value: unknown, options?: GpuModelRendererOptions): Promise<GpuModelRendererInput>;
98
+
1
99
  /** Package identity and rollout metadata for the initial repository baseline. */
2
100
  declare const packageName: "@plasius/gpu-model-renderer";
101
+ /** @deprecated Retained for compatibility with the bootstrap package identity. */
3
102
  declare const packageBootstrap: Readonly<{
4
103
  readonly packageName: "@plasius/gpu-model-renderer";
5
104
  readonly featureFlag: "gpu.model.conversion.enabled";
6
105
  readonly status: "bootstrap";
7
106
  }>;
8
107
 
9
- export { packageBootstrap, packageName };
108
+ export { GPU_MODEL_RENDERER_FEATURE_FLAG, GPU_MODEL_RENDERER_MAX_DECODED_BYTES, type GpuModelRendererAnimation, type GpuModelRendererBuffer, GpuModelRendererError, type GpuModelRendererErrorCode, type GpuModelRendererGeometry, type GpuModelRendererInput, type GpuModelRendererOptions, type GpuModelRendererPrimitive, type GpuModelRendererSkin, type GpuModelRendererTexture, packageBootstrap, packageName, prepareGpuModelRendererInput };
package/dist/index.js CHANGED
@@ -1,3 +1,194 @@
1
+ // src/renderer-input.ts
2
+ import {
3
+ evaluateGpuModelDiagnostics,
4
+ isGpuModelDocument
5
+ } from "@plasius/gpu-model-core";
6
+ var GPU_MODEL_RENDERER_MAX_DECODED_BYTES = 64 * 1024 * 1024;
7
+ var GPU_MODEL_RENDERER_FEATURE_FLAG = "gpu.model.conversion.enabled";
8
+ var GpuModelRendererError = class extends Error {
9
+ constructor(code) {
10
+ super(`GPU model renderer preparation failed: ${code}`);
11
+ this.code = code;
12
+ this.name = "GpuModelRendererError";
13
+ }
14
+ code;
15
+ };
16
+ var COMPONENT_BYTES = { i8: 1, u8: 1, i16: 2, u16: 2, u32: 4, f32: 4 };
17
+ var COMPONENTS = { scalar: 1, vec2: 2, vec3: 3, vec4: 4, mat2: 4, mat3: 9, mat4: 16 };
18
+ var readBlob = Blob.prototype.arrayBuffer;
19
+ function decode(accessor, view, check) {
20
+ const size = COMPONENT_BYTES[accessor.componentType];
21
+ const width = COMPONENTS[accessor.elementType];
22
+ const stride = accessor.byteStride ?? size * width;
23
+ const output = ["u8", "u16", "u32"].includes(accessor.componentType) && !accessor.normalized ? new Uint32Array(accessor.count * width) : new Float32Array(accessor.count * width);
24
+ for (let index = 0; index < output.length; index += 1) {
25
+ if (index % 4096 === 0) check();
26
+ const offset = accessor.byteOffset + Math.floor(index / width) * stride + index % width * size;
27
+ let value;
28
+ switch (accessor.componentType) {
29
+ case "i8":
30
+ value = view.getInt8(offset);
31
+ break;
32
+ case "u8":
33
+ value = view.getUint8(offset);
34
+ break;
35
+ case "i16":
36
+ value = view.getInt16(offset, true);
37
+ break;
38
+ case "u16":
39
+ value = view.getUint16(offset, true);
40
+ break;
41
+ case "u32":
42
+ value = view.getUint32(offset, true);
43
+ break;
44
+ case "f32":
45
+ value = view.getFloat32(offset, true);
46
+ break;
47
+ }
48
+ if (accessor.normalized) {
49
+ const divisor = { i8: 127, u8: 255, i16: 32767, u16: 65535, u32: 4294967295, f32: 1 }[accessor.componentType];
50
+ value = Math.max(-1, value / divisor);
51
+ }
52
+ output[index] = value;
53
+ }
54
+ return output;
55
+ }
56
+ async function prepareGpuModelRendererInput(value, options) {
57
+ if (options?.conversionEnabled !== true) throw new GpuModelRendererError("feature-disabled");
58
+ if (!isGpuModelDocument(value)) throw new GpuModelRendererError("unverified-document");
59
+ const document = value;
60
+ const maxBytes = options.maxDecodedBytes ?? GPU_MODEL_RENDERER_MAX_DECODED_BYTES;
61
+ const timeoutMs = options.timeoutMs ?? 3e4;
62
+ if (!Number.isSafeInteger(maxBytes) || maxBytes < 1 || maxBytes > GPU_MODEL_RENDERER_MAX_DECODED_BYTES || !Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 3e4) {
63
+ throw new GpuModelRendererError("invalid-options");
64
+ }
65
+ const diagnosticReport = options.diagnostics === void 0 ? void 0 : evaluateGpuModelDiagnostics(options.diagnostics);
66
+ if (diagnosticReport?.accepted === false || document.diagnostics.some(({ severity }) => severity === "error")) {
67
+ throw new GpuModelRendererError("diagnostics-rejected");
68
+ }
69
+ let allocation = 0;
70
+ for (const accessor of document.accessors) allocation += accessor.count * COMPONENTS[accessor.elementType] * 4;
71
+ for (const skin of document.skins) {
72
+ allocation += skin.inverseBindMatrices.length * 16 * 4;
73
+ for (const weights of skin.weightSets) allocation += weights.joints.length * weights.influencesPerVertex * 8;
74
+ }
75
+ for (const resource of document.resources) if (resource.kind === "buffer") allocation += resource.byteLength;
76
+ if (allocation > maxBytes) throw new GpuModelRendererError("budget-exceeded");
77
+ const deadline = performance.now() + timeoutMs;
78
+ const check = () => {
79
+ if (options.signal?.aborted || performance.now() >= deadline) throw new GpuModelRendererError("aborted");
80
+ };
81
+ check();
82
+ const accessors = /* @__PURE__ */ Object.create(null);
83
+ const accessorsByResource = /* @__PURE__ */ new Map();
84
+ for (const accessor of document.accessors) {
85
+ const entries = accessorsByResource.get(accessor.resourceId) ?? [];
86
+ entries.push(accessor);
87
+ accessorsByResource.set(accessor.resourceId, entries);
88
+ }
89
+ for (const resource of document.resources) {
90
+ const entries = accessorsByResource.get(resource.id);
91
+ if (!entries) continue;
92
+ let timer;
93
+ let abort;
94
+ try {
95
+ const buffer = await new Promise((resolve, reject) => {
96
+ abort = () => reject(new GpuModelRendererError("aborted"));
97
+ options.signal?.addEventListener("abort", abort, { once: true });
98
+ timer = setTimeout(abort, Math.max(1, deadline - performance.now()));
99
+ readBlob.call(resource.payload).then(resolve, () => reject(new GpuModelRendererError("resource-read-failed")));
100
+ });
101
+ check();
102
+ const view = new DataView(buffer);
103
+ for (const accessor of entries) {
104
+ check();
105
+ accessors[accessor.id] = decode(accessor, view, check);
106
+ }
107
+ } finally {
108
+ clearTimeout(timer);
109
+ if (abort) options.signal?.removeEventListener("abort", abort);
110
+ }
111
+ }
112
+ const primitives = [];
113
+ const geometry = [];
114
+ const materialSlots = new Map(document.materials.map((material, index) => [material.id, index]));
115
+ for (const mesh of document.meshes) for (const primitive of mesh.primitives) {
116
+ check();
117
+ const attributes = /* @__PURE__ */ Object.create(null);
118
+ for (const attribute of primitive.attributes) attributes[attribute.semantic] = accessors[attribute.accessorId];
119
+ primitives.push(Object.freeze({
120
+ meshId: mesh.id,
121
+ primitiveId: primitive.id,
122
+ topology: primitive.topology,
123
+ materialSlot: primitive.materialId === void 0 ? null : materialSlots.get(primitive.materialId),
124
+ attributes: Object.freeze(attributes)
125
+ }));
126
+ geometry.push(Object.freeze({
127
+ primitiveId: primitive.id,
128
+ positions: attributes.POSITION,
129
+ ...primitive.indicesAccessorId === void 0 ? {} : { indices: accessors[primitive.indicesAccessorId] },
130
+ ...attributes.NORMAL === void 0 ? {} : { normals: attributes.NORMAL },
131
+ ...attributes.TEXCOORD_0 === void 0 ? {} : { texcoords: attributes.TEXCOORD_0 }
132
+ }));
133
+ }
134
+ const pack = (rows, output) => {
135
+ let offset = 0;
136
+ for (const row of rows) {
137
+ check();
138
+ output.set(row, offset);
139
+ offset += row.length;
140
+ }
141
+ return output;
142
+ };
143
+ const skins = document.skins.map((skin) => {
144
+ check();
145
+ return Object.freeze({
146
+ id: skin.id,
147
+ skeletonId: skin.skeletonId,
148
+ jointIds: skin.jointIds,
149
+ inverseBindMatrices: pack(skin.inverseBindMatrices, new Float32Array(skin.inverseBindMatrices.length * 16)),
150
+ weightSets: Object.freeze(skin.weightSets.map((weights) => Object.freeze({
151
+ primitiveId: weights.primitiveId,
152
+ influencesPerVertex: weights.influencesPerVertex,
153
+ joints: pack(weights.joints, new Uint32Array(weights.joints.length * weights.influencesPerVertex)),
154
+ weights: pack(weights.weights, new Float32Array(weights.weights.length * weights.influencesPerVertex))
155
+ })))
156
+ });
157
+ });
158
+ const animations = document.animations.map((animation) => Object.freeze({
159
+ id: animation.id,
160
+ durationSeconds: animation.durationSeconds,
161
+ channels: animation.channels,
162
+ samplers: Object.freeze(animation.samplers.map((sampler) => Object.freeze({
163
+ id: sampler.id,
164
+ interpolation: sampler.interpolation,
165
+ input: accessors[sampler.inputAccessorId],
166
+ output: accessors[sampler.outputAccessorId]
167
+ })))
168
+ }));
169
+ const resources = new Map(document.resources.map((resource) => [resource.id, resource]));
170
+ check();
171
+ return Object.freeze({
172
+ document,
173
+ bounds: document.bounds,
174
+ roots: document.roots,
175
+ nodes: document.nodes,
176
+ materials: document.materials,
177
+ skeletons: document.skeletons,
178
+ joints: document.joints,
179
+ blendShapes: document.blendShapes,
180
+ analyticGeometry: document.analyticGeometry,
181
+ diagnostics: document.diagnostics,
182
+ ...diagnosticReport === void 0 ? {} : { diagnosticReport },
183
+ accessors: Object.freeze(accessors),
184
+ primitives: Object.freeze(primitives),
185
+ geometry: Object.freeze(geometry),
186
+ skins: Object.freeze(skins),
187
+ animations: Object.freeze(animations),
188
+ textures: Object.freeze(document.textures.map((texture) => Object.freeze({ texture, resource: resources.get(texture.imageResourceId) })))
189
+ });
190
+ }
191
+
1
192
  // src/index.ts
2
193
  var packageName = "@plasius/gpu-model-renderer";
3
194
  var packageBootstrap = Object.freeze({
@@ -6,7 +197,11 @@ var packageBootstrap = Object.freeze({
6
197
  status: "bootstrap"
7
198
  });
8
199
  export {
200
+ GPU_MODEL_RENDERER_FEATURE_FLAG,
201
+ GPU_MODEL_RENDERER_MAX_DECODED_BYTES,
202
+ GpuModelRendererError,
9
203
  packageBootstrap,
10
- packageName
204
+ packageName,
205
+ prepareGpuModelRendererInput
11
206
  };
12
207
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/** Package identity and rollout metadata for the initial repository baseline. */\nexport const packageName = \"@plasius/gpu-model-renderer\" as const;\n\nexport const packageBootstrap = Object.freeze({\n packageName,\n featureFlag: \"gpu.model.conversion.enabled\",\n status: \"bootstrap\",\n} as const);\n"],"mappings":";AACO,IAAM,cAAc;AAEpB,IAAM,mBAAmB,OAAO,OAAO;AAAA,EAC5C;AAAA,EACA,aAAa;AAAA,EACb,QAAQ;AACV,CAAU;","names":[]}
1
+ {"version":3,"sources":["../src/renderer-input.ts","../src/index.ts"],"sourcesContent":["import {\n evaluateGpuModelDiagnostics, isGpuModelDocument,\n type GpuModelAccessor, type GpuModelDiagnosticInput, type GpuModelDiagnosticReport,\n type GpuModelDocument, type GpuModelResource, type GpuModelTexture,\n} from \"@plasius/gpu-model-core\";\n\n/** Fixed allocation ceiling; callers may tighten it, never raise it. */\nexport const GPU_MODEL_RENDERER_MAX_DECODED_BYTES = 64 * 1024 * 1024;\n/** Remotely evaluated parent Feature flag. No environment override is read here. */\nexport const GPU_MODEL_RENDERER_FEATURE_FLAG = \"gpu.model.conversion.enabled\";\n\n/** Stable, payload-free failure categories for callers and worker boundaries. */\nexport type GpuModelRendererErrorCode = \"feature-disabled\" | \"unverified-document\" | \"invalid-options\" | \"budget-exceeded\" | \"aborted\" | \"diagnostics-rejected\" | \"resource-read-failed\";\n/** Bounded errors deliberately omit source paths, URIs and payload content. */\nexport class GpuModelRendererError extends Error {\n public constructor(public readonly code: GpuModelRendererErrorCode) {\n super(`GPU model renderer preparation failed: ${code}`);\n this.name = \"GpuModelRendererError\";\n }\n}\n\n/** Consumer-owned buffers; changing them never changes the canonical document. */\nexport type GpuModelRendererBuffer = Float32Array | Uint32Array;\n/** Decode policy. Gate decisions must come from the host's remote flag evaluator. */\nexport interface GpuModelRendererOptions {\n readonly conversionEnabled: boolean;\n readonly signal?: AbortSignal;\n readonly timeoutMs?: number;\n readonly maxDecodedBytes?: number;\n readonly diagnostics?: GpuModelDiagnosticInput;\n}\n/** Geometry in mesh-local coordinates, directly usable by the canonical renderer adapter. */\nexport interface GpuModelRendererGeometry {\n readonly primitiveId: string;\n readonly positions: Float32Array;\n readonly indices?: Uint32Array;\n readonly normals?: Float32Array;\n readonly texcoords?: Float32Array;\n}\n/** All attributes are retained, including UV sets, colours, joints and custom semantics. */\nexport interface GpuModelRendererPrimitive {\n readonly meshId: string;\n readonly primitiveId: string;\n readonly topology: GpuModelDocument[\"meshes\"][number][\"primitives\"][number][\"topology\"];\n /** Zero-based canonical material index; null denotes the renderer's default material. */\n readonly materialSlot: number | null;\n readonly attributes: Readonly<Record<string, GpuModelRendererBuffer>>;\n}\n/** Ordered joint palette and packed vertex influences; no animation is evaluated or baked. */\nexport interface GpuModelRendererSkin {\n readonly id: string;\n readonly skeletonId: string;\n readonly jointIds: readonly string[];\n readonly inverseBindMatrices: Float32Array;\n readonly weightSets: readonly {\n readonly primitiveId: string;\n readonly influencesPerVertex: number;\n readonly joints: Uint32Array;\n readonly weights: Float32Array;\n }[];\n}\n/** Canonical clip semantics with decoded, tightly packed sampler buffers. */\nexport interface GpuModelRendererAnimation {\n readonly id: string;\n readonly durationSeconds: number;\n readonly channels: GpuModelDocument[\"animations\"][number][\"channels\"];\n readonly samplers: readonly {\n readonly id: string;\n readonly interpolation: GpuModelDocument[\"animations\"][number][\"samplers\"][number][\"interpolation\"];\n readonly input: GpuModelRendererBuffer;\n readonly output: GpuModelRendererBuffer;\n }[];\n}\n/** Verified images remain encoded; the caller chooses its decoder/upload strategy. */\nexport interface GpuModelRendererTexture {\n readonly texture: GpuModelTexture;\n readonly resource: GpuModelResource;\n}\n/** Scene-aware preparation result. Geometry alone is not a baked world-space scene. */\nexport interface GpuModelRendererInput {\n readonly document: GpuModelDocument;\n readonly bounds: GpuModelDocument[\"bounds\"];\n readonly roots: GpuModelDocument[\"roots\"];\n readonly nodes: GpuModelDocument[\"nodes\"];\n readonly materials: GpuModelDocument[\"materials\"];\n readonly skeletons: GpuModelDocument[\"skeletons\"];\n readonly joints: GpuModelDocument[\"joints\"];\n readonly blendShapes: GpuModelDocument[\"blendShapes\"];\n readonly analyticGeometry: GpuModelDocument[\"analyticGeometry\"];\n readonly diagnostics: GpuModelDocument[\"diagnostics\"];\n readonly diagnosticReport?: GpuModelDiagnosticReport;\n readonly accessors: Readonly<Record<string, GpuModelRendererBuffer>>;\n readonly geometry: readonly GpuModelRendererGeometry[];\n readonly primitives: readonly GpuModelRendererPrimitive[];\n readonly textures: readonly GpuModelRendererTexture[];\n readonly skins: readonly GpuModelRendererSkin[];\n readonly animations: readonly GpuModelRendererAnimation[];\n}\n\nconst COMPONENT_BYTES = { i8: 1, u8: 1, i16: 2, u16: 2, u32: 4, f32: 4 } as const;\nconst COMPONENTS = { scalar: 1, vec2: 2, vec3: 3, vec4: 4, mat2: 4, mat3: 9, mat4: 16 } as const;\n\nconst readBlob = Blob.prototype.arrayBuffer;\n\nfunction decode(accessor: GpuModelAccessor, view: DataView, check: () => void): GpuModelRendererBuffer {\n const size = COMPONENT_BYTES[accessor.componentType];\n const width = COMPONENTS[accessor.elementType];\n const stride = accessor.byteStride ?? size * width;\n const output = [\"u8\", \"u16\", \"u32\"].includes(accessor.componentType) && !accessor.normalized\n ? new Uint32Array(accessor.count * width)\n : new Float32Array(accessor.count * width);\n for (let index = 0; index < output.length; index += 1) {\n if (index % 4096 === 0) check();\n const offset = accessor.byteOffset + Math.floor(index / width) * stride + (index % width) * size;\n let value: number;\n switch (accessor.componentType) {\n case \"i8\": value = view.getInt8(offset); break;\n case \"u8\": value = view.getUint8(offset); break;\n case \"i16\": value = view.getInt16(offset, true); break;\n case \"u16\": value = view.getUint16(offset, true); break;\n case \"u32\": value = view.getUint32(offset, true); break;\n case \"f32\": value = view.getFloat32(offset, true); break;\n }\n if (accessor.normalized) {\n const divisor = { i8: 127, u8: 255, i16: 32767, u16: 65535, u32: 4294967295, f32: 1 }[accessor.componentType];\n value = Math.max(-1, value / divisor);\n }\n output[index] = value;\n }\n return output;\n}\n\n/**\n * Prepares privately verified core output without parsing source formats, fetching\n * resources or importing a renderer. Structured clones must be reverified by core.\n * Run on a host worker for large inputs. Operations are sequential, bounded and\n * have no retries. The host owns scene transforms and animation evaluation.\n */\nexport async function prepareGpuModelRendererInput(\n value: unknown,\n options?: GpuModelRendererOptions,\n): Promise<GpuModelRendererInput> {\n if (options?.conversionEnabled !== true) throw new GpuModelRendererError(\"feature-disabled\");\n if (!isGpuModelDocument(value)) throw new GpuModelRendererError(\"unverified-document\");\n const document = value;\n const maxBytes = options.maxDecodedBytes ?? GPU_MODEL_RENDERER_MAX_DECODED_BYTES;\n const timeoutMs = options.timeoutMs ?? 30_000;\n if (!Number.isSafeInteger(maxBytes) || maxBytes < 1 || maxBytes > GPU_MODEL_RENDERER_MAX_DECODED_BYTES\n || !Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 30_000) {\n throw new GpuModelRendererError(\"invalid-options\");\n }\n const diagnosticReport = options.diagnostics === undefined ? undefined : evaluateGpuModelDiagnostics(options.diagnostics);\n if (diagnosticReport?.accepted === false || document.diagnostics.some(({ severity }) => severity === \"error\")) {\n throw new GpuModelRendererError(\"diagnostics-rejected\");\n }\n let allocation = 0;\n for (const accessor of document.accessors) allocation += accessor.count * COMPONENTS[accessor.elementType] * 4;\n for (const skin of document.skins) {\n allocation += skin.inverseBindMatrices.length * 16 * 4;\n for (const weights of skin.weightSets) allocation += weights.joints.length * weights.influencesPerVertex * 8;\n }\n // Include copies of encoded buffers in the peak budget; image bytes are not decoded here.\n for (const resource of document.resources) if (resource.kind === \"buffer\") allocation += resource.byteLength;\n if (allocation > maxBytes) throw new GpuModelRendererError(\"budget-exceeded\");\n const deadline = performance.now() + timeoutMs;\n const check = () => {\n if (options.signal?.aborted || performance.now() >= deadline) throw new GpuModelRendererError(\"aborted\");\n };\n check();\n const accessors: Record<string, GpuModelRendererBuffer> = Object.create(null);\n // One bounded read at a time. Abort/deadline rejects even if a host read stalls.\n const accessorsByResource = new Map<string, GpuModelAccessor[]>();\n for (const accessor of document.accessors) {\n const entries = accessorsByResource.get(accessor.resourceId) ?? [];\n entries.push(accessor);\n accessorsByResource.set(accessor.resourceId, entries);\n }\n for (const resource of document.resources) {\n const entries = accessorsByResource.get(resource.id);\n if (!entries) continue;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let abort: (() => void) | undefined;\n try {\n const buffer = await new Promise<ArrayBuffer>((resolve, reject) => {\n abort = () => reject(new GpuModelRendererError(\"aborted\"));\n options.signal?.addEventListener(\"abort\", abort, { once: true });\n timer = setTimeout(abort, Math.max(1, deadline - performance.now()));\n readBlob.call(resource.payload).then(resolve, () => reject(new GpuModelRendererError(\"resource-read-failed\")));\n });\n check();\n const view = new DataView(buffer);\n for (const accessor of entries) {\n check();\n accessors[accessor.id] = decode(accessor, view, check);\n }\n } finally {\n clearTimeout(timer);\n if (abort) options.signal?.removeEventListener(\"abort\", abort);\n }\n }\n const primitives: GpuModelRendererPrimitive[] = [];\n const geometry: GpuModelRendererGeometry[] = [];\n const materialSlots = new Map(document.materials.map((material, index) => [material.id, index]));\n for (const mesh of document.meshes) for (const primitive of mesh.primitives) {\n check();\n const attributes: Record<string, GpuModelRendererBuffer> = Object.create(null);\n for (const attribute of primitive.attributes) attributes[attribute.semantic] = accessors[attribute.accessorId]!;\n primitives.push(Object.freeze({ meshId: mesh.id, primitiveId: primitive.id, topology: primitive.topology,\n materialSlot: primitive.materialId === undefined ? null : materialSlots.get(primitive.materialId)!, attributes: Object.freeze(attributes) }));\n geometry.push(Object.freeze({ primitiveId: primitive.id, positions: attributes.POSITION! as Float32Array,\n ...(primitive.indicesAccessorId === undefined ? {} : { indices: accessors[primitive.indicesAccessorId]! as Uint32Array }),\n ...(attributes.NORMAL === undefined ? {} : { normals: attributes.NORMAL as Float32Array }),\n ...(attributes.TEXCOORD_0 === undefined ? {} : { texcoords: attributes.TEXCOORD_0 as Float32Array }) }));\n }\n const pack = <T extends Float32Array | Uint32Array>(rows: readonly (readonly number[])[], output: T): T => {\n let offset = 0;\n for (const row of rows) { check(); output.set(row, offset); offset += row.length; }\n return output;\n };\n const skins = document.skins.map(skin => {\n check();\n return Object.freeze({ id: skin.id, skeletonId: skin.skeletonId, jointIds: skin.jointIds,\n inverseBindMatrices: pack(skin.inverseBindMatrices, new Float32Array(skin.inverseBindMatrices.length * 16)),\n weightSets: Object.freeze(skin.weightSets.map(weights => Object.freeze({ primitiveId: weights.primitiveId,\n influencesPerVertex: weights.influencesPerVertex, joints: pack(weights.joints, new Uint32Array(weights.joints.length * weights.influencesPerVertex)), weights: pack(weights.weights, new Float32Array(weights.weights.length * weights.influencesPerVertex)) }))) });\n });\n const animations = document.animations.map(animation => Object.freeze({ id: animation.id, durationSeconds: animation.durationSeconds,\n channels: animation.channels, samplers: Object.freeze(animation.samplers.map(sampler => Object.freeze({ id: sampler.id,\n interpolation: sampler.interpolation, input: accessors[sampler.inputAccessorId]!, output: accessors[sampler.outputAccessorId]! }))) }));\n const resources = new Map(document.resources.map(resource => [resource.id, resource]));\n check();\n return Object.freeze({ document, bounds: document.bounds, roots: document.roots, nodes: document.nodes, materials: document.materials,\n skeletons: document.skeletons, joints: document.joints, blendShapes: document.blendShapes, analyticGeometry: document.analyticGeometry,\n diagnostics: document.diagnostics, ...(diagnosticReport === undefined ? {} : { diagnosticReport }), accessors: Object.freeze(accessors),\n primitives: Object.freeze(primitives), geometry: Object.freeze(geometry), skins: Object.freeze(skins), animations: Object.freeze(animations),\n textures: Object.freeze(document.textures.map(texture => Object.freeze({ texture, resource: resources.get(texture.imageResourceId)! }))) });\n}\n","/** Package identity and rollout metadata for the initial repository baseline. */\nexport const packageName = \"@plasius/gpu-model-renderer\" as const;\n\n/** @deprecated Retained for compatibility with the bootstrap package identity. */\nexport const packageBootstrap = Object.freeze({\n packageName,\n featureFlag: \"gpu.model.conversion.enabled\",\n status: \"bootstrap\",\n} as const);\n\nexport * from \"./renderer-input.js\";\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@plasius/gpu-model-renderer",
3
- "version": "0.1.5",
3
+ "version": "0.2.0",
4
4
  "description": "Canonical GPU model to renderer-ready buffers and animation inputs bridge.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -69,6 +69,8 @@
69
69
  "homepage": "https://github.com/Plasius-LTD/gpu-model-renderer#readme",
70
70
  "devDependencies": {
71
71
  "@eslint/js": "^10.0.1",
72
+ "@plasius/gpu-model-runtime": "0.2.4",
73
+ "@plasius/gpu-renderer": "0.2.51",
72
74
  "@types/node": "^26.0.1",
73
75
  "@typescript-eslint/eslint-plugin": "^8.59.3",
74
76
  "@typescript-eslint/parser": "^8.59.3",
@@ -102,5 +104,8 @@
102
104
  },
103
105
  "engines": {
104
106
  "node": ">=24"
107
+ },
108
+ "dependencies": {
109
+ "@plasius/gpu-model-core": "0.4.6"
105
110
  }
106
111
  }