@hatiolab/figure-model 0.1.92 → 0.1.94

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 (320) hide show
  1. package/CHANGELOG.md +12 -12
  2. package/README.md +25 -25
  3. package/dist/{v3-asset-types.d.ts → asset-types.d.ts} +73 -67
  4. package/dist/asset-types.d.ts.map +1 -0
  5. package/dist/asset-types.js +2 -0
  6. package/dist/asset-types.js.map +1 -0
  7. package/dist/asset.d.ts +20 -0
  8. package/dist/asset.d.ts.map +1 -0
  9. package/dist/{v3-asset.js → asset.js} +49 -28
  10. package/dist/asset.js.map +1 -0
  11. package/dist/{v3-authoring-actions.d.ts → authoring-actions.d.ts} +77 -66
  12. package/dist/authoring-actions.d.ts.map +1 -0
  13. package/dist/{v3-authoring-actions.js → authoring-actions.js} +129 -104
  14. package/dist/authoring-actions.js.map +1 -0
  15. package/dist/{v3-authoring-session.d.ts → authoring-session.d.ts} +23 -21
  16. package/dist/authoring-session.d.ts.map +1 -0
  17. package/dist/{v3-authoring-session.js → authoring-session.js} +4 -4
  18. package/dist/authoring-session.js.map +1 -0
  19. package/dist/capabilities.d.ts +3 -0
  20. package/dist/capabilities.d.ts.map +1 -0
  21. package/dist/{v3-capabilities.js → capabilities.js} +8 -8
  22. package/dist/capabilities.js.map +1 -0
  23. package/dist/clip-keeping.d.ts +30 -0
  24. package/dist/clip-keeping.d.ts.map +1 -0
  25. package/dist/clip-keeping.js +77 -0
  26. package/dist/clip-keeping.js.map +1 -0
  27. package/dist/command-preview.d.ts +125 -0
  28. package/dist/command-preview.d.ts.map +1 -0
  29. package/dist/command-preview.js +246 -0
  30. package/dist/command-preview.js.map +1 -0
  31. package/dist/contract.d.ts +7 -0
  32. package/dist/contract.d.ts.map +1 -0
  33. package/dist/contract.js +12 -0
  34. package/dist/contract.js.map +1 -0
  35. package/dist/{v3-cost.d.ts → cost.d.ts} +5 -5
  36. package/dist/cost.d.ts.map +1 -0
  37. package/dist/{v3-cost.js → cost.js} +11 -11
  38. package/dist/cost.js.map +1 -0
  39. package/dist/{v3-create.d.ts → create.d.ts} +8 -8
  40. package/dist/{v3-create.d.ts.map → create.d.ts.map} +1 -1
  41. package/dist/{v3-create.js → create.js} +26 -26
  42. package/dist/create.js.map +1 -0
  43. package/dist/document.d.ts +5 -0
  44. package/dist/document.d.ts.map +1 -0
  45. package/dist/document.js +31 -0
  46. package/dist/document.js.map +1 -0
  47. package/dist/{v3-driver.d.ts → driver.d.ts} +10 -10
  48. package/dist/driver.d.ts.map +1 -0
  49. package/dist/{v3-driver.js → driver.js} +10 -10
  50. package/dist/driver.js.map +1 -0
  51. package/dist/{v3-editor-workspace.d.ts → editor-workspace.d.ts} +99 -73
  52. package/dist/editor-workspace.d.ts.map +1 -0
  53. package/dist/{v3-editor-workspace.js → editor-workspace.js} +48 -32
  54. package/dist/editor-workspace.js.map +1 -0
  55. package/dist/{v3-examples.d.ts → examples.d.ts} +5 -5
  56. package/dist/examples.d.ts.map +1 -0
  57. package/dist/{v3-examples.js → examples.js} +11 -11
  58. package/dist/examples.js.map +1 -0
  59. package/dist/{v3-follow.d.ts → follow.d.ts} +5 -5
  60. package/dist/follow.d.ts.map +1 -0
  61. package/dist/{v3-follow.js → follow.js} +2 -2
  62. package/dist/follow.js.map +1 -0
  63. package/dist/{v3-gate.d.ts → gate.d.ts} +36 -28
  64. package/dist/gate.d.ts.map +1 -0
  65. package/dist/{v3-gate.js → gate.js} +54 -48
  66. package/dist/gate.js.map +1 -0
  67. package/dist/{v3-graph-types.d.ts → graph-types.d.ts} +33 -33
  68. package/dist/graph-types.d.ts.map +1 -0
  69. package/dist/graph-types.js +2 -0
  70. package/dist/graph-types.js.map +1 -0
  71. package/dist/{v3-graph.d.ts → graph.d.ts} +14 -14
  72. package/dist/graph.d.ts.map +1 -0
  73. package/dist/{v3-graph.js → graph.js} +16 -16
  74. package/dist/graph.js.map +1 -0
  75. package/dist/index.d.ts +39 -33
  76. package/dist/index.d.ts.map +1 -1
  77. package/dist/index.js +39 -33
  78. package/dist/index.js.map +1 -1
  79. package/dist/{v3-instance-size.d.ts → instance-size.d.ts} +14 -14
  80. package/dist/instance-size.d.ts.map +1 -0
  81. package/dist/{v3-instance-size.js → instance-size.js} +13 -13
  82. package/dist/instance-size.js.map +1 -0
  83. package/dist/json.d.ts +12 -0
  84. package/dist/json.d.ts.map +1 -0
  85. package/dist/{v3-json.js → json.js} +13 -13
  86. package/dist/json.js.map +1 -0
  87. package/dist/kernel-version.d.ts +8 -0
  88. package/dist/kernel-version.d.ts.map +1 -0
  89. package/dist/{v3-kernel-version.js → kernel-version.js} +4 -4
  90. package/dist/kernel-version.js.map +1 -0
  91. package/dist/{v3-part-edit.d.ts → part-edit.d.ts} +12 -11
  92. package/dist/part-edit.d.ts.map +1 -0
  93. package/dist/{v3-part-edit.js → part-edit.js} +84 -68
  94. package/dist/part-edit.js.map +1 -0
  95. package/dist/proposal.d.ts +55 -0
  96. package/dist/proposal.d.ts.map +1 -0
  97. package/dist/{v3-proposal.js → proposal.js} +29 -21
  98. package/dist/proposal.js.map +1 -0
  99. package/dist/{v3-public-inputs.d.ts → public-inputs.d.ts} +4 -4
  100. package/dist/public-inputs.d.ts.map +1 -0
  101. package/dist/{v3-public-inputs.js → public-inputs.js} +3 -3
  102. package/dist/public-inputs.js.map +1 -0
  103. package/dist/recipe-build.d.ts +27 -0
  104. package/dist/recipe-build.d.ts.map +1 -0
  105. package/dist/{v3-recipe-build.js → recipe-build.js} +9 -9
  106. package/dist/recipe-build.js.map +1 -0
  107. package/dist/recipe-from-parts.d.ts +8 -0
  108. package/dist/recipe-from-parts.d.ts.map +1 -0
  109. package/dist/{v3-recipe-from-parts.js → recipe-from-parts.js} +9 -9
  110. package/dist/recipe-from-parts.js.map +1 -0
  111. package/dist/{v3-recipe.d.ts → recipe.d.ts} +25 -25
  112. package/dist/recipe.d.ts.map +1 -0
  113. package/dist/{v3-recipe.js → recipe.js} +30 -30
  114. package/dist/recipe.js.map +1 -0
  115. package/dist/release-contract.d.ts +19 -0
  116. package/dist/release-contract.d.ts.map +1 -0
  117. package/dist/{v3-release-contract.js → release-contract.js} +8 -7
  118. package/dist/release-contract.js.map +1 -0
  119. package/dist/{v3-render-batches.d.ts → render-batches.d.ts} +8 -8
  120. package/dist/render-batches.d.ts.map +1 -0
  121. package/dist/{v3-render-batches.js → render-batches.js} +4 -4
  122. package/dist/render-batches.js.map +1 -0
  123. package/dist/resize-plan.d.ts +61 -0
  124. package/dist/resize-plan.d.ts.map +1 -0
  125. package/dist/resize-plan.js +189 -0
  126. package/dist/resize-plan.js.map +1 -0
  127. package/dist/room.d.ts +53 -0
  128. package/dist/room.d.ts.map +1 -0
  129. package/dist/room.js +90 -0
  130. package/dist/room.js.map +1 -0
  131. package/dist/{v3-score.d.ts → score.d.ts} +19 -19
  132. package/dist/score.d.ts.map +1 -0
  133. package/dist/{v3-score.js → score.js} +32 -32
  134. package/dist/score.js.map +1 -0
  135. package/dist/shape-provider.d.ts +37 -0
  136. package/dist/shape-provider.d.ts.map +1 -0
  137. package/dist/shape-provider.js +69 -0
  138. package/dist/shape-provider.js.map +1 -0
  139. package/dist/{v3-shape-sampling.d.ts → shape-sampling.d.ts} +4 -4
  140. package/dist/shape-sampling.d.ts.map +1 -0
  141. package/dist/{v3-shape-sampling.js → shape-sampling.js} +3 -3
  142. package/dist/shape-sampling.js.map +1 -0
  143. package/dist/size-edit.d.ts +38 -0
  144. package/dist/size-edit.d.ts.map +1 -0
  145. package/dist/size-edit.js +178 -0
  146. package/dist/size-edit.js.map +1 -0
  147. package/dist/{v3-surface.d.ts → surface.d.ts} +5 -5
  148. package/dist/surface.d.ts.map +1 -0
  149. package/dist/{v3-surface.js → surface.js} +7 -7
  150. package/dist/surface.js.map +1 -0
  151. package/dist/{v3-words.d.ts → words.d.ts} +3 -3
  152. package/dist/words.d.ts.map +1 -0
  153. package/dist/{v3-words.js → words.js} +3 -3
  154. package/dist/words.js.map +1 -0
  155. package/docs/{assembly-constraints-v3.md → assembly-constraints.md} +1 -1
  156. package/docs/{v3-asset-persistence.md → asset-persistence.md} +8 -8
  157. package/docs/{v3-authoring-transactions.md → authoring-transactions.md} +2 -2
  158. package/docs/{v3-capability-bindings.md → capability-bindings.md} +8 -8
  159. package/docs/{v3-common-kernel-experiment.md → common-kernel-experiment.md} +4 -4
  160. package/docs/{v3-core-semantics.md → core-semantics.md} +5 -5
  161. package/docs/{v3-cutover.md → cutover.md} +4 -4
  162. package/docs/{v3-design.md → design.md} +11 -11
  163. package/docs/{v3-document-contract.md → document-contract.md} +9 -9
  164. package/docs/{v3-dryroom-profile-validation.md → dryroom-profile-validation.md} +4 -4
  165. package/docs/{v3-editor-integration.md → editor-integration.md} +6 -6
  166. package/docs/{v3-full-conveyor-validation.md → full-conveyor-validation.md} +4 -4
  167. package/docs/{v3-full-dryroom-validation.md → full-dryroom-validation.md} +4 -4
  168. package/docs/{v3-full-forklift-validation.md → full-forklift-validation.md} +5 -5
  169. package/docs/{v3-full-robot-validation.md → full-robot-validation.md} +4 -4
  170. package/docs/{v3-layout-system.md → layout-system.md} +4 -4
  171. package/docs/{v3-legacy-risk-audit-2026-09-23.md → legacy-risk-audit-2026-09-23.md} +5 -5
  172. package/docs/{v3-minimal-model.md → minimal-model.md} +6 -6
  173. package/docs/{v3-motion-contract.md → motion-contract.md} +3 -3
  174. package/docs/{v3-openusd-review.md → openusd-review.md} +8 -8
  175. package/docs/{v3-operator-contracts.md → operator-contracts.md} +6 -6
  176. package/docs/{v3-payload-collision-validation.md → payload-collision-validation.md} +4 -4
  177. package/docs/{v3-payload-contact-validation.md → payload-contact-validation.md} +5 -5
  178. package/docs/prototypes/README.md +10 -10
  179. package/docs/prototypes/{v3-asset-samples.mjs → asset-samples.mjs} +6 -6
  180. package/docs/prototypes/{v3-asset-store.mjs → asset-store.mjs} +3 -3
  181. package/docs/prototypes/{v3-asset-store.test.mjs → asset-store.test.mjs} +6 -6
  182. package/docs/prototypes/asset.mjs +1 -0
  183. package/docs/prototypes/{v3-asset.schema.json → asset.schema.json} +2 -2
  184. package/docs/prototypes/{v3-asset.test.mjs → asset.test.mjs} +10 -10
  185. package/docs/prototypes/authoring-session.mjs +1 -0
  186. package/docs/prototypes/{v3-authoring-session.test.mjs → authoring-session.test.mjs} +6 -6
  187. package/docs/prototypes/capability-plan.mjs +1 -0
  188. package/docs/prototypes/{v3-capability-plan.test.mjs → capability-plan.test.mjs} +5 -5
  189. package/docs/prototypes/{v3-capability-samples.mjs → capability-samples.mjs} +2 -2
  190. package/docs/prototypes/document.mjs +2 -0
  191. package/docs/prototypes/{v3-document.schema.json → document.schema.json} +1 -1
  192. package/docs/prototypes/{v3-document.test.mjs → document.test.mjs} +7 -7
  193. package/docs/prototypes/{v3-dryroom-mesh.mjs → dryroom-mesh.mjs} +1 -1
  194. package/docs/prototypes/{v3-dryroom-mesh.test.mjs → dryroom-mesh.test.mjs} +1 -1
  195. package/docs/prototypes/{v3-editor-browser.mjs → editor-browser.mjs} +13 -13
  196. package/docs/prototypes/editor-workspace.mjs +1 -0
  197. package/docs/prototypes/{v3-editor-workspace.test.mjs → editor-workspace.test.mjs} +3 -3
  198. package/docs/prototypes/{v3-feature-pattern.test.mjs → feature-pattern.test.mjs} +1 -1
  199. package/docs/prototypes/{v3-full-conveyor.mjs → full-conveyor.mjs} +2 -2
  200. package/docs/prototypes/{v3-full-conveyor.test.mjs → full-conveyor.test.mjs} +3 -3
  201. package/docs/prototypes/{v3-full-dryroom.mjs → full-dryroom.mjs} +2 -2
  202. package/docs/prototypes/{v3-full-dryroom.test.mjs → full-dryroom.test.mjs} +3 -3
  203. package/docs/prototypes/{v3-full-forklift.mjs → full-forklift.mjs} +2 -2
  204. package/docs/prototypes/{v3-full-forklift.test.mjs → full-forklift.test.mjs} +3 -3
  205. package/docs/prototypes/{v3-full-robot.mjs → full-robot.mjs} +2 -2
  206. package/docs/prototypes/{v3-full-robot.test.mjs → full-robot.test.mjs} +4 -4
  207. package/docs/prototypes/{v3-kernel.test.mjs → kernel.test.mjs} +1 -1
  208. package/docs/prototypes/{v3-layout.test.mjs → layout.test.mjs} +1 -1
  209. package/docs/prototypes/{v3-more-samples.test.mjs → more-samples.test.mjs} +2 -2
  210. package/docs/prototypes/{v3-payload-collision.mjs → payload-collision.mjs} +2 -2
  211. package/docs/prototypes/{v3-payload-collision.test.mjs → payload-collision.test.mjs} +3 -3
  212. package/docs/prototypes/{v3-payload-fit.mjs → payload-fit.mjs} +2 -2
  213. package/docs/prototypes/{v3-payload-fit.test.mjs → payload-fit.test.mjs} +4 -4
  214. package/docs/prototypes/render-full-dryroom.mjs +12 -12
  215. package/docs/prototypes/{v3-repeated-binding.mjs → repeated-binding.mjs} +1 -1
  216. package/docs/prototypes/{v3-repeated-binding.test.mjs → repeated-binding.test.mjs} +6 -6
  217. package/docs/prototypes/{v3-runtime-browser.mjs → runtime-browser.mjs} +26 -26
  218. package/docs/prototypes/{v3-samples.test.mjs → samples.test.mjs} +1 -1
  219. package/docs/prototypes/{v3-spatial-plan.test.mjs → spatial-plan.test.mjs} +1 -1
  220. package/docs/prototypes/typed-plan.mjs +3 -0
  221. package/docs/prototypes/{v3-typed-plan.test.mjs → typed-plan.test.mjs} +1 -1
  222. package/docs/prototypes/{v3-typed-repeat.test.mjs → typed-repeat.test.mjs} +2 -2
  223. package/docs/{v3-repeated-binding-validation.md → repeated-binding-validation.md} +4 -4
  224. package/docs/{v3-research-review.md → research-review.md} +2 -2
  225. package/docs/{v3-review-2026-09-22.md → review-2026-09-22.md} +10 -10
  226. package/docs/{v3-runtime-extraction.md → runtime-extraction.md} +16 -16
  227. package/docs/{v3-sample-validation-expanded.md → sample-validation-expanded.md} +5 -5
  228. package/docs/{v3-sample-validation.md → sample-validation.md} +3 -3
  229. package/docs/{v3-shape-dimension-contract.md → shape-dimension-contract.md} +12 -12
  230. package/docs/{v3-shapeassembly-reproduction.md → shapeassembly-reproduction.md} +4 -4
  231. package/docs/{v3-spatial-contracts.md → spatial-contracts.md} +5 -5
  232. package/docs/status.md +12 -0
  233. package/docs/{v3-storage-integration.md → storage-integration.md} +5 -5
  234. package/docs/{v3-typed-repeat-contracts.md → typed-repeat-contracts.md} +3 -3
  235. package/package.json +3 -3
  236. package/dist/v3-asset-types.d.ts.map +0 -1
  237. package/dist/v3-asset-types.js +0 -2
  238. package/dist/v3-asset-types.js.map +0 -1
  239. package/dist/v3-asset.d.ts +0 -8
  240. package/dist/v3-asset.d.ts.map +0 -1
  241. package/dist/v3-asset.js.map +0 -1
  242. package/dist/v3-authoring-actions.d.ts.map +0 -1
  243. package/dist/v3-authoring-actions.js.map +0 -1
  244. package/dist/v3-authoring-session.d.ts.map +0 -1
  245. package/dist/v3-authoring-session.js.map +0 -1
  246. package/dist/v3-capabilities.d.ts +0 -3
  247. package/dist/v3-capabilities.d.ts.map +0 -1
  248. package/dist/v3-capabilities.js.map +0 -1
  249. package/dist/v3-contract.d.ts +0 -7
  250. package/dist/v3-contract.d.ts.map +0 -1
  251. package/dist/v3-contract.js +0 -12
  252. package/dist/v3-contract.js.map +0 -1
  253. package/dist/v3-cost.d.ts.map +0 -1
  254. package/dist/v3-cost.js.map +0 -1
  255. package/dist/v3-create.js.map +0 -1
  256. package/dist/v3-document.d.ts +0 -5
  257. package/dist/v3-document.d.ts.map +0 -1
  258. package/dist/v3-document.js +0 -31
  259. package/dist/v3-document.js.map +0 -1
  260. package/dist/v3-driver.d.ts.map +0 -1
  261. package/dist/v3-driver.js.map +0 -1
  262. package/dist/v3-editor-workspace.d.ts.map +0 -1
  263. package/dist/v3-editor-workspace.js.map +0 -1
  264. package/dist/v3-examples.d.ts.map +0 -1
  265. package/dist/v3-examples.js.map +0 -1
  266. package/dist/v3-follow.d.ts.map +0 -1
  267. package/dist/v3-follow.js.map +0 -1
  268. package/dist/v3-gate.d.ts.map +0 -1
  269. package/dist/v3-gate.js.map +0 -1
  270. package/dist/v3-graph-types.d.ts.map +0 -1
  271. package/dist/v3-graph-types.js +0 -2
  272. package/dist/v3-graph-types.js.map +0 -1
  273. package/dist/v3-graph.d.ts.map +0 -1
  274. package/dist/v3-graph.js.map +0 -1
  275. package/dist/v3-instance-size.d.ts.map +0 -1
  276. package/dist/v3-instance-size.js.map +0 -1
  277. package/dist/v3-json.d.ts +0 -12
  278. package/dist/v3-json.d.ts.map +0 -1
  279. package/dist/v3-json.js.map +0 -1
  280. package/dist/v3-kernel-version.d.ts +0 -8
  281. package/dist/v3-kernel-version.d.ts.map +0 -1
  282. package/dist/v3-kernel-version.js.map +0 -1
  283. package/dist/v3-part-edit.d.ts.map +0 -1
  284. package/dist/v3-part-edit.js.map +0 -1
  285. package/dist/v3-proposal.d.ts +0 -42
  286. package/dist/v3-proposal.d.ts.map +0 -1
  287. package/dist/v3-proposal.js.map +0 -1
  288. package/dist/v3-public-inputs.d.ts.map +0 -1
  289. package/dist/v3-public-inputs.js.map +0 -1
  290. package/dist/v3-recipe-build.d.ts +0 -27
  291. package/dist/v3-recipe-build.d.ts.map +0 -1
  292. package/dist/v3-recipe-build.js.map +0 -1
  293. package/dist/v3-recipe-from-parts.d.ts +0 -8
  294. package/dist/v3-recipe-from-parts.d.ts.map +0 -1
  295. package/dist/v3-recipe-from-parts.js.map +0 -1
  296. package/dist/v3-recipe.d.ts.map +0 -1
  297. package/dist/v3-recipe.js.map +0 -1
  298. package/dist/v3-release-contract.d.ts +0 -19
  299. package/dist/v3-release-contract.d.ts.map +0 -1
  300. package/dist/v3-release-contract.js.map +0 -1
  301. package/dist/v3-render-batches.d.ts.map +0 -1
  302. package/dist/v3-render-batches.js.map +0 -1
  303. package/dist/v3-score.d.ts.map +0 -1
  304. package/dist/v3-score.js.map +0 -1
  305. package/dist/v3-shape-sampling.d.ts.map +0 -1
  306. package/dist/v3-shape-sampling.js.map +0 -1
  307. package/dist/v3-surface.d.ts.map +0 -1
  308. package/dist/v3-surface.js.map +0 -1
  309. package/dist/v3-words.d.ts.map +0 -1
  310. package/dist/v3-words.js.map +0 -1
  311. package/docs/prototypes/v3-asset.mjs +0 -1
  312. package/docs/prototypes/v3-authoring-session.mjs +0 -1
  313. package/docs/prototypes/v3-capability-plan.mjs +0 -1
  314. package/docs/prototypes/v3-document.mjs +0 -2
  315. package/docs/prototypes/v3-editor-workspace.mjs +0 -1
  316. package/docs/prototypes/v3-typed-plan.mjs +0 -3
  317. package/docs/v3-status.md +0 -50
  318. /package/docs/prototypes/{v3-kernel.mjs → kernel.mjs} +0 -0
  319. /package/docs/prototypes/{v3-linear-comparison.py → linear-comparison.py} +0 -0
  320. /package/docs/prototypes/{v3-semantics.test.mjs → semantics.test.mjs} +0 -0
