@hatiolab/figure-model 0.1.92 → 0.1.93

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 (296) 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} +67 -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 +8 -0
  8. package/dist/asset.d.ts.map +1 -0
  9. package/dist/{v3-asset.js → asset.js} +23 -23
  10. package/dist/asset.js.map +1 -0
  11. package/dist/{v3-authoring-actions.d.ts → authoring-actions.d.ts} +66 -66
  12. package/dist/authoring-actions.d.ts.map +1 -0
  13. package/dist/{v3-authoring-actions.js → authoring-actions.js} +77 -77
  14. package/dist/authoring-actions.js.map +1 -0
  15. package/dist/{v3-authoring-session.d.ts → authoring-session.d.ts} +21 -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/contract.d.ts +7 -0
  24. package/dist/contract.d.ts.map +1 -0
  25. package/dist/contract.js +12 -0
  26. package/dist/contract.js.map +1 -0
  27. package/dist/{v3-cost.d.ts → cost.d.ts} +5 -5
  28. package/dist/cost.d.ts.map +1 -0
  29. package/dist/{v3-cost.js → cost.js} +11 -11
  30. package/dist/cost.js.map +1 -0
  31. package/dist/{v3-create.d.ts → create.d.ts} +8 -8
  32. package/dist/{v3-create.d.ts.map → create.d.ts.map} +1 -1
  33. package/dist/{v3-create.js → create.js} +26 -26
  34. package/dist/create.js.map +1 -0
  35. package/dist/document.d.ts +5 -0
  36. package/dist/document.d.ts.map +1 -0
  37. package/dist/document.js +31 -0
  38. package/dist/document.js.map +1 -0
  39. package/dist/{v3-driver.d.ts → driver.d.ts} +10 -10
  40. package/dist/driver.d.ts.map +1 -0
  41. package/dist/{v3-driver.js → driver.js} +10 -10
  42. package/dist/driver.js.map +1 -0
  43. package/dist/{v3-editor-workspace.d.ts → editor-workspace.d.ts} +73 -73
  44. package/dist/editor-workspace.d.ts.map +1 -0
  45. package/dist/{v3-editor-workspace.js → editor-workspace.js} +29 -29
  46. package/dist/editor-workspace.js.map +1 -0
  47. package/dist/{v3-examples.d.ts → examples.d.ts} +5 -5
  48. package/dist/examples.d.ts.map +1 -0
  49. package/dist/{v3-examples.js → examples.js} +11 -11
  50. package/dist/examples.js.map +1 -0
  51. package/dist/{v3-follow.d.ts → follow.d.ts} +5 -5
  52. package/dist/follow.d.ts.map +1 -0
  53. package/dist/{v3-follow.js → follow.js} +2 -2
  54. package/dist/follow.js.map +1 -0
  55. package/dist/{v3-gate.d.ts → gate.d.ts} +28 -28
  56. package/dist/gate.d.ts.map +1 -0
  57. package/dist/{v3-gate.js → gate.js} +42 -42
  58. package/dist/gate.js.map +1 -0
  59. package/dist/{v3-graph-types.d.ts → graph-types.d.ts} +33 -33
  60. package/dist/graph-types.d.ts.map +1 -0
  61. package/dist/graph-types.js +2 -0
  62. package/dist/graph-types.js.map +1 -0
  63. package/dist/{v3-graph.d.ts → graph.d.ts} +14 -14
  64. package/dist/graph.d.ts.map +1 -0
  65. package/dist/{v3-graph.js → graph.js} +16 -16
  66. package/dist/graph.js.map +1 -0
  67. package/dist/index.d.ts +33 -33
  68. package/dist/index.d.ts.map +1 -1
  69. package/dist/index.js +33 -33
  70. package/dist/index.js.map +1 -1
  71. package/dist/{v3-instance-size.d.ts → instance-size.d.ts} +14 -14
  72. package/dist/instance-size.d.ts.map +1 -0
  73. package/dist/{v3-instance-size.js → instance-size.js} +13 -13
  74. package/dist/instance-size.js.map +1 -0
  75. package/dist/json.d.ts +12 -0
  76. package/dist/json.d.ts.map +1 -0
  77. package/dist/{v3-json.js → json.js} +13 -13
  78. package/dist/json.js.map +1 -0
  79. package/dist/kernel-version.d.ts +8 -0
  80. package/dist/kernel-version.d.ts.map +1 -0
  81. package/dist/{v3-kernel-version.js → kernel-version.js} +4 -4
  82. package/dist/kernel-version.js.map +1 -0
  83. package/dist/{v3-part-edit.d.ts → part-edit.d.ts} +10 -10
  84. package/dist/part-edit.d.ts.map +1 -0
  85. package/dist/{v3-part-edit.js → part-edit.js} +65 -65
  86. package/dist/part-edit.js.map +1 -0
  87. package/dist/proposal.d.ts +42 -0
  88. package/dist/proposal.d.ts.map +1 -0
  89. package/dist/{v3-proposal.js → proposal.js} +21 -21
  90. package/dist/proposal.js.map +1 -0
  91. package/dist/{v3-public-inputs.d.ts → public-inputs.d.ts} +4 -4
  92. package/dist/public-inputs.d.ts.map +1 -0
  93. package/dist/{v3-public-inputs.js → public-inputs.js} +3 -3
  94. package/dist/public-inputs.js.map +1 -0
  95. package/dist/recipe-build.d.ts +27 -0
  96. package/dist/recipe-build.d.ts.map +1 -0
  97. package/dist/{v3-recipe-build.js → recipe-build.js} +9 -9
  98. package/dist/recipe-build.js.map +1 -0
  99. package/dist/recipe-from-parts.d.ts +8 -0
  100. package/dist/recipe-from-parts.d.ts.map +1 -0
  101. package/dist/{v3-recipe-from-parts.js → recipe-from-parts.js} +9 -9
  102. package/dist/recipe-from-parts.js.map +1 -0
  103. package/dist/{v3-recipe.d.ts → recipe.d.ts} +25 -25
  104. package/dist/recipe.d.ts.map +1 -0
  105. package/dist/{v3-recipe.js → recipe.js} +30 -30
  106. package/dist/recipe.js.map +1 -0
  107. package/dist/release-contract.d.ts +19 -0
  108. package/dist/release-contract.d.ts.map +1 -0
  109. package/dist/{v3-release-contract.js → release-contract.js} +5 -5
  110. package/dist/release-contract.js.map +1 -0
  111. package/dist/{v3-render-batches.d.ts → render-batches.d.ts} +8 -8
  112. package/dist/render-batches.d.ts.map +1 -0
  113. package/dist/{v3-render-batches.js → render-batches.js} +4 -4
  114. package/dist/render-batches.js.map +1 -0
  115. package/dist/{v3-score.d.ts → score.d.ts} +19 -19
  116. package/dist/score.d.ts.map +1 -0
  117. package/dist/{v3-score.js → score.js} +32 -32
  118. package/dist/score.js.map +1 -0
  119. package/dist/{v3-shape-sampling.d.ts → shape-sampling.d.ts} +4 -4
  120. package/dist/shape-sampling.d.ts.map +1 -0
  121. package/dist/{v3-shape-sampling.js → shape-sampling.js} +3 -3
  122. package/dist/shape-sampling.js.map +1 -0
  123. package/dist/{v3-surface.d.ts → surface.d.ts} +5 -5
  124. package/dist/surface.d.ts.map +1 -0
  125. package/dist/{v3-surface.js → surface.js} +7 -7
  126. package/dist/surface.js.map +1 -0
  127. package/dist/{v3-words.d.ts → words.d.ts} +3 -3
  128. package/dist/words.d.ts.map +1 -0
  129. package/dist/{v3-words.js → words.js} +3 -3
  130. package/dist/words.js.map +1 -0
  131. package/docs/{assembly-constraints-v3.md → assembly-constraints.md} +1 -1
  132. package/docs/{v3-asset-persistence.md → asset-persistence.md} +8 -8
  133. package/docs/{v3-authoring-transactions.md → authoring-transactions.md} +2 -2
  134. package/docs/{v3-capability-bindings.md → capability-bindings.md} +8 -8
  135. package/docs/{v3-common-kernel-experiment.md → common-kernel-experiment.md} +4 -4
  136. package/docs/{v3-core-semantics.md → core-semantics.md} +5 -5
  137. package/docs/{v3-cutover.md → cutover.md} +4 -4
  138. package/docs/{v3-design.md → design.md} +11 -11
  139. package/docs/{v3-document-contract.md → document-contract.md} +9 -9
  140. package/docs/{v3-dryroom-profile-validation.md → dryroom-profile-validation.md} +4 -4
  141. package/docs/{v3-editor-integration.md → editor-integration.md} +6 -6
  142. package/docs/{v3-full-conveyor-validation.md → full-conveyor-validation.md} +4 -4
  143. package/docs/{v3-full-dryroom-validation.md → full-dryroom-validation.md} +4 -4
  144. package/docs/{v3-full-forklift-validation.md → full-forklift-validation.md} +5 -5
  145. package/docs/{v3-full-robot-validation.md → full-robot-validation.md} +4 -4
  146. package/docs/{v3-layout-system.md → layout-system.md} +4 -4
  147. package/docs/{v3-legacy-risk-audit-2026-09-23.md → legacy-risk-audit-2026-09-23.md} +5 -5
  148. package/docs/{v3-minimal-model.md → minimal-model.md} +6 -6
  149. package/docs/{v3-motion-contract.md → motion-contract.md} +3 -3
  150. package/docs/{v3-openusd-review.md → openusd-review.md} +8 -8
  151. package/docs/{v3-operator-contracts.md → operator-contracts.md} +6 -6
  152. package/docs/{v3-payload-collision-validation.md → payload-collision-validation.md} +4 -4
  153. package/docs/{v3-payload-contact-validation.md → payload-contact-validation.md} +5 -5
  154. package/docs/prototypes/README.md +10 -10
  155. package/docs/prototypes/{v3-asset-samples.mjs → asset-samples.mjs} +6 -6
  156. package/docs/prototypes/{v3-asset-store.mjs → asset-store.mjs} +3 -3
  157. package/docs/prototypes/{v3-asset-store.test.mjs → asset-store.test.mjs} +6 -6
  158. package/docs/prototypes/asset.mjs +1 -0
  159. package/docs/prototypes/{v3-asset.schema.json → asset.schema.json} +2 -2
  160. package/docs/prototypes/{v3-asset.test.mjs → asset.test.mjs} +10 -10
  161. package/docs/prototypes/authoring-session.mjs +1 -0
  162. package/docs/prototypes/{v3-authoring-session.test.mjs → authoring-session.test.mjs} +6 -6
  163. package/docs/prototypes/capability-plan.mjs +1 -0
  164. package/docs/prototypes/{v3-capability-plan.test.mjs → capability-plan.test.mjs} +5 -5
  165. package/docs/prototypes/{v3-capability-samples.mjs → capability-samples.mjs} +2 -2
  166. package/docs/prototypes/document.mjs +2 -0
  167. package/docs/prototypes/{v3-document.schema.json → document.schema.json} +1 -1
  168. package/docs/prototypes/{v3-document.test.mjs → document.test.mjs} +7 -7
  169. package/docs/prototypes/{v3-dryroom-mesh.mjs → dryroom-mesh.mjs} +1 -1
  170. package/docs/prototypes/{v3-dryroom-mesh.test.mjs → dryroom-mesh.test.mjs} +1 -1
  171. package/docs/prototypes/{v3-editor-browser.mjs → editor-browser.mjs} +13 -13
  172. package/docs/prototypes/editor-workspace.mjs +1 -0
  173. package/docs/prototypes/{v3-editor-workspace.test.mjs → editor-workspace.test.mjs} +3 -3
  174. package/docs/prototypes/{v3-feature-pattern.test.mjs → feature-pattern.test.mjs} +1 -1
  175. package/docs/prototypes/{v3-full-conveyor.mjs → full-conveyor.mjs} +2 -2
  176. package/docs/prototypes/{v3-full-conveyor.test.mjs → full-conveyor.test.mjs} +3 -3
  177. package/docs/prototypes/{v3-full-dryroom.mjs → full-dryroom.mjs} +2 -2
  178. package/docs/prototypes/{v3-full-dryroom.test.mjs → full-dryroom.test.mjs} +3 -3
  179. package/docs/prototypes/{v3-full-forklift.mjs → full-forklift.mjs} +2 -2
  180. package/docs/prototypes/{v3-full-forklift.test.mjs → full-forklift.test.mjs} +3 -3
  181. package/docs/prototypes/{v3-full-robot.mjs → full-robot.mjs} +2 -2
  182. package/docs/prototypes/{v3-full-robot.test.mjs → full-robot.test.mjs} +4 -4
  183. package/docs/prototypes/{v3-kernel.test.mjs → kernel.test.mjs} +1 -1
  184. package/docs/prototypes/{v3-layout.test.mjs → layout.test.mjs} +1 -1
  185. package/docs/prototypes/{v3-more-samples.test.mjs → more-samples.test.mjs} +2 -2
  186. package/docs/prototypes/{v3-payload-collision.mjs → payload-collision.mjs} +2 -2
  187. package/docs/prototypes/{v3-payload-collision.test.mjs → payload-collision.test.mjs} +3 -3
  188. package/docs/prototypes/{v3-payload-fit.mjs → payload-fit.mjs} +2 -2
  189. package/docs/prototypes/{v3-payload-fit.test.mjs → payload-fit.test.mjs} +4 -4
  190. package/docs/prototypes/render-full-dryroom.mjs +12 -12
  191. package/docs/prototypes/{v3-repeated-binding.mjs → repeated-binding.mjs} +1 -1
  192. package/docs/prototypes/{v3-repeated-binding.test.mjs → repeated-binding.test.mjs} +6 -6
  193. package/docs/prototypes/{v3-runtime-browser.mjs → runtime-browser.mjs} +26 -26
  194. package/docs/prototypes/{v3-samples.test.mjs → samples.test.mjs} +1 -1
  195. package/docs/prototypes/{v3-spatial-plan.test.mjs → spatial-plan.test.mjs} +1 -1
  196. package/docs/prototypes/typed-plan.mjs +3 -0
  197. package/docs/prototypes/{v3-typed-plan.test.mjs → typed-plan.test.mjs} +1 -1
  198. package/docs/prototypes/{v3-typed-repeat.test.mjs → typed-repeat.test.mjs} +2 -2
  199. package/docs/{v3-repeated-binding-validation.md → repeated-binding-validation.md} +4 -4
  200. package/docs/{v3-research-review.md → research-review.md} +2 -2
  201. package/docs/{v3-review-2026-09-22.md → review-2026-09-22.md} +10 -10
  202. package/docs/{v3-runtime-extraction.md → runtime-extraction.md} +16 -16
  203. package/docs/{v3-sample-validation-expanded.md → sample-validation-expanded.md} +5 -5
  204. package/docs/{v3-sample-validation.md → sample-validation.md} +3 -3
  205. package/docs/{v3-shape-dimension-contract.md → shape-dimension-contract.md} +12 -12
  206. package/docs/{v3-shapeassembly-reproduction.md → shapeassembly-reproduction.md} +4 -4
  207. package/docs/{v3-spatial-contracts.md → spatial-contracts.md} +5 -5
  208. package/docs/status.md +12 -0
  209. package/docs/{v3-storage-integration.md → storage-integration.md} +5 -5
  210. package/docs/{v3-typed-repeat-contracts.md → typed-repeat-contracts.md} +3 -3
  211. package/package.json +3 -3
  212. package/dist/v3-asset-types.d.ts.map +0 -1
  213. package/dist/v3-asset-types.js +0 -2
  214. package/dist/v3-asset-types.js.map +0 -1
  215. package/dist/v3-asset.d.ts +0 -8
  216. package/dist/v3-asset.d.ts.map +0 -1
  217. package/dist/v3-asset.js.map +0 -1
  218. package/dist/v3-authoring-actions.d.ts.map +0 -1
  219. package/dist/v3-authoring-actions.js.map +0 -1
  220. package/dist/v3-authoring-session.d.ts.map +0 -1
  221. package/dist/v3-authoring-session.js.map +0 -1
  222. package/dist/v3-capabilities.d.ts +0 -3
  223. package/dist/v3-capabilities.d.ts.map +0 -1
  224. package/dist/v3-capabilities.js.map +0 -1
  225. package/dist/v3-contract.d.ts +0 -7
  226. package/dist/v3-contract.d.ts.map +0 -1
  227. package/dist/v3-contract.js +0 -12
  228. package/dist/v3-contract.js.map +0 -1
  229. package/dist/v3-cost.d.ts.map +0 -1
  230. package/dist/v3-cost.js.map +0 -1
  231. package/dist/v3-create.js.map +0 -1
  232. package/dist/v3-document.d.ts +0 -5
  233. package/dist/v3-document.d.ts.map +0 -1
  234. package/dist/v3-document.js +0 -31
  235. package/dist/v3-document.js.map +0 -1
  236. package/dist/v3-driver.d.ts.map +0 -1
  237. package/dist/v3-driver.js.map +0 -1
  238. package/dist/v3-editor-workspace.d.ts.map +0 -1
  239. package/dist/v3-editor-workspace.js.map +0 -1
  240. package/dist/v3-examples.d.ts.map +0 -1
  241. package/dist/v3-examples.js.map +0 -1
  242. package/dist/v3-follow.d.ts.map +0 -1
  243. package/dist/v3-follow.js.map +0 -1
  244. package/dist/v3-gate.d.ts.map +0 -1
  245. package/dist/v3-gate.js.map +0 -1
  246. package/dist/v3-graph-types.d.ts.map +0 -1
  247. package/dist/v3-graph-types.js +0 -2
  248. package/dist/v3-graph-types.js.map +0 -1
  249. package/dist/v3-graph.d.ts.map +0 -1
  250. package/dist/v3-graph.js.map +0 -1
  251. package/dist/v3-instance-size.d.ts.map +0 -1
  252. package/dist/v3-instance-size.js.map +0 -1
  253. package/dist/v3-json.d.ts +0 -12
  254. package/dist/v3-json.d.ts.map +0 -1
  255. package/dist/v3-json.js.map +0 -1
  256. package/dist/v3-kernel-version.d.ts +0 -8
  257. package/dist/v3-kernel-version.d.ts.map +0 -1
  258. package/dist/v3-kernel-version.js.map +0 -1
  259. package/dist/v3-part-edit.d.ts.map +0 -1
  260. package/dist/v3-part-edit.js.map +0 -1
  261. package/dist/v3-proposal.d.ts +0 -42
  262. package/dist/v3-proposal.d.ts.map +0 -1
  263. package/dist/v3-proposal.js.map +0 -1
  264. package/dist/v3-public-inputs.d.ts.map +0 -1
  265. package/dist/v3-public-inputs.js.map +0 -1
  266. package/dist/v3-recipe-build.d.ts +0 -27
  267. package/dist/v3-recipe-build.d.ts.map +0 -1
  268. package/dist/v3-recipe-build.js.map +0 -1
  269. package/dist/v3-recipe-from-parts.d.ts +0 -8
  270. package/dist/v3-recipe-from-parts.d.ts.map +0 -1
  271. package/dist/v3-recipe-from-parts.js.map +0 -1
  272. package/dist/v3-recipe.d.ts.map +0 -1
  273. package/dist/v3-recipe.js.map +0 -1
  274. package/dist/v3-release-contract.d.ts +0 -19
  275. package/dist/v3-release-contract.d.ts.map +0 -1
  276. package/dist/v3-release-contract.js.map +0 -1
  277. package/dist/v3-render-batches.d.ts.map +0 -1
  278. package/dist/v3-render-batches.js.map +0 -1
  279. package/dist/v3-score.d.ts.map +0 -1
  280. package/dist/v3-score.js.map +0 -1
  281. package/dist/v3-shape-sampling.d.ts.map +0 -1
  282. package/dist/v3-shape-sampling.js.map +0 -1
  283. package/dist/v3-surface.d.ts.map +0 -1
  284. package/dist/v3-surface.js.map +0 -1
  285. package/dist/v3-words.d.ts.map +0 -1
  286. package/dist/v3-words.js.map +0 -1
  287. package/docs/prototypes/v3-asset.mjs +0 -1
  288. package/docs/prototypes/v3-authoring-session.mjs +0 -1
  289. package/docs/prototypes/v3-capability-plan.mjs +0 -1
  290. package/docs/prototypes/v3-document.mjs +0 -2
  291. package/docs/prototypes/v3-editor-workspace.mjs +0 -1
  292. package/docs/prototypes/v3-typed-plan.mjs +0 -3
  293. package/docs/v3-status.md +0 -50
  294. /package/docs/prototypes/{v3-kernel.mjs → kernel.mjs} +0 -0
  295. /package/docs/prototypes/{v3-linear-comparison.py → linear-comparison.py} +0 -0
  296. /package/docs/prototypes/{v3-semantics.test.mjs → semantics.test.mjs} +0 -0
