@instruktlabs/kiln 1.2.1 → 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.
Files changed (219) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/CHANGELOG.md +86 -1
  4. package/README.md +18 -0
  5. package/dist/agent-run.mjs +6392 -1477
  6. package/dist/build.json +23 -23
  7. package/dist/cli.mjs +8453 -3407
  8. package/dist/evaluator-worker.mjs +16608 -12387
  9. package/dist/mcp-engine.mjs +6746 -1725
  10. package/dist/mcp-server.mjs +4 -4
  11. package/dist/viewer/app.js +203 -199
  12. package/dist/viewer/chat.html +209 -205
  13. package/dist/viewer/style.css +10 -0
  14. package/docs/atlas-provenance.md +23 -0
  15. package/docs/community-exporter.md +27 -0
  16. package/docs/export-profiles.md +20 -0
  17. package/docs/install.md +7 -6
  18. package/docs/material-library.md +9 -5
  19. package/docs/migration.md +16 -0
  20. package/docs/procedural-surfaces-v3.md +276 -0
  21. package/docs/projects-and-live-review.md +1 -1
  22. package/docs/rendering.md +41 -0
  23. package/docs/runtime.md +3 -3
  24. package/docs/sdk.md +55 -2
  25. package/docs/tools-operations.md +2 -2
  26. package/docs/tools.md +3 -3
  27. package/lib/asset-materials-node.d.ts +3 -3
  28. package/lib/asset-materials-node.js +29 -33
  29. package/lib/assets-node.d.ts +1 -1
  30. package/lib/assets-node.js +11 -4
  31. package/lib/assets.d.ts +4 -2
  32. package/lib/assets.js +61 -16
  33. package/lib/atlas-provenance.d.ts +86 -0
  34. package/lib/atlas-provenance.js +448 -0
  35. package/lib/character.d.ts +11 -2
  36. package/lib/character.js +90 -2
  37. package/lib/community-exporter.d.ts +3 -2
  38. package/lib/community-exporter.js +139 -3
  39. package/lib/discovery/helper-contracts.js +161 -7
  40. package/lib/discovery/helper-specs.js +49 -4
  41. package/lib/discovery/shapes.js +20 -7
  42. package/lib/engine-identity.d.ts +1 -1
  43. package/lib/engine-identity.js +1 -1
  44. package/lib/evaluator/authoring-diagnostic.d.ts +1 -1
  45. package/lib/evaluator/authoring-diagnostic.js +12 -0
  46. package/lib/evaluator/protocol.d.ts +2 -2
  47. package/lib/evaluator/protocol.js +16 -6
  48. package/lib/evaluator/subprocess.js +2 -2
  49. package/lib/exporter-node.js +9 -1
  50. package/lib/geometry-budget.d.ts +7 -0
  51. package/lib/geometry-budget.js +8 -0
  52. package/lib/gltf-texture-binding.d.ts +6 -0
  53. package/lib/gltf-texture-binding.js +54 -0
  54. package/lib/material-authoring-node.d.ts +6 -0
  55. package/lib/material-authoring-node.js +49 -0
  56. package/lib/material-authoring-schema.d.ts +871 -0
  57. package/lib/material-authoring-schema.js +310 -0
  58. package/lib/material-export.d.ts +5 -0
  59. package/lib/material-export.js +21 -0
  60. package/lib/material-library-node.d.ts +34 -8
  61. package/lib/material-library-node.js +691 -11
  62. package/lib/material-library.d.ts +3704 -4
  63. package/lib/material-library.js +272 -0
  64. package/lib/mcp-core.d.ts +1 -1
  65. package/lib/pinned-material-map.d.ts +33 -0
  66. package/lib/pinned-material-map.js +1 -0
  67. package/lib/portable-material-runtime.d.ts +5 -0
  68. package/lib/portable-material-runtime.js +160 -0
  69. package/lib/portable-sampler-runtime.d.ts +4 -0
  70. package/lib/portable-sampler-runtime.js +26 -0
  71. package/lib/portable-sampler.d.ts +11 -0
  72. package/lib/portable-sampler.js +42 -0
  73. package/lib/primitives.d.ts +15 -3
  74. package/lib/primitives.js +24 -4
  75. package/lib/procedural-material-v2.d.ts +2 -0
  76. package/lib/procedural-material-v2.js +2 -1
  77. package/lib/procedural-material-v3.d.ts +72 -0
  78. package/lib/procedural-material-v3.js +162 -0
  79. package/lib/procedural-texture-v2-compiler.d.ts +31 -0
  80. package/lib/procedural-texture-v2-compiler.js +172 -0
  81. package/lib/procedural-texture-v3-contract.d.ts +125 -0
  82. package/lib/procedural-texture-v3-contract.js +333 -0
  83. package/lib/procedural-texture-v3.d.ts +12 -0
  84. package/lib/procedural-texture-v3.js +165 -0
  85. package/lib/procedural-texture.d.ts +9 -31
  86. package/lib/procedural-texture.js +43 -170
  87. package/lib/project-bundle-node.d.ts +1 -1
  88. package/lib/project-bundle-node.js +70 -13
  89. package/lib/project-bundle.d.ts +91 -3
  90. package/lib/project-bundle.js +48 -7
  91. package/lib/qa/atlas.d.ts +21 -0
  92. package/lib/qa/atlas.js +474 -0
  93. package/lib/qa/index.d.ts +1 -0
  94. package/lib/qa/index.js +1 -0
  95. package/lib/qa/material.js +2 -0
  96. package/lib/qa/skin-integrity.d.ts +18 -0
  97. package/lib/qa/skin-integrity.js +221 -0
  98. package/lib/render-service-host.js +4 -7
  99. package/lib/render.d.ts +3 -3
  100. package/lib/render.js +108 -16
  101. package/lib/skin-binding.d.ts +20 -0
  102. package/lib/skin-binding.js +144 -0
  103. package/lib/texture-atlas-contract.d.ts +97 -0
  104. package/lib/texture-atlas-contract.js +414 -0
  105. package/lib/texture-atlas-pixels.d.ts +73 -0
  106. package/lib/texture-atlas-pixels.js +290 -0
  107. package/lib/texture-atlas.d.ts +10 -0
  108. package/lib/texture-atlas.js +143 -0
  109. package/lib/texture-bake.d.ts +3 -0
  110. package/lib/texture-bake.js +66 -11
  111. package/lib/texture-resolver.d.ts +22 -0
  112. package/lib/texture-resolver.js +24 -0
  113. package/lib/tools/materials.js +8 -7
  114. package/lib/tools/registry.js +5 -16
  115. package/lib/tools/review.js +1 -1
  116. package/lib/uv-data.d.ts +32 -0
  117. package/lib/uv-data.js +172 -0
  118. package/lib/uv-shapes.js +3 -0
  119. package/lib/uv.d.ts +9 -3
  120. package/lib/uv.js +53 -82
  121. package/lib/views/camera.d.ts +3 -3
  122. package/lib/views/camera.js +32 -28
  123. package/lib/views/face-policy.d.ts +9 -0
  124. package/lib/views/face-policy.js +16 -0
  125. package/lib/views/glb.js +218 -24
  126. package/lib/views/pose.d.ts +7 -1
  127. package/lib/views/pose.js +63 -12
  128. package/lib/views/raster.d.ts +6 -2
  129. package/lib/views/raster.js +49 -37
  130. package/lib/views/scene-copy.d.ts +6 -0
  131. package/lib/views/scene-copy.js +73 -0
  132. package/lib/views/scene-raster.js +2 -1
  133. package/lib/views/triangle-coverage.d.ts +8 -0
  134. package/lib/views/triangle-coverage.js +58 -0
  135. package/lib/workspace-node.js +7 -3
  136. package/lib/workspace.d.ts +2 -2
  137. package/package.json +3 -1
  138. package/plugin.json +1 -1
  139. package/plugins/kiln-engine/.claude-plugin/plugin.json +1 -1
  140. package/plugins/kiln-engine/README.md +3 -3
  141. package/plugins/kiln-engine/package-provenance.json +6 -6
  142. package/plugins/kiln-engine/plugin.json +1 -1
  143. package/plugins/kiln-engine/runtime.json +1 -1
  144. package/skills/kiln-author-asset/SKILL.md +1 -1
  145. package/skills/kiln-author-asset/references/camera-cli.md +13 -0
  146. package/skills/kiln-author-asset/references/geometry-recipes.md +134 -0
  147. package/skills/kiln-author-asset/references/projects-and-materials.md +32 -2
  148. package/skills/kiln-compose-scene/references/runtime-scenes.md +19 -0
  149. package/skills/kiln-qa-asset/references/integration-checks.md +37 -2
  150. package/src/asset-materials-node.ts +38 -45
  151. package/src/assets-node.ts +22 -5
  152. package/src/assets.ts +61 -20
  153. package/src/atlas-provenance.ts +522 -0
  154. package/src/character.ts +107 -2
  155. package/src/community-exporter.ts +143 -3
  156. package/src/discovery/helper-contracts.ts +188 -7
  157. package/src/discovery/helper-specs.ts +69 -4
  158. package/src/discovery/shapes.ts +25 -9
  159. package/src/engine-identity.ts +1 -1
  160. package/src/evaluator/authoring-diagnostic.ts +19 -1
  161. package/src/evaluator/protocol.ts +19 -9
  162. package/src/evaluator/subprocess.ts +2 -2
  163. package/src/exporter-node.ts +12 -1
  164. package/src/generated/mcp-manifest.json +3 -3
  165. package/src/geometry-budget.ts +8 -0
  166. package/src/gltf-texture-binding.ts +60 -0
  167. package/src/material-authoring-node.ts +68 -0
  168. package/src/material-authoring-schema.ts +343 -0
  169. package/src/material-export.ts +25 -0
  170. package/src/material-library-node.ts +840 -16
  171. package/src/material-library.ts +348 -5
  172. package/src/pinned-material-map.ts +43 -0
  173. package/src/portable-material-runtime.ts +200 -0
  174. package/src/portable-sampler-runtime.ts +40 -0
  175. package/src/portable-sampler.ts +54 -0
  176. package/src/primitives.ts +98 -4
  177. package/src/procedural-material-v2.ts +2 -1
  178. package/src/procedural-material-v3.ts +224 -0
  179. package/src/procedural-texture-v2-compiler.ts +234 -0
  180. package/src/procedural-texture-v3-contract.ts +437 -0
  181. package/src/procedural-texture-v3.ts +220 -0
  182. package/src/procedural-texture.ts +61 -229
  183. package/src/project-bundle-node.ts +106 -14
  184. package/src/project-bundle.ts +61 -18
  185. package/src/project-cli.ts +29 -17
  186. package/src/qa/atlas.ts +597 -0
  187. package/src/qa/index.ts +1 -0
  188. package/src/qa/material.ts +2 -0
  189. package/src/qa/skin-integrity.ts +291 -0
  190. package/src/render-service-host.ts +4 -6
  191. package/src/render.ts +133 -15
  192. package/src/skin-binding.ts +225 -0
  193. package/src/texture-atlas-contract.ts +558 -0
  194. package/src/texture-atlas-pixels.ts +456 -0
  195. package/src/texture-atlas.ts +185 -0
  196. package/src/texture-bake.ts +88 -10
  197. package/src/texture-resolver.ts +55 -0
  198. package/src/tools/materials.ts +15 -11
  199. package/src/tools/registry.ts +5 -15
  200. package/src/tools/review.ts +1 -1
  201. package/src/uv-data.ts +238 -0
  202. package/src/uv-shapes.ts +3 -0
  203. package/src/uv.ts +73 -128
  204. package/src/viewer/app.ts +37 -0
  205. package/src/viewer/live-panel.ts +57 -1
  206. package/src/viewer/material-preview-panel.ts +140 -0
  207. package/src/viewer/material-preview.ts +138 -0
  208. package/src/viewer/materials-panel.ts +34 -5
  209. package/src/viewer/navigation.ts +2 -0
  210. package/src/views/camera.ts +37 -40
  211. package/src/views/face-policy.ts +20 -0
  212. package/src/views/glb.ts +294 -17
  213. package/src/views/pose.ts +71 -13
  214. package/src/views/raster.ts +73 -46
  215. package/src/views/scene-copy.ts +86 -0
  216. package/src/views/scene-raster.ts +2 -1
  217. package/src/views/triangle-coverage.ts +78 -0
  218. package/src/workspace-node.ts +11 -3
  219. package/src/workspace.ts +2 -2