package/CHANGELOG.md CHANGED
@@ -8,30 +8,30 @@
8
8
 
9
9
  ### 속 빈 상자를 부품으로 (2026-09-26, G4)
10
10
 
11
- `addV3Primitive` · `add-part` 가 `hollow-box`(윗면이 열린 통: 폭 · 높이 · 깊이 · 모서리 · 벽 두께 · 바닥 두께, `hollow-box@2`)를 만든다.
11
+ `addFigurePrimitive` · `add-part` 가 `hollow-box`(윗면이 열린 통: 폭 · 높이 · 깊이 · 모서리 · 벽 두께 · 바닥 두께, `hollow-box@2`)를 만든다.
12
12
  안쪽 면(`inside-bottom` · `inside-left` · `inside-right` · `inside-back` · `inside-front`)도 붙이는 면이라 칸막이를 세울 수 있다.
13
13
  크기를 따를 때와 공간을 잴 때는 바깥이 치수다. 벽과 바닥은 두께를 지킨다. `set-joint` 도 `narrowRange` 를 받는다.
14
14
 
15
15
  ### 모델로 먼저 만든 템플릿을 레시피로 (2026-09-26, ADR-0095 고침)
16
16
 
17
- `buildV3Recipe(spec, models)`: 템플릿을 선택지 조합마다 도형(모델: `host` 상자와 거기에 붙은 부품)으로 만들고, 그 모델들을 레시피
17
+ `buildFigureRecipe(spec, models)`: 템플릿을 선택지 조합마다 도형(모델: `host` 상자와 거기에 붙은 부품)으로 만들고, 그 모델들을 레시피
18
18
  하나로 합친다. 모든 모델에 있는 명령은 그대로, 일부에만 있는 명령은 그것을 가르는 선택 하나의 `when` 을 붙인다. 사람이 정하는 수는