@@ -1,18 +1,18 @@
1
1
  # V3 연산·형상 계약 — 첫 실행 가능한 subset
2
2
 
3
- > 현재 구현·검증·제품 연결 상태는 [V3 통합 현황](v3-status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
3
+ > 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
4
4
 
5
- 후속: [좌표계 타입과 공간 의존 그래프 통합](v3-spatial-contracts.md).
5
+ 후속: [좌표계 타입과 공간 의존 그래프 통합](spatial-contracts.md).
6
6
  아래는 최초 scalar 단계의 기록이며, 현재 확장 범위는 후속 문서를 따른다.
7
7
 
8
- [r3 핵심 의미론](v3-core-semantics.md)을 구현하는 첫 단계다.
8
+ [r3 핵심 의미론](core-semantics.md)을 구현하는 첫 단계다.
9
9
  상태: scalar 컴파일러 실험. 정식 V3 전체 schema나 제품 runtime이 아니다.
10
10
  시스템 설계 절차에 따라 정적 오류, 입력 의존 오류, 미지원 기능을 구분했다.
11
11
 
12
12
  ## 1. 실행 구조
13
13
 
14
- `docs/prototypes/v3-typed-plan.mjs`는 `compile(source)`와 그 결과의 `evaluate(inputs)`를 제공한다.
15
- 기존 무단위 `v3-kernel.mjs`와 독립이다. 아직 두 엔진을 연결하지 않았다.
14
+ `docs/prototypes/typed-plan.mjs`는 `compile(source)`와 그 결과의 `evaluate(inputs)`를 제공한다.
15
+ 기존 무단위 `kernel.mjs`와 독립이다. 아직 두 엔진을 연결하지 않았다.
16
16
 
17
17
  ```text
18
18
  저작 선언 → 구조/단위/출력 소유권/참조/cycle 검사 → 불변 snapshot 실행 계획
@@ -152,7 +152,7 @@ UI에서는 연산 id를 부품/의도 이름으로 연결하고 수정할 입
152
152
  ## 7. 실행 증거
153
153
 
154
154
  ```sh
155
- node --test docs/prototypes/v3-typed-plan.test.mjs
155
+ node --test docs/prototypes/typed-plan.test.mjs
156
156
  ```
157
157
 
158
158
  9개 검사 통과:
@@ -1,10 +1,10 @@
1
1
  # 적재물 대 모델 전체 부품 충돌 검사 — 실험 v1
2
2
 
3
- > 현재 구현·검증·제품 연결 상태는 [V3 통합 현황](v3-status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
3
+ > 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
4
4
 
5
5
  ## 범위
6
6
 
7
- [실행 코드](prototypes/v3-payload-collision.mjs)는 공간/접촉 검사 결과에 별도 collision 판정을 더한다. **현재 상태의 payload 대 모든 모델 부품**을 검사한다. 모델 부품 상호 간 충돌, 다른 외부 자산, 움직이는 경로 전체의 연속 충돌, 물리 안정성은 범위 밖이다. 따라서 '전역 충돌 완성'이라고 부르지 않는다.
7
+ [실행 코드](prototypes/payload-collision.mjs)는 공간/접촉 검사 결과에 별도 collision 판정을 더한다. **현재 상태의 payload 대 모든 모델 부품**을 검사한다. 모델 부품 상호 간 충돌, 다른 외부 자산, 움직이는 경로 전체의 연속 충돌, 물리 안정성은 범위 밖이다. 따라서 '전역 충돌 완성'이라고 부르지 않는다.
8
8
 
9
9
  접촉 대상으로 선언된 포크도 충돌 검사에서 제외하지 않는다. 면 접촉과 내부 관통을 구분한다. 기존 geometry·capability 선언·제품 서버는 바꾸지 않는다.
10
10
 
@@ -26,7 +26,7 @@ OBB(회전 상자) 간 정적 분리축 검사(SAT)를 사용한다. 양쪽 상
26
26
 
27
27
  ## 검증
28
28
 
29
- [테스트](prototypes/v3-payload-collision.test.mjs):
29
+ [테스트](prototypes/payload-collision.test.mjs):
30
30
 
31
31
  - 분리/접촉/관통/완전 포함, 허용 오차 경계, AABB가 겹치지만 OBB는 분리된 경우.
32
32
  - 일반적인 3D 회전의 결정적 난수 **1,000쌍**을 기존 Three.js OBB 구현과 대조: 교차174·분리826, 전부 일치. 두 구현은 같은 SAT 원리를 사용하므로 수학적 전 범위 증명이 아니다.
@@ -35,7 +35,7 @@ OBB(회전 상자) 간 정적 분리축 검사(SAT)를 사용한다. 양쪽 상
35
35
  - 둥근 본체의 경계 내부에 들어가는 작은 payload는 자동 통과하지 않고 미검증.
36
36
  - 잘못된 OBB·정규직교 위반과 거의 평행한 축의 수치 불확실성을 검증.
37
37
 
38
- Chrome에서 `--collision` 실험 화면으로 정상 배치·상단 포크 관통·공중 부유·둥근 본체 내부 배치를 직접 확인했다. 접촉과 충돌 결과를 따로 표시하며 관통한 box 부품을 붉게 표시한다. 작은 적재물이 불투명 본체 안에 가려지는 사례도 있으므로 스크린샷만으로 비충돌을 판정하지 않는다. 임시 이미지: `/private/tmp/figure-v3-full-collision.png`.
38
+ Chrome에서 `--collision` 실험 화면으로 정상 배치·상단 포크 관통·공중 부유·둥근 본체 내부 배치를 직접 확인했다. 접촉과 충돌 결과를 따로 표시하며 관통한 box 부품을 붉게 표시한다. 작은 적재물이 불투명 본체 안에 가려지는 사례도 있으므로 스크린샷만으로 비충돌을 판정하지 않는다. 임시 이미지: `/private/tmp/figure-full-collision.png`.
39
39
 
40
40
  ## 남은 구현
41
41
 
@@ -1,10 +1,10 @@
1
1
  # 적재물 공간·평면 접촉 검사 — 실험 v1
2
2
 
3
- > 현재 구현·검증·제품 연결 상태는 [V3 통합 현황](v3-status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
3
+ > 현재 구현·검증·제품 연결 상태는 [구현·검증 현황](status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
4
4
 
5
5
  ## 구현 범위
6
6
 
7
- [검사 코드](prototypes/v3-payload-fit.mjs)는 기존 capability compiler를 내부에서 실행한다. 외부에서 조작한 표면 결과를 받아 인증하지 않는다. 이번 단계에서 지원하는 것은 **상자 적재물 바닥과 box 부품의 top 평면**이다. 전체 물리·충돌·안전성 solver는 아니다.
7
+ [검사 코드](prototypes/payload-fit.mjs)는 기존 capability compiler를 내부에서 실행한다. 외부에서 조작한 표면 결과를 받아 인증하지 않는다. 이번 단계에서 지원하는 것은 **상자 적재물 바닥과 box 부품의 top 평면**이다. 전체 물리·충돌·안전성 solver는 아니다.
8
8
 
9
9
  입력은 binding ID, 물체 종류와 점유 snapshot, 양의 상자 치수(mm), binding 좌표계 기준 중심(mm), Y축 회전각(deg)이다. 기울어진 적재물, 임의 메시, 곡면 받침, 파지 접촉은 이 검사 범위 밖이다. 모든 추가 필드와 잘못된 값은 거부한다.
10
10
 
@@ -37,7 +37,7 @@ binding의 centered-box region이 있을 때만 검사한다. 회전된 payload
37
37
 
38
38
  ## 검증 결과
39
39
 
40
- [테스트](prototypes/v3-payload-fit.test.mjs):
40
+ [테스트](prototypes/payload-fit.test.mjs):
41
41
 
42
42
  - 포크 길이3 × 상승3 × 내밈3 × 적재물 yaw3 = **81개 상태**의 양쪽 포크 접촉.
43
43
  - 회전0에서는 포크 하나당 교차 면적 `90 × forkLength`mm²와 일치.
@@ -47,10 +47,10 @@ binding의 centered-box region이 있을 때만 검사한다. 회전된 payload
47
47
  - 충돌 가능성이 있는 높은 물체에서도 충돌/안전성은 미검증을 유지.
48
48
  - 입력 오류·모델 불변성·오류 후 재평가 검사.
49
49
 
50
- `node docs/prototypes/render-full-dryroom.mjs --payload`로 네 상태(정상 접촉·150mm 부유·20mm 관통·포크 사이)를 Chrome에서 렌더링하고 직접 확인했다. 임시 이미지: `/private/tmp/figure-v3-full-payload.png`. 제품 서버/DB의 실제 자산을 편집하지 않았다.
50
+ `node docs/prototypes/render-full-dryroom.mjs --payload`로 네 상태(정상 접촉·150mm 부유·20mm 관통·포크 사이)를 Chrome에서 렌더링하고 직접 확인했다. 임시 이미지: `/private/tmp/figure-full-payload.png`. 제품 서버/DB의 실제 자산을 편집하지 않았다.
51
51
 
52
52
  ## 다음 게이트
53
53
 
54
54
  이 접촉 검사기는 사각 평면과 상자만 대상으로 한다. 반복 요소의 표면 참조는 별도 모듈에서 구현했다. 곡면·rounded profile·임의 메시 및 부분 접촉 정책, 일반적인 전역 충돌·안정성, 제품 UI·AI·저장 통합은 남아 있다. 이 검사 결과만으로 '적재 가능'이나 '안전'으로 표시하면 안 된다.
55
55
 
56
- 후속 단계로 [payload 대 모든 부품의 충돌 검사](v3-payload-collision-validation.md)를 별도 추가했다. 상자 쌍은 정밀 OBB 검사, 곡면은 보수적 경계 검사 후 미검증으로 분리한다. 기존 접촉 검사기만 호출하면 충돌은 여전히 미검증이다.
56
+ 후속 단계로 [payload 대 모든 부품의 충돌 검사](payload-collision-validation.md)를 별도 추가했다. 상자 쌍은 정밀 OBB 검사, 곡면은 보수적 경계 검사 후 미검증으로 분리한다. 기존 접촉 검사기만 호출하면 충돌은 여전히 미검증이다.
@@ -1,22 +1,22 @@
1
1
  # v3 레이아웃 설계 검증 예제
2
2
 
3
- `node --test docs/prototypes/v3-typed-repeat.test.mjs`: 단위/좌표계 그래프와 반복 조립체 통합.
4
- [배치 의도 변경과 검증 한계](../v3-typed-repeat-contracts.md)를 함께 확인한다.
3
+ `node --test docs/prototypes/typed-repeat.test.mjs`: 단위/좌표계 그래프와 반복 조립체 통합.
4
+ [배치 의도 변경과 검증 한계](../typed-repeat-contracts.md)를 함께 확인한다.
5
5
 
6
- `node --test docs/prototypes/v3-typed-plan.test.mjs`: 단위가 있는 scalar 컴파일러.
7
- [연산·형상 계약과 미지원 범위](../v3-operator-contracts.md)를 참조한다.
6
+ `node --test docs/prototypes/typed-plan.test.mjs`: 단위가 있는 scalar 컴파일러.
7
+ [연산·형상 계약과 미지원 범위](../operator-contracts.md)를 참조한다.
8
8
 
9
- 현재 설계 방향: [r3 핵심 의미론](../v3-core-semantics.md).
10
- `node --test docs/prototypes/v3-semantics.test.mjs`는 부착식과 반복식을 독립 검사한다.
9
+ 현재 설계 방향: [r3 핵심 의미론](../core-semantics.md).
10
+ `node --test docs/prototypes/semantics.test.mjs`는 부착식과 반복식을 독립 검사한다.
11
11
  기존 커널을 r3에 맞게 구현했다는 의미가 아니다.
12
12
 
13
13
  ## 공통 커널 실험
14
14
 
15
- `node --test docs/prototypes/v3-kernel.test.mjs`
15
+ `node --test docs/prototypes/kernel.test.mjs`
16
16
 
17
17
  모델별 분기 없는 실행기와 실제 샘플에서 유도한 선언을 분리했다.
18
18
  범위·213개 크기/상태 조합·반례·미지원 항목은
19
- [공통 커널 실험 기록](../v3-common-kernel-experiment.md)을 따른다.
19
+ [공통 커널 실험 기록](../common-kernel-experiment.md)을 따른다.
20
20
  제품 v3 구현이나 전체 샘플 변환 완료가 아니다.
21
21
 
22
22
  ## 외부 연구 구현 probe
@@ -24,7 +24,7 @@
24
24
  `shapeassembly-probe.py`는 제품 코드가 아니라 외부 고정 revision의 interpreter 호출기다.
25
25
  외부 소스/라이브러리를 이 저장소에 포함하지 않는다. 단독 실행에는 별도의 연구용 checkout과
26
26
  가상환경이 필요하다. 입력·출력은 `shapeassembly-probe-results.json`, 해석·라이선스 경계·
27
- 재현 명령은 [실행 기록](../v3-shapeassembly-reproduction.md)을 따른다.
27
+ 재현 명령은 [실행 기록](../shapeassembly-reproduction.md)을 따른다.
28
28
 
29
29
  아래 내용은 그와 별개인 자체 r1 수치 예제다.
30
30
 
@@ -32,7 +32,7 @@
32
32
  package.json, 의존성, 서버, 소비자 runtime을 변경하지 않는다.
33
33
 
34
34
  ```sh
35
- node --test docs/prototypes/v3-layout.test.mjs
35
+ node --test docs/prototypes/layout.test.mjs
36
36
  ```
37
37
 
38
38
  2026-09-20 실행 결과: 18개 테스트 통과.
@@ -1,15 +1,15 @@
1
- import * as dryroom from './v3-full-dryroom.mjs'
2
- import * as conveyor from './v3-full-conveyor.mjs'
3
- import * as robot from './v3-full-robot.mjs'
4
- import * as forklift from './v3-full-forklift.mjs'
5
- import {robotBinding,forkliftBindings} from './v3-capability-samples.mjs'
1
+ import * as dryroom from './full-dryroom.mjs'
2
+ import * as conveyor from './full-conveyor.mjs'
3
+ import * as robot from './full-robot.mjs'
4
+ import * as forklift from './full-forklift.mjs'
5
+ import {robotBinding,forkliftBindings} from './capability-samples.mjs'
6
6
  export function sampleAsset(kind){
7
7
  const modules={dryroom,conveyor,robot,forklift},sample=modules[kind]
8
8
  if(!sample)throw Error('unknown sample')
9
9
  const pair=kind==='robot'?robotBinding():kind==='forklift'?forkliftBindings():{model:sample.fullModel(),declaration:{version:'r3-capability-3',assetFrame:'world',bindings:[]}}
10
10
  const designInputs={},stateDefaults={}
11
11
  for(const i of pair.model.inputs)(i.role==='state'?stateDefaults:designInputs)[i.id]=sample.defaults[i.id]
12
- return {version:'figure-v3-asset-1',name:sample.seed.type,document:{version:'figure-v3-prototype-1',model:pair.model,capabilities:pair.declaration},designInputs,stateDefaults,
12
+ return {version:'figure-asset-1',name:sample.seed.type,document:{version:'figure-prototype-1',model:pair.model,capabilities:pair.declaration},designInputs,stateDefaults,
13
13
  palette:{'palette.primary':'#154473','palette.accent':'#f79c40','palette.neutral':'#96989b','palette.dark':'#27292c','palette.light':'#d6d7d9','palette.surface':'#56585b','palette.status-danger':'#f61b30','palette.status-warning':'#e68d1a','palette.status-info':'#158bde','palette.status-success':'#1cb648'},
14
14
  appearance:sample.seed.parts.map(p=>({target:p.name,material:structuredClone(p.material??{token:'palette.neutral'}),...(p.primitive==='cylinder'?{segments:p.segments??8}:{}),...(p.capability?{legacyCapability:structuredClone(p.capability)}:{})}))}
15
15
  }
@@ -2,7 +2,7 @@
2
2
  import {readFile, open, rename, unlink} from 'node:fs/promises'
3
3
  import {join, resolve} from 'node:path'
4
4
  import {randomUUID, createHash} from 'node:crypto'
5
- import {parseAsset, serializeAsset} from './v3-asset.mjs'
5
+ import {parseAsset, serializeAsset} from './asset.mjs'
6
6
 
7
7
  export class StoreError extends Error {
8
8
  constructor(code,message){super(message);this.code=code}
@@ -24,7 +24,7 @@ export function createAssetStore(directory){
24
24
  async function load(path,scope,id){
25
25
  let raw;try{raw=await readFile(path,'utf8')}catch(e){if(e.code==='ENOENT')return null;throw e}
26
26
  let record;try{record=JSON.parse(raw)}catch{fail('CORRUPT','stored record is not JSON')}
27
- if(record?.format!=='v3-store-experiment-1'||record.scope!==scope||record.id!==id||typeof record.revision!=='string'||!record.revision)fail('CORRUPT','stored record identity or revision invalid')
27
+ if(record?.format!=='store-experiment-1'||record.scope!==scope||record.id!==id||typeof record.revision!=='string'||!record.revision)fail('CORRUPT','stored record identity or revision invalid')
28
28
  // Stored content must pass the same semantic validation as incoming content.
29
29
  parseAsset(record.text)
30
30
  return record
@@ -37,7 +37,7 @@ export function createAssetStore(directory){
37
37
  return exclusive(path,async()=>{
38
38
  const current=await load(path,scope,id)
39
39
  if((current?.revision??null)!==expectedRevision)fail('CONFLICT','asset changed; reload before saving')
40
- const record={format:'v3-store-experiment-1',scope,id,revision:randomUUID(),text:canonical}
40
+ const record={format:'store-experiment-1',scope,id,revision:randomUUID(),text:canonical}
41
41
  const temporary=path+'.'+randomUUID()+'.tmp';let handle
42
42
  try{
43
43
  handle=await open(temporary,'wx',0o600);await handle.writeFile(JSON.stringify(record));await handle.sync();await handle.close();handle=null
@@ -5,11 +5,11 @@ import {tmpdir} from 'node:os'
5
5
  import {join} from 'node:path'
6
6
  import {execFile} from 'node:child_process'
7
7
  import {promisify} from 'node:util'
8
- import {createAssetStore} from './v3-asset-store.mjs'
9
- import {sampleAsset} from './v3-asset-samples.mjs'
10
- import {serializeAsset,parseAsset} from './v3-asset.mjs'
11
- import {createEditorWorkspace} from './v3-editor-workspace.mjs'
12
- async function fixture(t){const dir=await mkdtemp(join(tmpdir(),'v3-store-'));t.after(()=>rm(dir,{recursive:true,force:true}));return {dir,store:createAssetStore(dir)}}
8
+ import {createAssetStore} from './asset-store.mjs'
9
+ import {sampleAsset} from './asset-samples.mjs'
10
+ import {serializeAsset,parseAsset} from './asset.mjs'
11
+ import {createEditorWorkspace} from './editor-workspace.mjs'
12
+ async function fixture(t){const dir=await mkdtemp(join(tmpdir(),'store-'));t.after(()=>rm(dir,{recursive:true,force:true}));return {dir,store:createAssetStore(dir)}}
13
13
  const body=()=>serializeAsset(sampleAsset('forklift'))
14
14
  const key={scope:'test-domain',id:'forklift'}
15
15
  test('disk save survives independent store handle; explicit create and scoped identity',async t=>{
@@ -51,7 +51,7 @@ test('failed persistence does not clear editor dirty state',async t=>{
51
51
  test('a separate Node process can restore the saved asset without editor memory',async t=>{
52
52
  const {dir,store}=await fixture(t),asset=parseAsset(body());asset.designInputs.forkLength=1275
53
53
  const saved=await store.save({...key,expectedRevision:null,text:serializeAsset(asset)})
54
- const script=`import {createAssetStore} from ${JSON.stringify(new URL('./v3-asset-store.mjs',import.meta.url).href)};
54
+ const script=`import {createAssetStore} from ${JSON.stringify(new URL('./asset-store.mjs',import.meta.url).href)};
55
55
  const record=await createAssetStore(process.argv[1]).read(${JSON.stringify(key)});
56
56
  console.log(JSON.stringify({revision:record.revision,length:JSON.parse(record.text).designInputs.forkLength}));`
57
57
  const {stdout}=await promisify(execFile)(process.execPath,['--input-type=module','-e',script,dir])
@@ -0,0 +1 @@
1
+ export {compileFigureAsset as compileAsset,parseFigureAsset as parseAsset,serializeFigureAsset as serializeAsset,captureFigureAuthoredInputs as captureAuthoredInputs} from '../../src/asset.ts'
@@ -4,9 +4,9 @@
4
4
  "type": "object", "additionalProperties": false,
5
5
  "required": ["version", "name", "document", "designInputs", "stateDefaults", "palette", "appearance"],
6
6
  "properties": {
7
- "version": {"const": "figure-v3-asset-1"},
7
+ "version": {"const": "figure-asset-1"},
8
8
  "name": {"type": "string", "minLength": 1},
9
- "document": {"$ref": "v3-document.schema.json"},
9
+ "document": {"$ref": "document.schema.json"},
10
10
  "designInputs": {"type": "object", "additionalProperties": {"type": "number"}},
11
11
  "stateDefaults": {"type": "object", "additionalProperties": {"type": "number"}},
12
12
  "palette": {"type": "object", "additionalProperties": {"type": "string", "pattern": "^#[0-9a-fA-F]{6}$"}},
@@ -1,12 +1,12 @@
1
1
  import {test} from 'node:test'
2
2
  import assert from 'node:assert/strict'
3
- import {compileAsset,serializeAsset,parseAsset,captureAuthoredInputs} from './v3-asset.mjs'
4
- import {sampleAsset} from './v3-asset-samples.mjs'
5
- import {createAuthoringSession} from './v3-authoring-session.mjs'
6
- import * as dryroom from './v3-full-dryroom.mjs'
7
- import * as conveyor from './v3-full-conveyor.mjs'
8
- import * as robot from './v3-full-robot.mjs'
9
- import * as forklift from './v3-full-forklift.mjs'
3
+ import {compileAsset,serializeAsset,parseAsset,captureAuthoredInputs} from './asset.mjs'
4
+ import {sampleAsset} from './asset-samples.mjs'
5
+ import {createAuthoringSession} from './authoring-session.mjs'
6
+ import * as dryroom from './full-dryroom.mjs'
7
+ import * as conveyor from './full-conveyor.mjs'
8
+ import * as robot from './full-robot.mjs'
9
+ import * as forklift from './full-forklift.mjs'
10
10
  import fs from 'node:fs/promises'
11
11
  import os from 'node:os'
12
12
  import path from 'node:path'
@@ -55,9 +55,9 @@ test('asset parser retains duplicate-key and invalid JSON protections',()=>{
55
55
  const a=sampleAsset('forklift');a.stateDefaults.lift=NaN;assert.throws(()=>serializeAsset(a),e=>e.code==='JSON_VALUE')
56
56
  })
57
57
  test('schema validation and real temporary JSON file round-trip, without seed lookups on reload',async()=>{
58
- const ajv=new Ajv({allErrors:true});ajv.addSchema(JSON.parse(await fs.readFile(new URL('./v3-document.schema.json',import.meta.url))),'v3-document.schema.json')
59
- const validate=ajv.compile(JSON.parse(await fs.readFile(new URL('./v3-asset.schema.json',import.meta.url))))
60
- const directory=await fs.mkdtemp(path.join(os.tmpdir(),'figure-v3-asset-'))
58
+ const ajv=new Ajv({allErrors:true});ajv.addSchema(JSON.parse(await fs.readFile(new URL('./document.schema.json',import.meta.url))),'document.schema.json')
59
+ const validate=ajv.compile(JSON.parse(await fs.readFile(new URL('./asset.schema.json',import.meta.url))))
60
+ const directory=await fs.mkdtemp(path.join(os.tmpdir(),'figure-asset-'))
61
61
  try{
62
62
  for(const kind of Object.keys(samples)){
63
63
  const asset=sampleAsset(kind);assert.ok(validate(asset),JSON.stringify(validate.errors))
@@ -0,0 +1 @@
1
+ export {createFigureAuthoringSession as createAuthoringSession} from '../../src/authoring-session.ts'
@@ -1,11 +1,11 @@
1
1
  import {test} from 'node:test'
2
2
  import assert from 'node:assert/strict'
3
- import {createAuthoringSession} from './v3-authoring-session.mjs'
4
- import {repeatedBinding} from './v3-repeated-binding.mjs'
5
- import {forkliftBindings} from './v3-capability-samples.mjs'
6
- import {defaults as conveyorDefaults} from './v3-full-conveyor.mjs'
7
- import {defaults as forkliftDefaults} from './v3-full-forklift.mjs'
8
- const doc=s=>({version:'figure-v3-prototype-1',model:s.model,capabilities:s.declaration})
3
+ import {createAuthoringSession} from './authoring-session.mjs'
4
+ import {repeatedBinding} from './repeated-binding.mjs'
5
+ import {forkliftBindings} from './capability-samples.mjs'
6
+ import {defaults as conveyorDefaults} from './full-conveyor.mjs'
7
+ import {defaults as forkliftDefaults} from './full-forklift.mjs'
8
+ const doc=s=>({version:'figure-prototype-1',model:s.model,capabilities:s.declaration})
9
9
  const edit=(input,value,unit='mm',kind='set-design')=>({kind,input,value,unit})
10
10
  const request=(changes,expectedRevision=0,origin='ui')=>({origin,expectedRevision,changes})
11
11
  const session=()=>createAuthoringSession(doc(repeatedBinding()),{...conveyorDefaults,selectedIndex:13})
@@ -0,0 +1 @@
1
+ export {compileFigureCapabilities as compileCapabilities} from '../../src/capabilities.ts'
@@ -1,10 +1,10 @@
1
1
  import {test} from 'node:test'
2
2
  import assert from 'node:assert/strict'
3
- import {compileCapabilities} from './v3-capability-plan.mjs'
4
- import {robotBinding,forkliftBindings} from './v3-capability-samples.mjs'
5
- import {defaults as robotDefaults} from './v3-full-robot.mjs'
6
- import {defaults as forkDefaults} from './v3-full-forklift.mjs'
7
- import {compile} from './v3-typed-plan.mjs'
3
+ import {compileCapabilities} from './capability-plan.mjs'
4
+ import {robotBinding,forkliftBindings} from './capability-samples.mjs'
5
+ import {defaults as robotDefaults} from './full-robot.mjs'
6
+ import {defaults as forkDefaults} from './full-forklift.mjs'
7
+ import {compile} from './typed-plan.mjs'
8
8
  const near=(a,b)=>assert.ok(Math.abs(a-b)<1e-7)
9
9
  const run=s=>compileCapabilities(s.model,s.declaration)
10
10
  test('robot grip follows changing links and six joints without creating or hiding solids',()=>{
@@ -1,5 +1,5 @@
1
- import {fullModel as robotModel} from './v3-full-robot.mjs'
2
- import {fullModel as forkliftModel} from './v3-full-forklift.mjs'
1
+ import {fullModel as robotModel} from './full-robot.mjs'
2
+ import {fullModel as forkliftModel} from './full-forklift.mjs'
3
3
  export function robotBinding(){
4
4
  const model=robotModel()
5
5
  // Explicit experimental grip reference. Original tool-seat solid is NOT removed.
@@ -0,0 +1,2 @@
1
+ export {compileFigureDocument as compileDocument,parseFigureDocument as parseDocument,serializeFigureDocument as serializeDocument} from '../../src/document.ts'
2
+ export {assertFigureJson as jsonOnly,parseFigureJson as parseStrictJson,FIGURE_JSON_MAX_BYTES as MAX_BYTES,figureUtf8ByteLength} from '../../src/json.ts'
@@ -5,7 +5,7 @@
5
5
  "additionalProperties": false,
6
6
  "required": ["version", "model", "capabilities"],
7
7
  "properties": {
8
- "version": {"const": "figure-v3-prototype-1"},
8
+ "version": {"const": "figure-prototype-1"},
9
9
  "model": {"$ref": "#/$defs/model"},
10
10
  "capabilities": {"$ref": "#/$defs/capabilities"}
11
11
  },
@@ -2,13 +2,13 @@ import {test} from 'node:test'
2
2
  import assert from 'node:assert/strict'
3
3
  import fs from 'node:fs'
4
4
  import Ajv from '../../../things-factory/node_modules/ajv/lib/ajv.js'
5
- import {compileDocument,serializeDocument,parseDocument,MAX_BYTES} from './v3-document.mjs'
6
- import {compileCapabilities} from './v3-capability-plan.mjs'
7
- import {forkliftBindings,robotBinding} from './v3-capability-samples.mjs'
8
- import {defaults as forkDefaults} from './v3-full-forklift.mjs'
9
- import {defaults as robotDefaults} from './v3-full-robot.mjs'
10
- const envelope=s=>({version:'figure-v3-prototype-1',model:s.model,capabilities:s.declaration})
11
- const schema=JSON.parse(fs.readFileSync(new URL('./v3-document.schema.json',import.meta.url)))
5
+ import {compileDocument,serializeDocument,parseDocument,MAX_BYTES} from './document.mjs'
6
+ import {compileCapabilities} from './capability-plan.mjs'
7
+ import {forkliftBindings,robotBinding} from './capability-samples.mjs'
8
+ import {defaults as forkDefaults} from './full-forklift.mjs'
9
+ import {defaults as robotDefaults} from './full-robot.mjs'
10
+ const envelope=s=>({version:'figure-prototype-1',model:s.model,capabilities:s.declaration})
11
+ const schema=JSON.parse(fs.readFileSync(new URL('./document.schema.json',import.meta.url)))
12
12
  const validate=new Ajv({allErrors:true}).compile(schema)
13
13
  test('JSON Schema and semantic compiler: serialize/parse/recompile both complete models',()=>{
14
14
  for(const [sample,args] of [[forkliftBindings(),{...forkDefaults,lift:1000,reach:200}],[robotBinding(),{...robotDefaults,'shoulder-lift':40}]]){
@@ -2,7 +2,7 @@
2
2
  import fs from 'node:fs'
3
3
  import {fileURLToPath} from 'node:url'
4
4
  import * as THREE from '../../../things-scene/node_modules/three/build/three.module.js'
5
- import {compile} from './v3-typed-plan.mjs'
5
+ import {compile} from './typed-plan.mjs'
6
6
  export const seed=JSON.parse(fs.readFileSync(new URL('../../../operato-application/packages/operato-figure/server/seed/figure-samples.json',import.meta.url))).find(s=>s.type==='DRY_ROOM').source
7
7
  const c=(id,value,unit='mm')=>({id,value,unit})
8
8
  const n=(id,op,args,outputs,params)=>({id,op,args,outputs,...(params?{params}:{})})
@@ -1,6 +1,6 @@
1
1
  import {test} from 'node:test'
2
2
  import assert from 'node:assert/strict'
3
- import {evaluatePortal,meshOf,meshAudit,rayHit,seed} from './v3-dryroom-mesh.mjs'
3
+ import {evaluatePortal,meshOf,meshAudit,rayHit,seed} from './dryroom-mesh.mjs'
4
4
  const near=(a,b)=>assert.ok(Math.abs(a-b)<1e-5,`${a} != ${b}`)
5
5
  test('both actual portal profiles: baseline matches seed, bottom trim preserves top/opening/lamp',()=>{
6
6
  for(const name of ['portal-in','portal-out']){
@@ -6,14 +6,14 @@ import {join} from 'node:path'
6
6
  import {randomUUID} from 'node:crypto'
7
7
  import {chromium} from '/Users/super/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules/playwright/index.mjs'
8
8
  import assert from 'node:assert/strict'
9
- import {createEditorWorkspace} from './v3-editor-workspace.mjs'
10
- import {sampleAsset} from './v3-asset-samples.mjs'
11
- import {serializeAsset} from './v3-asset.mjs'
12
- import {createV3Asset} from '../../src/v3-create.ts'
13
- import {createAssetStore} from './v3-asset-store.mjs'
14
- import {geometryOf as ordinary} from './v3-full-conveyor.mjs'
15
- import {geometryOf as portal} from './v3-full-dryroom.mjs'
16
- const directory=await mkdtemp(join(tmpdir(),'v3-editor-store-'))
9
+ import {createEditorWorkspace} from './editor-workspace.mjs'
10
+ import {sampleAsset} from './asset-samples.mjs'
11
+ import {serializeAsset} from './asset.mjs'
12
+ import {createFigureAsset} from '../../src/create.ts'
13
+ import {createAssetStore} from './asset-store.mjs'
14
+ import {geometryOf as ordinary} from './full-conveyor.mjs'
15
+ import {geometryOf as portal} from './full-dryroom.mjs'
16
+ const directory=await mkdtemp(join(tmpdir(),'editor-store-'))
17
17
  const store=createAssetStore(directory),workspace=createEditorWorkspace();let saved=null,storage=null
18
18
  const view=()=>{const v=workspace.read();return {...v,render:v.geometry.map(g=>{const mesh=(g.shape.provider==='portal'?portal:ordinary)(g);const json=mesh.toJSON();mesh.dispose();return {id:g.id,geometry:json,material:g.material}})}}
19
19
  const html=`<!doctype html><meta charset="utf-8"><title>V3 편집 연결 검증</title>
@@ -49,7 +49,7 @@ const server=createServer(async(req,res)=>{try{
49
49
  let body='';for await(const chunk of req){body+=chunk;if(body.length>20000)throw Error('request too large')}
50
50
  const q=JSON.parse(body)
51
51
  if(q.action==='open'){workspace.open(serializeAsset(sampleAsset(q.kind)));storage={scope:'isolated-browser',id:randomUUID(),expectedRevision:null}}
52
- else if(q.action==='new'){workspace.open(serializeAsset(createV3Asset('새 Figure')));storage={scope:'isolated-browser',id:randomUUID(),expectedRevision:null}}
52
+ else if(q.action==='new'){workspace.open(serializeAsset(createFigureAsset('새 Figure')));storage={scope:'isolated-browser',id:randomUUID(),expectedRevision:null}}
53
53
  else if(q.action==='add'){const id='box'+(workspace.read().revision+1);workspace.addBox({context:q.context,origin:'ui',expectedRevision:q.revision,box:{id,size:{x:800,y:1000,z:600},position:{x:0,y:500,z:0}}})}
54
54
  else if(q.action==='redo')workspace.redo({context:q.context,origin:'ui',expectedRevision:q.revision})
55
55
  else if(q.action==='apply')workspace.apply(q.request)
@@ -74,12 +74,12 @@ try{
74
74
  await page.locator('#forkLength').fill('1275');await page.locator('button[data-input="forkLength"]').click();await page.waitForFunction(()=>lastView.revision===1)
75
75
  assert.equal(await page.evaluate(()=>lastView.geometry.find(g=>g.id==='fork-low-left').shape.dimensions.depth),1275)
76
76
  await page.locator('#save').click();await page.waitForFunction(()=>!lastView.dirty)
77
- await page.screenshot({path:'/private/tmp/figure-v3-editor.png',fullPage:true})
77
+ await page.screenshot({path:'/private/tmp/figure-editor.png',fullPage:true})
78
78
  await page.locator('#model').selectOption('robot');await page.locator('#open').click();await page.waitForFunction(()=>window.meshCount===10)
79
79
  const stale=await page.evaluate(async old=>{const r=await fetch('/api',{method:'POST',body:JSON.stringify({action:'apply',request:{context:old.context,expectedRevision:0,origin:'ai',changes:[{kind:'set-design',input:'forkLength',unit:'mm',value:1500}]}})});return r.json()},old);assert.match(stale.error,/CONTEXT_CONFLICT/)
80
80
  await page.locator('#reload').click();await page.waitForFunction(()=>window.meshCount===20);assert.equal(await page.locator('#forkLength').inputValue(),'1275')
81
81
  await page.locator('#close').click();await page.waitForFunction(()=>window.meshCount===0);assert.equal(await page.locator('#fields input').count(),0)
82
- await page.screenshot({path:'/private/tmp/figure-v3-editor-empty.png',fullPage:true})
82
+ await page.screenshot({path:'/private/tmp/figure-editor-empty.png',fullPage:true})
83
83
  await page.locator('#new').click();await page.waitForFunction(()=>lastView.name==='새 Figure'&&meshCount===0)
84
84
  await page.locator('#add').click();await page.waitForFunction(()=>meshCount===1&&lastView.dirty)
85
85
  await page.locator('[id="box1.size.y"]').fill('1500');await page.locator('button[data-input="box1.size.y"]').click();await page.waitForFunction(()=>lastView.revision===2)
@@ -91,7 +91,7 @@ try{
91
91
  await page.locator('#save').click();await page.waitForFunction(()=>!lastView.dirty)
92
92
  await page.locator('#reload').click();await page.waitForFunction(()=>lastView.revision===0)
93
93
  assert.equal(await page.locator('[id="box1.size.y"]').inputValue(),'1500')
94
- await page.screenshot({path:'/private/tmp/figure-v3-new-authoring.png',fullPage:true})
94
+ await page.screenshot({path:'/private/tmp/figure-new-authoring.png',fullPage:true})
95
95
  console.log('new empty asset -> add box -> edit -> undo edit -> undo creation -> redo both -> disk save/reload: passed')
96
- assert.deepEqual(errors,[]);console.log(JSON.stringify({checks:['open asset','edit changes actual rendered geometry','save through HTTP to disk','switch 20 meshes to 10 without leftovers','reject stale AI context','reload edited design from independent disk store handle','close clears meshes and fields'],pageErrors:errors,screenshot:'/private/tmp/figure-v3-editor.png'},null,2))
96
+ assert.deepEqual(errors,[]);console.log(JSON.stringify({checks:['open asset','edit changes actual rendered geometry','save through HTTP to disk','switch 20 meshes to 10 without leftovers','reject stale AI context','reload edited design from independent disk store handle','close clears meshes and fields'],pageErrors:errors,screenshot:'/private/tmp/figure-editor.png'},null,2))
97
97
  }finally{await browser?.close();await new Promise(r=>server.close(r));await rm(directory,{recursive:true,force:true})}
@@ -0,0 +1 @@
1
+ export {createFigureEditorWorkspace as createEditorWorkspace} from '../../src/editor-workspace.ts'
@@ -1,8 +1,8 @@
1
1
  import {test} from 'node:test'
2
2
  import assert from 'node:assert/strict'
3
- import {createEditorWorkspace} from './v3-editor-workspace.mjs'
4
- import {sampleAsset} from './v3-asset-samples.mjs'
5
- import {serializeAsset} from './v3-asset.mjs'
3
+ import {createEditorWorkspace} from './editor-workspace.mjs'
4
+ import {sampleAsset} from './asset-samples.mjs'
5
+ import {serializeAsset} from './asset.mjs'
6
6
  const text=kind=>serializeAsset(sampleAsset(kind))
7
7
  const edit=(view,id,value,kind='set-design')=>({context:view.context,origin:'ui',expectedRevision:view.revision,changes:[{kind,input:id,value,unit:'mm'}]})
8
8
  test('saved asset opens with fields/render appearance; edits and undo share the same session',()=>{
@@ -1,7 +1,7 @@
1
1
  import fs from 'node:fs'
2
2
  import assert from 'node:assert/strict'
3
3
  import {test} from 'node:test'
4
- import {resolve,point,DesignError} from './v3-kernel.mjs'
4
+ import {resolve,point,DesignError} from './kernel.mjs'
5
5
 
6
6
  const seeds=JSON.parse(fs.readFileSync(new URL('../../../operato-application/packages/operato-figure/server/seed/figure-samples.json',import.meta.url)))
7
7
  const src=t=>seeds.find(s=>s.type===t).source
@@ -1,6 +1,6 @@
1
1
  import fs from 'node:fs'
2
- import {compile} from './v3-typed-plan.mjs'
3
- import {THREE,rounded} from './v3-full-dryroom.mjs'
2
+ import {compile} from './typed-plan.mjs'
3
+ import {THREE,rounded} from './full-dryroom.mjs'
4
4
  export const seed=JSON.parse(fs.readFileSync(new URL('../../../operato-application/packages/operato-figure/server/seed/figure-samples.json',import.meta.url))).find(s=>s.type==='CONVEYOR').source
5
5
  export const defaults={length:2400,width:600,rollerHeight:500,angle:0}
6
6
  export function fullModel(){
@@ -1,8 +1,8 @@
1
1
  import {test} from 'node:test'
2
2
  import assert from 'node:assert/strict'
3
- import {seed,defaults,fullModel,evaluateFull,geometryOf,sourceGeometry} from './v3-full-conveyor.mjs'
4
- import {compile} from './v3-typed-plan.mjs'
5
- import {meshAudit} from './v3-dryroom-mesh.mjs'
3
+ import {seed,defaults,fullModel,evaluateFull,geometryOf,sourceGeometry} from './full-conveyor.mjs'
4
+ import {compile} from './typed-plan.mjs'
5
+ import {meshAudit} from './dryroom-mesh.mjs'
6
6
  const near=(a,b)=>assert.ok(Math.abs(a-b)<.001,`${a} != ${b}`)
7
7
  const vertices=g=>{const a=g.attributes.position;return Array.from({length:a.count},(_,i)=>[a.getX(i),a.getY(i),a.getZ(i)])}
8
8
  const deviation=(a,b)=>Math.max(...a.map(p=>Math.min(...b.map(q=>Math.hypot(...p.map((v,i)=>v-q[i]))))))
@@ -1,6 +1,6 @@
1
1
  import * as THREE from '../../../things-scene/node_modules/three/build/three.module.js'
2
- import {seed} from './v3-dryroom-mesh.mjs'
3
- import {compile} from './v3-typed-plan.mjs'
2
+ import {seed} from './dryroom-mesh.mjs'
3
+ import {compile} from './typed-plan.mjs'
4
4
  export {seed,THREE}
5
5
  const c=(id,value,unit='mm')=>({id,value,unit})
6
6
  const n=(id,op,args,outputs,params)=>({id,op,args,outputs,...(params?{params}:{})})
@@ -1,9 +1,9 @@
1
1
  import assert from 'node:assert/strict'
2
2
  import {test} from 'node:test'
3
3
  import {performance} from 'node:perf_hooks'
4
- import {fullModel,evaluateFull,geometryOf,sourceGeometry,seed,defaults} from './v3-full-dryroom.mjs'
5
- import {compile} from './v3-typed-plan.mjs'
6
- import {meshAudit} from './v3-dryroom-mesh.mjs'
4
+ import {fullModel,evaluateFull,geometryOf,sourceGeometry,seed,defaults} from './full-dryroom.mjs'
5
+ import {compile} from './typed-plan.mjs'
6
+ import {meshAudit} from './dryroom-mesh.mjs'
7
7
  const near=(a,b,tol=1e-3)=>assert.ok(Math.abs(a-b)<tol,`${a} != ${b}`)
8
8
  const vertices=g=>{const a=g.attributes.position;return Array.from({length:a.count},(_,i)=>[a.getX(i),a.getY(i),a.getZ(i)])}
9
9
  function deviation(a,b){return Math.max(...a.map(p=>Math.min(...b.map(q=>Math.hypot(...p.map((x,i)=>x-q[i]))))))}
@@ -1,6 +1,6 @@
1
1
  import fs from 'node:fs'
2
- import {compile} from './v3-typed-plan.mjs'
3
- import {geometryOf,sourceGeometry as primitiveGeometry} from './v3-full-conveyor.mjs'
2
+ import {compile} from './typed-plan.mjs'
3
+ import {geometryOf,sourceGeometry as primitiveGeometry} from './full-conveyor.mjs'
4
4
  export {geometryOf}
5
5
  export const seed=JSON.parse(fs.readFileSync(new URL('../../../operato-application/packages/operato-figure/server/seed/figure-samples.json',import.meta.url))).find(s=>s.type==='FORKLIFT').source
6
6
  export const defaults={forkLength:850,lift:0,reach:0,drive:0}
@@ -1,8 +1,8 @@
1
1
  import {test} from 'node:test'
2
2
  import assert from 'node:assert/strict'
3
- import {seed,defaults,fullModel,evaluateFull,geometryOf,sourceGeometry} from './v3-full-forklift.mjs'
4
- import {compile} from './v3-typed-plan.mjs'
5
- import {meshAudit} from './v3-dryroom-mesh.mjs'
3
+ import {seed,defaults,fullModel,evaluateFull,geometryOf,sourceGeometry} from './full-forklift.mjs'
4
+ import {compile} from './typed-plan.mjs'
5
+ import {meshAudit} from './dryroom-mesh.mjs'
6
6
  const near=(a,b,tol=1e-6)=>assert.ok(Math.abs(a-b)<tol,`${a} != ${b}`)
7
7
  const vertices=g=>{const a=g.attributes.position;return Array.from({length:a.count},(_,i)=>[a.getX(i),a.getY(i),a.getZ(i)])}
8
8
  const deviation=(a,b)=>Math.max(...a.map(p=>Math.min(...b.map(q=>Math.hypot(...p.map((v,i)=>v-q[i]))))))
@@ -1,6 +1,6 @@
1
1
  import fs from 'node:fs'
2
- import {compile} from './v3-typed-plan.mjs'
3
- import {geometryOf,sourceGeometry as primitiveGeometry} from './v3-full-conveyor.mjs'
2
+ import {compile} from './typed-plan.mjs'
3
+ import {geometryOf,sourceGeometry as primitiveGeometry} from './full-conveyor.mjs'
4
4
  export {geometryOf}
5
5
  export const seed=JSON.parse(fs.readFileSync(new URL('../../src/fixtures/robot-arm-6dof.json',import.meta.url)))
6
6
  export const defaults={upperLength:420,foreLength:380,gripper:0,...Object.fromEntries(seed.joints.map(j=>[j.name,0]))}
@@ -1,9 +1,9 @@
1
1
  import {test} from 'node:test'
2
2
  import assert from 'node:assert/strict'
3
- import {seed,defaults,fullModel,evaluateFull,geometryOf,sourceGeometry} from './v3-full-robot.mjs'
4
- import {THREE} from './v3-full-dryroom.mjs'
5
- import {compile} from './v3-typed-plan.mjs'
6
- import {meshAudit} from './v3-dryroom-mesh.mjs'
3
+ import {seed,defaults,fullModel,evaluateFull,geometryOf,sourceGeometry} from './full-robot.mjs'
4
+ import {THREE} from './full-dryroom.mjs'
5
+ import {compile} from './typed-plan.mjs'
6
+ import {meshAudit} from './dryroom-mesh.mjs'
7
7
  const near=(a,b,tol=1e-7)=>assert.ok(Math.abs(a-b)<tol,`${a} != ${b}`)
8
8
  const vec=(a,b)=>a.forEach((v,i)=>near(v,b[i]))
9
9
  const vertices=g=>{const a=g.attributes.position;return Array.from({length:a.count},(_,i)=>[a.getX(i),a.getY(i),a.getZ(i)])}
@@ -1,7 +1,7 @@
1
1
  import fs from 'node:fs'
2
2
  import assert from 'node:assert/strict'
3
3
  import {test} from 'node:test'
4
- import {resolve,point,DesignError} from './v3-kernel.mjs'
4
+ import {resolve,point,DesignError} from './kernel.mjs'
5
5
 
6
6
  const seeds=JSON.parse(fs.readFileSync(new URL('../../../operato-application/packages/operato-figure/server/seed/figure-samples.json',import.meta.url)))
7
7
  const robot=JSON.parse(fs.readFileSync(new URL('../../src/fixtures/robot-arm-6dof.json',import.meta.url)))
@@ -1,4 +1,4 @@
1
- // Design witnesses only. Not imported by production; not a complete v3 evaluator.
1
+ // Design witnesses only. Not imported by production; not a complete evaluator.
2
2
  import test from 'node:test'
3
3
  import assert from 'node:assert/strict'
4
4