@plasius/gpu-model-renderer 0.1.6 → 0.3.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,161 @@
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.
63
+
64
+ This bridge requires the published `@plasius/gpu-model-core` **0.5.0** contract.
65
+ Source adapters and the bridge must resolve the same core module instance and
66
+ module format. An equal version in a separate install, worker, or ESM/CJS module
67
+ instance does not share the private verification brand. Inspect
68
+ `npm ls @plasius/gpu-model-core` when integrating; explicitly reverify transferred
69
+ clones with the receiving core and its trusted resource-verification port. Do not
70
+ cast a plain object to a verified document or disable the brand check.
12
71
 
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
72
+ Preparation retains the additional `thickness`, `specular`, `specularColor`,
73
+ `iridescence`, `iridescenceThickness`, and `anisotropy` bindings, including their
74
+ samplers, selected UV sets, transforms, colour spaces, and verified encoded image
75
+ resources. Extension factors remain bounded canonical metadata. The bridge
76
+ preserves these contracts; the source adapter owns KHR admission, factors,
77
+ defaults, channels, and export, while the renderer owns actual texture sampling.
78
+ Missing references, mismatched slot usage, image identity, samplers, colour
79
+ spaces, or absent UV sets must fail core verification before preparation.
16
80
 
17
- ## Development
81
+ Use published renderer **0.2.53** or a compatible later release for the six
82
+ additional channel mappings. Its canonical mapper accepts UV0 and identity
83
+ transforms, and explicitly rejects unsupported UV sets or nonidentity transforms.
84
+ The generic bridge retains the authored data so the host can choose an appropriate
85
+ consumer; it never removes a transform or substitutes UV0 to evade a rejection.
86
+ The owning renderer contract is tracked by
87
+ [gpu-renderer #252](https://github.com/Plasius-LTD/gpu-renderer/issues/252).
88
+ Retaining fields in prepared output does not establish physical rendering fidelity or
89
+ [glTF #14](https://github.com/Plasius-LTD/gpu-model-gltf/issues/14) completion.
90
+ Keep unsupported assets on the existing consumer path until the released
91
+ renderer passes the real source-adapter compatibility fixtures.
18
92
 
19
- Requires Node.js 24 and npm.
93
+ Optional `diagnostics` uses the core `GpuModelDiagnosticInput` contract. Core
94
+ owns strict/tolerant/forensic evaluation and bounded repair/loss/evidence
95
+ ledgers. Strict is the default. Tolerant reports describe repairs already
96
+ performed by a source adapter; the bridge performs no repairs. Rejected reports
97
+ or canonical error diagnostics prevent preparation in every mode. Forensic raw
98
+ evidence is returned only in its explicit report and is never logged here.
99
+
100
+ `GpuModelRendererError.code` distinguishes `feature-disabled`,
101
+ `unverified-document`, `invalid-options`, `budget-exceeded`, `aborted`,
102
+ `diagnostics-rejected`, and `resource-read-failed`. Core may also throw its
103
+ bounded diagnostics error for malformed reports. Errors contain no payloads,
104
+ source URLs or identifiers. No partial output is returned.
105
+
106
+ The default/fixed ceiling is 64 MiB for encoded buffer copies plus decoded
107
+ accessors and skin buffers, preflighted before allocation. The timeout defaults
108
+ to 30 seconds and can only be tightened. Resource acquisition is sequential,
109
+ with no retries or shared mutable cache. Cancellation/deadline failures discard
110
+ partial output. CPU loops check the deadline; run large models in a host worker
111
+ so cancellation and main-thread responsiveness remain under host control.
112
+ Output containers are frozen; typed arrays are intentionally consumer-owned
113
+ and mutable for GPU upload. Accessor views within one result may share a buffer.
114
+ Mutations never affect the canonical document or a subsequent preparation.
115
+
116
+ ## Rollout and rollback
117
+
118
+ - Parent Feature: [site #1153](https://github.com/Plasius-LTD/plasius-ltd-site/issues/1153).
119
+ - Feature flag: `gpu.model.conversion.enabled`.
120
+ - Source-of-truth evaluator: the host's remote feature-flag service; pass its
121
+ decision as `conversionEnabled` on every preparation. Omission/false rejects.
122
+ - Capability: none for this data-only package layer.
123
+ - Rollback: disable the remote flag, cancel outstanding preparation via its
124
+ signal, and retain the previous consumer loader and validated package pin.
125
+ No local environment value is used as the normal control plane.
126
+
127
+ ## Development and release
128
+
129
+ Requires the Node.js 24 version pinned in `.nvmrc` and npm.
20
130
 
21
131
  ```bash
22
132
  npm ci
23
133
  npm run typecheck
24
134
  npm test
135
+ npm run test:coverage
25
136
  npm run lint
26
137
  npm run build
138
+ npm run pack:check
27
139
  npm pack --dry-run
28
140
  ```
29
141
 
30
- ## License
142
+ Tests cover canonical geometry/accessor fidelity, scene/rig/animation retention,
143
+ rollout and error paths, and the published runtime -> bridge -> published
144
+ renderer material-atlas/mesh-acceleration boundary. The runtime test adapter is
145
+ a deterministic canonical fixture, **not** a glTF parser. These tests do not
146
+ prove the full format conformance matrix in site Story #1160: the current
147
+ published GLB canonical importer supports a narrower texture-free static
148
+ profile. Actual format-adapter support must be verified separately.
149
+
150
+ Dependencies added for this API: runtime core `0.5.0` (canonical validation and
151
+ diagnostics); test-only runtime `0.2.4` and renderer `0.2.53` (published consumer
152
+ contract checks). No local package references or format SDKs are introduced.
153
+ See [ADR 0006](docs/adrs/adr-0006-canonical-renderer-preparation.md) and the
154
+ [design and NFR evidence](docs/design/canonical-renderer-preparation.md).
155
+ The core adoption and module-instance constraints are specified by
156
+ [ADR 0007](docs/adrs/adr-0007-extended-material-core-alignment.md).
31
157
 
32
- Apache-2.0. See LICENSE, SECURITY.md, and the files under legal/.
158
+ Apache-2.0. See LICENSE, SECURITY.md, and legal/.
33
159
 
34
160
  <!-- BEGIN PLASIUS RELEASE INTEGRITY -->
35
161
  ## 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.6",
3
+ "version": "0.3.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.53",
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.5.0"
105
110
  }
106
111
  }