19
19
  명세가 가리키는 명령의 값에 매개변수로 건다(기본값에 대한 배율). 모델이 빠진 조합 · 어느 선택으로도 말할 수 없는 명령 · 걸 수가
20
- 없는 수는 까닭과 함께 거절한다. `v3RecipeFromParts` 를 되살렸다(재질의 색은 부품마다 제 것만 적는다 — 선택지마다 같게).
20
+ 없는 수는 까닭과 함께 거절한다. `figureRecipeFromParts` 를 되살렸다(재질의 색은 부품마다 제 것만 적는다 — 선택지마다 같게).
21
21
 
22
22
  ### 조각 템플릿은 figure-service 의 정적 파일로 · 카탈로그용 설명 (2026-09-26, ADR-0095 고침)
23
23
 
24
24
  0.1.82 가 패키지의 `recipes/*.json` 으로 싣던 조각 셋은 figure-service 의 `recipes/<name>/` 로 옮겼다(백엔드가 정적 파일로 제공한다).
25
25
  figure-model 에는 적용과 검사만 남는다. `recipes/` 폴더와 `./recipes/*` export 는 없앴다. 매개변수는 짧은 설명 `hint`(언어별)를 가질 수
26
- 있다. `describeV3Recipe`: 카탈로그가 보일 것 — 선택에 따라 더해지는 부품 수(가장 적게 · 많게), 움직이는 부품과 방식(미끄러짐 ·
26
+ 있다. `describeFigureRecipe`: 카탈로그가 보일 것 — 선택에 따라 더해지는 부품 수(가장 적게 · 많게), 움직이는 부품과 방식(미끄러짐 ·
27
27
  회전 · 따라 움직임), 더해지는 조작값, 조작값에 따라 보이는 부품, 되풀이 줄. 글로 따로 적지 않고 명령에서 셈한다.
28
- `v3FollowOf`(치수가 무엇을 따르나, 거꾸로 읽기)를 figure-ui 에서 옮겨 왔다.
28
+ `figureFollowOf`(치수가 무엇을 따르나, 거꾸로 읽기)를 figure-ui 에서 옮겨 왔다.
29
29
 
30
30
  ### 조각(recipe) (2026-09-26, ADR-0095)
31
31
 
32
- 조각은 매개변수가 붙은 제안 명령 목록이다. `parseV3Recipe` · `resolveV3Recipe` · `applyV3Recipe`: 자리 채우기 셋(`{id}` ·
32
+ 조각은 매개변수가 붙은 제안 명령 목록이다. `parseFigureRecipe` · `resolveFigureRecipe` · `applyFigureRecipe`: 자리 채우기 셋(`{id}` ·
33
33
  `{target}` · `{매개변수}`), 한 매개변수의 일차식(`{ param, times?, plus? }`), 명령마다 `when` 하나. 식 언어는 없다. 값은 커널보다
34
- 먼저 범위와 선택지로 거르고, 풀린 목록은 `applyV3Proposal` 로 적용한다. 넣은 뒤에는 보통 부품이다. 기본 조각 셋을 패키지의
34
+ 먼저 범위와 선택지로 거르고, 풀린 목록은 `applyFigureProposal` 로 적용한다. 넣은 뒤에는 보통 부품이다. 기본 조각 셋을 패키지의
35
35
  `recipes/`(미닫이 문 · 여닫이 문 · 롤러 줄)에 싣는다. `make-repeat` 도 `narrowRange` 를 받는다 — 한 줄이 채우는 복제는
36
36
  REPEAT_LIMIT 개까지라, 크기를 따르는 도형에 가장 큰 크기가 생긴다.
37
37
 
@@ -45,7 +45,7 @@ REPEAT_LIMIT 개까지라, 크기를 따르는 도형에 가장 큰 크기가
45
45
 
46
46
  `portal-profile@1`(부호 있는 좌표 여덟)을 `portal-profile@2`로 바꿨다. 입력은 폭 · 높이 · 깊이 · 기둥 두께(`jamb`) · 인방 두께(`head`)이고,
47
47
  좌우로 가운데, 바닥에 서고, 깊이로 가운데다. 앞 셋이 상자와 같은 자리라 `link-dimension` 과 크기 따르기가 상자처럼 먹는다
48
- (이전에는 거절했다). 기둥과 인방은 크기를 따라도 두께를 지킨다. `addV3Primitive` 의 `portal` 치수도 이 다섯이다.
48
+ (이전에는 거절했다). 기둥과 인방은 크기를 따라도 두께를 지킨다. `addFigurePrimitive` 의 `portal` 치수도 이 다섯이다.
49
49
  @1 은 지웠다 — 저장된 도형 가운데 쓰는 것이 없었다.
50
50
 
51
51
  ### 자기 숫자로 놓인 부품 위의 되풀이 (2026-09-26)
@@ -63,12 +63,12 @@ REPEAT_LIMIT 개까지라, 크기를 따르는 도형에 가장 큰 크기가
63
63
 
64
64
  ### V1 · V2 형식을 지웠다 (2026-09-26)
65
65
 
66
- 남은 형식은 `figure-v3-asset-1` 하나다. `FigureSource` · `compile` · `validate` · `costOf` · `scoreOf` ·
67
- 크기 반응(`sizing`) · 발행 관문(`gate`) · `contractChanges` · V2→V3 변환기(`convertV2ToV3` 와 그 짝)와
66
+ 남은 형식은 `figure-asset-1` 하나다. `FigureSource` · `compile` · `validate` · `costOf` · `scoreOf` ·
67
+ 크기 반응(`sizing`) · 발행 관문(`gate`) · `contractChanges` · V2→V3 변환기(`convertV2ToFigure` 와 그 짝)와
68
68
  `./types` · `./validate` · `./blueprint` · `./cost` 하위 경로를 지웠다. V3 가 함께 쓰던 낱말(`AXES` ·
69
69
  `FIGURE_CAPABILITIES` · `CAPABILITY_NEEDS` · `MATERIAL_PRESETS` · `REPEAT_LIMIT` · `DETAIL_LEVELS` · `PART_LIMIT` ·
70
- `SKIN` · `LIMITS` · `SEGMENT_PRESETS` · `V3_SIZE_INPUTS` · `FigureGrade` · `TYPE_PATTERN` · `TYPE_LENGTH` ·
71
- `placeholderType` · `isPlaceholderType`)은 `v3-words.ts` 로 옮겨 그대로 내보낸다.
70
+ `SKIN` · `LIMITS` · `SEGMENT_PRESETS` · `FIGURE_SIZE_INPUTS` · `FigureGrade` · `TYPE_PATTERN` · `TYPE_LENGTH` ·
71
+ `placeholderType` · `isPlaceholderType`)은 `words.ts` 로 옮겨 그대로 내보낸다.
72
72
  V3 컴파일이 혼자 설 수 없는 능력(`Transferable`)을 거절한다 — V2 의 `validate` 가 하던 검사다.
73
73
 
74
74
  아래는 V2 시절의 기록이다.
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # @hatiolab/figure-model
2
2
 
3
- > Implementation and verification status: [docs/v3-status.md](docs/v3-status.md).
3
+ > Implementation and verification status: [docs/status.md](docs/status.md).
4
4
 
5
- The figure format, `figure-v3-asset-1`: its kernel, authoring commands, release gate, score and AI proposal
5
+ The figure format, `figure-asset-1`: its kernel, authoring commands, release gate, score and AI proposal
6
6
  grammar. No runtime dependencies.
7
7
 
8
8
  The package contains no renderer. The modeller authors with it, the server judges and stores with it, and the scene
@@ -31,26 +31,26 @@ npm install @hatiolab/figure-model
31
31
  Everything is exported from the package root.
32
32
 
33
33
  ```ts
34
- import { parseV3Asset, compileV3Asset, inspectV3Asset, v3ScoreOf } from '@hatiolab/figure-model'
34
+ import { parseFigureAsset, compileFigureAsset, inspectFigureAsset, figureScoreOf } from '@hatiolab/figure-model'
35
35
  ```
36
36
 
37
37
  ## Main exports
38
38
 
39
39
  | Area | Exports |
40
40
  | --- | --- |
41
- | Asset document | `parseV3Asset`, `serializeV3Asset`, `compileV3Asset`, `captureV3AuthoredInputs`; types from `v3-asset-types.ts`, `V3_PLACEMENTS` |
42
- | Kernel (typed graph) | `compileV3Graph`, `V3_OPERATORS`, `V3_NON_AFFINE_OPERATORS`, `V3_STATE_NON_AFFINE_OPERATORS`, `V3_OPERATOR_STATE_POLICY`, `v3ShapeFaces`, `V3_KERNEL_VERSION`, `V3_FACE_NORMALS`; graph types (`V3Graph`, `V3CompiledGraph`, …) |
43
- | Instance size | `V3_INSTANCE_SIZE_INPUTS`, `V3_INSTANCE_SIZE_DEFAULT`, `defaultInstanceSizeRange`, `foldInstanceSizeRange`, `v3InstanceSizeLimitsOf` |
44
- | Motion and state | `driverValue`, `driverStates`, `normalisePhase`, `validateV3Drivers`, `validateV3StateInputs`, `advanceStateValue`, `stateInputPolicy` |
45
- | Authoring commands | `createV3Asset`, `addV3Box`, `addV3Primitive`, `editV3Part`, `applyV3Authoring`, `proposeV3Occupancy`, `proposeV3Proportion`, `checkV3Joints`, `v3AttachmentsOf`, `v3BindingsOf` |
46
- | Authoring session | `createV3AuthoringSession`, `createV3EditorWorkspace` |
47
- | Release gate | `inspectV3Asset`, `v3WorldBoxesOf`, `v3OccupiedBoxesOf`, `v3WritersOf`, `v3PartsExtentOf`, `v3ContractChanges` |
48
- | Score and cost | `v3ScoreOf`, `v3GradeOf`, `v3PartCountOf`, `v3PartBudgetOf`, `v3CostOf`, `v3TrianglesOf` |
49
- | AI proposal grammar | `applyV3Proposal`, `V3_PROPOSAL_GRAMMAR`, `V3_PROPOSAL_KINDS` |
50
- | Capabilities and documents | `compileV3Capabilities`, `compileV3Document`, `parseV3Document`, `serializeV3Document` |
51
- | JSON input boundary | `parseV3Json`, `assertV3Json`, `V3_JSON_MAX_BYTES`, `V3_JSON_MAX_DEPTH`, `V3ContractError` |
52
- | Shared words | `AXES`, `FIGURE_CAPABILITIES`, `MATERIAL_PRESETS`, `SEGMENT_PRESETS`, `DETAIL_LEVELS`, `PART_LIMIT`, `LIMITS`, … (`v3-words.ts`) |
53
- | Example | `robotArmV3`, `ROBOT_ARM_CHAIN` |
41
+ | Asset document | `parseFigureAsset`, `serializeFigureAsset`, `compileFigureAsset`, `captureFigureAuthoredInputs`; types from `asset-types.ts`, `FIGURE_PLACEMENTS` |
42
+ | Kernel (typed graph) | `compileFigureGraph`, `FIGURE_OPERATORS`, `FIGURE_NON_AFFINE_OPERATORS`, `FIGURE_STATE_NON_AFFINE_OPERATORS`, `FIGURE_OPERATOR_STATE_POLICY`, `figureShapeFaces`, `FIGURE_KERNEL_VERSION`, `FIGURE_FACE_NORMALS`; graph types (`FigureGraph`, `FigureCompiledGraph`, …) |
43
+ | Instance size | `FIGURE_INSTANCE_SIZE_INPUTS`, `FIGURE_INSTANCE_SIZE_DEFAULT`, `defaultInstanceSizeRange`, `foldInstanceSizeRange`, `figureInstanceSizeLimitsOf` |
44
+ | Motion and state | `driverValue`, `driverStates`, `normalisePhase`, `validateFigureDrivers`, `validateFigureStateInputs`, `advanceStateValue`, `stateInputPolicy` |
45
+ | Authoring commands | `createFigureAsset`, `addFigureBox`, `addFigurePrimitive`, `editFigurePart`, `applyFigureAuthoring`, `proposeFigureOccupancy`, `proposeFigureProportion`, `checkFigureJoints`, `figureAttachmentsOf`, `figureBindingsOf` |
46
+ | Authoring session | `createFigureAuthoringSession`, `createFigureEditorWorkspace` |
47
+ | Release gate | `inspectFigureAsset`, `figureWorldBoxesOf`, `figureOccupiedBoxesOf`, `figureWritersOf`, `figurePartsExtentOf`, `figureContractChanges` |
48
+ | Score and cost | `figureScoreOf`, `figureGradeOf`, `figurePartCountOf`, `figurePartBudgetOf`, `figureCostOf`, `figureTrianglesOf` |
49
+ | AI proposal grammar | `applyFigureProposal`, `FIGURE_PROPOSAL_GRAMMAR`, `FIGURE_PROPOSAL_KINDS` |
50
+ | Capabilities and documents | `compileFigureCapabilities`, `compileFigureDocument`, `parseFigureDocument`, `serializeFigureDocument` |
51
+ | JSON input boundary | `parseFigureJson`, `assertFigureJson`, `FIGURE_JSON_MAX_BYTES`, `FIGURE_JSON_MAX_DEPTH`, `FigureContractError` |
52
+ | Shared words | `AXES`, `FIGURE_CAPABILITIES`, `MATERIAL_PRESETS`, `SEGMENT_PRESETS`, `DETAIL_LEVELS`, `PART_LIMIT`, `LIMITS`, … (`words.ts`) |
53
+ | Example | `robotArmFigure`, `ROBOT_ARM_CHAIN` |
54
54
 
55
55
  ## Commands
56
56
 
@@ -76,12 +76,12 @@ No runtime dependencies; it runs unchanged in the browser. The three devDependen
76
76
 
77
77
  ## Documents
78
78
 
79
- - [v3-design.md](docs/v3-design.md) — the design and its reasons
80
- - [v3-core-semantics.md](docs/v3-core-semantics.md) — core semantics of the kernel
81
- - [v3-shape-dimension-contract.md](docs/v3-shape-dimension-contract.md) — shape dimensions and how they respond to size
82
- - [v3-spatial-contracts.md](docs/v3-spatial-contracts.md) — spatial contracts
83
- - [v3-motion-contract.md](docs/v3-motion-contract.md) — joints, state inputs and drivers
84
- - [v3-asset-persistence.md](docs/v3-asset-persistence.md) — the stored asset document
85
- - [v3-authoring-transactions.md](docs/v3-authoring-transactions.md) — authoring commands
86
- - [v3-capability-bindings.md](docs/v3-capability-bindings.md) — capability bindings
87
- - [v3-status.md](docs/v3-status.md) — implementation and verification status
79
+ - [design.md](docs/design.md) — the design and its reasons
80
+ - [core-semantics.md](docs/core-semantics.md) — core semantics of the kernel
81
+ - [shape-dimension-contract.md](docs/shape-dimension-contract.md) — shape dimensions and how they respond to size
82
+ - [spatial-contracts.md](docs/spatial-contracts.md) — spatial contracts
83
+ - [motion-contract.md](docs/motion-contract.md) — joints, state inputs and drivers
84
+ - [asset-persistence.md](docs/asset-persistence.md) — the stored asset document
85
+ - [authoring-transactions.md](docs/authoring-transactions.md) — authoring commands
86
+ - [capability-bindings.md](docs/capability-bindings.md) — capability bindings
87
+ - [status.md](docs/status.md) — implementation and verification status
@@ -1,27 +1,27 @@
1
- import type { V3Joint } from './v3-authoring-actions.ts';
2
- import type { V3Graph, V3Geometry, V3Pose, V3RuntimeValue, V3ValueType } from './v3-graph-types.ts';
3
- export interface V3SurfaceReference {
1
+ import type { FigureJoint } from './authoring-actions.ts';
2
+ import type { FigureGraph, FigureGeometry, FigurePose, FigureRuntimeValue, FigureValueType } from './graph-types.ts';
3
+ export interface FigureSurfaceReference {
4
4
  placement: string;
5
5
  feature: string;
6
6
  }
7
- export interface V3BindingDeclaration {
7
+ export interface FigureBindingDeclaration {
8
8
  id: string;
9
9
  label: string;
10
10
  role: 'seat' | 'grip';
11
11
  frame: string;
12
- pose: string | V3SurfaceReference;
12
+ pose: string | FigureSurfaceReference;
13
13
  accepts: string[];
14
14
  capacity: number;
15
15
  region?: {
16
16
  kind: 'centered-box';
17
17
  dimensions: [string, string, string];
18
18
  };
19
- contacts?: V3SurfaceReference[];
19
+ contacts?: FigureSurfaceReference[];
20
20
  }
21
- export interface V3Capabilities {
21
+ export interface FigureCapabilities {
22
22
  version: 'r3-capability-3';
23
23
  assetFrame: string;
24
- bindings: V3BindingDeclaration[];
24
+ bindings: FigureBindingDeclaration[];
25
25
  /**
26
26
  * What the figure can do, by name, for the scene to attach behaviour (ADR-0051 ④, ADR-0087 decision 3).
27
27
  * Every name must be in `FIGURE_CAPABILITIES`; the check reads that list, it does not copy it.
@@ -32,7 +32,7 @@ export interface V3Capabilities {
32
32
  * The volume the author declares the figure occupies, and the face it is mounted on (ADR-0044, ADR-0045,
33
33
  * ADR-0087 decision 3).
34
34
  *
35
- * **The reach on each side of the asset origin, not an extent rising from it** (V3 designer's ruling
35
+ * **The reach on each side of the asset origin, not an extent rising from it** (designer's ruling
36
36
  * 2026-09-23). The origin is where the figure is mounted; it is a coordinate reference, not a surface nothing
37
37
  * may pass. A robot arm bolted to a bench reaches below the bench, and that is the machine working, not a
38
38
  * fault. An extent could only grow upward and outward from the centre, so it could say neither that, nor a
@@ -40,7 +40,7 @@ export interface V3Capabilities {
40
40
  *
41
41
  * Each of the six names a length value in the graph; `min` is normally negative below or left of the origin.
42
42
  * A part outside the declared volume, or a floor figure whose parts do not reach the plane it is mounted on,
43
- * is a release violation reported by `inspectV3Asset`.
43
+ * is a release violation reported by `inspectFigureAsset`.
44
44
  *
45
45
  * What this is not: a rule about what the figure may do. It describes the room the figure takes up. Whether
46
46
  * that room is free is the scene's question, against the real obstacles it has placed.
@@ -50,9 +50,9 @@ export interface V3Capabilities {
50
50
  * plane Y = 0 -- a part stands on it by its bottom or hangs from it by its top; a wall is the plane Z = 0, the figure
51
51
  * coming out of it along +Z, a part fastened to it by its back; `center` has no plane of its own.
52
52
  */
53
- export type V3Placement = 'floor' | 'ceiling' | 'center' | 'wall';
54
- export declare const V3_PLACEMENTS: readonly V3Placement[];
55
- export interface V3Occupancy {
53
+ export type FigurePlacement = 'floor' | 'ceiling' | 'center' | 'wall';
54
+ export declare const FIGURE_PLACEMENTS: readonly FigurePlacement[];
55
+ export interface FigureOccupancy {
56
56
  bounds: {
57
57
  x: {
58
58
  min: string;
@@ -67,9 +67,8 @@ export interface V3Occupancy {
67
67
  max: string;
68
68
  };
69
69
  };
70
- placement: V3Placement;
71
70
  /**
72
- * The face of the figure that lies on the plane it is mounted on (V3 designer's ruling 2026-09-23).
71
+ * The face of the figure that lies on the plane it is mounted on (designer's ruling 2026-09-23).
73
72
  *
74
73
  * Absent means the figure is not asked to touch anything. The origin is a coordinate reference, not a surface
75
74
  * the drawing must reach: a figure may be fastened through a bracket nobody drew, or by a mounting structure
@@ -80,75 +79,75 @@ export interface V3Occupancy {
80
79
  * asking for it is a one-sided position test, which passes a body that hangs entirely below the plane and fails
81
80
  * a design that reaches under it on purpose. It is also the smallest gap over the parts, which folds, so it
82
81
  * could not be settled over a state range. One named face is a single equality and settles both
83
- * (V3 designer's ruling 2026-09-23, after two counterexamples).
82
+ * (designer's ruling 2026-09-23, after two counterexamples).
84
83
  */
85
84
  contact?: {
86
85
  plane: 'mounting-plane';
87
- surface: V3SurfaceReference;
86
+ surface: FigureSurfaceReference;
88
87
  };
89
88
  }
90
- export interface V3Document {
91
- version: 'figure-v3-prototype-1';
92
- model: V3Graph;
93
- capabilities: V3Capabilities;
89
+ export interface FigureDocument {
90
+ version: 'figure-prototype-1';
91
+ model: FigureGraph;
92
+ capabilities: FigureCapabilities;
94
93
  }
95
- export interface V3BindingRequest {
94
+ export interface FigureBindingRequest {
96
95
  type: string;
97
96
  occupied: number;
98
97
  }
99
- export type V3Check = {
98
+ export type FigureCheck = {
100
99
  status: 'unverified';
101
100
  reason: string;
102
101
  } | {
103
102
  status: 'satisfied' | 'failed';
104
103
  reasons?: string[];
105
104
  };
106
- export interface V3EvaluatedSurface extends V3SurfaceReference {
105
+ export interface FigureEvaluatedSurface extends FigureSurfaceReference {
107
106
  geometryId: string;
108
107
  provider: string;
109
108
  face: string;
110
- pose: V3Pose;
109
+ pose: FigurePose;
111
110
  normal: number[];
112
111
  provenance: 'verified-planar-surface';
113
112
  }
114
- export interface V3EvaluatedBinding {
113
+ export interface FigureEvaluatedBinding {
115
114
  id: string;
116
115
  label: string;
117
116
  role: 'seat' | 'grip';
118
117
  frame: string;
119
- pose: V3Pose;
118
+ pose: FigurePose;
120
119
  targetGeometryId?: string;
121
120
  region: {
122
121
  kind: 'centered-box';
123
122
  dimensions: number[];
124
123
  } | null;
125
- contacts: V3EvaluatedSurface[];
124
+ contacts: FigureEvaluatedSurface[];
126
125
  checks: {
127
- declaration: V3Check;
128
- eligibility: V3Check;
129
- spatial: V3Check;
130
- collision: V3Check;
131
- safety: V3Check;
126
+ declaration: FigureCheck;
127
+ eligibility: FigureCheck;
128
+ spatial: FigureCheck;
129
+ collision: FigureCheck;
130
+ safety: FigureCheck;
132
131
  };
133
132
  }
134
- export interface V3CapabilityEvaluation {
135
- geometry: V3Geometry[];
136
- bindings: V3EvaluatedBinding[];
133
+ export interface FigureCapabilityEvaluation {
134
+ geometry: FigureGeometry[];
135
+ bindings: FigureEvaluatedBinding[];
137
136
  /** Every value the graph produced, so a reader can resolve a reference it declared (such as a visibility flag). */
138
- values: Record<string, V3RuntimeValue>;
137
+ values: Record<string, FigureRuntimeValue>;
139
138
  }
140
- export interface V3CompiledCapabilities {
139
+ export interface FigureCompiledCapabilities {
141
140
  /** The compiled graph's value types, so a reader can check what a reference names before evaluating. */
142
- outputTypes: Record<string, V3ValueType>;
141
+ outputTypes: Record<string, FigureValueType>;
143
142
  /** Which state inputs each value depends on (shape-dimension contract §2). */
144
143
  dependence: Record<string, string[]>;
145
- evaluate(inputs: Record<string, number>, requests?: Record<string, V3BindingRequest>): V3CapabilityEvaluation;
144
+ evaluate(inputs: Record<string, number>, requests?: Record<string, FigureBindingRequest>): FigureCapabilityEvaluation;
146
145
  /** An evaluator for one instance: it keeps its last evaluation and runs again only what changed since. */
147
146
  evaluator(): {
148
- evaluate(inputs: Record<string, number>, requests?: Record<string, V3BindingRequest>): V3CapabilityEvaluation;
147
+ evaluate(inputs: Record<string, number>, requests?: Record<string, FigureBindingRequest>): FigureCapabilityEvaluation;
149
148
  };
150
149
  }
151
- export interface V3Material {
150
+ export interface FigureMaterial {
152
151
  token: string;
153
152
  preset?: 'default' | 'metal' | 'glass' | 'plastic' | 'wood' | 'ceramic' | 'rubber';
154
153
  transparent?: boolean;
@@ -158,12 +157,12 @@ export interface V3Material {
158
157
  on: boolean;
159
158
  };
160
159
  }
161
- export interface V3Appearance {
160
+ export interface FigureAppearance {
162
161
  target: string;
163
- material: V3Material;
162
+ material: FigureMaterial;
164
163
  segments?: number;
165
164
  /**
166
- * A `flag` value in the graph saying whether this part is shown (V3 designer's ruling 2026-09-22).
165
+ * A `flag` value in the graph saying whether this part is shown (designer's ruling 2026-09-22).
167
166
  * Absent means always shown.
168
167
  *
169
168
  * The evaluation contract for a hidden part:
@@ -176,10 +175,10 @@ export interface V3Appearance {
176
175
  visibility?: string;
177
176
  }
178
177
  /**
179
- * A driver computes one state input from time (docs/v3-motion-contract.md). The kernel never sees time; the
178
+ * A driver computes one state input from time (docs/motion-contract.md). The kernel never sees time; the
180
179
  * consumer that owns time calls `driverValue` and writes the result into the state input it names.
181
180
  */
182
- export interface V3Driver {
181
+ export interface FigureDriver {
183
182
  /** An opaque identifier, unique among the asset's drivers. Nothing is read out of its spelling. */
184
183
  id: string;
185
184
  /**
@@ -206,9 +205,9 @@ export interface V3Driver {
206
205
  }
207
206
  /**
208
207
  * What a person sees for a state input, and how the figure moves toward a new value for it
209
- * (V3 designer's ruling 2026-09-22). Keyed by the input's id, which stays the stable identifier.
208
+ * (designer's ruling 2026-09-22). Keyed by the input's id, which stays the stable identifier.
210
209
  */
211
- export interface V3StateInputPolicy {
210
+ export interface FigureStateInputPolicy {
212
211
  /** The name shown to a person. Kept apart from the id so renaming the label never renames the input. */
213
212
  label?: string;
214
213
  /**
@@ -220,18 +219,25 @@ export interface V3StateInputPolicy {
220
219
  */
221
220
  sweep?: number;
222
221
  }
223
- export interface V3Asset {
224
- version: 'figure-v3-asset-1';
222
+ export interface FigureAsset {
223
+ version: 'figure-asset-1';
225
224
  name: string;
226
- document: V3Document;
225
+ document: FigureDocument;
227
226
  designInputs: Record<string, number>;
228
227
  stateDefaults: Record<string, number>;
229
228
  palette: Record<string, string>;
230
- appearance: V3Appearance[];
231
- occupancy?: V3Occupancy;
232
- drivers?: V3Driver[];
229
+ appearance: FigureAppearance[];
230
+ occupancy?: FigureOccupancy;
231
+ /**
232
+ * Where the figure is authored from -- the floor, the ceiling, a wall or its centre (ADR-0097, designer 2026-09-27).
233
+ * The figure's own setting, apart from the room it declares: it can be chosen before there is a part to measure.
234
+ * Left out, the figure stands on the floor. An asset written before stored it in `occupancy.placement`;
235
+ * `upgradeFigurePlacement` moves it here when the asset is read.
236
+ */
237
+ placement?: FigurePlacement;
238
+ drivers?: FigureDriver[];
233
239
  /** Per state input: its display label and its transition time. Inputs absent here have neither. */
234
- stateInputs?: Record<string, V3StateInputPolicy>;
240
+ stateInputs?: Record<string, FigureStateInputPolicy>;
235
241
  /**
236
242
  * How the figure grows when a board gives it another size. Absent: each part follows its own rules. `uniform`:
237
243
  * the whole figure by one ratio, the geometric mean of the three axes' -- a mechanism does not shear (chief
@@ -245,18 +251,18 @@ export interface V3Asset {
245
251
  */
246
252
  detailLevel?: 'S' | 'M' | 'L';
247
253
  /**
248
- * The joints, URDF's records with V3 values (ADR-0093): the canon of how parts hang together and move. Their graph
254
+ * The joints, URDF's records with values (ADR-0093): the canon of how parts hang together and move. Their graph
249
255
  * nodes are made from them; an asset whose nodes disagree with them is refused on reading.
250
256
  */
251
- joints?: V3Joint[];
257
+ joints?: FigureJoint[];
252
258
  /**
253
259
  * The design inputs a board may set per instance, chosen by the figure's author (ADR-0096): a roller row's pitch.
254
260
  * Each points at an input of the model; its unit, default and range are the input's own. Not the size inputs (a
255
261
  * board sets the size from its bounds), not state inputs, and only inputs with a finite range.
256
262
  */
257
- publicInputs?: V3PublicInput[];
263
+ publicInputs?: FigurePublicInput[];
258
264
  }
259
- export interface V3PublicInput {
265
+ export interface FigurePublicInput {
260
266
  /** The design input's id. */
261
267
  input: string;
262
268
  /** The name shown to a person on a board. */
@@ -264,17 +270,17 @@ export interface V3PublicInput {
264
270
  /** One line on what it sets. */
265
271
  hint?: string;
266
272
  }
267
- export type V3AssetGeometry = V3Geometry & Omit<V3Appearance, 'target' | 'visibility'> & {
273
+ export type FigureAssetGeometry = FigureGeometry & Omit<FigureAppearance, 'target' | 'visibility'> & {
268
274
  /** Whether the consumer draws this body. False bodies are still evaluated, placed and gated. */
269
275
  visible: boolean;
270
276
  };
271
- export interface V3AssetEvaluation {
272
- geometry: V3AssetGeometry[];
273
- bindings: V3EvaluatedBinding[];
277
+ export interface FigureAssetEvaluation {
278
+ geometry: FigureAssetGeometry[];
279
+ bindings: FigureEvaluatedBinding[];
274
280
  inputs: Record<string, number>;
275
281
  palette: Record<string, string>;
276
282
  }
277
- export interface V3CompiledAsset {
278
- evaluate(stateOverrides?: Record<string, number>): V3AssetEvaluation;
283
+ export interface FigureCompiledAsset {
284
+ evaluate(stateOverrides?: Record<string, number>): FigureAssetEvaluation;
279
285
  }
280
- //# sourceMappingURL=v3-asset-types.d.ts.map
286
+ //# sourceMappingURL=asset-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset-types.d.ts","sourceRoot":"","sources":["../src/asset-types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export const FIGURE_PLACEMENTS = ['floor', 'ceiling', 'center', 'wall'];
2
+ //# sourceMappingURL=asset-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset-types.js","sourceRoot":"","sources":["../src/asset-types.ts"],"names":[],"mappings":"AAoDA,MAAM,CAAC,MAAM,iBAAiB,GAA+B,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAA"}
@@ -0,0 +1,20 @@
1
+ import type { FigureAsset, FigureCompiledAsset } from './asset-types.ts';
2
+ import { type FigurePlacement } from './asset-types.ts';
3
+ export declare function compileFigureAsset(source: unknown): FigureCompiledAsset;
4
+ /**
5
+ * An asset written before the placement was its own setting kept it in the room it declared (`occupancy.placement`).
6
+ * Read, it is moved to `placement` -- the one place it is kept now (ADR-0097, designer 2026-09-27: 「두 곳에 서로 다른
7
+ * 배치 값을 유지하지 않는다」). Released snapshots are not rewritten; they are read this way. An asset holding both,
8
+ * differently, is refused: which one was meant cannot be told. Returns the asset itself when there is nothing to move.
9
+ */
10
+ export declare function upgradeFigurePlacement<T>(source: T): T;
11
+ /** Where the figure is authored from: its own setting, or the floor when it names none. */
12
+ export declare function figurePlacementOf(asset: {
13
+ placement?: FigurePlacement;
14
+ }): FigurePlacement;
15
+ export declare function serializeFigureAsset(asset: unknown): string;
16
+ export declare function parseFigureAsset(text: string): FigureAsset;
17
+ export declare function captureFigureAuthoredInputs(asset: FigureAsset, inputs: Record<string, number>, options?: {
18
+ captureStateDefaults?: boolean;
19
+ }): FigureAsset;
20
+ //# sourceMappingURL=asset.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"asset.d.ts","sourceRoot":"","sources":["../src/asset.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAyB,MAAM,kBAAkB,CAAA;AAC/F,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAc1E,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,GAAG,mBAAmB,CAEvE;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAQtD;AAED,2FAA2F;AAC3F,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IAAE,SAAS,CAAC,EAAE,eAAe,CAAA;CAAE,GAAG,eAAe,CAEzF;AA4JD,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,UAGlD;AACD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,CAO1D;AACD,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,OAAO,GAAE;IAAE,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAAO,GAC/C,WAAW,CAeb"}
@@ -1,12 +1,12 @@
1
1
  // Self-contained experimental asset envelope; no product DB/file writes.
2
- import { checkV3Joints } from "./v3-authoring-actions.js";
3
- import { compileV3Document as compileDocument } from "./v3-document.js";
4
- import { checkPublicInput } from "./v3-public-inputs.js";
5
- import { assertV3Json as jsonOnly, parseV3Json as parseStrictJson, V3_JSON_MAX_BYTES as MAX_BYTES, v3Utf8ByteLength } from "./v3-json.js";
6
- import { V3_PLACEMENTS } from "./v3-asset-types.js";
7
- import { V3ContractError as ContractError } from "./v3-contract.js";
8
- import { validateV3Drivers, validateV3StateInputs } from "./v3-driver.js";
9
- import { resolveV3Surface } from "./v3-surface.js";
2
+ import { checkFigureJoints } from "./authoring-actions.js";
3
+ import { compileFigureDocument as compileDocument } from "./document.js";
4
+ import { checkPublicInput } from "./public-inputs.js";
5
+ import { assertFigureJson as jsonOnly, parseFigureJson as parseStrictJson, FIGURE_JSON_MAX_BYTES as MAX_BYTES, figureUtf8ByteLength } from "./json.js";
6
+ import { FIGURE_PLACEMENTS } from "./asset-types.js";
7
+ import { FigureContractError as ContractError } from "./contract.js";
8
+ import { validateFigureDrivers, validateFigureStateInputs } from "./driver.js";
9
+ import { resolveFigureSurface } from "./surface.js";
10
10
  const fail = (code, path, message) => {
11
11
  throw new ContractError(code, path, message);
12
12
  };
@@ -20,15 +20,38 @@ function fields(o, required, optional, path) {
20
20
  if (![...required, ...optional].includes(k))
21
21
  fail('ASSET_SCHEMA', path, `unknown ${k}`);
22
22
  }
23
- export function compileV3Asset(source) {
23
+ export function compileFigureAsset(source) {
24
24
  return compileAsset(source);
25
25
  }
26
- function compileAsset(source) {
27
- jsonOnly(source);
28
- if (v3Utf8ByteLength(JSON.stringify(source)) > MAX_BYTES)
26
+ /**
27
+ * An asset written before the placement was its own setting kept it in the room it declared (`occupancy.placement`).
28
+ * Read, it is moved to `placement` -- the one place it is kept now (ADR-0097, designer 2026-09-27: 「두 곳에 서로 다른
29
+ * 배치 값을 유지하지 않는다」). Released snapshots are not rewritten; they are read this way. An asset holding both,
30
+ * differently, is refused: which one was meant cannot be told. Returns the asset itself when there is nothing to move.
31
+ */
32
+ export function upgradeFigurePlacement(source) {
33
+ const asset = source;
34
+ const old = asset?.occupancy && typeof asset.occupancy === 'object' ? asset.occupancy.placement : undefined;
35
+ if (old === undefined)
36
+ return source;
37
+ if (asset.placement !== undefined && asset.placement !== old)
38
+ fail('PLACEMENT_CONFLICT', 'placement', `the asset says ${String(asset.placement)} and its room says ${String(old)}; keep one`);
39
+ const { placement: _moved, ...occupancy } = asset.occupancy;
40
+ return { ...asset, placement: old, occupancy };
41
+ }
42
+ /** Where the figure is authored from: its own setting, or the floor when it names none. */
43
+ export function figurePlacementOf(asset) {
44
+ return asset.placement ?? 'floor';
45
+ }
46
+ function compileAsset(given) {
47
+ jsonOnly(given);
48
+ const source = upgradeFigurePlacement(given);
49
+ if (figureUtf8ByteLength(JSON.stringify(source)) > MAX_BYTES)
29
50
  fail('DOCUMENT_LIMIT', 'asset', 'over 1 MiB');
30
- fields(source, ['version', 'name', 'document', 'designInputs', 'stateDefaults', 'palette', 'appearance'], ['occupancy', 'drivers', 'stateInputs', 'sizing', 'detailLevel', 'joints', 'publicInputs'], 'asset');
31
- if (source.version !== 'figure-v3-asset-1')
51
+ fields(source, ['version', 'name', 'document', 'designInputs', 'stateDefaults', 'palette', 'appearance'], ['occupancy', 'placement', 'drivers', 'stateInputs', 'sizing', 'detailLevel', 'joints', 'publicInputs'], 'asset');
52
+ if (source.placement !== undefined && !FIGURE_PLACEMENTS.includes(source.placement))
53
+ fail('ASSET_SCHEMA', 'placement', `one of ${FIGURE_PLACEMENTS.join(', ')} required`);
54
+ if (source.version !== 'figure-asset-1')
32
55
  fail('VERSION', 'asset', source.version);
33
56
  if (typeof source.name !== 'string' || !source.name.trim())
34
57
  fail('ASSET_SCHEMA', 'name', 'nonempty name required');
@@ -114,15 +137,15 @@ function compileAsset(source) {
114
137
  if (looks.size !== placements.size)
115
138
  fail('APPEARANCE_MISSING', 'appearance', 'every source placement/member requires appearance');
116
139
  if (asset.occupancy !== undefined) {
117
- // ADR-0044 · ADR-0045 in V3: the declared volume names three length values; the placement is one of the declared placements.
118
- fields(asset.occupancy, ['bounds', 'placement'], ['contact'], 'occupancy');
140
+ // ADR-0044 · ADR-0045: the declared volume names three length values. The placement is the asset's own (ADR-0097).
141
+ fields(asset.occupancy, ['bounds'], ['contact'], 'occupancy');
119
142
  if (asset.occupancy.contact !== undefined) {
120
143
  const contact = asset.occupancy.contact;
121
144
  fields(contact, ['plane', 'surface'], [], 'occupancy.contact');
122
145
  if (contact.plane !== 'mounting-plane')
123
146
  fail('OCCUPANCY', 'occupancy.contact', `${String(contact.plane)} is not a plane the figure can be mounted on`);
124
147
  // The same reader the capability contacts use, so a mounting face is a real planar face of a drawn body.
125
- resolveV3Surface({ types: plan.outputTypes, writers, model, assetFrame: asset.document.capabilities.assetFrame }, contact.surface, 'occupancy.contact.surface');
148
+ resolveFigureSurface({ types: plan.outputTypes, writers, model, assetFrame: asset.document.capabilities.assetFrame }, contact.surface, 'occupancy.contact.surface');
126
149
  }
127
150
  fields(asset.occupancy.bounds, ['x', 'y', 'z'], [], 'occupancy.bounds');
128
151
  const lengthType = JSON.stringify([1, 0, 0]);
@@ -138,18 +161,16 @@ function compileAsset(source) {
138
161
  fail('OCCUPANCY_STATE', path, `${ref} depends on state input ${plan.dependence[ref].join(', ')}; the occupancy is state-independent`);
139
162
  }
140
163
  }
141
- if (!V3_PLACEMENTS.includes(asset.occupancy.placement))
142
- fail('OCCUPANCY', 'occupancy.placement', `one of ${V3_PLACEMENTS.join(', ')} required`);
143
164
  }
144
- validateV3Drivers(asset);
145
- validateV3StateInputs(asset);
165
+ validateFigureDrivers(asset);
166
+ validateFigureStateInputs(asset);
146
167
  function evaluate(stateOverrides = {}) {
147
168
  fields(stateOverrides, [], state, 'state overrides');
148
169
  const inputs = { ...asset.designInputs, ...asset.stateDefaults, ...stateOverrides }, r = plan.evaluate(inputs);
149
170
  const targetOf = (g) => (g.key ? writers.get(g.key)?.id : g.id);
150
171
  /*
151
172
  Bodies come back in the appearance order — the parts list's order, and the order they are drawn in. The graph
152
- lists nodes in whatever order they were written, so a list that followed it could not be reordered (the V3
173
+ lists nodes in whatever order they were written, so a list that followed it could not be reordered (the
153
174
  modeller's 「위로」 did nothing, 2026-09-24). The sort is stable: a repeated template's members keep their order.
154
175
  */
155
176
  const rank = new Map(asset.appearance.map((look, i) => [look.target, i]));
@@ -173,20 +194,20 @@ function compileAsset(source) {
173
194
  evaluate(); // Stored design and state defaults must themselves be executable.
174
195
  return { evaluate };
175
196
  }
176
- export function serializeV3Asset(asset) {
197
+ export function serializeFigureAsset(asset) {
177
198
  compileAsset(asset);
178
199
  return JSON.stringify(asset);
179
200
  }
180
- export function parseV3Asset(text) {
181
- const asset = parseStrictJson(text);
201
+ export function parseFigureAsset(text) {
202
+ const asset = upgradeFigurePlacement(parseStrictJson(text));
182
203
  compileAsset(asset);
183
204
  if (asset.joints !== undefined && !Array.isArray(asset.joints))
184
205
  fail('ASSET_SCHEMA', 'joints', 'joints is a list');
185
206
  // The joint records are the canon; nodes edited apart from them are refused (ADR-0093).
186
- checkV3Joints(asset);
207
+ checkFigureJoints(asset);
187
208
  return asset;
188
209
  }
189
- export function captureV3AuthoredInputs(asset, inputs, options = {}) {
210
+ export function captureFigureAuthoredInputs(asset, inputs, options = {}) {
190
211
  fields(options, [], ['captureStateDefaults'], 'capture options');
191
212
  const captureStateDefaults = options.captureStateDefaults ?? false;
192
213
  if (typeof captureStateDefaults !== 'boolean')
@@ -205,4 +226,4 @@ export function captureV3AuthoredInputs(asset, inputs, options = {}) {
205
226
  compileAsset(next);
206
227
  return next;
207
228
  }
208
- //# sourceMappingURL=v3-asset.js.map
229
+ //# sourceMappingURL=asset.js.map