@@ -49,3 +49,13 @@ main{grid-template-columns:216px minmax(0,1fr);min-height:calc(100vh - 80px)}
49
49
  @media(max-width:800px){header{height:70px;padding:0 18px}main{display:block}.workspace-sidebar{height:auto;position:static;padding:12px 15px}#workspace-nav{display:flex;gap:5px}#workspace-nav button{white-space:nowrap;font-size:12px;flex:1;justify-content:center;padding:11px 7px}#workspace-nav button span{display:none}#collections{padding-top:6px}#collections:empty{padding:0}.workspace-panel{padding:25px 18px}.workspace-panel h1{font-size:31px}.project-layout{grid-template-columns:1fr;margin-top:23px}.project-list{display:flex;overflow:auto}.project-list button{min-width:180px}.review-layout{grid-template-columns:1fr}.timeline{display:flex;max-height:190px}.timeline-item{min-width:220px;max-width:260px}.timeline .empty{padding:18px}.panel-title{padding:12px 17px}.profile-grid{grid-template-columns:1fr}.review-viewports.comparing{grid-template-columns:1fr}.heading{gap:15px}.heading>button{font-size:12px;white-space:nowrap}.live-toolbar{align-items:flex-start}.live-toolbar .inline-field{flex-direction:column;align-items:flex-start}.local-dot{display:none}.live-stage{height:380px}}
50
50
  /* Manual LOD review: whole-asset shortcuts plus independent part choices. */
51
51
  .lod-controls{margin:12px 0;font-size:12px}.lod-total{margin:8px 0;color:var(--ink)}.lod-parts{padding:10px 12px;border:1px solid var(--line);border-radius:8px}.lod-parts summary{cursor:pointer;font-weight:600}.lod-parts .subtle{line-height:1.5}.lod-part-fields{display:grid;gap:10px;max-height:280px;overflow:auto;padding:4px 2px}.lod-part-fields .inline-field{justify-content:space-between;flex-wrap:wrap}.lod-part-fields select{max-width:100%}.comparison-lod{padding:12px 16px}.comparison-lod:has(.inline-field[hidden]){display:none}
52
+ .material-card[data-selected-material="true"]{border-color:var(--accent)}
53
+ .material-map{object-fit:contain;image-rendering:pixelated}
54
+ .material-map-inspection{margin:14px 0}.material-inspection{min-width:0;overflow-wrap:anywhere}
55
+ .material-inspection-controls{display:flex;gap:10px;flex-wrap:wrap;margin:14px 0}.material-inspection-controls .inline-field{flex-direction:column;align-items:flex-start}.material-inspection-controls select{max-width:100%;font-size:11px;padding:7px}
56
+ .material-pixel-frame{max-height:360px;overflow:auto;border:1px solid var(--line);border-radius:5px;background:#202020}
57
+ .material-pixel-frame[data-backdrop="checker"]{background-color:#d0d0d0;background-image:conic-gradient(#7a7a7a 25%,#d0d0d0 0 50%,#7a7a7a 0 75%,#d0d0d0 0);background-size:16px 16px}
58
+ .material-pixel-frame[data-backdrop="light"]{background:#f2f2f2}.material-pixel-frame[data-backdrop="dark"]{background:#151515}
59
+ .material-pixel-sheet{position:relative;flex:none;min-width:0}.material-pixel-image{display:block!important;width:100%!important;height:100%!important;max-height:none!important;object-fit:fill!important;image-rendering:pixelated;border-radius:0!important}
60
+ .material-region-overlay{position:absolute;inset:0;pointer-events:none}.material-region-box{position:absolute;border:1px solid #ffce37;overflow:visible}.material-region-box>span{position:absolute;left:0;top:0;font-size:10px;line-height:1.2;background:#151515df;color:#ffefaf;white-space:nowrap;max-width:200px;overflow:hidden;text-overflow:ellipsis}.material-region-box.selected{border:2px solid #fff;box-shadow:0 0 0 2px #111}.material-region-list{display:grid;gap:6px;margin:12px 0}.material-region-list h4{font-size:11px;margin:5px 0}.material-region-list button{text-align:left;font-size:10px;padding:7px;overflow-wrap:anywhere}.material-region-list button[aria-pressed="true"]{border-color:var(--accent)}
61
+ .material-inspection dl{font-size:11px}.material-inspection dt{color:var(--dim);margin-top:7px}.material-inspection dd{margin:0}.live-material-inspection{grid-column:1/-1}.live-material-inspection details{margin-top:12px}.asset-material-inputs{font-size:11px;margin:15px 0}.asset-material-inputs h3{font-size:12px}.asset-material-inputs a{color:var(--accent)}
@@ -0,0 +1,23 @@
1
+ # Atlas provenance in delivered GLBs
2
+
3
+ `src/atlas-provenance.ts` is the internal owner of atlas metadata validation. It uses the existing atlas canonicalizer and manifest validator. It has no Node dependency and its live-scene readers are available to image-free structural QA. These internal helpers are not SDK authoring APIs.
4
+
5
+ The default glTF scene owns `extras.kilnAtlasProvenance`:
6
+
7
+ ```json
8
+ {"version":"kiln.atlas-provenance.v1","atlases":[{"id":"sha256:<manifest hash>","spec":{},"manifest":{}}]}
9
+ ```
10
+
11
+ Each entry contains one complete canonical recipe and validated manifest. Entries deduplicate by exact manifest identity, with a content conflict check. Recipes are never repeated per mesh. Editable source and saved material records remain the authoring owners.
12
+
13
+ Each material-slot `TextureInfo` owns `extras.kilnAtlasReference` with `version`, `id`, `effectiveSampler` (`minFilter`, `magFilter`, `wrapS`, `wrapT` as glTF values), `finalMime`, and `finalImageSha256`. Source collection creates only the version/id pair; final export fills actual sampler and encoded-image identities. The reference belongs to a texture use because one image can serve multiple samplers. glTF Transform preserves TextureInfo extras and does not preserve extras on glTF texture binding objects. Image extras would incorrectly conflate those uses.
14
+
15
+ A primitive using a named remap owns `extras.kilnAtlasBinding`: `version`, `atlasId`, `region`, `inputOrigin`, and `mode`. Export checks the complete source geometry stamp against the primary atlas, including hashes, rectangles, scale and offset. Reimport derives that full geometry stamp from the validated manifest and compact binding. A geometry-wide binding requires its exact primary atlas among the primitive material slots. Companion color/data maps may have different manifest hashes with the same region layout. Manual full-sheet atlas use carries texture references without an inferred named binding. Ordinary textures carry no atlas metadata.
16
+
17
+ Admission allows 128 unique identities, at most 256 KiB per JSON entry, a 4 MiB aggregate table including its envelope/separators, and 1,024 source binding observations. Exported documents independently bound slot references and primitive bindings to 1,024 each. Source graph admission precedes manifest cloning and scene export copies. Distinct atlas texture objects conservatively charge their full RGBA output toward a 64 MiB bake decoded-pixel budget. Encoded-image hashing admits at most 16 MiB per image and 64 MiB in aggregate before hashing. These are metadata/buffer-work bounds, not an operating-system or native codec RSS guarantee. Existing scene traversal remains proportional to the scene.
18
+
19
+ Before first PNG encoding, baking verifies raw RGBA dimensions and SHA-256 against the compiled manifest. Already encoded source maps receive bounded PNG dimension/decode verification. Editing pixels while retaining an atlas stamp fails with a stale-provenance diagnostic. A validated GLB loader establishes a private WeakMap identity for exporter-derived delivery bytes; authored flags cannot establish this identity. Re-export checks those exact bytes against the validated delivery reference rather than comparing legitimate converted normal pixels to the original compiler pixels. The source recipe/pixel identity and final encoded-image identity remain separate. No GLB contains its own final artifact hash; that hash remains in external baked provenance.
20
+
21
+ Both exporters write the same table, references and compact bindings. The optimizer validates input lineage and refreshes the final image identities after its transforms. Composition admits and merges the tables before copying source graphs and deleting their scenes. Import validates final bytes and samplers, never repairs a tampered reference. External transforms that rewrite images must update delivery references through the validated engine export path; retaining old image hashes makes the transformed artifact fail import validation.
22
+
23
+ Structural metadata proves identities, named selectors and remap formulas. It does not prove an author's intended corner orientation after arbitrary within-domain UV edits, visual quality, or inferred physical density. Generic author `kiln*` userData remains excluded; only this owner's validated engine metadata is explicitly promoted.
@@ -57,6 +57,28 @@ partitions are rejected by the shared preflight. Private `userData` is excluded;
57
57
  semantic extras and bounded review clips retain their existing policy. Export copies keep caller
58
58
  texture sources and skeleton references intact.
59
59
 
60
+ Both converters preserve standard magnification/minification filters and S/T wrap
61
+ modes on supported texture bindings, including different samplers sharing image
62
+ bytes. Kiln's loader and procedural texture defaults remain repeat wrapping,
63
+ linear magnification and trilinear minification. The default converter now writes
64
+ these choices explicitly; regenerated GLBs can therefore have different bytes
65
+ and material fingerprints from older exports. Existing saved revisions are
66
+ unchanged. Mipmap generation itself is a consumer policy, not a glTF sampler flag.
67
+
68
+ Already encoded PNG/JPEG images on direct, unflipped texture bindings retain their
69
+ original bytes. This matters for cutout RGB padding under zero alpha and for exact
70
+ partial-alpha color: canvas conversion can erase or round those channels. Derived
71
+ channel maps and explicitly flipped images still require conversion. Raw byte maps
72
+ used for metallic/roughness packing or normal-channel inversion are adapted on the
73
+ export copy; caller images and texture references remain unchanged. For cutout atlas
74
+ delivery, keep the canonical image orientation with `flipY: false`; pixel-exact
75
+ transparent RGB through a requested vertical image flip is not qualified.
76
+
77
+ If the optional native canvas binding cannot load, textured headless export reports
78
+ the dependency and recovery steps. Reinstall with optional dependencies enabled and
79
+ check the binding in the same Node runtime and platform as the Kiln host. It does not
80
+ silently switch converters. Flat-material exports do not require that binding.
81
+
60
82
  This describes serialization capability. It does not automatically extend all authoring helpers,
61
83
  QA rules, preview materials or optimization algorithms. In particular, skin/morph deformation,
62
84
  complex texture transforms, material extensions in every review path, and runtime codec support
@@ -65,6 +87,11 @@ converter rather than bypassing the triangle pipeline's metadata and geometry po
65
87
 
66
88
  ## Qualify a consumer
67
89
 
90
+ Both converters reject used `BackSide` materials because glTF has no back-only
91
+ material flag. See the [portable sidedness contract](export-profiles.md#material-sidedness-at-export)
92
+ for explicit inward geometry and deliberate two-sided sheets. This prevents silent
93
+ front-face substitution; it does not change the default exporter or existing GLBs.
94
+
68
95
  Keep a canonical GLB and name the actual engine, importer, version and render pipeline in results.
69
96
  For example, Unity 6 Built-in RP with glTFast is a different target from Unity URP or an FBX workflow.
70
97
  Tests should check hierarchy, world-space positions, part names, material assignments, texture pixels,
@@ -44,6 +44,26 @@ unsupported UV transforms and destination feature support still need qualificati
44
44
  Neither setting automatically enables mesh merging, geometry simplification, Draco,
45
45
  Meshopt or KTX2 compression. Those require separate choices and validation.
46
46
 
47
+ ## Material sidedness at export
48
+
49
+ glTF represents front-only or double-sided surfaces. Both Kiln converters preserve
50
+ `FrontSide` and `DoubleSide`. A used `BackSide` material now stops a source build
51
+ with `EXPORT_MATERIAL_SIDE_UNSUPPORTED`. The direct scene API names the part and
52
+ material; CLI/MCP carry closed repair advice without authored identifiers across
53
+ the evaluator boundary. Use `kiln_source` with query `BackSide` to locate the
54
+ authored material. This applies
55
+ in both `warn` and `strict` geometry modes and before texture baking or conversion;
56
+ unused material-array slots do not block export. Existing saved GLBs remain readable
57
+ and exporting their exact bytes does not rebuild them.
58
+
59
+ For a one-sided interior surface, author triangles facing inward and use
60
+ `FrontSide`. For a leaf or other deliberate sheet visible from either side, use
61
+ `DoubleSide`. Neither choice supplies thickness or missing caps. Do not flip only
62
+ normals to repair winding. Automatic back-only conversion is not provided: winding,
63
+ normal/tangent basis, groups, shared geometry and deformation data must remain
64
+ consistent. A destination shader override is an explicit runtime choice, separate
65
+ from the portable asset.
66
+
47
67
  ## CLI
48
68
 
49
69
  From an asset workspace, using the IDs returned by `save` or `assets`:
package/docs/install.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Install Kiln for your coding agent
2
2
 
3
- This guide describes **Kiln 1.1** under the package name `@instruktlabs/kiln`.
3
+ This guide covers the stable `@instruktlabs/kiln` package. Feature-specific
4
+ minimum versions are noted where they matter.
4
5
  Use a version available in the [npm registry](https://www.npmjs.com/package/@instruktlabs/kiln),
5
6
  or build a [local package](#install-a-local-package) to test an unpublished checkout.
6
7
  [CHANGELOG.md](../CHANGELOG.md) lists changes; read the
@@ -154,7 +155,7 @@ For agent-assisted installation, give your agent the repository URL and ask:
154
155
 
155
156
  ## Release compatibility
156
157
 
157
- The current candidate's connected MCP server lists the fourteen tools in the
158
+ The packaged local MCP server lists the fourteen base tools in the
158
159
  [generated tool reference](tools.md), plus `kiln_project`, `kiln_material` and
159
160
  `kiln_review` from the packaged local host: seventeen in all. When installing an
160
161
  older release, use the documentation and receipt attached to that release; newer
@@ -163,7 +164,7 @@ tools and migration changes are not retroactively available there.
163
164
  Package publication requires per-platform receipts (Linux, Windows, macOS arm64,
164
165
  macOS x64) and `SHA256SUMS.txt` for the exact tarball. Check the artifacts actually
165
166
  attached to the selected release; do not treat an older receipt or a source archive
166
- as qualification of the current candidate.
167
+ as qualification of a different package version.
167
168
 
168
169
  A successful local build or an unreleased fix does not update the GitHub release: a
169
170
  checkout can be ahead of it. Registry and GitHub release receipts each identify the
@@ -483,7 +484,7 @@ The v1 local plugin below uses a smaller bundle and creates an explicit workspac
483
484
 
484
485
  ## Local Claude Code and Codex plugins
485
486
 
486
- The commands below select the 1.1.0 plugin, which supports new workspaces and
487
+ The commands below select the 1.2.1 plugin, which supports new workspaces and
487
488
  existing-project adoption. Use them once the matching GitHub tag and npm version
488
489
  are available. To qualify an unpublished candidate, select its exact source ref
489
490
  and supply the matching local engine archive as described in its bundled setup
@@ -498,14 +499,14 @@ does not start a second global Kiln MCP server.
498
499
  For Claude Code:
499
500
 
500
501
  ```sh
501
- claude plugin marketplace add instruktlabs/kiln#v1.1.0 --sparse .claude-plugin plugins/kiln-engine
502
+ claude plugin marketplace add instruktlabs/kiln#v1.2.1 --sparse .claude-plugin plugins/kiln-engine
502
503
  claude plugin install kiln-engine@instruktlabs
503
504
  ```
504
505
 
505
506
  For Codex:
506
507
 
507
508
  ```sh
508
- codex plugin marketplace add instruktlabs/kiln --ref v1.1.0 --sparse .agents/plugins --sparse plugins/kiln-engine
509
+ codex plugin marketplace add instruktlabs/kiln --ref v1.2.1 --sparse .agents/plugins --sparse plugins/kiln-engine
509
510
  codex plugin add kiln-engine@instruktlabs
510
511
  ```
511
512
 
@@ -35,8 +35,9 @@ node kiln.mjs material get RETURNED_MATERIAL_ID RETURNED_REVISION
35
35
  node kiln.mjs material export RETURNED_MATERIAL_ID RETURNED_REVISION --out wood-payload.json
36
36
  ```
37
37
 
38
- Copy the returned `portableSpec` into authored source and use
39
- `compilePortableMaterialSpecV2(portableSpec)` with the exact dependency pin.
38
+ Copy the returned `portableSpec` into authored source with the exact dependency
39
+ pin. Use `compilePortableMaterialSpecV2` for `portableSpec.schemaVersion === 2`
40
+ and `compilePortableMaterialSpecV3` for version 3. Existing presets return V2.
40
41
  Custom draft creation uses CLI `material procedural --file draft.json`, corresponding
41
42
  to MCP `create-procedural`. These paths need no imports from internal `dist/` files
42
43
  or extra TypeScript loader. The public host APIs below are for a configured TypeScript
@@ -44,7 +45,10 @@ toolchain; ordinary Node cannot directly execute TypeScript inside `node_modules
44
45
 
45
46
  `list` returns compact summaries and accepts a `tag`. `get` requires `materialId` and `revisionId`
46
47
  and returns provenance plus a code-ready `portableSpec`. `create-procedural` accepts an editable
47
- draft using the same bounded layer recipes as the existing procedural compiler. An optional
48
+ draft using the same bounded layer recipes as the existing procedural compiler. Opt-in
49
+ drafts with `schemaVersion:2` also support RGBA recipes, named atlases and explicit
50
+ per-map samplers; see the [standalone texture workflow](procedural-surfaces-v3.md#standalone-saved-materials-and-atlases).
51
+ An optional
48
52
  `derive: {"kind":"normal-from-height","strength":2}` on a normal map converts the recipe's
49
53
  height pixels through the existing wrapped normal derivation. `import` accepts a complete
50
54
  normalized payload. None of these operations acquires source images from a provider.
@@ -66,8 +70,8 @@ Pin the returned material ID and revision hash before using its resource IDs. A
66
70
  optional: pass a pin array as MCP `materialDependencies` or CLI `--materials pins.json` for
67
71
  an individual operation, or put the array in a project's `materialDependencies` for shared use.
68
72
  The pin's `resourceId` is the material ID; its `revisionId` and `sha256` both equal the
69
- manifest's immutable `revisionId`. `compilePortableMaterialSpecV2(portableSpec)` then creates the
70
- material inside authored source. The host supplies complete map bytes through `materialResources`
73
+ manifest's immutable `revisionId`. The compiler matching `portableSpec.schemaVersion`
74
+ creates the material inside authored source. The host supplies complete map bytes through `materialResources`
71
75
  before build-cache lookup, including when evaluation uses the default subprocess.
72
76
 
73
77
  Editable standalone asset ZIPs carry the saved dependency closure in `materials.kiln.json`;
package/docs/migration.md CHANGED
@@ -4,6 +4,22 @@ Existing inline-code transport and the legacy capture format remain supported. T
4
4
  Discovery and authoring-helper changes below require explicit migration; retired
5
5
  names have no callable compatibility aliases.
6
6
 
7
+ ## Changes in 1.2
8
+
9
+ Version 1.2.0 adds an opt-in named-operation presentation derived from the shared
10
+ tool registry. The default local MCP interface retains its seventeen tools;
11
+ ordinary local callers need no migration. Embedding hosts can adopt the
12
+ [named-operation presentation](sdk.md#named-operation-presentation), including
13
+ consolidated asset search and material operations. Host capabilities determine
14
+ which tools are available; do not maintain a separate schema copy.
15
+
16
+ Version 1.2.1 fixes embedded texture loading in the shared presentation viewer
17
+ under restrictive MCP Apps content security policies, reports failed texture
18
+ decoding, and advances the widget resource URI to refresh cached components.
19
+ Upgrade the installed package and rebuild embedding hosts to use those fixes.
20
+ No tool-count change or saved-asset migration is required. Package publication
21
+ does not establish that a particular hosted deployment has been upgraded.
22
+
7
23
  ## Changes in 1.1
8
24
 
9
25
  Version 1.1 adds existing-project setup
@@ -0,0 +1,276 @@
1
+ # Procedural RGBA surfaces V3
2
+
3
+ `proceduralTexture({ schemaVersion: 3, ... })` creates rectangular RGBA pixels
4
+ through the same authored-source helper as V1/V2. The standalone compiler is
5
+ `compileProceduralTextureSpecV3` from the primitives SDK. Its contract helpers
6
+ are `canonicalizeProceduralTextureSpecV3`, `canonicalProceduralTextureJsonV3`
7
+ and `hashProceduralTextureSpecV3`.
8
+
9
+ V1 (absent or `1` version) and V2 remain on their existing compiler, square
10
+ power-of-two dimensions, opaque output, canonical JSON and hashes. An explicitly
11
+ undefined version retains historical V1 behavior; V3 itself accepts strict JSON,
12
+ so undefined fields are invalid. Unknown versions fail before dispatch. Existing
13
+ portable material V2 references remain V2. New portable V3 material references
14
+ and V2 saved material records are opt-in contracts described below.
15
+
16
+ ## Contract
17
+
18
+ ```ts
19
+ {
20
+ schemaVersion: 3,
21
+ width: 4..1024, height: 4..1024, // integers, need not be powers of two
22
+ usage?: 'albedo' | 'emissive' | 'normal' | 'roughness' | 'metalness'
23
+ | 'metallicRoughness' | 'occlusion', // default albedo
24
+ name?: string, // 1..80 visible characters
25
+ background?: [r,g,b,a], // bytes 0..255, default [0,0,0,0]
26
+ operations: OperationV3[], // ordered, zero to 64 entries
27
+ palette?: { colors: RGB[], dither?: 'none' | 'bayer4' }
28
+ }
29
+ ```
30
+
31
+ RGBA channels are straight bytes. RGB is authored encoded color for albedo and
32
+ emissive; other usages retain linear data. Transparent RGBA input canonicalizes
33
+ to `[0,0,0,0]`, and every output pixel with zero alpha has zero RGB. Palette
34
+ mapping and stamps support only albedo/emissive; they reject all data usages.
35
+ Shapes and masks operate on declared bytes without interpreting data channels.
36
+
37
+ Operations have these exact fields:
38
+
39
+ | `op` | Fields |
40
+ | --- | --- |
41
+ | `paint` | `shape`, `rgba`, optional byte `opacity` (default 255) |
42
+ | `mask` | `shape`, optional byte `alpha` (default 255), optional boolean `invert` (default false) |
43
+ | `stamps` | `shape`, `rgba`, `count`, uint32 `seed`, `area`, optional byte `opacity`, optional boolean `periodic` (default false) |
44
+ | `legacy-v2` | `spec` with explicit schemaVersion 2, optional byte `alpha` and byte `opacity` (both default 255) |
45
+
46
+ V3 opacity is a byte, unlike V2's fractional opacity. The legacy layer delegates
47
+ to the existing V2 compiler, including its six operators and first-layer rules.
48
+ Its square size and usage must match the V3 surface; its output RGB is composited
49
+ using the explicitly selected V3 alpha and opacity. It does not reinterpret V2
50
+ blend modes or silently migrate a V2 recipe into V3 operations.
51
+
52
+ ## Coverage and compositing
53
+
54
+ Coordinates describe integer pixel edges; a pixel `(x,y)` samples `(x+0.5,y+0.5)`.
55
+ Shapes clip to the output extent. There is no antialiasing or fractional shape
56
+ coverage in this compiler version.
57
+
58
+ | Shape `kind` | Fields and coverage |
59
+ | --- | --- |
60
+ | `rectangle` | `x,y,width,height`; left/top inclusive, right/bottom exclusive |
61
+ | `ellipse` | `x,y,width,height`; inscribed ellipse, boundary inclusive |
62
+ | `polygon` | `points:[[x,y],...]`; even-odd fill, boundary inclusive, 3..64 vertices; self-intersections use that same fill rule |
63
+ | `line` | `from:[x,y],to:[x,y],width`; capsule with inclusive round caps; coincident endpoints create a disk |
64
+
65
+ Coordinates are integers -4096..4096. Shape widths/heights and line width are
66
+ integers 1..2048. A one-pixel line on an integer edge can cover centers on both
67
+ sides of the edge; width measures continuous distance, not a promised count of
68
+ covered columns. Polygon degeneracies are deterministic rather than repaired.
69
+
70
+ `paint` uses source-over. Define `round(n/d) = floor(n/d + 0.5)`. For source alpha
71
+ `a`, operation opacity `o` and destination alpha `d`:
72
+
73
+ ```text
74
+ s = round(a * o / 255)
75
+ N = s * 255 + d * (255 - s)
76
+ output alpha = round(N / 255)
77
+ output channel = round((source channel * s * 255
78
+ + destination channel * d * (255 - s)) / N)
79
+ ```
80
+
81
+ When `s=0`, painting is inert. RGB division uses the unrounded alpha numerator,
82
+ then alpha and RGB are stored as bytes after each operation. This blends authored
83
+ byte values; it does not linearize encoded colors or introduce floating opacity.
84
+
85
+ `mask` multiplies destination alpha by the mask byte and rounds half-up. Outside
86
+ the covered shape it clears alpha. With `invert:true`, outside retains the mask
87
+ alpha factor and inside clears alpha. It preserves destination RGB while alpha
88
+ remains positive and clears RGB when alpha becomes zero. A mask affects only
89
+ pixels already painted; subsequent paint can add pixels again.
90
+
91
+ ## Palettes and periodic stamps
92
+
93
+ Palette mapping runs once after all operations. `colors` is an ordered array of
94
+ 1..32 RGB integers 0..0xffffff. The nearest color minimizes squared distance in
95
+ encoded RGB bytes; a tie selects the first array entry. Alpha is preserved and
96
+ transparent pixels stay black. `dither:'none'` is the default.
97
+
98
+ `bayer4` repeats this fixed matrix from image origin `(0,0)`:
99
+
100
+ ```text
101
+ 0 8 2 10
102
+ 12 4 14 6
103
+ 3 11 1 9
104
+ 15 7 13 5
105
+ ```
106
+
107
+ Before nearest-color selection, each RGB channel receives integer offset
108
+ `(2 * matrixEntry - 15) * 2`, clipped to 0..255. Palette membership is therefore
109
+ exact, and dither does not add alpha variation or random noise.
110
+
111
+ Stamp `area` is `{x,y,width,height}`, with the same rectangle coordinate bounds.
112
+ Each stamp translates its local shape by two integer offsets within that area.
113
+ The PRNG starts from `(seed ^ 0xa3c59ac3) >>> 0`, substitutes fixed state
114
+ `0x6d2b79f5` if that value is zero, performs Xorshift32 with shifts 13,17,5,
115
+ and consumes X then Y in operation order. Offsets use unsigned state
116
+ modulo area width/height. Counts are 1..256. Seeds use the full unsigned 32-bit
117
+ range, including zero. No clock or random global is involved.
118
+
119
+ `periodic:true` explicitly wraps the translated shape's bounding origin into one
120
+ surface period, then clips copies translated by -period, 0 and +period on each
121
+ axis. Its shape bounds must fit one period on each axis. Each periodic stamp
122
+ counts as nine expanded copies, with at most 256 expanded copies across the
123
+ recipe. Ordinary stamps clip at edges. Periodic placement does not establish
124
+ that other operations tile; inspect repeat neighbors and the resulting patch.
125
+
126
+ ## Admission and identity
127
+
128
+ Validation inspects every object and array data descriptor before field reads.
129
+ Custom prototypes, accessors, symbols, holes, non-index array fields, forbidden
130
+ prototype keys, functions, undefined, nonfinite numbers and unknown schema
131
+ fields are rejected. Admission precedes the output pixel allocation.
132
+
133
+ The limits are 1,048,576 output texels, 64 operations, 64 polygon vertices,
134
+ 256 expanded stamps and 32 palette colors. JSON preflight admits at most
135
+ 16,384 nodes and depth 10, at most 1024 fields per container, and at most
136
+ 262,144 characters of canonical JSON. The only arbitrary text is an 80-character
137
+ name, so this also bounds UTF-8 recipe storage with a small fixed overhead.
138
+
139
+ The conservative work ceiling is 64,000,000 units. It includes output
140
+ initialization, clipped shape tests (each polygon edge counts), full mask scans,
141
+ per-copy stamp bounds, palette comparisons and legacy pattern/noise work. V3
142
+ transient pixel buffers stay below 64MiB. The compiler creates one RGBA output;
143
+ legacy layers temporarily create matching RGBA outputs and palette metadata is
144
+ bounded. These limits do not raise legacy or portable-material budgets.
145
+
146
+ The compiler ID is `kiln.procedural-rgba.v3.1`. V3 recipe hashes are SHA-256 of
147
+ `compilerId + '\n' + canonicalJson`; property order and omitted defaults produce
148
+ the same canonical result. A changed pixel algorithm requires a new compiler ID.
149
+ V3 metadata records that ID, canonical JSON and recipe hash. V2's hashes and
150
+ material-record compiler ID `kiln.procedural-texture.v2` remain unchanged.
151
+
152
+ Failures use closed evaluator diagnostic `PROCEDURAL_TEXTURE_V3_CONTRACT`;
153
+ direct SDK calls also include the rejected field in the exception text.
154
+
155
+ ## Authored-source example
156
+
157
+ ```js
158
+ function build() {
159
+ const root = createRoot('CutoutStudy');
160
+ const texture = proceduralTexture({
161
+ schemaVersion: 3, width: 16, height: 32, name: 'LeafStudy',
162
+ operations: [
163
+ { op: 'paint', shape: { kind: 'ellipse', x: 3, y: 2, width: 10, height: 28 },
164
+ rgba: [66, 100, 42, 255] },
165
+ { op: 'paint', shape: { kind: 'line', from: [8, 4], to: [8, 29], width: 1 },
166
+ rgba: [118, 132, 60, 255] }
167
+ ],
168
+ palette: { colors: [0x42642a, 0x76843c] }
169
+ });
170
+ const material = pbrMaterial({ albedo: texture, alphaMode: 'mask',
171
+ alphaCutoff: 0.5, doubleSided: true, roughness: 1 });
172
+ createPart('Card', planeGeo(0.5, 1), material, { parent: root });
173
+ return root;
174
+ }
175
+ ```
176
+
177
+ Textures keep existing repeat/linear/mipmap defaults. Sampling choices remain
178
+ explicit Three.js texture settings; creating V3 does not select a pixel-art
179
+ policy. The material's alpha mode and sidedness are separate from pixel alpha.
180
+
181
+ ## Standalone saved materials and atlases
182
+
183
+ No mesh or project is required to create or save a procedural texture. The
184
+ existing `kiln_material` action `create-procedural`, named operation
185
+ `kiln_material_create`, and `kiln material procedural --file draft.json` share
186
+ one JSON authoring boundary. An unversioned layered material draft retains its
187
+ V1 record format and existing defaults. An opt-in material draft with
188
+ `schemaVersion:2` accepts V2 layer recipes, V3 RGBA recipes, or named atlases and
189
+ saves a V2 material record. This material-record version is distinct from a
190
+ texture recipe's `schemaVersion`.
191
+
192
+ Each new map supplies exactly one `procedural` or `atlas` recipe, its map slot,
193
+ source provenance, transforms, and an explicit sampler:
194
+
195
+ ```json
196
+ {
197
+ "minFilter": "nearest",
198
+ "magFilter": "nearest",
199
+ "wrapS": "clamp-to-edge",
200
+ "wrapT": "clamp-to-edge"
201
+ }
202
+ ```
203
+
204
+ This example is a choice for a pixel texture, not a global engine default.
205
+ Minification also supports `linear`, `nearest-mipmap-nearest`,
206
+ `nearest-mipmap-linear`, `linear-mipmap-nearest`, and `linear-mipmap-linear`.
207
+ Wrapping supports `repeat`, `mirrored-repeat`, and `clamp-to-edge`.
208
+ Evaluate minification in the consuming scene; nearest magnification alone does
209
+ not establish acceptable motion, distant cutouts, or atlas gutter behavior.
210
+
211
+ Read `shape:material-draft` and `shape:material-import` with Discovery for the
212
+ complete runtime-validated fields. Sources keep explicit creator and license
213
+ records. The JSON authoring surface accepts no file paths, URLs to fetch, or
214
+ raw image bytes. Existing external image records enter through verified import.
215
+
216
+ `textureAtlas(spec)` compiles named, fixed pixel rectangles. The atlas has
217
+ `schemaVersion:1`, width, height, usage, an optional sampler, and regions.
218
+ Coordinates are integer pixels from the top-left. Each region has a stable
219
+ lowercase `name`, a `content` rectangle, a `source`, and optional crop, gutter,
220
+ and edge mode. Default gutters are two pixels; padded allocations must fit
221
+ without overlap. Sources must already match the requested crop size: this
222
+ operation does not pack, resize, rotate, or resample images.
223
+
224
+ A source is either `{kind:'procedural',spec:<V3 recipe>}` or
225
+ `{kind:'resource',resourceId:<exact map id>,pin:{resourceId:<material id>,
226
+ revisionId:<revision hash>,sha256:<same revision hash>}}`. Resource IDs identify
227
+ the saved map, while the pin identifies its immutable material revision.
228
+ Resolution uses only the explicitly injected material library or evaluator
229
+ dependencies, never nearby projects or network requests. The shared dependency
230
+ walker admits the entire metadata graph before loading source PNGs.
231
+
232
+ `copy-edge` copies edge RGBA into the gutter. `mask-rgb-dilate` keeps gutter alpha
233
+ zero and fills RGB from the nearest positive-alpha source texel, with a stable
234
+ tie break. This reduces dark cutout fringes but does not guarantee safe mipmaps
235
+ for every region size or viewing distance.
236
+
237
+ Use `remapUVToAtlas(geometry, atlas, regionName, {inputOrigin,mode})` to map unit
238
+ UVs into a named region on an owned geometry clone. `inputOrigin` is explicit
239
+ `top-left` or `bottom-left`; `mode` is `content-boundary` or `texel-center`. Rich attributes,
240
+ morphs and skin data are retained according to the UV helper's contract. A
241
+ region binding describes that geometry's region; it does not infer independent
242
+ region assignments for material groups.
243
+
244
+ Saved atlas maps retain the canonical recipe, named-region/source manifest,
245
+ compiler identity, encoded-image hash, decoded pixel hash and exact source
246
+ revision pins. `kiln material export` includes the complete verified material
247
+ closure; importing it into an offline workspace restores those revisions.
248
+ Old-only payloads retain schemaVersion 1. Mixed or new records use schemaVersion
249
+ 2 without rewriting old identities. Projects remain optional and pin exact
250
+ saved revisions when explicitly selected.
251
+
252
+ ## Atlas delivery and inspection
253
+
254
+ Both GLB converters retain a bounded `kilnAtlasProvenance` table in scene extras,
255
+ an exact `kilnAtlasReference` on each material texture use, and a compact
256
+ `kilnAtlasBinding` on primitives created from a named remap. These optional extras
257
+ describe Kiln lineage; ordinary glTF textures, UVs and samplers still render in
258
+ consumers that ignore them. Manual full-sheet use needs no named binding.
259
+ The [delivery metadata contract](atlas-provenance.md) specifies the fields,
260
+ validation and bounds.
261
+
262
+ The source manifest identifies compiled RGBA pixels and recipe inputs. The
263
+ delivery reference separately identifies final encoded image bytes and the
264
+ effective sampler for that use. Conversion may legitimately alter pixels, such
265
+ as an explicit normal-channel conversion, so these identities are distinct.
266
+ Import validates the recorded delivery identity; it never silently replaces a
267
+ stale hash. Editing compiled atlas pixels requires recompilation or removal of
268
+ the atlas metadata to make an ordinary manually authored texture.
269
+
270
+ Structural QA checks declared regions, referenced UVs, slots and sampling without
271
+ decoding images. Quantized UV storage has a bounded precision allowance. Work
272
+ limits or unavailable dimensions produce partial coverage; a valid UV domain
273
+ does not prove the intended orientation or visual quality. Inspect exact saved
274
+ maps in Materials, or follow the material links from Library and Live Review.
275
+ Use a material-faithful rendered view and the destination scene for cutout,
276
+ lighting and motion decisions.
@@ -29,7 +29,7 @@ Authoring commands accept `--project` and `--project-revision`. MCP tools use `p
29
29
  node kiln.mjs render asset.kiln.js --no-project --materials pins.json --out asset.glb
30
30
  ```
31
31
 
32
- `pins.json` contains an array of exact `{resourceId, revisionId, sha256}` material dependencies. MCP accepts the same array as `materialDependencies`. These per-call pins work independently of project membership. With a project, additional pins can extend its lock, but conflicting revisions for the same resource are rejected. Copy returned identities rather than constructing them, and preserve the selected dependencies on subsequent calls that evaluate the source.
32
+ `pins.json` contains an array of exact `{resourceId, revisionId, sha256}` material dependencies. MCP accepts the same array as `materialDependencies`. These per-call pins work independently of project membership. With a project, additional pins extend its lock and an explicit pin replaces the project pin for the same resource for that invocation. The saved project revision remains unchanged. Copy returned identities rather than constructing them, and preserve the selected dependencies on subsequent calls that evaluate the source.
33
33
 
34
34
  ## Materials and coherent art direction
35
35
 
package/docs/rendering.md CHANGED
@@ -27,6 +27,47 @@ safety. See `kiln animation --help` for the complete options.
27
27
 
28
28
  CPU views show silhouette, orientation, proportion, and contact. They do not reproduce the asset's PBR materials. Translucent (opacity below 1) surfaces are composited after opaque geometry, farthest first, so parts behind glazing stay visible whatever order the scene lists them in. Use GPU views to review textures, roughness, metalness, and normal relief. GPU output can vary by device and driver.
29
29
 
30
+ GLB review reconstructs skins with up to four joint influences per vertex,
31
+ including normalized weights and inverse bind matrices. CPU triangles and pose
32
+ bounds follow the sampled joint pose rather than the undeformed position buffer.
33
+ Unsupported additional influence sets produce an explicit error. GLB review
34
+ also reconstructs position/normal morph deltas, node-over-mesh default weights,
35
+ and STEP, LINEAR or CUBICSPLINE weight animation before applying skin transforms.
36
+ Missing target attributes contribute zero displacement. Other morph semantics
37
+ retain `GLB_FLAT_MORPH_TARGETS_UNSUPPORTED`; they are not qualified by this path.
38
+ Expanded morph attributes are bounded to 64 MiB per review scene, including
39
+ zero-filled attributes. Weight tracks use the review limits of 4,096 keys and
40
+ 16,384 scalar values. Invalid counts and nonfinite weights/deltas are rejected.
41
+ Morph primitive children receive unique binding-safe names beneath the original
42
+ named node; use that parent for a stable authored-part selection. Copies have
43
+ independent morph influences. Loop-closure evidence remains transform-only and
44
+ reports weight tracks as unassessed rather than labeling them as scale tracks.
45
+ Isolated, two-sided and composed-scene review
46
+ copies own their skeletons and preserve required hidden joint ancestors as
47
+ transforms without drawing their geometry. Include all referenced bones in the
48
+ review root; copying an incomplete hierarchy reports the missing dependency.
49
+ Geometry and textures remain shared read-only, while two-sided overrides own
50
+ their materials. Qualify material-faithful derivatives separately from the
51
+ whole-character CPU view.
52
+
53
+ CPU views honor front-only, back-only and double-sided source materials in both
54
+ camera paths. Facing follows triangle winding after deformation, with the mesh's
55
+ world-transform reflection parity; changing vertex normals does not change culling.
56
+ Visible back faces reverse their flat lighting normal. Disabling culling for a
57
+ diagnostic view acts as a two-sided override. Singular transforms do not flip
58
+ winding; collapsed triangles do not draw. CPU output remains geometry evidence,
59
+ not PBR evidence. Back-only source materials are not directly portable to GLB;
60
+ see [material sidedness at export](export-profiles.md#material-sidedness-at-export).
61
+
62
+ Both CPU camera paths sample pixel centres with top-left shared-edge ownership.
63
+ They evaluate all three edges directly from canonical endpoints, preventing
64
+ rounding gaps and duplicate blending where adjacent triangles meet. Near/far
65
+ clipping uses direction-independent intersections. Interpolation uses unbiased
66
+ edge weights, including reciprocal depth for perspective cameras. This is a
67
+ floating-point geometry preview, not hardware subpixel/MSAA emulation; perimeter
68
+ pixels can differ from GPU views. Degenerate or nonfinite projected triangles
69
+ are discarded, and raster loops stay within the output image.
70
+
30
71
  ## Review lighting
31
72
 
32
73
  New GPU tool captures use **`review-neutral-v1`**. The rig uses the room PMREM
package/docs/runtime.md CHANGED
@@ -133,9 +133,9 @@ Advanced geometry callbacks also have operation-specific input limits. Those che
133
133
 
134
134
  ### Bake defaults
135
135
 
136
- The rigid-group `full` contract and `rigid-v1` rebuild policy below are included in
137
- 1.0 and its release candidate. They are not implemented by the downloadable 0.10.0
138
- package; see the [migration notes](migration.md#changes-in-10).
136
+ The rigid-group `full` contract and `rigid-v1` rebuild policy below are supported
137
+ in stable Kiln releases from 1.0 onward. When upgrading a 0.10.0 integration,
138
+ see the [migration notes](migration.md#changes-in-10).
139
139
 
140
140
  `KILN_BAKE_OPTIMIZE` and `KILN_BAKE_INSTANCE` choose the bake passes for a render that does not pass `optimize` or `instance`; a value the call passes always wins.
141
141