@instruktlabs/kiln 1.2.2 → 1.2.3
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/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/CHANGELOG.md +74 -0
- package/README.md +7 -0
- package/dist/agent-run.mjs +6392 -1477
- package/dist/build.json +23 -23
- package/dist/cli.mjs +8453 -3407
- package/dist/evaluator-worker.mjs +16608 -12387
- package/dist/mcp-engine.mjs +6746 -1725
- package/dist/mcp-server.mjs +4 -4
- package/dist/viewer/app.js +203 -199
- package/dist/viewer/chat.html +209 -205
- package/dist/viewer/style.css +10 -0
- package/docs/atlas-provenance.md +23 -0
- package/docs/community-exporter.md +27 -0
- package/docs/export-profiles.md +20 -0
- package/docs/material-library.md +9 -5
- package/docs/procedural-surfaces-v3.md +276 -0
- package/docs/projects-and-live-review.md +1 -1
- package/docs/rendering.md +41 -0
- package/docs/sdk.md +53 -0
- package/docs/tools-operations.md +2 -2
- package/docs/tools.md +3 -3
- package/lib/asset-materials-node.d.ts +3 -3
- package/lib/asset-materials-node.js +29 -33
- package/lib/assets-node.d.ts +1 -1
- package/lib/assets-node.js +11 -4
- package/lib/assets.d.ts +4 -2
- package/lib/assets.js +61 -16
- package/lib/atlas-provenance.d.ts +86 -0
- package/lib/atlas-provenance.js +448 -0
- package/lib/character.d.ts +11 -2
- package/lib/character.js +90 -2
- package/lib/community-exporter.d.ts +3 -2
- package/lib/community-exporter.js +139 -3
- package/lib/discovery/helper-contracts.js +161 -7
- package/lib/discovery/helper-specs.js +49 -4
- package/lib/discovery/shapes.js +20 -7
- package/lib/engine-identity.d.ts +1 -1
- package/lib/engine-identity.js +1 -1
- package/lib/evaluator/authoring-diagnostic.d.ts +1 -1
- package/lib/evaluator/authoring-diagnostic.js +12 -0
- package/lib/evaluator/protocol.d.ts +2 -2
- package/lib/evaluator/protocol.js +16 -6
- package/lib/evaluator/subprocess.js +2 -2
- package/lib/exporter-node.js +9 -1
- package/lib/geometry-budget.d.ts +7 -0
- package/lib/geometry-budget.js +8 -0
- package/lib/gltf-texture-binding.d.ts +6 -0
- package/lib/gltf-texture-binding.js +54 -0
- package/lib/material-authoring-node.d.ts +6 -0
- package/lib/material-authoring-node.js +49 -0
- package/lib/material-authoring-schema.d.ts +871 -0
- package/lib/material-authoring-schema.js +310 -0
- package/lib/material-export.d.ts +5 -0
- package/lib/material-export.js +21 -0
- package/lib/material-library-node.d.ts +34 -8
- package/lib/material-library-node.js +691 -11
- package/lib/material-library.d.ts +3704 -4
- package/lib/material-library.js +272 -0
- package/lib/mcp-core.d.ts +1 -1
- package/lib/pinned-material-map.d.ts +33 -0
- package/lib/pinned-material-map.js +1 -0
- package/lib/portable-material-runtime.d.ts +5 -0
- package/lib/portable-material-runtime.js +160 -0
- package/lib/portable-sampler-runtime.d.ts +4 -0
- package/lib/portable-sampler-runtime.js +26 -0
- package/lib/portable-sampler.d.ts +11 -0
- package/lib/portable-sampler.js +42 -0
- package/lib/primitives.d.ts +15 -3
- package/lib/primitives.js +24 -4
- package/lib/procedural-material-v2.d.ts +2 -0
- package/lib/procedural-material-v2.js +2 -1
- package/lib/procedural-material-v3.d.ts +72 -0
- package/lib/procedural-material-v3.js +162 -0
- package/lib/procedural-texture-v2-compiler.d.ts +31 -0
- package/lib/procedural-texture-v2-compiler.js +172 -0
- package/lib/procedural-texture-v3-contract.d.ts +125 -0
- package/lib/procedural-texture-v3-contract.js +333 -0
- package/lib/procedural-texture-v3.d.ts +12 -0
- package/lib/procedural-texture-v3.js +165 -0
- package/lib/procedural-texture.d.ts +9 -31
- package/lib/procedural-texture.js +43 -170
- package/lib/project-bundle-node.d.ts +1 -1
- package/lib/project-bundle-node.js +70 -13
- package/lib/project-bundle.d.ts +91 -3
- package/lib/project-bundle.js +48 -7
- package/lib/qa/atlas.d.ts +21 -0
- package/lib/qa/atlas.js +474 -0
- package/lib/qa/index.d.ts +1 -0
- package/lib/qa/index.js +1 -0
- package/lib/qa/material.js +2 -0
- package/lib/qa/skin-integrity.d.ts +18 -0
- package/lib/qa/skin-integrity.js +221 -0
- package/lib/render-service-host.js +4 -7
- package/lib/render.d.ts +3 -3
- package/lib/render.js +108 -16
- package/lib/skin-binding.d.ts +20 -0
- package/lib/skin-binding.js +144 -0
- package/lib/texture-atlas-contract.d.ts +97 -0
- package/lib/texture-atlas-contract.js +414 -0
- package/lib/texture-atlas-pixels.d.ts +73 -0
- package/lib/texture-atlas-pixels.js +290 -0
- package/lib/texture-atlas.d.ts +10 -0
- package/lib/texture-atlas.js +143 -0
- package/lib/texture-bake.d.ts +3 -0
- package/lib/texture-bake.js +66 -11
- package/lib/texture-resolver.d.ts +22 -0
- package/lib/texture-resolver.js +24 -0
- package/lib/tools/materials.js +8 -7
- package/lib/tools/registry.js +5 -16
- package/lib/tools/review.js +1 -1
- package/lib/uv-data.d.ts +32 -0
- package/lib/uv-data.js +172 -0
- package/lib/uv-shapes.js +3 -0
- package/lib/uv.d.ts +9 -3
- package/lib/uv.js +53 -82
- package/lib/views/camera.d.ts +3 -3
- package/lib/views/camera.js +32 -28
- package/lib/views/face-policy.d.ts +9 -0
- package/lib/views/face-policy.js +16 -0
- package/lib/views/glb.js +218 -24
- package/lib/views/pose.d.ts +7 -1
- package/lib/views/pose.js +63 -12
- package/lib/views/raster.d.ts +6 -2
- package/lib/views/raster.js +49 -37
- package/lib/views/scene-copy.d.ts +6 -0
- package/lib/views/scene-copy.js +73 -0
- package/lib/views/scene-raster.js +2 -1
- package/lib/views/triangle-coverage.d.ts +8 -0
- package/lib/views/triangle-coverage.js +58 -0
- package/lib/workspace-node.js +7 -3
- package/lib/workspace.d.ts +2 -2
- package/package.json +3 -1
- package/plugin.json +1 -1
- package/plugins/kiln-engine/.claude-plugin/plugin.json +1 -1
- package/plugins/kiln-engine/README.md +3 -3
- package/plugins/kiln-engine/package-provenance.json +6 -6
- package/plugins/kiln-engine/plugin.json +1 -1
- package/plugins/kiln-engine/runtime.json +1 -1
- package/skills/kiln-author-asset/references/geometry-recipes.md +124 -0
- package/skills/kiln-author-asset/references/projects-and-materials.md +32 -2
- package/skills/kiln-compose-scene/references/runtime-scenes.md +19 -0
- package/skills/kiln-qa-asset/references/integration-checks.md +37 -2
- package/src/asset-materials-node.ts +38 -45
- package/src/assets-node.ts +22 -5
- package/src/assets.ts +61 -20
- package/src/atlas-provenance.ts +522 -0
- package/src/character.ts +107 -2
- package/src/community-exporter.ts +143 -3
- package/src/discovery/helper-contracts.ts +188 -7
- package/src/discovery/helper-specs.ts +69 -4
- package/src/discovery/shapes.ts +25 -9
- package/src/engine-identity.ts +1 -1
- package/src/evaluator/authoring-diagnostic.ts +19 -1
- package/src/evaluator/protocol.ts +19 -9
- package/src/evaluator/subprocess.ts +2 -2
- package/src/exporter-node.ts +12 -1
- package/src/generated/mcp-manifest.json +3 -3
- package/src/geometry-budget.ts +8 -0
- package/src/gltf-texture-binding.ts +60 -0
- package/src/material-authoring-node.ts +68 -0
- package/src/material-authoring-schema.ts +343 -0
- package/src/material-export.ts +25 -0
- package/src/material-library-node.ts +840 -16
- package/src/material-library.ts +348 -5
- package/src/pinned-material-map.ts +43 -0
- package/src/portable-material-runtime.ts +200 -0
- package/src/portable-sampler-runtime.ts +40 -0
- package/src/portable-sampler.ts +54 -0
- package/src/primitives.ts +98 -4
- package/src/procedural-material-v2.ts +2 -1
- package/src/procedural-material-v3.ts +224 -0
- package/src/procedural-texture-v2-compiler.ts +234 -0
- package/src/procedural-texture-v3-contract.ts +437 -0
- package/src/procedural-texture-v3.ts +220 -0
- package/src/procedural-texture.ts +61 -229
- package/src/project-bundle-node.ts +106 -14
- package/src/project-bundle.ts +61 -18
- package/src/project-cli.ts +29 -17
- package/src/qa/atlas.ts +597 -0
- package/src/qa/index.ts +1 -0
- package/src/qa/material.ts +2 -0
- package/src/qa/skin-integrity.ts +291 -0
- package/src/render-service-host.ts +4 -6
- package/src/render.ts +133 -15
- package/src/skin-binding.ts +225 -0
- package/src/texture-atlas-contract.ts +558 -0
- package/src/texture-atlas-pixels.ts +456 -0
- package/src/texture-atlas.ts +185 -0
- package/src/texture-bake.ts +88 -10
- package/src/texture-resolver.ts +55 -0
- package/src/tools/materials.ts +15 -11
- package/src/tools/registry.ts +5 -15
- package/src/tools/review.ts +1 -1
- package/src/uv-data.ts +238 -0
- package/src/uv-shapes.ts +3 -0
- package/src/uv.ts +73 -128
- package/src/viewer/app.ts +37 -0
- package/src/viewer/live-panel.ts +57 -1
- package/src/viewer/material-preview-panel.ts +140 -0
- package/src/viewer/material-preview.ts +138 -0
- package/src/viewer/materials-panel.ts +34 -5
- package/src/viewer/navigation.ts +2 -0
- package/src/views/camera.ts +37 -40
- package/src/views/face-policy.ts +20 -0
- package/src/views/glb.ts +294 -17
- package/src/views/pose.ts +71 -13
- package/src/views/raster.ts +73 -46
- package/src/views/scene-copy.ts +86 -0
- package/src/views/scene-raster.ts +2 -1
- package/src/views/triangle-coverage.ts +78 -0
- package/src/workspace-node.ts +11 -3
- package/src/workspace.ts +2 -2
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"kind": "kiln-local-plugin",
|
|
4
|
-
"pluginVersion": "1.2.
|
|
5
|
-
"engineVersion": "1.2.
|
|
4
|
+
"pluginVersion": "1.2.3",
|
|
5
|
+
"engineVersion": "1.2.3",
|
|
6
6
|
"executables": [
|
|
7
7
|
"bin/kiln-setup-workspace.mjs"
|
|
8
8
|
],
|
|
9
9
|
"files": {
|
|
10
10
|
".claude-plugin/icon.png": "sha256:b4b651c402793b7e27cab780f04b14f80daec6d0cd5b7e4e90313930581a54e9",
|
|
11
|
-
".claude-plugin/plugin.json": "sha256:
|
|
11
|
+
".claude-plugin/plugin.json": "sha256:af0bc7b37b75ce5e4ab52230eded4d3e4ee999dd324b67665d57d5ce30ef56cf",
|
|
12
12
|
"bin/kiln-setup-workspace.mjs": "sha256:3d9a30236919a6ca91acb6b26f808cec442e6edc3dd88fe010645b010d76e838",
|
|
13
13
|
"LICENSE": "sha256:cdba278ebf1d6de618869936226bf03be4887179c128efc7aaa13d22034826a5",
|
|
14
|
-
"plugin.json": "sha256:
|
|
14
|
+
"plugin.json": "sha256:2e646847a58364094a9cd12c602553d73bda68785dfc216dbae9c07dafecd819",
|
|
15
15
|
"PRIVACY.md": "sha256:5f58d981667e40441e21c2dec411f269a9a67a6141cec61976d27088fb12573b",
|
|
16
|
-
"README.md": "sha256:
|
|
17
|
-
"runtime.json": "sha256:
|
|
16
|
+
"README.md": "sha256:fcc6364d1b08689fd531a154383cf752a3d21cb26aa5623ac0acfc11057a9fb3",
|
|
17
|
+
"runtime.json": "sha256:797090aec0b46f4f6220a5b85ab58eebd1b82d7079ece0258c94c975021fdc7f",
|
|
18
18
|
"skills/kiln-setup-workspace/references/plugin-install.md": "sha256:c338fb792e7fad0364c3e1a13c94c506afa1395489ec1b6e83b36d04728935fb",
|
|
19
19
|
"skills/kiln-setup-workspace/references/renderer-setup.md": "sha256:b743b1b2827fa814385990e1e5b849391cb427413e9c016d273aa19cebd46031",
|
|
20
20
|
"skills/kiln-setup-workspace/SKILL.md": "sha256:65ed926b3503a33f4fe793e84e4a045ce36e3967f0e6b340e456a15dd010ce54"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
|
|
3
3
|
"name": "kiln-engine",
|
|
4
|
-
"version": "1.2.
|
|
4
|
+
"version": "1.2.3",
|
|
5
5
|
"description": "Set up a local Kiln workspace to create, inspect and revise editable 3D assets with Claude Code or Codex.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Instrukt Labs",
|
|
@@ -17,6 +17,18 @@ and release. Matching endpoints can still produce a path through the payload or
|
|
|
17
17
|
support. Keep joints, contact markers and payload motion in the intended hierarchy;
|
|
18
18
|
repair the geometry or path where the swept volumes collide.
|
|
19
19
|
|
|
20
|
+
Measure a resting or mounting frame against the exported geometry, including
|
|
21
|
+
angled feet, supports and small protrusions. A nominal primitive bottom or a
|
|
22
|
+
locator called `ground` can differ from the actual lowest surface after rotation.
|
|
23
|
+
Preserve intentional hanging origins and provide a separate resting socket when
|
|
24
|
+
both placements are useful; do not silently move every asset to its bounds.
|
|
25
|
+
|
|
26
|
+
For directional repeated surfaces, preserve grain direction and texel scale while
|
|
27
|
+
varying the phase between neighboring pieces. Identical knots aligned in columns
|
|
28
|
+
can make separate boards read as one repeated stamp. Compare a single module with
|
|
29
|
+
an assembled span. Random rotation is inappropriate for directional grain and
|
|
30
|
+
must not change named atlas regions or their sampling margins.
|
|
31
|
+
|
|
20
32
|
For ears, handles or other details attached to a rotated or lofted body, derive
|
|
21
33
|
their bases from the carrier's local surface and transform them through the same
|
|
22
34
|
frame. A nearby world-space point can leave a visible gap after the body rotates.
|
|
@@ -62,6 +74,15 @@ winding or missing geometry rather than hiding the defect with double-sided shad
|
|
|
62
74
|
deliberate thin sheets may need it. Check ceiling and trim extents against the actual sloping roof, including
|
|
63
75
|
the eaves, rather than its bounding box.
|
|
64
76
|
|
|
77
|
+
Choose sidedness deliberately: an inward-facing tunnel lining can use `FrontSide`
|
|
78
|
+
with inward triangle winding; a leaf card viewed from both sides can use
|
|
79
|
+
`DoubleSide`. GLB has no back-only material flag, so Kiln rejects a used `BackSide`
|
|
80
|
+
material instead of exporting it as front-only. Reversing normals alone does not
|
|
81
|
+
reverse winding. Double-sided shading adds neither thickness nor end caps. A
|
|
82
|
+
negative node scale mirrors the front-face convention; baking that reflection into
|
|
83
|
+
vertex positions is a different operation and requires consistent winding and
|
|
84
|
+
normal/tangent data. Inspect both sides after export in the intended consumer.
|
|
85
|
+
|
|
65
86
|
For a pane or panel fitted into a sloping frame, derive its corners and surface
|
|
66
87
|
normal in the frame's coordinates. A bar's long axis and a sheet's plane may use
|
|
67
88
|
different local axes, so copying a slope angle does not align them. Check all
|
|
@@ -125,11 +146,51 @@ joint each pivot represents before reversing its bend direction. Correct exposed
|
|
|
125
146
|
attachment caps, gaps and snapping through the motion, without assuming every
|
|
126
147
|
stylized creature needs one rigging or deformation technique.
|
|
127
148
|
|
|
149
|
+
Choose the mechanism deliberately: rigid armor plates or robot links can follow
|
|
150
|
+
`createJointChain` pivots; a continuous elbow or flexible appendage can use
|
|
151
|
+
`createBoneChain` plus `createSkinnedPart` when the installed Discovery exposes
|
|
152
|
+
them. Both chains carry the same joint roles and local rest frames. Bones are
|
|
153
|
+
opt-in; rigid pivots do not become bones merely because their names say `Joint_`.
|
|
154
|
+
|
|
155
|
+
For explicit skinning, assemble the bones under the asset root in the rest pose
|
|
156
|
+
before binding. Finish topology and UV operations first where practical. Supply
|
|
157
|
+
four indices and weights for every final vertex, including duplicated UV seam
|
|
158
|
+
vertices; use valid indices even for zero-weight lanes. Weights should sum to one.
|
|
159
|
+
`normalizeWeights:true` normalizes a positive sum but cannot infer missing weights
|
|
160
|
+
or repair a zero sum. The helper owns cloned geometry and inverse bind matrices;
|
|
161
|
+
the caller still owns the bones and shared materials. Changing rest geometry or
|
|
162
|
+
reparenting afterward needs deliberate rebinding, not just another animation pose.
|
|
163
|
+
|
|
164
|
+
If export reports `SKIN_*` integrity findings, repair the named mesh, joint or
|
|
165
|
+
vertex range before another render. A missing inverse matrix needs the intended
|
|
166
|
+
rest binding restored; an invalid joint index needs the bone order and influence
|
|
167
|
+
lanes corrected. Normalizing weights cannot repair either. These source-data
|
|
168
|
+
checks also run on review derivatives and in QA warning mode. A valid current-pose
|
|
169
|
+
bound does not prove all animation poses, good deformation or collision clearance.
|
|
170
|
+
|
|
171
|
+
A two-bone ramp is useful for a simple strip or tube, not a general anatomical
|
|
172
|
+
weighting rule: for a chosen local transition interval `[startY, endY]`, with
|
|
173
|
+
`endY > startY`, use `t = Math.max(0, Math.min(1, (y-startY)/(endY-startY)))`,
|
|
174
|
+
indices `[baseIndex, tipIndex, baseIndex, baseIndex]` and weights `[1-t,t,0,0]`.
|
|
175
|
+
Keep the interval, joint placement and profile appropriate to the asset. Inspect
|
|
176
|
+
rest, intermediate and extreme poses under the actual parent transforms; correct
|
|
177
|
+
volume loss, exposed caps and pinching in the geometry/weights. Verify the chosen
|
|
178
|
+
converter preserves skinning: the explicit Three exporter supports this path,
|
|
179
|
+
while the legacy converter remains the default and does not preserve skins.
|
|
180
|
+
|
|
128
181
|
Before mirroring a hand, inspect its local frame, palm, thumb web and any tool grip.
|
|
129
182
|
Weak anatomical cues can look reversed without a left/right frame error. Refine the
|
|
130
183
|
shape while preserving a correct wrist pivot and attachment frame, then check hand
|
|
131
184
|
clearance through the relevant motion and against the complete carried tool.
|
|
132
185
|
|
|
186
|
+
Define the palm normal, finger direction and thumb side in each hand's local frame.
|
|
187
|
+
A grip marker reaching a handle does not establish a natural grip orientation.
|
|
188
|
+
Solve reach with elbow and torso clearance as well as wrist alignment, distributing
|
|
189
|
+
rotation through the forearm when appropriate. Inspect finger wrap and the actual
|
|
190
|
+
skinned wrist and shoulder surfaces between keys; a correct joint frame can still
|
|
191
|
+
produce a stretched sleeve cap. Neutral palm direction and pose belong to the
|
|
192
|
+
asset brief, rather than a universal character default.
|
|
193
|
+
|
|
133
194
|
For a shield or other broad carried plate, define the intended support pose as
|
|
134
195
|
well as its mounting frame: which way the plate faces, where the grip lies, and
|
|
135
196
|
how the forearm runs along the inner surface. Solve the elbow within a plausible
|
|
@@ -152,6 +213,12 @@ in the host). Recheck what each
|
|
|
152
213
|
lookup controls, clip targets and intermediate poses after export; fewer meshes
|
|
153
214
|
alone does not establish a successful optimization.
|
|
154
215
|
|
|
216
|
+
In custom consolidation, a scalar mesh material applies to every geometry group.
|
|
217
|
+
Group `materialIndex` selects an entry only when `mesh.material` is an array;
|
|
218
|
+
indexing a one-element array for box face groups can silently create default
|
|
219
|
+
materials on some faces. Preserve valid material assignments, then inspect the
|
|
220
|
+
exported faces rather than relying on a successful merge or export.
|
|
221
|
+
|
|
155
222
|
Budget materials within each rigid group. Reuse the parent's material for tiny
|
|
156
223
|
fixed details when it gives the intended appearance; a separate material adds a
|
|
157
224
|
potential draw even when the detail is small. One material does not guarantee
|
|
@@ -159,6 +226,15 @@ one draw: vertex layouts, protected parts, transparency and vertex-limit splits
|
|
|
159
226
|
also constrain merging. Available `drawDiagnostics` can help locate these costs;
|
|
160
227
|
read its scope and skip reasons, then measure in the destination.
|
|
161
228
|
|
|
229
|
+
Budget skinned mesh count as well as triangles. A small articulated asset can
|
|
230
|
+
still submit many draws when each segment is a separate skin, even if the parts
|
|
231
|
+
share one texture. Where the authoring/export path supports it, combine
|
|
232
|
+
compatible surfaces into a skin with a shared skeleton and material. A skin-aware
|
|
233
|
+
consolidation must preserve bind transforms, joint indices and weights, normals,
|
|
234
|
+
UVs, morph channels and attachment frames. Keep separate skins when their
|
|
235
|
+
materials, skeletons or visibility controls require them. Do not send skins
|
|
236
|
+
through a rigid merge by weakening its rejection checks.
|
|
237
|
+
|
|
162
238
|
Avoid unintentionally overlapping coplanar faces on separate parts. Merging can
|
|
163
239
|
change which face wins a depth tie even when geometry and colours are preserved.
|
|
164
240
|
Use a shared surface, remove hidden duplicate faces or give a deliberate overlay
|
|
@@ -174,6 +250,36 @@ material capabilities before choosing a delivery resource, then inspect GPU view
|
|
|
174
250
|
and destination filtering/backfaces. Raw `THREE.DataTexture` is not an available
|
|
175
251
|
authoring route. Solid leaves and custom surfaces remain valid alternatives.
|
|
176
252
|
|
|
253
|
+
For original cutouts, `proceduralTexture` V3 authors rectangular RGBA pixels;
|
|
254
|
+
`textureAtlas` combines named fixed regions from V3 recipes or exact saved map
|
|
255
|
+
revisions. Discover their full contracts before authoring. Atlas regions do not
|
|
256
|
+
pack or resize themselves. Reserve nonoverlapping gutters and choose edge copying
|
|
257
|
+
or transparent RGB dilation for the actual filtering and alpha policy.
|
|
258
|
+
|
|
259
|
+
Map unit UVs with
|
|
260
|
+
`remapUVToAtlas(geometry, atlas, 'region-name', {inputOrigin:'bottom-left', mode:'texel-center'})`.
|
|
261
|
+
Choose `inputOrigin` from the source UV convention and `mode` deliberately:
|
|
262
|
+
`texel-center` insets to edge texel centers, while `content-boundary` uses the
|
|
263
|
+
content rectangle boundary. Finish topology and then remap the correct region;
|
|
264
|
+
do not rotate arbitrary charts over a painted atlas and expect the artwork to
|
|
265
|
+
follow. A geometry-wide region binding does not assign separate regions to
|
|
266
|
+
material groups. For repeating grass or directional wood, preserve or project
|
|
267
|
+
UVs and tile a standalone texture instead of forcing every surface into an atlas.
|
|
268
|
+
Neither atlas remapping nor `autoUnwrap` creates painted detail.
|
|
269
|
+
|
|
270
|
+
For repeated boards or other directional surfaces, align UV length with the
|
|
271
|
+
physical grain direction and retain the chosen texel density. Repeating the same
|
|
272
|
+
narrow UV band can miss a texture's authored detail even when the map is bound.
|
|
273
|
+
Use deliberate deterministic offsets when variation is intended, and inspect a
|
|
274
|
+
close perspective view as well as the assembly; a low-contrast surface alone
|
|
275
|
+
does not prove missing textures or a rendering defect.
|
|
276
|
+
|
|
277
|
+
When projecting along a chosen grain axis, use an alternate projection for faces
|
|
278
|
+
whose normal is parallel to that axis; otherwise their UV area can collapse to a
|
|
279
|
+
line. Check exported nondegenerate faces for usable UV area, including end faces
|
|
280
|
+
and caps. A separate visible end-grain cap can be intentional, but does not repair
|
|
281
|
+
the underlying face's UVs or justify claiming every chart is valid.
|
|
282
|
+
|
|
177
283
|
For lengthwise grain or stripes through bends, discover `recipe:directional-sweep-v1`.
|
|
178
284
|
It demonstrates sweep side U around the profile and V along path distance. Preserve
|
|
179
285
|
that convention when editing the path; arbitrary atlas rotations suit baked detail
|
|
@@ -337,3 +443,21 @@ box or cylindrical mapping in a geometry-local frame. Fetch its exact Discovery
|
|
|
337
443
|
contract for rotated frames, partial angular ranges, caps and seam sampling.
|
|
338
444
|
`autoUnwrap` is the separate atlas operation. Removed shape unwrap names do not
|
|
339
445
|
select a preservation or projection fallback.
|
|
446
|
+
|
|
447
|
+
For a packed baked texture, `await autoUnwrap(geometry, options)` returns new
|
|
448
|
+
buffers and leaves the source unchanged. It duplicates seam vertices and remaps
|
|
449
|
+
vertex colors, skin indices/weights, extra UVs, custom per-vertex attributes
|
|
450
|
+
(1..4 components), and position/normal/color morphs. It retains triangle groups,
|
|
451
|
+
draw range and JSON metadata. It replaces UV0 and drops stale tangents; recompute
|
|
452
|
+
tangents after the final UV layout. Skin bindings and animation remain on the
|
|
453
|
+
mesh/skeleton, so verify an exported posed mesh before relying on deformation.
|
|
454
|
+
|
|
455
|
+
Default unwrapping recomputes normals. Use `useNormals: true` to preserve authored
|
|
456
|
+
normals and when normal morphs need their original reference frame. The installed
|
|
457
|
+
xatlas adapter supports at most 65,536 vertices both before and after seam
|
|
458
|
+
splitting; split larger geometry. Instanced data and unsupported morph semantics
|
|
459
|
+
fail explicitly. Read the returned `userData.atlas.width/height`; requested
|
|
460
|
+
`resolution` is a target and the packed image can be rectangular. Unwrapping
|
|
461
|
+
cannot preserve the appearance of a texture painted for the old UV0: rebake it.
|
|
462
|
+
For directional wood grain or a tiled wall, prefer existing primitive UVs or
|
|
463
|
+
`projectUV` rather than an arbitrarily rotated atlas.
|
|
@@ -46,7 +46,25 @@ For library materials, use CLI `material create-preset --file options.json`, the
|
|
|
46
46
|
`material get MATERIAL_ID REVISION` for the code-ready `portableSpec`. Custom recipes
|
|
47
47
|
use `material procedural --file draft.json`. These CLI paths do not need an internal
|
|
48
48
|
`dist/` import or an extra TypeScript loader. Copy the returned spec into source,
|
|
49
|
-
compile
|
|
49
|
+
compile schemaVersion 2 with `compilePortableMaterialSpecV2` or schemaVersion 3
|
|
50
|
+
with `compilePortableMaterialSpecV3`, and supply the exact pins below.
|
|
51
|
+
|
|
52
|
+
For a texture without geometry, create the material directly; do not invent a
|
|
53
|
+
mesh or project just to save PNG maps. Read `shape:material-draft` with Discovery.
|
|
54
|
+
Unversioned layered drafts keep their existing V1 records. Opt-in
|
|
55
|
+
`schemaVersion:2` material drafts add explicit samplers and a `procedural` V3
|
|
56
|
+
RGBA recipe or `atlas` recipe per map. The material-record version and texture-
|
|
57
|
+
recipe version describe different contracts. V3 recipes support rectangular
|
|
58
|
+
surfaces and alpha; a mask material still needs actual opaque and transparent
|
|
59
|
+
texels to produce a cutout.
|
|
60
|
+
|
|
61
|
+
An atlas resource source names an exact map `resourceId` plus its material
|
|
62
|
+
revision pin. It does not load arbitrary URLs or paths. Save sources first,
|
|
63
|
+
reuse returned identifiers, then create the atlas. The library resolves the
|
|
64
|
+
transitive closure. Export a saved material with
|
|
65
|
+
`node kiln.mjs material export MATERIAL_ID REVISION --out material.json` and
|
|
66
|
+
import that complete payload with `material import --file material.json`;
|
|
67
|
+
copying only the atlas PNG loses editable sources and named regions.
|
|
50
68
|
|
|
51
69
|
## Create and revise a project when useful
|
|
52
70
|
|
|
@@ -104,7 +122,7 @@ editable design guidance, not trusted requirements or release authorization.
|
|
|
104
122
|
Inspect `kiln_material` with `action: "presets"`, `"list"` or `"get"`. CLI equivalents
|
|
105
123
|
are `material presets`, `material list`, and `material get ID REVISION`. Creation
|
|
106
124
|
and import preserve creator, license, recipe/seed and source provenance. Copy the
|
|
107
|
-
returned `portableSpec` into source and
|
|
125
|
+
returned `portableSpec` into source and select its matching V2 or V3 compiler;
|
|
108
126
|
the host provides the selected immutable map bytes before evaluating source.
|
|
109
127
|
|
|
110
128
|
A pin uses the returned material ID as `resourceId`; both hashes equal its returned
|
|
@@ -129,9 +147,21 @@ already pins replaces the project's for that call. Update the lock deliberately
|
|
|
129
147
|
changing shared art direction. A missing resource or mismatched hash must be resolved
|
|
130
148
|
before building; neither source URLs nor material names authorize an implicit download.
|
|
131
149
|
|
|
150
|
+
Keep project defaults to a deliberate shared authoring palette, not every material
|
|
151
|
+
used anywhere in a growing inventory. An evaluation currently resolves at most 16
|
|
152
|
+
resources, including transitive dependencies; call-level pins replace matching
|
|
153
|
+
defaults but do not remove unrelated defaults. If that merged context exceeds the
|
|
154
|
+
budget, use an explicit standalone operation with the asset's complete small pin
|
|
155
|
+
set, then link the exact saved revision to the project. Refine the project defaults
|
|
156
|
+
through a deliberate revision update. Saved asset closures retain their own exact
|
|
157
|
+
materials independently of those authoring defaults.
|
|
158
|
+
|
|
132
159
|
Material records carry physical repeat scale, but the author controls mesh UV scale.
|
|
133
160
|
Review seams, repeats, roughness and normal strength on representative geometry with
|
|
134
161
|
actual GPU views. A project palette is guidance, not automatic recoloring.
|
|
162
|
+
Keep explicit nearest sampling for a requested pixel texture local to that
|
|
163
|
+
material. Smooth or physically based materials may need linear filtering and
|
|
164
|
+
mipmaps; neither a project nor an atlas implies one sampling policy.
|
|
135
165
|
|
|
136
166
|
## Retain and deliver the work
|
|
137
167
|
|
|
@@ -38,6 +38,19 @@ Check closed, open and moving door states and safe dismounts. A path over a rive
|
|
|
38
38
|
needs a real supporting collision surface. Broad-phase bounds alone do not prove
|
|
39
39
|
that a person can pass through an opening.
|
|
40
40
|
|
|
41
|
+
Exercise each one-shot interaction at least twice, including after its action has
|
|
42
|
+
finished and clamped. In Three AnimationMixer, seeking a completed paused action
|
|
43
|
+
does not restart it; explicitly reset/play for a new use while preserving the
|
|
44
|
+
action during the same use. Tie damage or resource consumption to the reviewed
|
|
45
|
+
contact event and check range or interruption again there.
|
|
46
|
+
|
|
47
|
+
Visual gaps and gameplay barriers are different scene contracts. A sparse gate
|
|
48
|
+
or boarded opening can have visible gaps while blocking an actor or melee reach.
|
|
49
|
+
Use the chosen interaction rule and the opening's actual frame for that test;
|
|
50
|
+
a single ray through decorative triangles cannot establish protection. Keep
|
|
51
|
+
project-specific damage, collision and barrier rules out of standalone asset
|
|
52
|
+
requirements. Compare the actor path, visual geometry and interaction result.
|
|
53
|
+
|
|
41
54
|
For a follow camera, run its actual update and controls during passage checks.
|
|
42
55
|
A controller-only loop can pass while the rendered camera hides the actor behind
|
|
43
56
|
an eave or lintel. Inspect the animated head and accessories, not only a clear
|
|
@@ -240,6 +253,12 @@ placements the application knows will remain fixed. Keep animated and controlled
|
|
|
240
253
|
hierarchies live, and restore or rebuild the cache before placement or variant
|
|
241
254
|
changes. Check exact world transforms, visibility and culling in the consumer.
|
|
242
255
|
|
|
256
|
+
For spatial instance batches, changing a source root's visibility must also
|
|
257
|
+
update its batch membership and culling bounds. Synchronize on a relevant change;
|
|
258
|
+
avoid scanning every immutable source each frame. Test hidden and restored
|
|
259
|
+
instances, preserving interactive or independently moving objects outside the
|
|
260
|
+
static batch.
|
|
261
|
+
|
|
243
262
|
Hiding draws does not necessarily stop CPU animation. Count evaluated rigs and
|
|
244
263
|
motion owners as well as visible actors. A projected-error selector may demand
|
|
245
264
|
exact poses behind the camera. For a qualified shared clip, the consumer can
|
|
@@ -19,6 +19,27 @@ Kiln authors metres, +X forward, +Y up, +Z right. Confirm importer conversion in
|
|
|
19
19
|
|
|
20
20
|
Source refs name source revisions. They do not identify arbitrary externally modified GLB bytes. Track the exact exported file used for integration.
|
|
21
21
|
|
|
22
|
+
For a first-person presentation, review the held assembly from its actual animated
|
|
23
|
+
eye frame at the destination field of view and aspect ratio. Inspect ready, lift,
|
|
24
|
+
contact and recovery; an external pose can fit both hands while obscuring the
|
|
25
|
+
crosshair or passing through the camera. Keep any view-specific presentation in
|
|
26
|
+
the asset or consuming scene selected by the brief, not in universal rig defaults.
|
|
27
|
+
|
|
28
|
+
Measure deformed surface vertices as well as contact locators. Planted foot markers
|
|
29
|
+
do not rule out a sole, claw or swinging hand passing below the ground. Sample
|
|
30
|
+
between animation keys and between the usual quarter poses; record the sampling
|
|
31
|
+
density and tolerance rather than claiming a continuous guarantee from a few views.
|
|
32
|
+
|
|
33
|
+
For atlas cutouts, first inspect the exact saved sheet on light, dark and checker
|
|
34
|
+
backgrounds for alpha, edge RGB and region placement. Raw map pixels establish
|
|
35
|
+
image content, not shaded material appearance. Then inspect the exported asset
|
|
36
|
+
with the destination's actual sampler, alpha cutoff, sidedness and lighting,
|
|
37
|
+
including receding and moving views. A still nearest-filtered preview cannot
|
|
38
|
+
clear mip bleed, shimmering or disappearing thin details. Keep material revision,
|
|
39
|
+
atlas region and compiler identity with the reviewed file. Structural UV-domain
|
|
40
|
+
checks cannot prove intended corner orientation without source correspondence;
|
|
41
|
+
use an asymmetric corner fixture when qualifying a mapping pipeline.
|
|
42
|
+
|
|
22
43
|
`composeSceneGLB` defaults to static composition (`keepAnimations: false`). Explicitly keep animations when required. Its material optimization policy can change scene material organization; choose it deliberately, then inspect the result. Warnings can report skipped inputs, so successful export alone does not prove every required asset was included.
|
|
23
44
|
|
|
24
45
|
Do not invent a universal performance cap. State the destination, tested conditions, and material limits of the evidence.
|
|
@@ -40,8 +61,13 @@ closure; flush rest-pose joins can separate or expose caps during motion.
|
|
|
40
61
|
|
|
41
62
|
For articulated actors carrying equipment, inspect the limb bend as well as hand
|
|
42
63
|
attachment closure. A hand can reach its target while the elbow folds through the
|
|
43
|
-
body. Include headgear and carried items in intermediate-pose clearance checks
|
|
44
|
-
|
|
64
|
+
body. Include headgear and carried items in intermediate-pose clearance checks.
|
|
65
|
+
Verify palm/finger orientation and wrist continuity against the full handle.
|
|
66
|
+
Sample the interpolated skinned surfaces as well as joint centres; shoulder
|
|
67
|
+
weights can create a pointed cap or a sleeve crossing the torso despite valid
|
|
68
|
+
attachment distances. Inspect the actual first-person view when the destination
|
|
69
|
+
requires it, without treating camera offsets as a repair for an invalid grip.
|
|
70
|
+
Also inspect cables or strings at their moving attachment points. A convincing
|
|
45
71
|
draw or tensioning action needs compatible equipment deformation, not just a
|
|
46
72
|
moving hand and an arbitrarily stretched connector. Keep controller choices and
|
|
47
73
|
equipment fit in the destination; a scene repair need not change the saved master.
|
|
@@ -79,6 +105,15 @@ instancing, so it does not predict complete `full` output or GPU speed. Check
|
|
|
79
105
|
Measure actual destination draws by anchor, material and pass after export, then
|
|
80
106
|
exercise the interactions and attachments those anchors protect.
|
|
81
107
|
|
|
108
|
+
For a composed scene, inventory every placed asset family and conditional visible
|
|
109
|
+
state, then verify actual submitted draws from representative views. Report
|
|
110
|
+
pack-only assets separately. A source primitive count is not a visible draw
|
|
111
|
+
count; one mesh may have several material groups, and repeated geometry may be
|
|
112
|
+
instanced into spatial batches. Compare skin counts and material/texture variants
|
|
113
|
+
when a low-triangle asset still contributes many submissions. Separate coverage
|
|
114
|
+
snapshots from timed benchmarks and preserve exact camera, viewport and quality
|
|
115
|
+
settings when comparing runtime derivatives.
|
|
116
|
+
|
|
82
117
|
Read each observation's `evidence` and sampling/omission counts.
|
|
83
118
|
`mirroredTangents` identifies static tangent-bearing parts with mirrored transforms;
|
|
84
119
|
it does not establish a shading defect. `coplanarParts` samples triangle overlaps
|
|
@@ -1,43 +1,25 @@
|
|
|
1
1
|
/** Exact saved material closure, shared by standalone asset and project delivery. */
|
|
2
2
|
import type { AssetRecord } from './assets';
|
|
3
|
-
import { validateAssetMaterialClosure } from './assets';
|
|
3
|
+
import { assetMaterialRootManifests, validateAssetMaterialClosure } from './assets';
|
|
4
4
|
import {
|
|
5
|
-
canonicalMaterialJson,
|
|
6
5
|
MATERIAL_LIBRARY_LIMITS,
|
|
7
6
|
type MaterialLibrary,
|
|
8
|
-
type
|
|
9
|
-
type
|
|
7
|
+
type MaterialManifest,
|
|
8
|
+
type MaterialRecord,
|
|
10
9
|
} from './material-library';
|
|
11
10
|
import {
|
|
12
11
|
decodeMaterialLibraryPayload,
|
|
13
|
-
|
|
12
|
+
validateMaterialManifestIdentityAny,
|
|
13
|
+
resolveMaterialRecordClosure,
|
|
14
14
|
} from './material-library-node';
|
|
15
15
|
|
|
16
|
-
export function dependencyManifests(asset: AssetRecord):
|
|
17
|
-
const result =
|
|
18
|
-
|
|
19
|
-
if (!raw || typeof raw !== 'object' || Array.isArray(raw))
|
|
20
|
-
throw new Error('Invalid saved asset dependency');
|
|
21
|
-
const dependency = raw as Record<string, unknown>;
|
|
22
|
-
if (dependency.kind === 'kiln.material.v1') {
|
|
23
|
-
if (dependency.delivery !== 'runtime')
|
|
24
|
-
throw new Error('Invalid material dependency delivery');
|
|
25
|
-
const manifest = validateMaterialManifestIdentity(dependency.manifest);
|
|
26
|
-
result.set(`${manifest.materialId}/${manifest.revisionId}`, manifest);
|
|
27
|
-
if (result.size > MATERIAL_LIBRARY_LIMITS.maxPayloadRecords)
|
|
28
|
-
throw new Error('Saved asset material dependency count exceeds limit');
|
|
29
|
-
} else if (dependency.delivery === 'runtime')
|
|
30
|
-
throw new Error(
|
|
31
|
-
`Unsupported runtime dependency: ${String(dependency.resourceId ?? 'unknown')}`,
|
|
32
|
-
);
|
|
33
|
-
else if (dependency.delivery !== 'embedded')
|
|
34
|
-
throw new Error('Unsupported saved asset dependency');
|
|
35
|
-
}
|
|
36
|
-
if (asset.manifest.build?.rebuild === 'external-dependencies-required' && !result.size)
|
|
16
|
+
export function dependencyManifests(asset: AssetRecord): MaterialManifest[] {
|
|
17
|
+
const result = assetMaterialRootManifests(asset).map(validateMaterialManifestIdentityAny);
|
|
18
|
+
if (asset.manifest.build?.rebuild === 'external-dependencies-required' && !result.length)
|
|
37
19
|
throw new Error('Saved asset has unrecorded external dependencies');
|
|
38
20
|
let bytes = 0;
|
|
39
21
|
let pixels = 0;
|
|
40
|
-
for (const manifest of result
|
|
22
|
+
for (const manifest of result)
|
|
41
23
|
for (const map of manifest.maps) {
|
|
42
24
|
bytes += map.bytes;
|
|
43
25
|
pixels += map.width * map.height;
|
|
@@ -47,32 +29,43 @@ export function dependencyManifests(asset: AssetRecord): MaterialManifestV1[] {
|
|
|
47
29
|
pixels > MATERIAL_LIBRARY_LIMITS.maxPayloadPixels
|
|
48
30
|
)
|
|
49
31
|
throw new Error('Saved asset material allocation exceeds limit');
|
|
50
|
-
return
|
|
32
|
+
return result;
|
|
51
33
|
}
|
|
52
34
|
|
|
53
35
|
export async function resolveSavedAssetMaterials(
|
|
54
36
|
asset: AssetRecord,
|
|
55
37
|
library?: MaterialLibrary,
|
|
56
|
-
): Promise<
|
|
38
|
+
): Promise<MaterialRecord[]> {
|
|
57
39
|
const dependencies = dependencyManifests(asset);
|
|
58
40
|
if (asset.materialResources) {
|
|
59
41
|
validateAssetMaterialClosure(asset, true);
|
|
60
42
|
return decodeMaterialLibraryPayload(asset.materialResources);
|
|
61
43
|
}
|
|
62
|
-
return
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
44
|
+
if (!dependencies.length) return [];
|
|
45
|
+
if (!library)
|
|
46
|
+
throw new Error('Locked asset material unavailable: No material library configured');
|
|
47
|
+
const roots = new Map(dependencies.map((m) => [`${m.materialId}/${m.revisionId}`, m]));
|
|
48
|
+
const wrap = async <T>(id: string, revision: string, load: () => Promise<T>): Promise<T> => {
|
|
49
|
+
try {
|
|
50
|
+
return await load();
|
|
51
|
+
} catch (error) {
|
|
52
|
+
throw new Error(`Locked asset material unavailable: ${id} at ${revision}`, { cause: error });
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
return resolveMaterialRecordClosure(dependencies, {
|
|
56
|
+
readManifest: async (id, revision) =>
|
|
57
|
+
wrap(id, revision, async () => {
|
|
58
|
+
const root = roots.get(`${id}/${revision}`);
|
|
59
|
+
if (root) return root;
|
|
60
|
+
if (!library.readManifest)
|
|
61
|
+
throw new Error('Material library requires manifest-first dependency capability');
|
|
62
|
+
return library.readManifest(id, revision);
|
|
63
|
+
}),
|
|
64
|
+
read: async (id, revision) =>
|
|
65
|
+
wrap(id, revision, () =>
|
|
66
|
+
library.readRecordFiles
|
|
67
|
+
? library.readRecordFiles(id, revision)
|
|
68
|
+
: library.read(id, revision),
|
|
69
|
+
),
|
|
70
|
+
});
|
|
78
71
|
}
|
package/src/assets-node.ts
CHANGED
|
@@ -18,7 +18,11 @@ import {
|
|
|
18
18
|
type AssetManifest,
|
|
19
19
|
type AssetRecord,
|
|
20
20
|
} from './assets';
|
|
21
|
-
import
|
|
21
|
+
import {
|
|
22
|
+
canonicalMaterialJson,
|
|
23
|
+
type MaterialLibrary,
|
|
24
|
+
type MaterialRecord,
|
|
25
|
+
} from './material-library';
|
|
22
26
|
import { FileMaterialLibrary, createMaterialLibraryPayload } from './material-library-node';
|
|
23
27
|
import { dependencyManifests, resolveSavedAssetMaterials } from './asset-materials-node';
|
|
24
28
|
import { renameDirectoryAtomically } from './atomic-directory';
|
|
@@ -230,7 +234,9 @@ export class FileAssetLibrary implements AssetLibrary {
|
|
|
230
234
|
(raw) =>
|
|
231
235
|
raw &&
|
|
232
236
|
typeof raw === 'object' &&
|
|
233
|
-
|
|
237
|
+
['kiln.material.v1', 'kiln.material.v2'].includes(
|
|
238
|
+
String((raw as Record<string, unknown>).kind),
|
|
239
|
+
),
|
|
234
240
|
),
|
|
235
241
|
),
|
|
236
242
|
);
|
|
@@ -243,7 +249,7 @@ export class FileAssetLibrary implements AssetLibrary {
|
|
|
243
249
|
if (resourceBytes > ASSET_LIMIT)
|
|
244
250
|
throw new Error('Asset material import exceeds allocation limit');
|
|
245
251
|
const prepared: AssetRecord[] = [];
|
|
246
|
-
const resources = new Map<string,
|
|
252
|
+
const resources = new Map<string, MaterialRecord>();
|
|
247
253
|
// Validate the whole input before writing anything; per-revision commits are atomic.
|
|
248
254
|
for (const record of records) {
|
|
249
255
|
await verifyAssetRecord(record);
|
|
@@ -256,11 +262,22 @@ export class FileAssetLibrary implements AssetLibrary {
|
|
|
256
262
|
(raw) =>
|
|
257
263
|
raw &&
|
|
258
264
|
typeof raw === 'object' &&
|
|
259
|
-
|
|
265
|
+
['kiln.material.v1', 'kiln.material.v2'].includes(
|
|
266
|
+
String((raw as Record<string, unknown>).kind),
|
|
267
|
+
),
|
|
260
268
|
))
|
|
261
269
|
) {
|
|
262
270
|
const materials = await resolveSavedAssetMaterials(record, this.materials);
|
|
263
|
-
for (const material of materials)
|
|
271
|
+
for (const material of materials) {
|
|
272
|
+
const key = `${material.manifest.materialId}/${material.manifest.revisionId}`;
|
|
273
|
+
const previous = resources.get(key);
|
|
274
|
+
if (
|
|
275
|
+
previous &&
|
|
276
|
+
canonicalMaterialJson(previous.manifest) !== canonicalMaterialJson(material.manifest)
|
|
277
|
+
)
|
|
278
|
+
throw new Error('Conflicting asset material dependencies');
|
|
279
|
+
resources.set(key, material);
|
|
280
|
+
}
|
|
264
281
|
prepared.push({
|
|
265
282
|
...record,
|
|
266
283
|
materialResources: await createMaterialLibraryPayload(materials),
|