@plasius/gpu-model-renderer 0.3.0 → 0.4.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 +23 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -61,7 +61,7 @@ objects and structured clones fail closed; verify clones through
|
|
|
61
61
|
versions/module instances consistent across adapters and bridge consumers.
|
|
62
62
|
The deprecated `packageBootstrap` identity export remains compatible.
|
|
63
63
|
|
|
64
|
-
This bridge requires the published `@plasius/gpu-model-core` **0.
|
|
64
|
+
This bridge requires the published `@plasius/gpu-model-core` **0.6.0** contract.
|
|
65
65
|
Source adapters and the bridge must resolve the same core module instance and
|
|
66
66
|
module format. An equal version in a separate install, worker, or ESM/CJS module
|
|
67
67
|
instance does not share the private verification brand. Inspect
|
|
@@ -69,6 +69,23 @@ instance does not share the private verification brand. Inspect
|
|
|
69
69
|
clones with the receiving core and its trusted resource-verification port. Do not
|
|
70
70
|
cast a plain object to a verified document or disable the brand check.
|
|
71
71
|
|
|
72
|
+
`nodes` retains optional authored `restLocalTransform` (including quaternion
|
|
73
|
+
sign and signed scales) and each node's complete ordered `morphWeights`.
|
|
74
|
+
For `node-weights` animation, interpret the output in the target node's binding
|
|
75
|
+
order, which can differ between instances of one mesh. For K keys and N bindings,
|
|
76
|
+
step/linear outputs contain K*N scalar values; cubic-spline outputs contain
|
|
77
|
+
K*3*N scalars, ordered per key as N incoming tangents, N values, N outgoing
|
|
78
|
+
tangents. Signed weights and tangents are preserved. The host owns interpolation,
|
|
79
|
+
deformation and time-dependent bounds; the bridge retains core's validated base
|
|
80
|
+
geometry bounds. Legacy single-shape `weights` channels keep their existing
|
|
81
|
+
meaning. New documents must not be handed to an older core instance.
|
|
82
|
+
|
|
83
|
+
Published renderer **0.2.53** still accepts the mesh/material projection without
|
|
84
|
+
a dependency upgrade: that projection does not evaluate node morph animation.
|
|
85
|
+
Its test-only core0.5.0 dependency can remain nested because it never performs
|
|
86
|
+
the private document-brand check. Source producers and this bridge, which do
|
|
87
|
+
check the brand, must share core0.6.0. No resolution override is required.
|
|
88
|
+
|
|
72
89
|
Preparation retains the additional `thickness`, `specular`, `specularColor`,
|
|
73
90
|
`iridescence`, `iridescenceThickness`, and `anisotropy` bindings, including their
|
|
74
91
|
samplers, selected UV sets, transforms, colour spaces, and verified encoded image
|
|
@@ -121,7 +138,8 @@ Mutations never affect the canonical document or a subsequent preparation.
|
|
|
121
138
|
decision as `conversionEnabled` on every preparation. Omission/false rejects.
|
|
122
139
|
- Capability: none for this data-only package layer.
|
|
123
140
|
- Rollback: disable the remote flag, cancel outstanding preparation via its
|
|
124
|
-
signal, and retain the previous consumer loader and
|
|
141
|
+
signal, and retain the previous consumer loader and compatible producer/core/
|
|
142
|
+
bridge package pins together. Do not feed new node-weight documents to core0.5.
|
|
125
143
|
No local environment value is used as the normal control plane.
|
|
126
144
|
|
|
127
145
|
## Development and release
|
|
@@ -147,13 +165,15 @@ prove the full format conformance matrix in site Story #1160: the current
|
|
|
147
165
|
published GLB canonical importer supports a narrower texture-free static
|
|
148
166
|
profile. Actual format-adapter support must be verified separately.
|
|
149
167
|
|
|
150
|
-
Dependencies
|
|
168
|
+
Dependencies used by this API: runtime core `0.6.0` (canonical validation and
|
|
151
169
|
diagnostics); test-only runtime `0.2.4` and renderer `0.2.53` (published consumer
|
|
152
170
|
contract checks). No local package references or format SDKs are introduced.
|
|
153
171
|
See [ADR 0006](docs/adrs/adr-0006-canonical-renderer-preparation.md) and the
|
|
154
172
|
[design and NFR evidence](docs/design/canonical-renderer-preparation.md).
|
|
155
173
|
The core adoption and module-instance constraints are specified by
|
|
156
174
|
[ADR 0007](docs/adrs/adr-0007-extended-material-core-alignment.md).
|
|
175
|
+
Node morph animation adoption and its limits are specified by
|
|
176
|
+
[ADR 0008](docs/adrs/adr-0008-node-morph-animation-core-alignment.md).
|
|
157
177
|
|
|
158
178
|
Apache-2.0. See LICENSE, SECURITY.md, and legal/.
|
|
159
179
|
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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":[]}
|
|
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/**\n * Canonical clip semantics with decoded, tightly packed sampler buffers.\n * A node-weights channel uses its target node's morphWeights order. Cubic\n * output retains per-key incoming tangents, values, then outgoing tangents;\n * preparation never evaluates, clamps, or normalizes those values.\n */\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 /** Retains authored rest TRS and independent ordered per-node morph weights. */\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
|
@@ -51,7 +51,12 @@ interface GpuModelRendererSkin {
|
|
|
51
51
|
readonly weights: Float32Array;
|
|
52
52
|
}[];
|
|
53
53
|
}
|
|
54
|
-
/**
|
|
54
|
+
/**
|
|
55
|
+
* Canonical clip semantics with decoded, tightly packed sampler buffers.
|
|
56
|
+
* A node-weights channel uses its target node's morphWeights order. Cubic
|
|
57
|
+
* output retains per-key incoming tangents, values, then outgoing tangents;
|
|
58
|
+
* preparation never evaluates, clamps, or normalizes those values.
|
|
59
|
+
*/
|
|
55
60
|
interface GpuModelRendererAnimation {
|
|
56
61
|
readonly id: string;
|
|
57
62
|
readonly durationSeconds: number;
|
|
@@ -73,6 +78,7 @@ interface GpuModelRendererInput {
|
|
|
73
78
|
readonly document: GpuModelDocument;
|
|
74
79
|
readonly bounds: GpuModelDocument["bounds"];
|
|
75
80
|
readonly roots: GpuModelDocument["roots"];
|
|
81
|
+
/** Retains authored rest TRS and independent ordered per-node morph weights. */
|
|
76
82
|
readonly nodes: GpuModelDocument["nodes"];
|
|
77
83
|
readonly materials: GpuModelDocument["materials"];
|
|
78
84
|
readonly skeletons: GpuModelDocument["skeletons"];
|
package/dist/index.d.ts
CHANGED
|
@@ -51,7 +51,12 @@ interface GpuModelRendererSkin {
|
|
|
51
51
|
readonly weights: Float32Array;
|
|
52
52
|
}[];
|
|
53
53
|
}
|
|
54
|
-
/**
|
|
54
|
+
/**
|
|
55
|
+
* Canonical clip semantics with decoded, tightly packed sampler buffers.
|
|
56
|
+
* A node-weights channel uses its target node's morphWeights order. Cubic
|
|
57
|
+
* output retains per-key incoming tangents, values, then outgoing tangents;
|
|
58
|
+
* preparation never evaluates, clamps, or normalizes those values.
|
|
59
|
+
*/
|
|
55
60
|
interface GpuModelRendererAnimation {
|
|
56
61
|
readonly id: string;
|
|
57
62
|
readonly durationSeconds: number;
|
|
@@ -73,6 +78,7 @@ interface GpuModelRendererInput {
|
|
|
73
78
|
readonly document: GpuModelDocument;
|
|
74
79
|
readonly bounds: GpuModelDocument["bounds"];
|
|
75
80
|
readonly roots: GpuModelDocument["roots"];
|
|
81
|
+
/** Retains authored rest TRS and independent ordered per-node morph weights. */
|
|
76
82
|
readonly nodes: GpuModelDocument["nodes"];
|
|
77
83
|
readonly materials: GpuModelDocument["materials"];
|
|
78
84
|
readonly skeletons: GpuModelDocument["skeletons"];
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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":[]}
|
|
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/**\n * Canonical clip semantics with decoded, tightly packed sampler buffers.\n * A node-weights channel uses its target node's morphWeights order. Cubic\n * output retains per-key incoming tangents, values, then outgoing tangents;\n * preparation never evaluates, clamps, or normalizes those values.\n */\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 /** Retains authored rest TRS and independent ordered per-node morph weights. */\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.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Canonical GPU model to renderer-ready buffers and animation inputs bridge.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|
|
@@ -106,6 +106,6 @@
|
|
|
106
106
|
"node": ">=24"
|
|
107
107
|
},
|
|
108
108
|
"dependencies": {
|
|
109
|
-
"@plasius/gpu-model-core": "0.
|
|
109
|
+
"@plasius/gpu-model-core": "0.6.0"
|
|
110
110
|
}
|
|
111
111
|
}
|