@plasius/gpu-model-renderer 0.2.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 +54 -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 +3 -3
package/README.md
CHANGED
|
@@ -61,6 +61,52 @@ 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.6.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.
|
|
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
|
+
|
|
89
|
+
Preparation retains the additional `thickness`, `specular`, `specularColor`,
|
|
90
|
+
`iridescence`, `iridescenceThickness`, and `anisotropy` bindings, including their
|
|
91
|
+
samplers, selected UV sets, transforms, colour spaces, and verified encoded image
|
|
92
|
+
resources. Extension factors remain bounded canonical metadata. The bridge
|
|
93
|
+
preserves these contracts; the source adapter owns KHR admission, factors,
|
|
94
|
+
defaults, channels, and export, while the renderer owns actual texture sampling.
|
|
95
|
+
Missing references, mismatched slot usage, image identity, samplers, colour
|
|
96
|
+
spaces, or absent UV sets must fail core verification before preparation.
|
|
97
|
+
|
|
98
|
+
Use published renderer **0.2.53** or a compatible later release for the six
|
|
99
|
+
additional channel mappings. Its canonical mapper accepts UV0 and identity
|
|
100
|
+
transforms, and explicitly rejects unsupported UV sets or nonidentity transforms.
|
|
101
|
+
The generic bridge retains the authored data so the host can choose an appropriate
|
|
102
|
+
consumer; it never removes a transform or substitutes UV0 to evade a rejection.
|
|
103
|
+
The owning renderer contract is tracked by
|
|
104
|
+
[gpu-renderer #252](https://github.com/Plasius-LTD/gpu-renderer/issues/252).
|
|
105
|
+
Retaining fields in prepared output does not establish physical rendering fidelity or
|
|
106
|
+
[glTF #14](https://github.com/Plasius-LTD/gpu-model-gltf/issues/14) completion.
|
|
107
|
+
Keep unsupported assets on the existing consumer path until the released
|
|
108
|
+
renderer passes the real source-adapter compatibility fixtures.
|
|
109
|
+
|
|
64
110
|
Optional `diagnostics` uses the core `GpuModelDiagnosticInput` contract. Core
|
|
65
111
|
owns strict/tolerant/forensic evaluation and bounded repair/loss/evidence
|
|
66
112
|
ledgers. Strict is the default. Tolerant reports describe repairs already
|
|
@@ -92,7 +138,8 @@ Mutations never affect the canonical document or a subsequent preparation.
|
|
|
92
138
|
decision as `conversionEnabled` on every preparation. Omission/false rejects.
|
|
93
139
|
- Capability: none for this data-only package layer.
|
|
94
140
|
- Rollback: disable the remote flag, cancel outstanding preparation via its
|
|
95
|
-
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.
|
|
96
143
|
No local environment value is used as the normal control plane.
|
|
97
144
|
|
|
98
145
|
## Development and release
|
|
@@ -118,11 +165,15 @@ prove the full format conformance matrix in site Story #1160: the current
|
|
|
118
165
|
published GLB canonical importer supports a narrower texture-free static
|
|
119
166
|
profile. Actual format-adapter support must be verified separately.
|
|
120
167
|
|
|
121
|
-
Dependencies
|
|
122
|
-
diagnostics); test-only runtime `0.2.4` and renderer `0.2.
|
|
168
|
+
Dependencies used by this API: runtime core `0.6.0` (canonical validation and
|
|
169
|
+
diagnostics); test-only runtime `0.2.4` and renderer `0.2.53` (published consumer
|
|
123
170
|
contract checks). No local package references or format SDKs are introduced.
|
|
124
171
|
See [ADR 0006](docs/adrs/adr-0006-canonical-renderer-preparation.md) and the
|
|
125
172
|
[design and NFR evidence](docs/design/canonical-renderer-preparation.md).
|
|
173
|
+
The core adoption and module-instance constraints are specified by
|
|
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).
|
|
126
177
|
|
|
127
178
|
Apache-2.0. See LICENSE, SECURITY.md, and legal/.
|
|
128
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":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,4BAIO;AAGA,IAAM,uCAAuC,KAAK,OAAO;AAEzD,IAAM,kCAAkC;AAKxC,IAAM,wBAAN,cAAoC,MAAM;AAAA,EACxC,YAA4B,MAAiC;AAClE,UAAM,0CAA0C,IAAI,EAAE;AADrB;AAEjC,SAAK,OAAO;AAAA,EACd;AAAA,EAHmC;AAIrC;AAgFA,IAAM,kBAAkB,EAAE,IAAI,GAAG,IAAI,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,EAAE;AACvE,IAAM,aAAa,EAAE,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG;AAEtF,IAAM,WAAW,KAAK,UAAU;AAEhC,SAAS,OAAO,UAA4B,MAAgB,OAA2C;AACrG,QAAM,OAAO,gBAAgB,SAAS,aAAa;AACnD,QAAM,QAAQ,WAAW,SAAS,WAAW;AAC7C,QAAM,SAAS,SAAS,cAAc,OAAO;AAC7C,QAAM,SAAS,CAAC,MAAM,OAAO,KAAK,EAAE,SAAS,SAAS,aAAa,KAAK,CAAC,SAAS,aAC9E,IAAI,YAAY,SAAS,QAAQ,KAAK,IACtC,IAAI,aAAa,SAAS,QAAQ,KAAK;AAC3C,WAAS,QAAQ,GAAG,QAAQ,OAAO,QAAQ,SAAS,GAAG;AACrD,QAAI,QAAQ,SAAS,EAAG,OAAM;AAC9B,UAAM,SAAS,SAAS,aAAa,KAAK,MAAM,QAAQ,KAAK,IAAI,SAAU,QAAQ,QAAS;AAC5F,QAAI;AACJ,YAAQ,SAAS,eAAe;AAAA,MAC9B,KAAK;AAAM,gBAAQ,KAAK,QAAQ,MAAM;AAAG;AAAA,MACzC,KAAK;AAAM,gBAAQ,KAAK,SAAS,MAAM;AAAG;AAAA,MAC1C,KAAK;AAAO,gBAAQ,KAAK,SAAS,QAAQ,IAAI;AAAG;AAAA,MACjD,KAAK;AAAO,gBAAQ,KAAK,UAAU,QAAQ,IAAI;AAAG;AAAA,MAClD,KAAK;AAAO,gBAAQ,KAAK,UAAU,QAAQ,IAAI;AAAG;AAAA,MAClD,KAAK;AAAO,gBAAQ,KAAK,WAAW,QAAQ,IAAI;AAAG;AAAA,IACrD;AACA,QAAI,SAAS,YAAY;AACvB,YAAM,UAAU,EAAE,IAAI,KAAK,IAAI,KAAK,KAAK,OAAO,KAAK,OAAO,KAAK,YAAY,KAAK,EAAE,EAAE,SAAS,aAAa;AAC5G,cAAQ,KAAK,IAAI,IAAI,QAAQ,OAAO;AAAA,IACtC;AACA,WAAO,KAAK,IAAI;AAAA,EAClB;AACA,SAAO;AACT;AAQA,eAAsB,6BACpB,OACA,SACgC;AAChC,MAAI,SAAS,sBAAsB,KAAM,OAAM,IAAI,sBAAsB,kBAAkB;AAC3F,MAAI,KAAC,0CAAmB,KAAK,EAAG,OAAM,IAAI,sBAAsB,qBAAqB;AACrF,QAAM,WAAW;AACjB,QAAM,WAAW,QAAQ,mBAAmB;AAC5C,QAAM,YAAY,QAAQ,aAAa;AACvC,MAAI,CAAC,OAAO,cAAc,QAAQ,KAAK,WAAW,KAAK,WAAW,wCAC7D,CAAC,OAAO,cAAc,SAAS,KAAK,YAAY,KAAK,YAAY,KAAQ;AAC5E,UAAM,IAAI,sBAAsB,iBAAiB;AAAA,EACnD;AACA,QAAM,mBAAmB,QAAQ,gBAAgB,SAAY,aAAY,mDAA4B,QAAQ,WAAW;AACxH,MAAI,kBAAkB,aAAa,SAAS,SAAS,YAAY,KAAK,CAAC,EAAE,SAAS,MAAM,aAAa,OAAO,GAAG;AAC7G,UAAM,IAAI,sBAAsB,sBAAsB;AAAA,EACxD;AACA,MAAI,aAAa;AACjB,aAAW,YAAY,SAAS,UAAW,eAAc,SAAS,QAAQ,WAAW,SAAS,WAAW,IAAI;AAC7G,aAAW,QAAQ,SAAS,OAAO;AACjC,kBAAc,KAAK,oBAAoB,SAAS,KAAK;AACrD,eAAW,WAAW,KAAK,WAAY,eAAc,QAAQ,OAAO,SAAS,QAAQ,sBAAsB;AAAA,EAC7G;AAEA,aAAW,YAAY,SAAS,UAAW,KAAI,SAAS,SAAS,SAAU,eAAc,SAAS;AAClG,MAAI,aAAa,SAAU,OAAM,IAAI,sBAAsB,iBAAiB;AAC5E,QAAM,WAAW,YAAY,IAAI,IAAI;AACrC,QAAM,QAAQ,MAAM;AAClB,QAAI,QAAQ,QAAQ,WAAW,YAAY,IAAI,KAAK,SAAU,OAAM,IAAI,sBAAsB,SAAS;AAAA,EACzG;AACA,QAAM;AACN,QAAM,YAAoD,uBAAO,OAAO,IAAI;AAE5E,QAAM,sBAAsB,oBAAI,IAAgC;AAChE,aAAW,YAAY,SAAS,WAAW;AACzC,UAAM,UAAU,oBAAoB,IAAI,SAAS,UAAU,KAAK,CAAC;AACjE,YAAQ,KAAK,QAAQ;AACrB,wBAAoB,IAAI,SAAS,YAAY,OAAO;AAAA,EACtD;AACA,aAAW,YAAY,SAAS,WAAW;AACzC,UAAM,UAAU,oBAAoB,IAAI,SAAS,EAAE;AACnD,QAAI,CAAC,QAAS;AACd,QAAI;AACJ,QAAI;AACJ,QAAI;AACF,YAAM,SAAS,MAAM,IAAI,QAAqB,CAAC,SAAS,WAAW;AACjE,gBAAQ,MAAM,OAAO,IAAI,sBAAsB,SAAS,CAAC;AACzD,gBAAQ,QAAQ,iBAAiB,SAAS,OAAO,EAAE,MAAM,KAAK,CAAC;AAC/D,gBAAQ,WAAW,OAAO,KAAK,IAAI,GAAG,WAAW,YAAY,IAAI,CAAC,CAAC;AACnE,iBAAS,KAAK,SAAS,OAAO,EAAE,KAAK,SAAS,MAAM,OAAO,IAAI,sBAAsB,sBAAsB,CAAC,CAAC;AAAA,MAC/G,CAAC;AACD,YAAM;AACN,YAAM,OAAO,IAAI,SAAS,MAAM;AAChC,iBAAW,YAAY,SAAS;AAC9B,cAAM;AACN,kBAAU,SAAS,EAAE,IAAI,OAAO,UAAU,MAAM,KAAK;AAAA,MACvD;AAAA,IACF,UAAE;AACA,mBAAa,KAAK;AAClB,UAAI,MAAO,SAAQ,QAAQ,oBAAoB,SAAS,KAAK;AAAA,IAC/D;AAAA,EACF;AACA,QAAM,aAA0C,CAAC;AACjD,QAAM,WAAuC,CAAC;AAC9C,QAAM,gBAAgB,IAAI,IAAI,SAAS,UAAU,IAAI,CAAC,UAAU,UAAU,CAAC,SAAS,IAAI,KAAK,CAAC,CAAC;AAC/F,aAAW,QAAQ,SAAS,OAAQ,YAAW,aAAa,KAAK,YAAY;AAC3E,UAAM;AACN,UAAM,aAAqD,uBAAO,OAAO,IAAI;AAC7E,eAAW,aAAa,UAAU,WAAY,YAAW,UAAU,QAAQ,IAAI,UAAU,UAAU,UAAU;AAC7G,eAAW,KAAK,OAAO,OAAO;AAAA,MAAE,QAAQ,KAAK;AAAA,MAAI,aAAa,UAAU;AAAA,MAAI,UAAU,UAAU;AAAA,MAC9F,cAAc,UAAU,eAAe,SAAY,OAAO,cAAc,IAAI,UAAU,UAAU;AAAA,MAAI,YAAY,OAAO,OAAO,UAAU;AAAA,IAAE,CAAC,CAAC;AAC9I,aAAS,KAAK,OAAO,OAAO;AAAA,MAAE,aAAa,UAAU;AAAA,MAAI,WAAW,WAAW;AAAA,MAC7E,GAAI,UAAU,sBAAsB,SAAY,CAAC,IAAI,EAAE,SAAS,UAAU,UAAU,iBAAiB,EAAkB;AAAA,MACvH,GAAI,WAAW,WAAW,SAAY,CAAC,IAAI,EAAE,SAAS,WAAW,OAAuB;AAAA,MACxF,GAAI,WAAW,eAAe,SAAY,CAAC,IAAI,EAAE,WAAW,WAAW,WAA2B;AAAA,IAAG,CAAC,CAAC;AAAA,EAC3G;AACA,QAAM,OAAO,CAAuC,MAAsC,WAAiB;AACzG,QAAI,SAAS;AACb,eAAW,OAAO,MAAM;AAAE,YAAM;AAAG,aAAO,IAAI,KAAK,MAAM;AAAG,gBAAU,IAAI;AAAA,IAAQ;AAClF,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,SAAS,MAAM,IAAI,UAAQ;AACvC,UAAM;AACN,WAAO,OAAO,OAAO;AAAA,MAAE,IAAI,KAAK;AAAA,MAAI,YAAY,KAAK;AAAA,MAAY,UAAU,KAAK;AAAA,MAC9E,qBAAqB,KAAK,KAAK,qBAAqB,IAAI,aAAa,KAAK,oBAAoB,SAAS,EAAE,CAAC;AAAA,MAC1G,YAAY,OAAO,OAAO,KAAK,WAAW,IAAI,aAAW,OAAO,OAAO;AAAA,QAAE,aAAa,QAAQ;AAAA,QAC5F,qBAAqB,QAAQ;AAAA,QAAqB,QAAQ,KAAK,QAAQ,QAAQ,IAAI,YAAY,QAAQ,OAAO,SAAS,QAAQ,mBAAmB,CAAC;AAAA,QAAG,SAAS,KAAK,QAAQ,SAAS,IAAI,aAAa,QAAQ,QAAQ,SAAS,QAAQ,mBAAmB,CAAC;AAAA,MAAE,CAAC,CAAC,CAAC;AAAA,IAAE,CAAC;AAAA,EACzQ,CAAC;AACD,QAAM,aAAa,SAAS,WAAW,IAAI,eAAa,OAAO,OAAO;AAAA,IAAE,IAAI,UAAU;AAAA,IAAI,iBAAiB,UAAU;AAAA,IACnH,UAAU,UAAU;AAAA,IAAU,UAAU,OAAO,OAAO,UAAU,SAAS,IAAI,aAAW,OAAO,OAAO;AAAA,MAAE,IAAI,QAAQ;AAAA,MAClH,eAAe,QAAQ;AAAA,MAAe,OAAO,UAAU,QAAQ,eAAe;AAAA,MAAI,QAAQ,UAAU,QAAQ,gBAAgB;AAAA,IAAG,CAAC,CAAC,CAAC;AAAA,EAAE,CAAC,CAAC;AAC1I,QAAM,YAAY,IAAI,IAAI,SAAS,UAAU,IAAI,cAAY,CAAC,SAAS,IAAI,QAAQ,CAAC,CAAC;AACrF,QAAM;AACN,SAAO,OAAO,OAAO;AAAA,IAAE;AAAA,IAAU,QAAQ,SAAS;AAAA,IAAQ,OAAO,SAAS;AAAA,IAAO,OAAO,SAAS;AAAA,IAAO,WAAW,SAAS;AAAA,IAC1H,WAAW,SAAS;AAAA,IAAW,QAAQ,SAAS;AAAA,IAAQ,aAAa,SAAS;AAAA,IAAa,kBAAkB,SAAS;AAAA,IACtH,aAAa,SAAS;AAAA,IAAa,GAAI,qBAAqB,SAAY,CAAC,IAAI,EAAE,iBAAiB;AAAA,IAAI,WAAW,OAAO,OAAO,SAAS;AAAA,IACtI,YAAY,OAAO,OAAO,UAAU;AAAA,IAAG,UAAU,OAAO,OAAO,QAAQ;AAAA,IAAG,OAAO,OAAO,OAAO,KAAK;AAAA,IAAG,YAAY,OAAO,OAAO,UAAU;AAAA,IAC3I,UAAU,OAAO,OAAO,SAAS,SAAS,IAAI,aAAW,OAAO,OAAO,EAAE,SAAS,UAAU,UAAU,IAAI,QAAQ,eAAe,EAAG,CAAC,CAAC,CAAC;AAAA,EAAE,CAAC;AAC9I;;;AD3OO,IAAM,cAAc;AAGpB,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/**\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,
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@eslint/js": "^10.0.1",
|
|
72
72
|
"@plasius/gpu-model-runtime": "0.2.4",
|
|
73
|
-
"@plasius/gpu-renderer": "0.2.
|
|
73
|
+
"@plasius/gpu-renderer": "0.2.53",
|
|
74
74
|
"@types/node": "^26.0.1",
|
|
75
75
|
"@typescript-eslint/eslint-plugin": "^8.59.3",
|
|
76
76
|
"@typescript-eslint/parser": "^8.59.3",
|
|
@@ -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
|
}
|