@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
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
/** Advertisable field shapes only. Existing canonicalizers own semantics and budgets. */
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { MIN_PROCEDURAL_SIZE, MAX_PROCEDURAL_SIZE, MAX_PROCEDURAL_LAYERS, MAX_PROCEDURAL_PATTERN_COUNT, MAX_NOISE_OCTAVES, } from "./procedural-material-v2.js";
|
|
4
|
+
import { MAX_PROCEDURAL_V3_EDGE, MAX_PROCEDURAL_V3_OPERATIONS, MAX_PROCEDURAL_V3_VERTICES, MAX_PROCEDURAL_V3_STAMPS, MAX_PROCEDURAL_V3_PALETTE, PROCEDURAL_TEXTURE_V3_COMPILER_ID, } from "./procedural-texture-v3-contract.js";
|
|
5
|
+
import { TEXTURE_ATLAS_COMPILER_ID, TEXTURE_ATLAS_LIMITS } from "./texture-atlas-contract.js";
|
|
6
|
+
import { PORTABLE_MIN_FILTERS_V1, PORTABLE_MAG_FILTERS_V1, PORTABLE_WRAPS_V1, } from "./portable-sampler.js";
|
|
7
|
+
import { TEXTURE_USAGES } from "./texture-contract.js";
|
|
8
|
+
/** Persisted V2 shape: all canonical fields required, no author defaults or transforms. */
|
|
9
|
+
export const canonicalLegacyV2FieldSchema = (() => {
|
|
10
|
+
const color = z.number().int().min(0).max(0xffffff);
|
|
11
|
+
const count = z.number().int().min(1).max(MAX_PROCEDURAL_PATTERN_COUNT);
|
|
12
|
+
const angleDeg = z.number().min(-36000).max(36000);
|
|
13
|
+
const unit = z.number().min(0).max(1);
|
|
14
|
+
const common = { blend: z.enum(['normal', 'multiply', 'screen', 'overlay']), opacity: unit };
|
|
15
|
+
return z
|
|
16
|
+
.object({
|
|
17
|
+
schemaVersion: z.literal(2),
|
|
18
|
+
size: z.number().int().min(MIN_PROCEDURAL_SIZE).max(MAX_PROCEDURAL_SIZE),
|
|
19
|
+
usage: z.enum(TEXTURE_USAGES),
|
|
20
|
+
name: z.string().min(1).max(80).optional(),
|
|
21
|
+
layers: z
|
|
22
|
+
.array(z.discriminatedUnion('op', [
|
|
23
|
+
z.object({ op: z.literal('solid'), color, ...common }).strict(),
|
|
24
|
+
z
|
|
25
|
+
.object({
|
|
26
|
+
op: z.literal('checker'),
|
|
27
|
+
colorA: color,
|
|
28
|
+
colorB: color,
|
|
29
|
+
squares: count,
|
|
30
|
+
...common,
|
|
31
|
+
})
|
|
32
|
+
.strict(),
|
|
33
|
+
z
|
|
34
|
+
.object({
|
|
35
|
+
op: z.literal('stripes'),
|
|
36
|
+
colorA: color,
|
|
37
|
+
colorB: color,
|
|
38
|
+
count,
|
|
39
|
+
angleDeg,
|
|
40
|
+
...common,
|
|
41
|
+
})
|
|
42
|
+
.strict(),
|
|
43
|
+
z
|
|
44
|
+
.object({ op: z.literal('gradient'), from: color, to: color, angleDeg, ...common })
|
|
45
|
+
.strict(),
|
|
46
|
+
z
|
|
47
|
+
.object({
|
|
48
|
+
op: z.literal('bricks'),
|
|
49
|
+
brick: color,
|
|
50
|
+
mortar: color,
|
|
51
|
+
rows: count,
|
|
52
|
+
cols: count,
|
|
53
|
+
mortarWidth: unit,
|
|
54
|
+
stagger: unit,
|
|
55
|
+
...common,
|
|
56
|
+
})
|
|
57
|
+
.strict(),
|
|
58
|
+
z
|
|
59
|
+
.object({
|
|
60
|
+
op: z.literal('noise'),
|
|
61
|
+
colorA: color,
|
|
62
|
+
colorB: color,
|
|
63
|
+
scale: count,
|
|
64
|
+
octaves: z.number().int().min(1).max(MAX_NOISE_OCTAVES),
|
|
65
|
+
seed: z.number().int().min(-2147483648).max(2147483647),
|
|
66
|
+
...common,
|
|
67
|
+
})
|
|
68
|
+
.strict(),
|
|
69
|
+
]))
|
|
70
|
+
.min(1)
|
|
71
|
+
.max(MAX_PROCEDURAL_LAYERS),
|
|
72
|
+
})
|
|
73
|
+
.strict();
|
|
74
|
+
})();
|
|
75
|
+
/** Inject author V2 without a circular import. Optional persisted leaf must have no defaults. */
|
|
76
|
+
export function makeMaterialAuthoringSchemas(legacyV2Schema, canonicalLegacyV2Schema = canonicalLegacyV2FieldSchema) {
|
|
77
|
+
const integer = (min, max) => z.number().int().min(min).max(max);
|
|
78
|
+
const byte = integer(0, 255);
|
|
79
|
+
const coordinate = integer(-4096, 4096);
|
|
80
|
+
const point = z.tuple([coordinate, coordinate]);
|
|
81
|
+
const rgba = z.tuple([byte, byte, byte, byte]);
|
|
82
|
+
const usage = z.enum(TEXTURE_USAGES);
|
|
83
|
+
const hash = z.templateLiteral(['sha256:', z.string().regex(/^[a-f0-9]{64}$/)]);
|
|
84
|
+
const name = z.string().min(1).max(80);
|
|
85
|
+
const stableId = z.string().regex(/^[a-z][a-z0-9_-]{0,79}$/);
|
|
86
|
+
const mapId = z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_.:/-]{0,199}$/);
|
|
87
|
+
const dimensions = { width: integer(1, 4096), height: integer(1, 4096) };
|
|
88
|
+
const pixelRectangleSchema = z
|
|
89
|
+
.object({ x: coordinate, y: coordinate, width: integer(1, 2048), height: integer(1, 2048) })
|
|
90
|
+
.strict();
|
|
91
|
+
const atlasRectangleSchema = z
|
|
92
|
+
.object({ x: integer(0, 4096), y: integer(0, 4096), ...dimensions })
|
|
93
|
+
.strict();
|
|
94
|
+
const shape = z.discriminatedUnion('kind', [
|
|
95
|
+
pixelRectangleSchema.extend({ kind: z.literal('rectangle') }).strict(),
|
|
96
|
+
pixelRectangleSchema.extend({ kind: z.literal('ellipse') }).strict(),
|
|
97
|
+
z
|
|
98
|
+
.object({
|
|
99
|
+
kind: z.literal('polygon'),
|
|
100
|
+
points: z.array(point).min(3).max(MAX_PROCEDURAL_V3_VERTICES),
|
|
101
|
+
})
|
|
102
|
+
.strict(),
|
|
103
|
+
z.object({ kind: z.literal('line'), from: point, to: point, width: integer(1, 2048) }).strict(),
|
|
104
|
+
]);
|
|
105
|
+
const paint = z.object({ op: z.literal('paint'), shape, rgba, opacity: byte }).strict();
|
|
106
|
+
const mask = z
|
|
107
|
+
.object({ op: z.literal('mask'), shape, alpha: byte, invert: z.boolean() })
|
|
108
|
+
.strict();
|
|
109
|
+
const stamps = z
|
|
110
|
+
.object({
|
|
111
|
+
op: z.literal('stamps'),
|
|
112
|
+
shape,
|
|
113
|
+
rgba,
|
|
114
|
+
opacity: byte,
|
|
115
|
+
count: integer(1, MAX_PROCEDURAL_V3_STAMPS),
|
|
116
|
+
seed: integer(0, 0xffffffff),
|
|
117
|
+
area: pixelRectangleSchema,
|
|
118
|
+
periodic: z.boolean(),
|
|
119
|
+
})
|
|
120
|
+
.strict();
|
|
121
|
+
const legacy = z
|
|
122
|
+
.object({ op: z.literal('legacy-v2'), spec: legacyV2Schema, alpha: byte, opacity: byte })
|
|
123
|
+
.strict();
|
|
124
|
+
const palette = z
|
|
125
|
+
.object({
|
|
126
|
+
colors: z.array(integer(0, 0xffffff)).min(1).max(MAX_PROCEDURAL_V3_PALETTE),
|
|
127
|
+
dither: z.enum(['none', 'bayer4']),
|
|
128
|
+
})
|
|
129
|
+
.strict();
|
|
130
|
+
const proceduralBase = {
|
|
131
|
+
schemaVersion: z.literal(3),
|
|
132
|
+
width: integer(4, MAX_PROCEDURAL_V3_EDGE),
|
|
133
|
+
height: integer(4, MAX_PROCEDURAL_V3_EDGE),
|
|
134
|
+
usage,
|
|
135
|
+
name: name.optional(),
|
|
136
|
+
background: rgba,
|
|
137
|
+
};
|
|
138
|
+
const canonicalProceduralTextureSpecV3Schema = z
|
|
139
|
+
.object({
|
|
140
|
+
...proceduralBase,
|
|
141
|
+
operations: z
|
|
142
|
+
.array(z.discriminatedUnion('op', [
|
|
143
|
+
paint,
|
|
144
|
+
mask,
|
|
145
|
+
stamps,
|
|
146
|
+
legacy.extend({ spec: canonicalLegacyV2Schema }),
|
|
147
|
+
]))
|
|
148
|
+
.max(MAX_PROCEDURAL_V3_OPERATIONS),
|
|
149
|
+
palette: palette.optional(),
|
|
150
|
+
})
|
|
151
|
+
.strict();
|
|
152
|
+
const proceduralTextureSpecV3Schema = z
|
|
153
|
+
.object({
|
|
154
|
+
...proceduralBase,
|
|
155
|
+
usage: usage.optional(),
|
|
156
|
+
background: rgba.optional(),
|
|
157
|
+
operations: z
|
|
158
|
+
.array(z.discriminatedUnion('op', [
|
|
159
|
+
paint.partial({ opacity: true }),
|
|
160
|
+
mask.partial({ alpha: true, invert: true }),
|
|
161
|
+
stamps.partial({ opacity: true, periodic: true }),
|
|
162
|
+
legacy.partial({ alpha: true, opacity: true }),
|
|
163
|
+
]))
|
|
164
|
+
.max(MAX_PROCEDURAL_V3_OPERATIONS),
|
|
165
|
+
palette: palette.partial({ dither: true }).optional(),
|
|
166
|
+
})
|
|
167
|
+
.strict();
|
|
168
|
+
const portableSamplerSchema = z
|
|
169
|
+
.object({
|
|
170
|
+
minFilter: z.enum(PORTABLE_MIN_FILTERS_V1),
|
|
171
|
+
magFilter: z.enum(PORTABLE_MAG_FILTERS_V1),
|
|
172
|
+
wrapS: z.enum(PORTABLE_WRAPS_V1),
|
|
173
|
+
wrapT: z.enum(PORTABLE_WRAPS_V1),
|
|
174
|
+
})
|
|
175
|
+
.strict();
|
|
176
|
+
const materialMapPinSchema = z
|
|
177
|
+
.object({ resourceId: stableId, revisionId: hash, sha256: hash })
|
|
178
|
+
.strict();
|
|
179
|
+
const resourceSource = z
|
|
180
|
+
.object({
|
|
181
|
+
kind: z.literal('resource'),
|
|
182
|
+
resourceId: mapId,
|
|
183
|
+
pin: materialMapPinSchema,
|
|
184
|
+
expected: z
|
|
185
|
+
.object({ ...dimensions, imageSha256: hash, decodedPixelHash: hash })
|
|
186
|
+
.partial()
|
|
187
|
+
.strict()
|
|
188
|
+
.optional(),
|
|
189
|
+
})
|
|
190
|
+
.strict();
|
|
191
|
+
const region = z
|
|
192
|
+
.object({
|
|
193
|
+
name: stableId,
|
|
194
|
+
content: atlasRectangleSchema,
|
|
195
|
+
gutter: integer(0, 32),
|
|
196
|
+
edgeMode: z.enum(['copy-edge', 'mask-rgb-dilate']),
|
|
197
|
+
source: z.discriminatedUnion('kind', [
|
|
198
|
+
z
|
|
199
|
+
.object({ kind: z.literal('procedural'), spec: canonicalProceduralTextureSpecV3Schema })
|
|
200
|
+
.strict(),
|
|
201
|
+
resourceSource,
|
|
202
|
+
]),
|
|
203
|
+
crop: atlasRectangleSchema.optional(),
|
|
204
|
+
})
|
|
205
|
+
.strict();
|
|
206
|
+
const atlasBase = {
|
|
207
|
+
schemaVersion: z.literal(1),
|
|
208
|
+
width: integer(4, TEXTURE_ATLAS_LIMITS.edge),
|
|
209
|
+
height: integer(4, TEXTURE_ATLAS_LIMITS.edge),
|
|
210
|
+
usage,
|
|
211
|
+
sampler: portableSamplerSchema,
|
|
212
|
+
};
|
|
213
|
+
const canonicalTextureAtlasSpecV1Schema = z
|
|
214
|
+
.object({ ...atlasBase, regions: z.array(region).min(1).max(TEXTURE_ATLAS_LIMITS.regions) })
|
|
215
|
+
.strict();
|
|
216
|
+
const textureAtlasSpecV1Schema = z
|
|
217
|
+
.object({
|
|
218
|
+
...atlasBase,
|
|
219
|
+
sampler: portableSamplerSchema.optional(),
|
|
220
|
+
regions: z
|
|
221
|
+
.array(region
|
|
222
|
+
.extend({
|
|
223
|
+
source: z.discriminatedUnion('kind', [
|
|
224
|
+
z
|
|
225
|
+
.object({ kind: z.literal('procedural'), spec: proceduralTextureSpecV3Schema })
|
|
226
|
+
.strict(),
|
|
227
|
+
resourceSource,
|
|
228
|
+
]),
|
|
229
|
+
})
|
|
230
|
+
.partial({ gutter: true, edgeMode: true }))
|
|
231
|
+
.min(1)
|
|
232
|
+
.max(TEXTURE_ATLAS_LIMITS.regions),
|
|
233
|
+
})
|
|
234
|
+
.strict();
|
|
235
|
+
const verifiedPinnedMaterialMapDescriptorSchema = z
|
|
236
|
+
.object({
|
|
237
|
+
materialId: stableId,
|
|
238
|
+
revisionId: hash,
|
|
239
|
+
resourceId: mapId,
|
|
240
|
+
slot: z.enum(['baseColor', 'normal', 'metallicRoughness', 'emissive', 'occlusion']),
|
|
241
|
+
usage,
|
|
242
|
+
colorSpace: z.enum(['srgb', 'linear']),
|
|
243
|
+
...dimensions,
|
|
244
|
+
encodedByteLength: integer(1, TEXTURE_ATLAS_LIMITS.encodedSourceBytes),
|
|
245
|
+
imageSha256: hash,
|
|
246
|
+
decodedPixelHash: hash.optional(),
|
|
247
|
+
})
|
|
248
|
+
.strict();
|
|
249
|
+
const sourceManifestBase = {
|
|
250
|
+
id: z.string().min(1).max(1024),
|
|
251
|
+
...dimensions,
|
|
252
|
+
decodedPixelHash: hash,
|
|
253
|
+
};
|
|
254
|
+
const sourceManifest = z.discriminatedUnion('kind', [
|
|
255
|
+
z
|
|
256
|
+
.object({
|
|
257
|
+
...sourceManifestBase,
|
|
258
|
+
kind: z.literal('procedural'),
|
|
259
|
+
recipeHash: hash,
|
|
260
|
+
compilerId: z.literal(PROCEDURAL_TEXTURE_V3_COMPILER_ID),
|
|
261
|
+
})
|
|
262
|
+
.strict(),
|
|
263
|
+
z
|
|
264
|
+
.object({
|
|
265
|
+
...sourceManifestBase,
|
|
266
|
+
kind: z.literal('resource'),
|
|
267
|
+
descriptor: verifiedPinnedMaterialMapDescriptorSchema,
|
|
268
|
+
})
|
|
269
|
+
.strict(),
|
|
270
|
+
]);
|
|
271
|
+
const textureAtlasManifestV1Schema = z
|
|
272
|
+
.object({
|
|
273
|
+
version: z.literal('kiln.atlas-manifest.v1'),
|
|
274
|
+
compilerId: z.literal(TEXTURE_ATLAS_COMPILER_ID),
|
|
275
|
+
width: atlasBase.width,
|
|
276
|
+
height: atlasBase.height,
|
|
277
|
+
usage,
|
|
278
|
+
origin: z.literal('top-left'),
|
|
279
|
+
sampler: portableSamplerSchema,
|
|
280
|
+
specHash: hash,
|
|
281
|
+
layoutHash: hash,
|
|
282
|
+
decodedPixelHash: hash,
|
|
283
|
+
atlasPixelHash: hash,
|
|
284
|
+
sources: z.array(sourceManifest).min(1).max(TEXTURE_ATLAS_LIMITS.sources),
|
|
285
|
+
regions: z
|
|
286
|
+
.array(z
|
|
287
|
+
.object({
|
|
288
|
+
name: stableId,
|
|
289
|
+
content: atlasRectangleSchema,
|
|
290
|
+
allocation: atlasRectangleSchema,
|
|
291
|
+
crop: atlasRectangleSchema,
|
|
292
|
+
sourceId: z.string().min(1).max(1024),
|
|
293
|
+
})
|
|
294
|
+
.strict())
|
|
295
|
+
.min(1)
|
|
296
|
+
.max(TEXTURE_ATLAS_LIMITS.regions),
|
|
297
|
+
manifestHash: hash,
|
|
298
|
+
})
|
|
299
|
+
.strict();
|
|
300
|
+
return {
|
|
301
|
+
portableSamplerSchema,
|
|
302
|
+
proceduralTextureSpecV3Schema,
|
|
303
|
+
canonicalProceduralTextureSpecV3Schema,
|
|
304
|
+
textureAtlasSpecV1Schema,
|
|
305
|
+
canonicalTextureAtlasSpecV1Schema,
|
|
306
|
+
textureAtlasManifestV1Schema,
|
|
307
|
+
materialMapPinSchema,
|
|
308
|
+
verifiedPinnedMaterialMapDescriptorSchema,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type Object3D } from 'three';
|
|
2
|
+
/** glTF has front-only or double-sided materials, but no back-only flag. Reject
|
|
3
|
+
* that intent before baking/conversion instead of silently changing visibility.
|
|
4
|
+
* Unused material slots do not describe an exported primitive. */
|
|
5
|
+
export declare function assertPortableMaterialSides(root: Object3D): void;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { BackSide } from 'three';
|
|
2
|
+
import { AuthoringDiagnosticError } from "./evaluator/authoring-diagnostic.js";
|
|
3
|
+
/** glTF has front-only or double-sided materials, but no back-only flag. Reject
|
|
4
|
+
* that intent before baking/conversion instead of silently changing visibility.
|
|
5
|
+
* Unused material slots do not describe an exported primitive. */
|
|
6
|
+
export function assertPortableMaterialSides(root) {
|
|
7
|
+
root.traverse((node) => {
|
|
8
|
+
const mesh = node;
|
|
9
|
+
if (!mesh.isMesh && !node.isSprite)
|
|
10
|
+
return;
|
|
11
|
+
const materials = mesh.material;
|
|
12
|
+
const used = Array.isArray(materials)
|
|
13
|
+
? [...new Set(mesh.geometry.groups.map((group) => group.materialIndex ?? 0))].map((index) => ({ material: materials[index], index }))
|
|
14
|
+
: [{ material: materials, index: 0 }];
|
|
15
|
+
for (const { material, index } of used) {
|
|
16
|
+
if (!material || material.side !== BackSide)
|
|
17
|
+
continue;
|
|
18
|
+
throw new AuthoringDiagnosticError('EXPORT_MATERIAL_SIDE_UNSUPPORTED', `EXPORT_MATERIAL_SIDE_UNSUPPORTED ${node.name || '<unnamed part>'}: material ${material.name || `<slot ${index}>`} uses BackSide, which glTF cannot encode directly. Author inward-facing geometry with FrontSide, or choose DoubleSide when both faces are intended.`);
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type MaterialLibraryPayloadV1, type MaterialLibrarySlot, type MaterialManifestV1, type MaterialRecordV1, type MaterialSourceV1, type MaterialTransformV1 } from "./material-library.js";
|
|
2
|
-
import type
|
|
1
|
+
import { type MaterialLibraryPayloadV1, type MaterialLibrarySlot, type MaterialManifestV1, type MaterialRecordV1, type MaterialSourceV1, type MaterialTransformV1, type MaterialManifest, type MaterialRecord, type MaterialRecordV2, type MaterialLibraryPayload } from "./material-library.js";
|
|
2
|
+
import { type ProceduralTextureSpecV2 } from "./procedural-material-v2.js";
|
|
3
3
|
import { type TextureResolver } from "./texture-resolver.js";
|
|
4
4
|
type MapDraftCommon = {
|
|
5
5
|
slot: MaterialLibrarySlot;
|
|
@@ -40,17 +40,43 @@ export declare function createMaterialRecordV1(draft: MaterialDraftV1): Promise<
|
|
|
40
40
|
/** Verify identity, normalized PNG contents, and the complete procedural recipe/output relation. */
|
|
41
41
|
export declare function verifyMaterialRecordV1(record: MaterialRecordV1): Promise<void>;
|
|
42
42
|
export declare function validateMaterialLibraryPayload(value: unknown): MaterialLibraryPayloadV1;
|
|
43
|
-
export declare function
|
|
44
|
-
export declare function decodeMaterialLibraryPayload(value: unknown): Promise<MaterialRecordV1[]>;
|
|
45
|
-
export declare function createMaterialLibraryTextureResolver(records: MaterialRecordV1[], fallback?: TextureResolver): Promise<TextureResolver>;
|
|
43
|
+
export declare function createMaterialLibraryTextureResolver(records: MaterialRecord[], fallback?: TextureResolver): Promise<TextureResolver>;
|
|
46
44
|
/** Files live under a trusted host root; every path component and map name is closed data. */
|
|
47
45
|
export declare class FileMaterialLibrary {
|
|
48
46
|
readonly root: string;
|
|
49
47
|
constructor(root: string);
|
|
50
48
|
private path;
|
|
51
49
|
private file;
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
50
|
+
readManifest(materialId: string, revisionId: string): Promise<MaterialManifest>;
|
|
51
|
+
/** Host-only file materialization after metadata admission; pixel/recipe verification is deferred. */
|
|
52
|
+
readRecordFiles(materialId: string, revisionId: string): Promise<MaterialRecord>;
|
|
53
|
+
read(materialId: string, revisionId: string): Promise<MaterialRecord>;
|
|
54
|
+
list(): Promise<MaterialManifest[]>;
|
|
55
|
+
import(records: MaterialRecord[], options?: {
|
|
56
|
+
materials?: readonly MaterialRecord[];
|
|
57
|
+
}): Promise<MaterialManifest[]>;
|
|
58
|
+
}
|
|
59
|
+
export declare function validateMaterialManifestIdentityAny(value: unknown): MaterialManifest;
|
|
60
|
+
export interface MaterialRecordClosureReader {
|
|
61
|
+
readManifest(materialId: string, revisionId: string): Promise<MaterialManifest>;
|
|
62
|
+
/** Return owned bytes after metadata admission; the walker verifies the complete closure. */
|
|
63
|
+
read(materialId: string, revisionId: string): Promise<MaterialRecord>;
|
|
55
64
|
}
|
|
65
|
+
export interface MaterialRecordClosureLimits {
|
|
66
|
+
maxRecords: number;
|
|
67
|
+
maxBytes: number;
|
|
68
|
+
maxPixels: number;
|
|
69
|
+
}
|
|
70
|
+
export declare function resolveMaterialRecordClosure(roots: readonly MaterialManifest[], reader: MaterialRecordClosureReader, limits?: MaterialRecordClosureLimits): Promise<MaterialRecord[]>;
|
|
71
|
+
/** Verify the complete immutable dependency closure; admission precedes byte snapshots and PNG decode. */
|
|
72
|
+
export declare function verifyMaterialRecord(record: MaterialRecord, options?: {
|
|
73
|
+
materials?: readonly MaterialRecord[];
|
|
74
|
+
}): Promise<void>;
|
|
75
|
+
export declare function validateMaterialLibraryPayloadAny(value: unknown): MaterialLibraryPayload;
|
|
76
|
+
export declare function createMaterialLibraryPayload(records: MaterialRecordV1[]): Promise<MaterialLibraryPayloadV1>;
|
|
77
|
+
export declare function createMaterialLibraryPayload(records: MaterialRecord[]): Promise<MaterialLibraryPayload>;
|
|
78
|
+
export declare function decodeMaterialLibraryPayload(value: unknown): Promise<MaterialRecord[]>;
|
|
79
|
+
export declare function createMaterialRecordV2(draft: unknown, options?: {
|
|
80
|
+
materials?: readonly MaterialRecord[];
|
|
81
|
+
}): Promise<MaterialRecordV2>;
|
|
56
82
|
export {};
|