@hatiolab/figure-model 0.1.76 โ†’ 0.1.77

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 (135) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/README.md +60 -138
  3. package/dist/index.d.ts +1 -13
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.js +3 -26
  6. package/dist/index.js.map +1 -1
  7. package/dist/v3-asset-types.d.ts +1 -2
  8. package/dist/v3-asset-types.d.ts.map +1 -1
  9. package/dist/v3-asset.js +1 -1
  10. package/dist/v3-asset.js.map +1 -1
  11. package/dist/v3-authoring-actions.d.ts +9 -12
  12. package/dist/v3-authoring-actions.d.ts.map +1 -1
  13. package/dist/v3-authoring-actions.js +4 -5
  14. package/dist/v3-authoring-actions.js.map +1 -1
  15. package/dist/v3-capabilities.js +4 -1
  16. package/dist/v3-capabilities.js.map +1 -1
  17. package/dist/v3-cost.d.ts.map +1 -1
  18. package/dist/v3-cost.js +3 -5
  19. package/dist/v3-cost.js.map +1 -1
  20. package/dist/v3-create.d.ts +1 -1
  21. package/dist/v3-create.d.ts.map +1 -1
  22. package/dist/v3-examples.js +1 -1
  23. package/dist/v3-gate.d.ts +7 -8
  24. package/dist/v3-gate.d.ts.map +1 -1
  25. package/dist/v3-gate.js +11 -14
  26. package/dist/v3-gate.js.map +1 -1
  27. package/dist/v3-graph.d.ts +1 -2
  28. package/dist/v3-graph.d.ts.map +1 -1
  29. package/dist/v3-graph.js +5 -7
  30. package/dist/v3-graph.js.map +1 -1
  31. package/dist/v3-instance-size.d.ts +3 -5
  32. package/dist/v3-instance-size.d.ts.map +1 -1
  33. package/dist/v3-instance-size.js +2 -4
  34. package/dist/v3-instance-size.js.map +1 -1
  35. package/dist/v3-kernel-version.d.ts +1 -1
  36. package/dist/v3-kernel-version.js +1 -1
  37. package/dist/v3-part-edit.d.ts +4 -5
  38. package/dist/v3-part-edit.d.ts.map +1 -1
  39. package/dist/v3-part-edit.js +2 -2
  40. package/dist/v3-part-edit.js.map +1 -1
  41. package/dist/v3-proposal.js +1 -1
  42. package/dist/v3-proposal.js.map +1 -1
  43. package/dist/v3-release-contract.js +1 -1
  44. package/dist/v3-release-contract.js.map +1 -1
  45. package/dist/v3-score.d.ts +4 -5
  46. package/dist/v3-score.d.ts.map +1 -1
  47. package/dist/v3-score.js +7 -8
  48. package/dist/v3-score.js.map +1 -1
  49. package/dist/v3-words.d.ts +87 -0
  50. package/dist/v3-words.d.ts.map +1 -0
  51. package/dist/v3-words.js +87 -0
  52. package/dist/v3-words.js.map +1 -0
  53. package/docs/assembly-constraints-v3.md +13 -23
  54. package/docs/v3-asset-persistence.md +4 -4
  55. package/docs/v3-common-kernel-experiment.md +1 -1
  56. package/docs/v3-core-semantics.md +3 -3
  57. package/docs/v3-cutover.md +5 -3
  58. package/docs/v3-design.md +13 -26
  59. package/docs/v3-editor-integration.md +2 -2
  60. package/docs/v3-full-conveyor-validation.md +3 -3
  61. package/docs/v3-layout-system.md +1 -1
  62. package/docs/v3-minimal-model.md +0 -1
  63. package/docs/v3-motion-contract.md +21 -56
  64. package/docs/v3-runtime-extraction.md +7 -7
  65. package/docs/v3-sample-validation-expanded.md +1 -1
  66. package/docs/v3-sample-validation.md +1 -1
  67. package/docs/v3-shape-dimension-contract.md +23 -57
  68. package/docs/v3-status.md +5 -5
  69. package/docs/v3-storage-integration.md +4 -4
  70. package/package.json +2 -20
  71. package/dist/blueprint-shape.d.ts +0 -10
  72. package/dist/blueprint-shape.d.ts.map +0 -1
  73. package/dist/blueprint-shape.js +0 -194
  74. package/dist/blueprint-shape.js.map +0 -1
  75. package/dist/blueprint.d.ts +0 -73
  76. package/dist/blueprint.d.ts.map +0 -1
  77. package/dist/blueprint.js +0 -388
  78. package/dist/blueprint.js.map +0 -1
  79. package/dist/cost-chart.d.ts +0 -35
  80. package/dist/cost-chart.d.ts.map +0 -1
  81. package/dist/cost-chart.js +0 -150
  82. package/dist/cost-chart.js.map +0 -1
  83. package/dist/cost.d.ts +0 -162
  84. package/dist/cost.d.ts.map +0 -1
  85. package/dist/cost.js +0 -194
  86. package/dist/cost.js.map +0 -1
  87. package/dist/gate.d.ts +0 -65
  88. package/dist/gate.d.ts.map +0 -1
  89. package/dist/gate.js +0 -284
  90. package/dist/gate.js.map +0 -1
  91. package/dist/grouping.d.ts +0 -121
  92. package/dist/grouping.d.ts.map +0 -1
  93. package/dist/grouping.js +0 -224
  94. package/dist/grouping.js.map +0 -1
  95. package/dist/keys.d.ts +0 -45
  96. package/dist/keys.d.ts.map +0 -1
  97. package/dist/keys.js +0 -84
  98. package/dist/keys.js.map +0 -1
  99. package/dist/origin.d.ts +0 -33
  100. package/dist/origin.d.ts.map +0 -1
  101. package/dist/origin.js +0 -46
  102. package/dist/origin.js.map +0 -1
  103. package/dist/release-contract.d.ts +0 -38
  104. package/dist/release-contract.d.ts.map +0 -1
  105. package/dist/release-contract.js +0 -246
  106. package/dist/release-contract.js.map +0 -1
  107. package/dist/sizing.d.ts +0 -231
  108. package/dist/sizing.d.ts.map +0 -1
  109. package/dist/sizing.js +0 -550
  110. package/dist/sizing.js.map +0 -1
  111. package/dist/types.d.ts +0 -1233
  112. package/dist/types.d.ts.map +0 -1
  113. package/dist/types.js +0 -547
  114. package/dist/types.js.map +0 -1
  115. package/dist/v3-from-v2.d.ts +0 -203
  116. package/dist/v3-from-v2.d.ts.map +0 -1
  117. package/dist/v3-from-v2.js +0 -2053
  118. package/dist/v3-from-v2.js.map +0 -1
  119. package/dist/v3-mesh-compare.d.ts +0 -24
  120. package/dist/v3-mesh-compare.d.ts.map +0 -1
  121. package/dist/v3-mesh-compare.js +0 -55
  122. package/dist/v3-mesh-compare.js.map +0 -1
  123. package/dist/validate.d.ts +0 -7
  124. package/dist/validate.d.ts.map +0 -1
  125. package/dist/validate.js +0 -1119
  126. package/dist/validate.js.map +0 -1
  127. package/dist/visual-evidence.d.ts +0 -21
  128. package/dist/visual-evidence.d.ts.map +0 -1
  129. package/dist/visual-evidence.js +0 -52
  130. package/dist/visual-evidence.js.map +0 -1
  131. package/docs/design.md +0 -193
  132. package/docs/format-survey.md +0 -108
  133. package/docs/format.md +0 -704
  134. package/docs/sizing.md +0 -183
  135. package/docs/validation.md +0 -357
@@ -11,13 +11,13 @@
11
11
  - ๋ธŒ๋ผ์šฐ์ €: `node docs/prototypes/render-full-dryroom.mjs --conveyor`
12
12
  - ์ „์ฒด ํ…Œ์ŠคํŠธ: `node --test docs/prototypes/v3-*.test.mjs`
13
13
 
14
- ## V2์™€ ์˜๋„์ ์œผ๋กœ ๋‹ฌ๋ผ์ง„ ์ 
14
+ ## ๋ ๋กค๋Ÿฌ ๊ณต๊ฐ„์„ ๋จผ์ € ํ™•๋ณดํ•˜๋Š” ์ด์œ 
15
15
 
16
- ๊ธฐ๋ณธ ๊ธธ์ด 2,400mm์—์„œ V2 ๋ฐ˜๋ณต ๊ณต์‹์€ ์ผ๋ฐ˜ ๋กค๋Ÿฌ 16๊ฐœ๋ฅผ ์ค‘์‹ฌ ๊ฐ„๊ฒฉ 150mm๋กœ ์ƒ์„ฑํ•œ๋‹ค. ์–‘ ๋ ์ผ๋ฐ˜ ๋กค๋Ÿฌ ์ค‘์‹ฌ์€ ยฑ1,125mm์ด๋ฉฐ, ๋ณ„๋„์˜ ๊ตต์€ ๋ ๋กค๋Ÿฌ ์ค‘์‹ฌ์€ ยฑ1,140mm๋‹ค.
16
+ ๋ ๊ณต๊ฐ„์„ ๋”ฐ๋กœ ๋‘์ง€ ์•Š๊ณ  ์ผ๋ฐ˜ ๋กค๋Ÿฌ๋ฅผ ์ค‘์‹ฌ ๊ฐ„๊ฒฉ 150mm๋กœ ๊ธธ์ด ์ „์ฒด์— ๊น”๋ฉด, ๊ธฐ๋ณธ ๊ธธ์ด 2,400mm์—์„œ ์ผ๋ฐ˜ ๋กค๋Ÿฌ๋Š” 16๊ฐœ๋‹ค. ์–‘ ๋ ์ผ๋ฐ˜ ๋กค๋Ÿฌ ์ค‘์‹ฌ์€ ยฑ1,125mm์ด๋ฉฐ, ๋ณ„๋„์˜ ๊ตต์€ ๋ ๋กค๋Ÿฌ ์ค‘์‹ฌ์€ ยฑ1,140mm๋‹ค.
17
17
 
18
18
  ์ผ๋ฐ˜ ๋กค๋Ÿฌ ๋ฐ˜์ง€๋ฆ„ 48mm, ๋ ๋กค๋Ÿฌ ๋ฐ˜์ง€๋ฆ„ 75mm์ด๊ณ  ์ค‘์‹ฌ ๊ฑฐ๋ฆฌ๋Š” 15mm์ด๋ฏ€๋กœ, `15 + 48 < 75`๋‹ค. ์ผ๋ฐ˜ ๋กค๋Ÿฌ ๊ธธ์ด 520mm๋„ ๋ ๋กค๋Ÿฌ ๊ธธ์ด 560mm๋ณด๋‹ค ์ž‘๋‹ค. ์ฆ‰ **์ผ๋ฐ˜ ๋กค๋Ÿฌ ๋‘ ๊ฐœ๊ฐ€ ๋ ๋กค๋Ÿฌ ๋‚ด๋ถ€์— ์™„์ „ํžˆ ๋ฌปํžŒ๋‹ค.** ์ถ• ๋ฐฉํ–ฅ ํšŒ์ „์œผ๋กœ ์ด ๋ฌธ์ œ๋Š” ํ•ด๊ฒฐ๋˜์ง€ ์•Š๋Š”๋‹ค.
19
19
 
20
- V3๋Š” ์–‘์ชฝ ๋ ๊ณต๊ฐ„์„ ๋จผ์ € ํ™•๋ณดํ•œ๋‹ค.
20
+ ๊ทธ๋ž˜์„œ ์–‘์ชฝ ๋ ๊ณต๊ฐ„์„ ๋จผ์ € ํ™•๋ณดํ•œ๋‹ค.
21
21
 
22
22
  ```
23
23
  ๋ ์—ฌ๋ฐฑ = ๋ ๋กค๋Ÿฌ ์ค‘์‹ฌ์˜ ๊ฐ€์žฅ์ž๋ฆฌ ๊ฑฐ๋ฆฌ 60 + ๋ฐ˜์ง€๋ฆ„ 75 + ์ตœ์†Œ ๊ฐ„๊ฒฉ 10 = 145mm
@@ -302,7 +302,7 @@ AI: ๋™์ผ typed transaction, sourceHash ์‚ฌ์ „์กฐ๊ฑด, atomic apply, undo, ๋ณ€
302
302
  | L1 production kernel | schema/DAG/measure/allocate/arrange | cycle, writer, NaN, overflow, ๊ฒฐ์ •์„ฑ, fuzz |
303
303
  | L2 geometry/motion | ๋ชจ๋“  ์ง€์› primitive์˜ ์น˜์ˆ˜ยทfeature ๊ณ„์•ฝ | bounds/๊ฐœ๊ตฌ๋ถ€/normal, shear, pose ํ•ฉ์„ฑ |
304
304
  | L3 modeller | ๊ณ„์ธต ํŽธ์ง‘ยท๋ฏธ๋ฆฌ๋ณด๊ธฐยทundoยทAI transaction | ์›ํด๋ฆญ ํŽธ์ง‘, ๋™์‹œ ๋ณ€๊ฒฝ, ์˜ค๋ฅ˜ ๋ณต๊ตฌ E2E |
305
- | L4 consumer/์ „ํ™˜ | v2โ†’v3 ํ›„๋ณด, 2D/3D ๊ณตํ†ต ๊ฒฐ๊ณผ | ์‹ค์ œ ๋“œ๋ผ์ด๋ฃธ/๋กค ํ”„๋ ˆ์Šค, ํšŒ๊ท€ ์Šค๋ƒ…์ƒท |
305
+ | L4 consumer | 2D/3D ๊ณตํ†ต ๊ฒฐ๊ณผ | ์‹ค์ œ ๋“œ๋ผ์ด๋ฃธ/๋กค ํ”„๋ ˆ์Šค, ํšŒ๊ท€ ์Šค๋ƒ…์ƒท |
306
306
  | L5 ๋น„์šฉ/๋ฒ”์œ„ | 1/100/500 instance, ๋ฒ”์œ„ ๊ฒ€์ฆ | p95ยทdraw callยท๋ฉ”๋ชจ๋ฆฌ ์‹ค์ธก, ์ฆ๋ช… ๋ถ„๋ฅ˜ |
307
307
 
308
308
  r1์€ ๋ ˆ์ด์•„์›ƒ ๊ทœ์น™์˜ ๊ฒ€ํ†  ๊ฐ€๋Šฅํ•œ ๊ธฐ์ค€์•ˆ์ด๋‹ค. ์ „์ฒด v3 ์ถœํ•˜ ๋ช…์„ธ/๊ตฌํ˜„์ด ๋๋‚ฌ๋‹ค๋Š” ๋œป์ด ์•„๋‹ˆ๋‹ค.
@@ -234,7 +234,6 @@ UI๋Š” ์›์ธ ์ž…๋ ฅ์„ ์ˆ˜์ •ํ•˜๋Š” ํ›„๋ณด๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์ง€๋งŒ evaluator๊ฐ€
234
234
  - ๊ฐ’ DAG/feature frame์€ ๋ฐ˜๋“œ์‹œ scene node๋กœ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค. compile์—์„œ ์ •๋ฆฌํ•œ๋‹ค.
235
235
  - compile์€ ์ €์ž‘ ๋ณ€๊ฒฝ, dimension resolve๋Š” ํฌ๊ธฐ ๋ณ€๊ฒฝ, pose๋Š” ์ƒํƒœ ๋ณ€๊ฒฝ ๋•Œ ์ˆ˜ํ–‰ํ•œ๋‹ค.
236
236
  - ๋™์ผ ์น˜์ˆ˜/์žฌ์งˆ/์šด๋™์˜ ๋ณ‘ํ•ฉยท๊ณต์œ  ๊ฐ€๋Šฅ์„ฑ์„ ์‹ค์ œ renderer์—์„œ ์ธก์ •ํ•œ๋‹ค.
237
- - v2โ†’v3 ๋ณ€ํ™˜์€ ์›๋ณธ ๋ณด์กด, id/์™ธ๋ถ€ binding ๋Œ€์‘, ์™ธํ˜• ์ฐจ๋ถ„, ์˜๋„ ์„ ํƒ์„ ํฌํ•จํ•œ๋‹ค.
238
237
  - ์ƒˆ Figure๋Š” ๋…๋ฆฝ ์ƒํƒœ์—์„œ ์‹œ์ž‘ํ•˜๊ณ  ์‹คํŒจํ•œ ํ›„๋ณด๋Š” ๊ธฐ์กด ์žฅ๋ฉด์— ๋ง๋ถ™์ด์ง€ ์•Š๋Š”๋‹ค.
239
238
  - typed edit๋Š” sourceHash ๊ฒ€์‚ฌ, ์›์ž ์ ์šฉ, undo, ์žฌ์†ก์‹  ๋ฉฑ๋“ฑ์„ฑ์„ ๊ฐ–์ถ˜๋‹ค.
240
239
  - ๋ฐœํ–‰ ์ •์ฑ…์€ invalid / assertion violation / unverified / advisory๋ฅผ ๊ตฌ๋ณ„ํ•œ๋‹ค.
@@ -2,12 +2,8 @@
2
2
 
3
3
  Status: **contract, fixed 2026-09-22; revised the same day after the chief architect's review; implemented the
4
4
  same day** (ADR-0087 decision 2, ruling 4). Implementation: `src/v3-graph.ts` (`axis-turn@1`, `axis-slide@1`),
5
- `src/v3-driver.ts` (`driverValue`, `driverStates`, `validateV3Drivers`), the motion part of `src/v3-from-v2.ts`
6
- (`planMotion`), tests in `src/v3-motion.test.ts`. The converter and every consumer use this contract; none of them
7
- defines motion on its own. Not yet covered by the converter: prismatic joints (none in the live assets; V2 scaled
8
- their travel by the instance, the contract does not), scale channels (refused as shape deformation), a rotation
9
- channel with a pivot off the part centre, channels that vary more than one axis, and parameter curves other than
10
- two linear keys. The review changed three things: the direction of every transform is written down, continuous
5
+ `src/v3-driver.ts` (`driverValue`, `driverStates`, `validateV3Drivers`), tests in `src/v3-motion.test.ts`. Every
6
+ consumer uses this contract; none of them defines motion on its own. The review changed three things: the direction of every transform is written down, continuous
11
7
  rotation is split into an accumulated amount and a phase, and drivers carry an explicit time convention.
12
8
 
13
9
  ## What a person sees
@@ -19,7 +15,7 @@ moves. Setting the value back to its default puts the arm exactly where it was d
19
15
 
20
16
  On a board, the same arm has the same six values. A connector writes them; the arm follows. Stretching the arm's
21
17
  instance size does not change where its joints turn: a joint sits on the part that carries it and moves with that
22
- part under sizing, as ADR-0066 decision 3 already says for V2.
18
+ part under sizing.
23
19
 
24
20
  ## One rule for how a child moves, with every direction written down
25
21
 
@@ -37,15 +33,15 @@ part under sizing, as ADR-0066 decision 3 already says for V2.
37
33
  - `jointParent` and `jointChild` are two named frames per joint, `<joint>.onParent` and `<joint>.onChild`. They
38
34
  **coincide at `q = 0`**: `motion(0)` is the identity, and the two frames are placed so that the child then sits in
39
35
  its rest pose.
40
- - A part with no joint to its parent has `motion = identity` (V2 `FigurePart.parent` without a joint).
41
- - The parent and child joint frames come from the rest pose and sizing (`jointOriginPosition`), so a joint moves
36
+ - A part with no joint to its parent has `motion = identity`.
37
+ - The parent and child joint frames come from the rest pose and sizing, so a joint moves
42
38
  with the part that carries it when the instance is resized.
43
39
  - `attach@1` already computes `A ร— O ร— inverse(B)`, and its type checker refuses a chain whose frames do not meet.
44
40
  No parent-chain node is added; `compose@1` and `attach@1` are enough.
45
41
 
46
- **`q = 0` is the rest pose. That is not the same claim as "the default is the rest pose."** A V2 parameter whose
47
- default is not 0 drew its rest pose at that default. The converter keeps V2's meaning: the joint frames are placed
48
- for the drawn pose, and the state default stays what V2 stored. It never subtracts the default or forces it to 0.
42
+ **`q = 0` is the rest pose. That is not the same claim as "the default is the rest pose."** A state input's default
43
+ may be non-zero. The joint frames are placed for the pose at `q = 0`, and the state default is stored as authored;
44
+ nothing subtracts the default or forces it to 0.
49
45
 
50
46
  ## Joint kinds, their state input, and the two motion operators
51
47
 
@@ -64,10 +60,10 @@ axis-slide@1 args [ax, ay, az (ratio), q (length)] params { from, to }
64
60
  - An arbitrary axis is carried as three numbers and turned with axisโ€“angle. It is **never** collapsed into one
65
61
  Euler component.
66
62
 
67
- | V2 `FigureJoint.type` | state input | unit stored | `motion(q)` |
63
+ | joint type | state input | unit stored | `motion(q)` |
68
64
  |---|---|---|---|
69
- | `revolute` | one angle, `role: 'state'`, V2 limits as range | rad (an input may declare `deg`; the kernel converts) | `axis-turn@1` |
70
- | `prismatic` | one length, `role: 'state'`, V2 limits as range | mm | `axis-slide@1` |
65
+ | `revolute` | one angle, `role: 'state'`, joint limits as range | rad (an input may declare `deg`; the kernel converts) | `axis-turn@1` |
66
+ | `prismatic` | one length, `role: 'state'`, joint limits as range | mm | `axis-slide@1` |
71
67
  | `continuous` | one **phase** angle, `role: 'state'`, range `[โˆ’180ยฐ, 180ยฐ)` | rad | `axis-turn@1` |
72
68
 
73
69
  ### Continuous rotation: an amount and a phase, not a limit
@@ -86,16 +82,15 @@ values first would interpolate 350 โ†’ 10 and turn the wrong way. Widening the r
86
82
 
87
83
  ## Parameters
88
84
 
89
- A V2 `FigureParameter` keeps its **name, unit, range, default and target**. In V3 it is the state input itself:
90
- `id` = the parameter name, `unit` and `min`/`max` from the range, `role: 'state'`, and the asset's `stateDefaults`
91
- carries the default as V2 stored it. Its target is the joint (or part channel) whose `motion(q)` reads it. A
92
- parameter that V2 let drive several joints becomes one input read by several `axis-turn@1` nodes: one writer, many
93
- readers, which the graph already allows.
85
+ A parameter is a state input: `id` is its name, `unit` and `min`/`max` give its range, `role: 'state'`, and the
86
+ asset's `stateDefaults` carries its default. Its target is the joint (or part channel) whose `motion(q)` reads it. A
87
+ parameter that drives several joints is one input read by several `axis-turn@1` nodes: one writer, many readers,
88
+ which the graph already allows.
94
89
 
95
90
  ## Drivers: the asset declares, figure-model evaluates, the consumer owns time
96
91
 
97
- The kernel has **no clock**. Same inputs, same result, always. A V2 `AnimationClip` becomes a **driver**
98
- declaration on the asset, not a graph node. Responsibilities:
92
+ The kernel has **no clock**. Same inputs, same result, always. An animation is a **driver** declaration on the asset,
93
+ not a graph node. Responsibilities:
99
94
 
100
95
  | who | does |
101
96
  |---|---|
@@ -119,9 +114,7 @@ drivers: [{
119
114
  ```
120
115
 
121
116
  - **Time convention, one for all drivers.** `time.unit` is seconds; `duration` is the clip length in seconds; every
122
- key `at` is a fraction of the duration in `[0, 1]`. The converter normalises V2's two habits (seconds in
123
- `duration`, fractions in `at`, ADR-0051 โ‘ก) into exactly this and records the source form in the report. A driver
124
- with a missing or non-positive duration is refused.
117
+ key `at` is a fraction of the duration in `[0, 1]`. A driver with a missing or non-positive duration is refused.
125
118
  - **Loop end.** `wrap`: time `t` maps to `t mod duration`, and the sample at `duration` equals the sample at 0 (the
126
119
  last key's value is reached at `at = 1` and the next period starts from key 0). For an accumulating driver, wrapping
127
120
  adds the full-period delta to the accumulated value, so the roller keeps turning rather than snapping back.
@@ -131,45 +124,17 @@ drivers: [{
131
124
  source per state** explicitly (`driver` or `external`). Values are never summed and "last call wins" is not a
132
125
  rule. figure-model's validation refuses two drivers naming the same state.
133
126
 
134
- A V2 part channel (`path: 'rotation'` on a part with no joint, like the conveyor roller) converts to a continuous
135
- state input on that part, `<part>.spin`, driving an `axis-turn@1` about the part's own axis, and a driver for the
136
- clip with `accumulates: true`. The conveyor's rotation animation is therefore carried, not lost.
137
-
138
- ## What the converter does with the seven motion assets
139
-
140
- 1. For every `FigureJoint`: two joint frames from the rest pose and sizing, one state input, one `axis-turn@1` or
141
- `axis-slide@1`, one `attach@1`, and the child's `place@1` reads the attached pose.
142
- 2. For every part with `parent` and no joint: `compose@1` of the parent's pose and the rigid offset.
143
- 3. For every `parameter`: a state input as above; refuse (`PARAMETER_TARGET`) if its target is not a joint or a part
144
- channel this contract covers.
145
- 4. For every animation clip: a driver, with the clip's channels mapped to state inputs; refuse
146
- (`ANIMATION_CHANNEL`) for a channel path this contract does not cover (`scale`).
127
+ A part that spins without a joint (the conveyor roller) has a continuous state input on that part, `<part>.spin`,
128
+ driving an `axis-turn@1` about the part's own axis, and a driver with `accumulates: true`.
147
129
 
148
130
  ## Two corrections to earlier wording
149
131
 
150
132
  - **Rigid does not mean affine in the state.** A rigid pose is affine in the spatial coordinates it maps, but a
151
133
  rotation matrix is a sin/cos function of the joint angle. So `axis-turn@1` is **not affine in `q`**, and the
152
134
  operator-list guard is restated: `geomean@1` is the only node that is non-affine in the *design inputs*;
153
- `axis-turn@1` is non-affine in a *state input*. The 8-size comparison therefore stays a limited regression check for
154
- the rest pose and does not become a proof of equivalence under motion.
135
+ `axis-turn@1` is non-affine in a *state input*.
155
136
  - **Rotation is compared as a relative angle**, the angle of `Rโ‚‚ ยท Rโ‚แต€`, never as a difference of Euler components.
156
137
 
157
- ## "The same" for motion (completion criterion)
158
-
159
- For every converted motion asset, V2 and V3 are compared at the base size and the doubled sizes with:
160
-
161
- - each joint at its default, its mid-point and both limits;
162
- - **parent and child joints changed at the same time**, not one at a time;
163
- - at least one joint with an arbitrary (non-principal) axis;
164
- - a non-zero default, checked at the default and away from it;
165
- - a continuous joint just before and just after the phase boundary (e.g. 179ยฐ and 181ยฐ);
166
- - a looping driver just before and just after the loop end (e.g. 0.99 and 1.01 durations), and a `hold` driver past
167
- its end.
168
-
169
- Same part list, same centre and extents within 1 mm, same relative rotation within 0.1ยฐ. For each driver, the state
170
- value at time 0, half and end must equal V2's clip value at those times. Exact conversion and deliberate
171
- re-authoring are marked separately in the report.
172
-
173
138
  ## Not in this contract
174
139
 
175
140
  - Inverse kinematics, reach checks, collision between links. Consumers may add them on top; the kernel does not.
@@ -2,11 +2,11 @@
2
2
 
3
3
  > ํ˜„์žฌ ๊ตฌํ˜„ยท๊ฒ€์ฆยท์ œํ’ˆ ์—ฐ๊ฒฐ ์ƒํƒœ๋Š” [V3 ํ†ตํ•ฉ ํ˜„ํ™ฉ](v3-status.md)์„ ๋”ฐ๋ฅธ๋‹ค. ๋ณธ๋ฌธ์˜ ๋‹จ๊ณ„๋ณ„ ์—ฐ๊ตฌ/๊ฒ€์ฆ ๊ธฐ๋ก์€ ์ œํ’ˆ ์ „์ฒด ์™„๋ฃŒ ์„ ์–ธ์ด ์•„๋‹ˆ๋‹ค.
4
4
 
5
- > ์ตœ์‹  ์ž‘์—… ๊ธฐ์ค€: [V3 ๋‹จ์ผ ์ฒด๊ณ„ ์ „ํ™˜](v3-cutover.md). ์•„๋ž˜์˜ V2 ์œ ์ง€ ๋ฐ ๋ฒ„์ „๋ณ„ ์ œํ’ˆ ์—ฐ๊ฒฐ ๋ฐฉํ–ฅ์€ ๊ณผ๊ฑฐ ์ž‘์—… ๊ธฐ๋ก์ด๋ฉฐ, ํ–ฅํ›„ ์„ค๊ณ„ ์กฐ๊ฑด์—์„œ ์ œ์™ธํ•œ๋‹ค.
5
+ > ์ตœ์‹  ์ž‘์—… ๊ธฐ์ค€: [V3 ๋‹จ์ผ ์ฒด๊ณ„ ์ „ํ™˜](v3-cutover.md). ์•„๋ž˜์˜ ๋ฒ„์ „๋ณ„ ์ œํ’ˆ ์—ฐ๊ฒฐ ๋ฐฉํ–ฅ์€ ๊ณผ๊ฑฐ ์ž‘์—… ๊ธฐ๋ก์ด๋ฉฐ, ํ–ฅํ›„ ์„ค๊ณ„ ์กฐ๊ฑด์—์„œ ์ œ์™ธํ•œ๋‹ค.
6
6
 
7
7
  ## ์ด๋ฒˆ ์ด๊ด€ ๋ฒ”์œ„
8
8
 
9
- ์‹คํ—˜์šฉ JSON ์ž…๋ ฅ ๊ฒ€์‚ฌ์™€ ์˜ค๋ฅ˜ ๊ณ„์•ฝ์„ `src/v3-json.ts`, `src/v3-contract.ts`์˜ strict TypeScript ์†Œ์Šค๋กœ ์˜ฎ๊ฒผ๋‹ค. ๊ธฐ๋ณธ ๋นŒ๋“œ์—์„œ JSยทํƒ€์ž… ์„ ์–ธ์„ ์ƒ์„ฑํ•˜๋ฉฐ ๊ธฐ์กด package ๋ฃจํŠธ์—์„œ ์ด๋ฆ„์ด ๊ตฌ๋ถ„๋œ API๋กœ ๋‚ด๋ณด๋‚ธ๋‹ค. package.jsonยท์˜์กด์„ฑยทV2 validate/compile ๊ตฌํ˜„์€ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์•˜๋‹ค.
9
+ ์‹คํ—˜์šฉ JSON ์ž…๋ ฅ ๊ฒ€์‚ฌ์™€ ์˜ค๋ฅ˜ ๊ณ„์•ฝ์„ `src/v3-json.ts`, `src/v3-contract.ts`์˜ strict TypeScript ์†Œ์Šค๋กœ ์˜ฎ๊ฒผ๋‹ค. ๊ธฐ๋ณธ ๋นŒ๋“œ์—์„œ JSยทํƒ€์ž… ์„ ์–ธ์„ ์ƒ์„ฑํ•˜๋ฉฐ ๊ธฐ์กด package ๋ฃจํŠธ์—์„œ ์ด๋ฆ„์ด ๊ตฌ๋ถ„๋œ API๋กœ ๋‚ด๋ณด๋‚ธ๋‹ค. package.jsonยท์˜์กด์„ฑ์€ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์•˜๋‹ค.
10
10
 
11
11
  | ๊ณต๊ฐœ API | ์ฑ…์ž„ |
12
12
  |---|---|
@@ -15,7 +15,7 @@
15
15
  | v3Utf8ByteLength | ๋ธŒ๋ผ์šฐ์ €์™€ ์„œ๋ฒ„์˜ ๋™์ผ UTF-8 ๋ฐ”์ดํŠธ ๊ณ„์‚ฐ |
16
16
  | V3ContractError | code/path๋ฅผ ๊ฐ€์ง„ ๊ณตํ†ต ์˜ค๋ฅ˜ |
17
17
 
18
- **parseV3Json์€ ๋ชจ๋ธ ์˜๋ฏธ ๊ฒ€์ฆ๊ธฐ๊ฐ€ ์•„๋‹ˆ๋‹ค.** JSON ํ˜•์‹์ด ์˜ฌ๋ฐ”๋ฅธ V2 ๊ฐ์ฒด๋„ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค. V3 ์ž์‚ฐ ๋ฒ„์ „ยท๋‹จ์œ„ยท๊ทธ๋ž˜ํ”„ยทappearance ๊ฒ€์‚ฌ๋Š” ์—ฌ์ „ํžˆ ์ž์‚ฐ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋‹ด๋‹นํ•œ๋‹ค. ๊ณต๊ฐœ๋œ ์ด๋ฆ„์ด ์ „์ฒด V3 ์ง€์›์ด๋‚˜ ์•ˆ์ •ํ™” ์™„๋ฃŒ๋ฅผ ๋œปํ•˜์ง€ ์•Š๋Š”๋‹ค.
18
+ **parseV3Json์€ ๋ชจ๋ธ ์˜๋ฏธ ๊ฒ€์ฆ๊ธฐ๊ฐ€ ์•„๋‹ˆ๋‹ค.** JSON ํ˜•์‹๋งŒ ์˜ฌ๋ฐ”๋ฅด๋ฉด V3 ์ž์‚ฐ์ด ์•„๋‹Œ ๊ฐ์ฒด๋„ ์ฝ๋Š”๋‹ค. V3 ์ž์‚ฐ ๋ฒ„์ „ยท๋‹จ์œ„ยท๊ทธ๋ž˜ํ”„ยทappearance ๊ฒ€์‚ฌ๋Š” ์—ฌ์ „ํžˆ ์ž์‚ฐ ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋‹ด๋‹นํ•œ๋‹ค. ๊ณต๊ฐœ๋œ ์ด๋ฆ„์ด ์ „์ฒด V3 ์ง€์›์ด๋‚˜ ์•ˆ์ •ํ™” ์™„๋ฃŒ๋ฅผ ๋œปํ•˜์ง€ ์•Š๋Š”๋‹ค.
19
19
 
20
20
  ## ๋‹จ์ผ ๊ตฌํ˜„ ์œ ์ง€
21
21
 
@@ -27,7 +27,7 @@
27
27
 
28
28
  2026-09-21:
29
29
 
30
- - `npm test`: ๊ธฐ์กด V2 ํšŒ๊ท€ ๋ฐ ์ƒˆ ์ž…๋ ฅ ๊ฒฝ๊ณ„ ๊ฒ€์‚ฌ ํฌํ•จ **442๊ฐœ ํ†ต๊ณผ**.
30
+ - `npm test`: ๋‹น์‹œ ์†Œ์Šค ์ „์ฒด์™€ ์ƒˆ ์ž…๋ ฅ ๊ฒฝ๊ณ„ ๊ฒ€์‚ฌ ํฌํ•จ **442๊ฐœ ํ†ต๊ณผ**.
31
31
  - `node --test docs/prototypes/v3-*.test.mjs`: **143๊ฐœ ํ†ต๊ณผ**.
32
32
  - `npm run build`: ์„ฑ๊ณต, JS์™€ ํƒ€์ž… ์„ ์–ธ ์ƒ์„ฑ.
33
33
  - `node docs/prototypes/v3-runtime-browser.mjs`: ์‹ค์ œ Chrome์—์„œ ๋นŒ๋“œ๋œ ESM ์‹คํ–‰ ์„ฑ๊ณต. Buffer/process๊ฐ€ ์—†๋Š” ์ƒํƒœ์—์„œ ํ•œ๊ธ€ยท์ด๋ชจ์ง€ UTF-8 ๊ณ„์‚ฐ๊ณผ ์ด์Šค์ผ€์ดํ”„ ์ค‘๋ณต ํ‚ค ๊ฑฐ๋ถ€ ํ™•์ธ.
@@ -36,7 +36,7 @@
36
36
 
37
37
  ## ๊ทธ๋ž˜ํ”„ ํ‰๊ฐ€๊ธฐ ์ด๊ด€
38
38
 
39
- `src/v3-graph.ts`์— ๊ธฐ์กด ํ‰๊ฐ€๊ธฐ ์ „์ฒด๋ฅผ ์˜ฎ๊ธฐ๊ณ  ๋ฃจํŠธ API์— `compileV3Graph`๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค. V2์˜ `compile`์€ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์•˜๋‹ค. `src/v3-graph-types.ts`๋Š” ์ž…๋ ฅ/์ƒ์ˆ˜/๋…ธ๋“œ, ๋‹จ์œ„ยท์ฐจ์›, ์ขŒํ‘œ๊ณ„ ํƒ€์ž…, ํ˜•์ƒยท๋ฐฐ์น˜, ํ‰๊ฐ€ ๊ฒฐ๊ณผ์™€ ์ปดํŒŒ์ผ๋œ ๊ณ„ํš์˜ ๊ณต๊ฐœ ํƒ€์ž…์„ ์ •์˜ํ•œ๋‹ค.
39
+ `src/v3-graph.ts`์— ๊ธฐ์กด ํ‰๊ฐ€๊ธฐ ์ „์ฒด๋ฅผ ์˜ฎ๊ธฐ๊ณ  ๋ฃจํŠธ API์— `compileV3Graph`๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋‹ค. `src/v3-graph-types.ts`๋Š” ์ž…๋ ฅ/์ƒ์ˆ˜/๋…ธ๋“œ, ๋‹จ์œ„ยท์ฐจ์›, ์ขŒํ‘œ๊ณ„ ํƒ€์ž…, ํ˜•์ƒยท๋ฐฐ์น˜, ํ‰๊ฐ€ ๊ฒฐ๊ณผ์™€ ์ปดํŒŒ์ผ๋œ ๊ณ„ํš์˜ ๊ณต๊ฐœ ํƒ€์ž…์„ ์ •์˜ํ•œ๋‹ค.
40
40
 
41
41
  ์‹คํ—˜ ์ง„์ž…์  `docs/prototypes/v3-typed-plan.mjs`๋Š” ๋‘ export๋งŒ ๋‚จ๊ธด ํ˜ธํ™˜ ์–ด๋Œ‘ํ„ฐ๋‹ค. ๋‹จ์œ„ ๊ณ„์‚ฐยท์œ„์ƒ ์ •๋ ฌยท์ขŒํ‘œ๊ณ„ ๊ฒ€์‚ฌยทํ˜•์ƒ ์ƒ์„ฑยท๋ฐ˜๋ณต ๋ฐฐ์น˜์˜ ๊ตฌํ˜„์„ ๋‘ ๋ฒŒ ์œ ์ง€ํ•˜์ง€ ์•Š๋Š”๋‹ค. ๊ธฐ์กด ์—ฐ์‚ฐ์ž ๋ฒ„์ „๊ณผ ์‹คํŒจ ์ฝ”๋“œ๋ฅผ ์œ ์ง€ํ–ˆ๋‹ค.
42
42
 
@@ -62,7 +62,7 @@
62
62
  | v3-asset.ts | compileV3Asset, parseV3Asset, serializeV3Asset, captureV3AuthoredInputs |
63
63
  | v3-asset-types.ts | ๋ฌธ์„œยท์ž์‚ฐยท์žฌ์งˆยทbinding ์„ ์–ธ ๋ฐ ํ‰๊ฐ€ ๊ฒฐ๊ณผ ํƒ€์ž… |
64
64
 
65
- ๋ฒ„์ „ ์‹๋ณ„์ž๋Š” ๊ธฐ์กด ์‹คํ—˜ ๋ฒ„์ „์„ ์œ ์ง€ํ•œ๋‹ค. ์ •์‹ ์†Œ์Šค์— ํฌํ•จ๋˜์—ˆ๋‹ค๊ณ  ํŒŒ์ผ ํฌ๋งท ์•ˆ์ •ํ™”๋‚˜ ์ œํ’ˆ ์ €์žฅ ํ—ˆ์šฉ์„ ์„ ์–ธํ•˜์ง€ ์•Š๋Š”๋‹ค. package.json๊ณผ V2 compile/validate๋Š” ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์•˜๋‹ค.
65
+ ๋ฒ„์ „ ์‹๋ณ„์ž๋Š” ๊ธฐ์กด ์‹คํ—˜ ๋ฒ„์ „์„ ์œ ์ง€ํ•œ๋‹ค. ์ •์‹ ์†Œ์Šค์— ํฌํ•จ๋˜์—ˆ๋‹ค๊ณ  ํŒŒ์ผ ํฌ๋งท ์•ˆ์ •ํ™”๋‚˜ ์ œํ’ˆ ์ €์žฅ ํ—ˆ์šฉ์„ ์„ ์–ธํ•˜์ง€ ์•Š๋Š”๋‹ค. package.json์€ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์•˜๋‹ค.
66
66
 
67
67
  ์œ ์ง€ํ•œ ๊ณ„์•ฝ:
68
68
 
@@ -104,4 +104,4 @@ workspace ์ด๊ด€ ๋‹น์‹œ ๊ฒ€์ฆ: ์†Œ์Šค ํ…Œ์ŠคํŠธ **451๊ฐœ**, V3 ์‹คํ—˜ ํ…Œ์ŠคํŠธ
104
104
 
105
105
  ํ•ต์‹ฌ ์ž…๋ ฅยท๊ทธ๋ž˜ํ”„ยทcapabilityยท์ž์‚ฐยทํŽธ์ง‘ workspace๋Š” src๋กœ ์ด๊ด€ํ–ˆ๋‹ค. ์ œํ’ˆ์˜ ์ €์žฅยท๋ฐœํ–‰ยทํŽธ์ง‘ยท๋ Œ๋”๋Ÿฌ๋ฅผ V3 ๋‹จ์ผ ์ฒด๊ณ„๋กœ ์ „ํ™˜ํ•ด์•ผ ํ•˜๋ฉฐ, ์ œํ’ˆ ์—ฐ๊ฒฐ์€ ์•„์ง ๋ฏธ์™„๋ฃŒ๋‹ค. ํŒŒ์ผ ์ €์žฅ ์‹คํ—˜๋„ ์ œํ’ˆ DB ๊ตฌํ˜„์œผ๋กœ ๊ฐ„์ฃผํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ ‘์ด‰/์ถฉ๋Œ ์—ฐ๊ตฌ ๋ชจ๋“ˆ๊ณผ ๋Œ€ํ‘œ ๋ชจ๋ธ ์ƒ์„ฑ๊ธฐ๋Š” ๊ณ„์† ์‹คํ—˜ ์˜์—ญ์— ์žˆ๋‹ค.
106
106
 
107
- ๋‹ค์Œ ๋‹จ๊ณ„๋Š” V3 ๋‹จ์ผ ์ €์ž‘ยท์ €์žฅยท๋ Œ๋”๋ง ๊ฒฝ๋กœ์˜ ์ œํ’ˆ ์—ฐ๊ฒฐ์ด๋‹ค. ๊ธฐ์กด ์ž์‚ฐ์€ V3 ๊ธฐ์ค€์œผ๋กœ ๋ฐ”๊พผ๋‹ค. V2 ๋ณ‘ํ–‰ ์šด์˜์„ ์œ„ํ•œ ๊ฒฝ๋กœ๋Š” ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๋Š”๋‹ค. ์ œํ’ˆ API ๋ฐฐํฌ๋Š” ์•„์ง ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์•˜๋‹ค.
107
+ ๋‹ค์Œ ๋‹จ๊ณ„๋Š” V3 ๋‹จ์ผ ์ €์ž‘ยท์ €์žฅยท๋ Œ๋”๋ง ๊ฒฝ๋กœ์˜ ์ œํ’ˆ ์—ฐ๊ฒฐ์ด๋‹ค. ๊ธฐ์กด ์ž์‚ฐ์€ V3 ๊ธฐ์ค€์œผ๋กœ ๋ฐ”๊พผ๋‹ค. ์ œํ’ˆ API ๋ฐฐํฌ๋Š” ์•„์ง ์ˆ˜ํ–‰ํ•˜์ง€ ์•Š์•˜๋‹ค.
@@ -3,7 +3,7 @@
3
3
  > ํ˜„์žฌ ๊ตฌํ˜„ยท๊ฒ€์ฆยท์ œํ’ˆ ์—ฐ๊ฒฐ ์ƒํƒœ๋Š” [V3 ํ†ตํ•ฉ ํ˜„ํ™ฉ](v3-status.md)์„ ๋”ฐ๋ฅธ๋‹ค. ๋ณธ๋ฌธ์˜ ๋‹จ๊ณ„๋ณ„ ์—ฐ๊ตฌ/๊ฒ€์ฆ ๊ธฐ๋ก์€ ์ œํ’ˆ ์ „์ฒด ์™„๋ฃŒ ์„ ์–ธ์ด ์•„๋‹ˆ๋‹ค.
4
4
 
5
5
  2026-09-20. [1์ฐจ ๊ฒ€์‚ฌ](v3-sample-validation.md)์˜ ํ›„์†์ด๋‹ค.
6
- **ํ˜„์žฌ v2 ํ•จ์ˆ˜ ๊ฒ€์‚ฌ / ๋ช…์‹œํ•œ v3 ์˜๋„ ํ›„๋ณด ๊ณ„์‚ฐ / ๊ธฐ๊ตฌํ•™ ์ˆ˜์น˜ ์‹คํ—˜**์„ ๊ตฌ๋ณ„ํ•œ๋‹ค.
6
+ **๋‹น์‹œ ๊ธฐ์กด ํ•จ์ˆ˜ ๊ฒ€์‚ฌ / ๋ช…์‹œํ•œ v3 ์˜๋„ ํ›„๋ณด ๊ณ„์‚ฐ / ๊ธฐ๊ตฌํ•™ ์ˆ˜์น˜ ์‹คํ—˜**์„ ๊ตฌ๋ณ„ํ•œ๋‹ค.
7
7
  ํ…Œ์ŠคํŠธ๊ฐ€ ํ†ต๊ณผํ–ˆ๋‹ค๋Š” ๊ฒƒ์€ ์•„๋ž˜ ๊ด€์ฐฐ์ด ์žฌํ˜„๋๋‹ค๋Š” ๋œป์ด๋ฉฐ, ๊ฒฐํ•จ์ด ํ•ด๊ฒฐ๋๋‹ค๋Š” ๋œป์ด ์•„๋‹ˆ๋‹ค.
8
8
  ์ œํ’ˆ ์†Œ์Šค, ์„œ๋ฒ„, ์›๋ณธ ์ƒ˜ํ”Œ์„ ๋ณ€๊ฒฝํ•˜์ง€ ์•Š์•˜๋‹ค.
9
9
 
@@ -41,7 +41,7 @@ node --test docs/prototypes/v3-samples.test.mjs
41
41
 
42
42
  ### ๋กœ๋ด‡์•”: ์ขŒํ‘œ๊ณ„๋Š” ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ๋งํฌ ํฌ๊ธฐ ๋ณ€๊ฒฝ์€ ๋ณ„๋„ ๋ฌธ์ œ
43
43
 
44
- v2์˜ position๊ณผ joint.origin์€ ์ •์ง€ ๋ชจ๋ธ ์ขŒํ‘œ๋‹ค. ์ด๋ฅผ ๋ถ€๋ชจ-relative offset๊ณผ
44
+ ์›๋ณธ ์ƒ˜ํ”Œ์˜ position๊ณผ joint.origin์€ ์ •์ง€ ๋ชจ๋ธ ์ขŒํ‘œ๋‹ค. ์ด๋ฅผ ๋ถ€๋ชจ-relative offset๊ณผ
45
45
  ์ž์‹-local pivot์œผ๋กœ ๋ณ€ํ™˜ํ•œ ๋’ค `parent ยท rest ยท joint`๋กœ ๊ณ„์‚ฐํ–ˆ๋‹ค.
46
46
  ๊ด€์ ˆ ์–‘์ชฝ์—์„œ ๊ณ„์‚ฐํ•œ ๋™์ผ pivot์˜ ์›”๋“œ ์œ„์น˜๊ฐ€ ์ผ์น˜ํ•˜๋Š”์ง€ ๊ฒ€์‚ฌํ–ˆ๋‹ค.
47
47
  ๋‹จ์ˆœํžˆ ๋ถ€ํ’ˆ ์ค‘์‹ฌ ๊ฑฐ๋ฆฌ๊ฐ€ ์ผ์ •ํ•˜๋‹ค๋Š” ๊ฒ€์‚ฌ๋ณด๋‹ค ๊ตฌ์ฒด์ ์ธ ๊ธฐ๊ตฌํ•™ ๋ถˆ๋ณ€๋Ÿ‰์ด๋‹ค.
@@ -1,15 +1,14 @@
1
1
  # V3 shape-dimension contract โ€” per-axis radii, elliptic sections, and dimensions that follow state
2
2
 
3
3
  Status: **contract, fixed 2026-09-22 by the V3 designer** (ADR-0087, stage-review rulings 3 and 5). ยง1 (per-axis
4
- dimensions) implemented the same day: `cylinder-shape@2`, `rounded-box@2`, `hollow-box@2`, the converter writing
5
- them, the sampler reading them. ยง2โ€“3 implemented the same night: dependence on state is tracked per value in the
4
+ dimensions) implemented the same day: `cylinder-shape@2`, `rounded-box@2`, `hollow-box@2`, and the sampler reading
5
+ them. ยง2โ€“3 implemented the same night: dependence on state is tracked per value in the
6
6
  compiler and printed as `dependence` beside `outputTypes`; every operator carries a `state` policy (`follows` or
7
7
  `refuses`; an operator without one fails with `STATE_POLICY`); `occupancy.extent` may not depend on state
8
8
  (`OCCUPANCY_STATE`); `inspectV3Asset` covers the state range and reports `proven` (corners; no state-dependent
9
9
  rotation), `sampled` (a rotation depends on state; corners plus per-input sweeps, step stated, not a proof) or
10
10
  `defaults` (one state, as asked). The `bounded` method of ยง3 (swept envelope) is not implemented; such assets report
11
- `sampled`. The converter writes a two-key scale channel as dimensions ร— affine(parameter) for percent or ratio
12
- parameters (`STATE_DIMENSION` note). This is one rule for what a shape's dimensions are and what they may depend on. It is not three
11
+ `sampled`. This is one rule for what a shape's dimensions are and what they may depend on. It is not three
13
12
  exceptions bolted on for the three assets that needed them.
14
13
 
15
14
  ## What a person sees
@@ -19,11 +18,11 @@ cradle gets thinner: its radius shrinks, its length does not. The edge plates th
19
18
  stay on its surface. Nothing else moves. At 0 % the roll is exactly the drawn roll.
20
19
 
21
20
  An author stretches a kiosk to twice its width. The bezel's corners stay the same round in front view where the
22
- section did not stretch, and go wider than they are tall where it did, because V2 drew them that way. Nothing pops
23
- back to a circle on its own.
21
+ section did not stretch, and go wider than they are tall where it did, because each corner radius follows its own
22
+ axis. Nothing pops back to a circle on its own.
24
23
 
25
24
  An author opens the worker figure and stretches it sideways. The legs, which the author chose not to keep round,
26
- become oval like V2 drew them. The renderer draws the oval it is given. It never "fixes" it to a circle.
25
+ become oval. The renderer draws the oval it is given. It never "fixes" it to a circle.
27
26
 
28
27
  ## 1. Every round thing has per-axis dimensions
29
28
 
@@ -32,7 +31,7 @@ A section is round only when its two cross dimensions are equal. The providers w
32
31
  | operator | evaluated provider | dimensions | round when | status |
33
32
  |---|---|---|---|---|
34
33
  | `cylinder-shape@2` | `ellipticCylinder` | `radiusX`, `radiusZ`, `length` (axis Y) | `radiusX = radiusZ` | implemented 2026-09-22 |
35
- | `frustum-shape@2` | โ€” | `topRadiusX`, `topRadiusZ`, `bottomRadiusX`, `bottomRadiusZ`, `height` | pairs equal | not implemented; no V2 shape needs it (V2 draws no frustum) |
34
+ | `frustum-shape@2` | โ€” | `topRadiusX`, `topRadiusZ`, `bottomRadiusX`, `bottomRadiusZ`, `height` | pairs equal | not implemented |
36
35
  | `sphere-shape@1` | `sphere` | `radiusX`, `radiusY`, `radiusZ` (already so) | all equal | implemented |
37
36
  | `rounded-box@2` | `roundedBoxXZ` | `width`, `height`, `depth`, `roundX`, `roundZ` | `roundX = roundZ` | implemented 2026-09-22 |
38
37
  | `hollow-box@2` | `hollowBoxXZ` | as `hollow-box@1` with `roundX`, `roundZ` in place of `round` | same | implemented 2026-09-22 |
@@ -41,38 +40,32 @@ The evaluated provider name is distinct from the `@1` one so a renderer can neve
41
40
  single radius. Features on `ellipticCylinder` are `start` and `end` only; `radialBottom` has no single meaning on an
42
41
  ellipse.
43
42
 
44
- - `@1` of each provider stays valid and means the equal case; the converter writes `@2` only where V2 drew an
45
- unequal section. Nothing that exists today is invalidated.
43
+ - `@1` of each provider stays valid and means the equal case. `@2` is needed only for an unequal section.
46
44
  - **The renderer draws what it is given.** An elliptic section is an ellipse; an elliptic corner is the quadratic
47
45
  Bรฉzier from `(hw โˆ’ roundX, โˆ’hd)` to `(hw, โˆ’hd + roundZ)` with the corner `(hw, โˆ’hd)` as control point, which is
48
- what things-scene's `roundedRect` draws and what `src/v3-mesh-compare.ts` samples. It is not a circular or
49
- elliptic arc: an arc differs from the Bรฉzier by up to 0.06 ร— round at the corner's middle. A renderer that snaps a
50
- section to a circle is wrong, and the mesh-level comparison of the completion criterion is what catches it.
46
+ what things-scene's `roundedRect` draws. It is not a circular or elliptic arc: an arc differs from the Bรฉzier by
47
+ up to 0.06 ร— round at the corner's middle. A renderer that snaps a section to a circle is wrong.
51
48
  - Validity: every dimension positive (a corner radius may be 0), `roundX โ‰ค width/2`, `roundZ โ‰ค depth/2`. A
52
- declared corner larger than the section is refused at compile; the converter normalises V2's declared value to
53
- what V2 drew (ruling 2) and reports it.
49
+ declared corner larger than the section is refused at compile.
54
50
 
55
- ### What `keepRound` becomes
51
+ ### A round section under non-uniform sizing
56
52
 
57
- V2's `keepRound` was a rule about **what happens to a round section under non-uniform sizing**: keep it round by
58
- the geometric mean of the two factors. In V3 that is not a flag; it is two possible expressions for two dimensions:
53
+ What happens to a round section when the instance is sized differently along its two cross axes is not a flag. It
54
+ is two possible expressions for two dimensions:
59
55
 
60
56
  ```
61
- kept round radiusX = radiusZ = rโ‚€ ยท geomean(fx, fz) (V2 keepRound on, the default)
62
- follows axes radiusX = rโ‚€ ยท fx, radiusZ = rโ‚€ ยท fz (V2 keepRound off)
57
+ kept round radiusX = radiusZ = rโ‚€ ยท geomean(fx, fz)
58
+ follows axes radiusX = rโ‚€ ยท fx, radiusZ = rโ‚€ ยท fz
63
59
  ```
64
60
 
65
- Both are ordinary length expressions. The converter chooses by the V2 flag and writes the expression; the
66
- `ELLIPTIC_SECTION` refusal is now a note on the report (implemented 2026-09-22), and `CORNER_PER_AXIS` notes a
67
- corner written with two semi-axes. The same two shapes apply to corners: V2 scaled a rounded box's finished mesh
68
- per axis, so a corner drawn with radius `rโ‚€` becomes `roundX = rโ‚€ยทfx`, `roundZ = rโ‚€ยทfz`. That is what
69
- `ROUND_NOT_SCALED` (40 parts in the last run) was reporting as a loss; with `@2` corners it is no longer a loss.
61
+ Both are ordinary length expressions; the author chooses which one to write. The same two shapes apply to corners:
62
+ a corner drawn with radius `rโ‚€` that follows the axes is `roundX = rโ‚€ยทfx`, `roundZ = rโ‚€ยทfz`.
70
63
 
71
64
  ## 2. A dimension may depend on state
72
65
 
73
66
  A state input (`role: 'state'`) may be an argument of a shape or length node. A consumed roll's radius is
74
67
  `rโ‚€ โˆ’ fed ยท k`; a lamp's glow radius grows with the gate. This is the core-semantics ยง2 invariant ("state changes the
75
- actual shape dimension") made concrete, and it is what a V2 `scale` channel means: `dims ร— affine(p)`.
68
+ actual shape dimension") made concrete. A dimension that scales with a state input is `dims ร— affine(p)`.
76
69
 
77
70
  ### Dependence is tracked in the type, apart from unit and frame
78
71
 
@@ -114,30 +107,14 @@ range, and says how it knows:
114
107
  - The endpoint-only shortcut is **wrong** for a rotating long part: inside at both end angles, out in the middle.
115
108
  That case takes the `bounded` row, not the `proven` one.
116
109
 
117
- ## 4. What the converter writes with this contract
118
-
119
- - V2 cylinder with `keepRound: false` and differing cross factors โ†’ `cylinder-shape@2` with `radiusX`, `radiusZ`
120
- following their own axes. WORKER converts; `ELLIPTIC_SECTION` is retired.
121
- - V2 rect or hollow rect whose section follows the instance โ†’ `rounded-box@2` / `hollow-box@2` with per-axis corner
122
- radii `rยทfx`, `rยทfz`. `ROUND_NOT_SCALED` is retired.
123
- - V2 `scale` channel on a part, two linear keys, from a parameter โ†’ each scaled dimension becomes
124
- `dim ร— affine(p)`; the part's centre is unchanged (V2 scaled about the part centre). The dependence set of every
125
- affected length includes the parameter. DRY_ROOM's lamps and ROLL_CRADLE's roll convert; `ANIMATION_CHANNEL`
126
- stays only for channels the contract does not cover (pivots, compound axes, curves other than two linear keys).
127
- - The report marks every state-dependent dimension it wrote, and the occupancy inspection of a converted asset
128
- runs over the parameter ranges as ยง3 says.
129
-
130
- ## 5. Completion criterion for this contract
110
+ ## 4. Completion criterion for this contract
131
111
 
132
112
  - The four providers' `@2` forms compile, evaluate, and their `@1` forms are unchanged (the operator-list guard
133
113
  gains the four names).
134
114
  - Dependence appears in `outputTypes`; a synthetic new operator with no policy fails to compile when handed a
135
115
  state-dependent value; `fit-pitch@1` and `fixed-count@1` still refuse it; a shape provider accepts it.
136
- - The three assets convert and match V2 at box level at 8 sizes ร— states, and the WORKER's legs match as ovals.
137
116
  - An occupancy check on the roll cradle reports `proven` over the `fed` range, and a synthetic rotating long part
138
117
  reports `bounded`, with a violation found at a middle angle that the endpoints alone would have missed.
139
- - The mesh-level comparison of the completion criterion covers sections and corners, so an elliptic section drawn
140
- round would fail it.
141
118
 
142
119
  ## Not in this contract
143
120
 
@@ -145,10 +122,9 @@ range, and says how it knows:
145
122
  - Shape deformation beyond dimensions: bending, twisting, free-form profiles that change with state. Those would be
146
123
  new providers with their own contracts.
147
124
 
148
- ## 4. ํ‘œ์‹œ ์—ฌ๋ถ€ (visibility) โ€” ์•ˆ ๋ณด์ด๋Š” ๊ฒƒ๊ณผ ์ž‘์€ ๊ฒƒ์€ ๋‹ค๋ฅด๋‹ค
125
+ ## 5. ํ‘œ์‹œ ์—ฌ๋ถ€ (visibility) โ€” ์•ˆ ๋ณด์ด๋Š” ๊ฒƒ๊ณผ ์ž‘์€ ๊ฒƒ์€ ๋‹ค๋ฅด๋‹ค
149
126
 
150
- **V3 ์„ค๊ณ„์ž ๊ฒฐ์ • 2026-09-22.** V2 ๋Š” ๋ถ€ํ’ˆ์„ ์ˆจ๊ธธ ๋•Œ ํฌ๊ธฐ๋ฅผ 0 ์œผ๋กœ ๋งŒ๋“ ๋‹ค. V3 ๋Š” ๊ทธ ๋ฐฉ๋ฒ•์„ ์“ฐ์ง€
151
- ์•Š๋Š”๋‹ค. 0 ์„ ์•„์ฃผ ์ž‘์€ ์–‘์ˆ˜๋กœ ๋ฐ”๊พธ๋Š” ๊ฒƒ๋„ ์“ฐ์ง€ ์•Š๋Š”๋‹ค โ€” ํ™•๋Œ€ยท๊ทธ๋ฆผ์žยทํฌ์ธํ„ฐ ์„ ํƒ์—์„œ ์ฐจ์ด๊ฐ€
127
+ **V3 ์„ค๊ณ„์ž ๊ฒฐ์ • 2026-09-22.** ๋ถ€ํ’ˆ์„ ์ˆจ๊ธฐ๋ ค๊ณ  ํฌ๊ธฐ๋ฅผ 0 ์œผ๋กœ ๋งŒ๋“ค์ง€ ์•Š๋Š”๋‹ค. 0 ์„ ์•„์ฃผ ์ž‘์€ ์–‘์ˆ˜๋กœ ๋ฐ”๊พธ๋Š” ๊ฒƒ๋„ ์“ฐ์ง€ ์•Š๋Š”๋‹ค โ€” ํ™•๋Œ€ยท๊ทธ๋ฆผ์žยทํฌ์ธํ„ฐ ์„ ํƒ์—์„œ ์ฐจ์ด๊ฐ€
152
128
  ์ƒ๊ธฐ๊ณ , ใ€Œ์•ˆ ๋ณด์ž„ใ€์ด ใ€Œ์•„์ฃผ ์ž‘์Œใ€์ด ๋˜์–ด ๋ฒ„๋ฆฐ๋‹ค.
153
129
 
154
130
  ### ๊ทœ์น™
@@ -172,19 +148,9 @@ range, and says how it knows:
172
148
 
173
149
  | ๋ชฉ๋ก | ๋ฌด์—‡์ด ๋“ค์–ด๊ฐ€๋Š”๊ฐ€ | ๋ˆ„๊ฐ€ ์“ฐ๋Š”๊ฐ€ |
174
150
  | --- | --- | --- |
175
- | `v3WorldBoxesOf` | ๊ทธ๋ฆฌ๋Š” ๋ชธํ†ต๋งŒ (`visible === false` ์ œ์™ธ) | renderer, V2 ๋น„๊ต |
151
+ | `v3WorldBoxesOf` | ๊ทธ๋ฆฌ๋Š” ๋ชธํ†ต๋งŒ (`visible === false` ์ œ์™ธ) | renderer |
176
152
  | `v3OccupiedBoxesOf` | ๋†“์ธ ๋ชธํ†ต ์ „๋ถ€ (์ˆจ๊ธด ๊ฒƒ ํฌํ•จ) | occupancy ๊ฒ€์‚ฌ |
177
153
 
178
- ### ๋ณ€ํ™˜๊ธฐ๊ฐ€ V2 ์˜ scale 0 ์„ ์˜ฎ๊ธฐ๋Š” ๋ฐฉ๋ฒ•
179
-
180
- ์ฑ„๋„์ด **๋ชจ๋“  ๋ณ€ํ•˜๋Š” ์ถ•์—์„œ 0 ์œผ๋กœ ์‹œ์ž‘ํ•˜๊ณ , ์ฒ˜์Œ 0 ์ด ์•„๋‹Œ key ๋ถ€ํ„ฐ ๋๊นŒ์ง€ ์ •ํ™•ํžˆ 1** ์ด๋ฉด
181
- (= ๋ถ€ํ’ˆ ์ œ ํฌ๊ธฐ) visibility ๋กœ ์˜ฎ๊ธด๋‹ค. ๋ถ€ํ’ˆ์€ ์ œ ์น˜์ˆ˜๋ฅผ ๊ณ„์† ๊ฐ–๊ณ , flag ๊ฐ€ ๊ทธ key ์˜ `at` ์—์„œ
182
- ์ผœ์ง„๋‹ค. ๊ทธ ์™ธ โ€” ์ˆจ๊ธฐ๋ฉด์„œ ํฌ๊ธฐ๋„ ๋ฐ”๊พธ๋Š” ์ฑ„๋„ โ€” ์€ `SCALE_ZERO` ๋กœ ๊ฑฐ์ ˆํ•œ๋‹ค.
183
-
184
- ์ด๊ฒƒ์€ **์˜๋„์  ์žฌ์ €์ž‘์ด๋‹ค**(`method: 're-authored'`, `RE_AUTHORED_VISIBILITY` note). 0 ๊ณผ
185
- ๋ฌธํ„ฑ ์‚ฌ์ด์—์„œ V2 ๋Š” ์ž๋ผ๋‚˜๋Š” ๋ถ€ํ’ˆ์„ ๊ทธ๋ฆฌ๊ณ  V3 ๋Š” ์•ˆ ๊ทธ๋ฆฐ๋‹ค. DRY_ROOM ์—์„œ ์‹ค์ธกํ–ˆ๋‹ค: ๋ฌธํ„ฑ์€
186
- ํŒŒ๋ผ๋ฏธํ„ฐ ๋ฒ”์œ„์˜ 1 %, ๊ทธ ๋ฐ– ๋ชจ๋“  ์ƒํƒœ์—์„œ V2 ์™€ ๊ฐ™๊ณ  ์ฐจ์ด๋Š” ๊ทธ 1 % ์•ˆ์—์„œ๋งŒ ๋‚œ๋‹ค.
187
-
188
154
  ## When `proven` may be said (added 2026-09-23, after two counterexamples from the V3 designer)
189
155
 
190
156
  `proven` means the gate evaluated the corners of the state box and nothing else. That is only a proof when every
package/docs/v3-status.md CHANGED
@@ -2,14 +2,14 @@
2
2
 
3
3
  > **2026-09-22 โ€” this file is a progress note, not the document of record.** The decision and the order of work are
4
4
  > `operato-application/adr/ADR-0087.md`; the current state is the app's
5
- > `operato-application/packages/operato-figure/docs/CURRENT_STATUS.md` (section "figure-model V2 โ†’ V3"). Where this
5
+ > `operato-application/packages/operato-figure/docs/CURRENT_STATUS.md`. Where this
6
6
  > file disagrees with those two, they win.
7
7
 
8
8
  ๊ธฐ์ค€์ผ: 2026-09-21. **ํ˜„์žฌ ์ƒํƒœ๋ฅผ ํŒ๋‹จํ•˜๋Š” ๋ฌธ์„œ๋‹ค.** ๊ฐœ๋ณ„ ์—ฐ๊ตฌยท๊ฒ€์ฆ ๋ฌธ์„œ์˜ ๊ณผ๊ฑฐ ๋‹จ๊ณ„ ์ˆ˜์น˜๋‚˜ '๋‹ค์Œ ๋‹จ๊ณ„'๋ณด๋‹ค ์ด ํ˜„ํ™ฉ์„ ์šฐ์„ ํ•œ๋‹ค.
9
9
 
10
10
  ## ์ œํ’ˆ ๋ฐฉํ–ฅ
11
11
 
12
- ๋ชจ๋ธ๋ŸฌยทAIยท์ €์žฅยท๋ Œ๋”๋Ÿฌ๋ฅผ **V3 ํ•˜๋‚˜๋กœ ์ „ํ™˜**ํ•œ๋‹ค. V2 ํ˜ธํ™˜์„ฑยท๋ณ‘ํ–‰ ์šด์˜์€ ์š”๊ตฌ์‚ฌํ•ญ์ด ์•„๋‹ˆ๋‹ค. ๊ธฐ์กด ์ž์‚ฐ์€ V3๋กœ ๋ณ€ํ™˜ํ•˜๊ฑฐ๋‚˜ ์žฌ์ž‘์„ฑํ•œ๋‹ค. ์›๋ณธ ๋ณต๊ตฌ๋ณธ์€ ๋ฐ์ดํ„ฐ ๊ต์ฒด๋ฅผ ์œ„ํ•œ ์•ˆ์ „ ์กฐ์น˜์ผ ๋ฟ V2 ์‹คํ–‰ ์ง€์›์„ ๋œปํ•˜์ง€ ์•Š๋Š”๋‹ค. [์ „ํ™˜ ๊ฒฐ์ •](v3-cutover.md)
12
+ ๋ชจ๋ธ๋ŸฌยทAIยท์ €์žฅยท๋ Œ๋”๋Ÿฌ๋Š” **V3(`figure-v3-asset-1`) ํ•˜๋‚˜**๋ฅผ ์“ด๋‹ค. V2์™€ V1์€ 2026-09-26 ์ฝ”๋“œ์™€ ๋ช…์„ธ์—์„œ ์ œ๊ฑฐํ–ˆ๋‹ค(ADR-0087 ์ „ํ™˜์„ ์ œ๊ฑฐ๋กœ ๋งˆ์ณค๋‹ค). [์ „ํ™˜ ๊ฒฐ์ •](v3-cutover.md)
13
13
 
14
14
  ## ์™„๋ฃŒ ๋ฒ”์œ„์™€ ๋ฏธ์™„๋ฃŒ ๋ฒ”์œ„
15
15
 
@@ -27,7 +27,7 @@
27
27
 
28
28
  ## ๊ฒ€์ฆ ๊ทผ๊ฑฐ
29
29
 
30
- - `npm test`: ์†Œ์Šค **455๊ฐœ ํ†ต๊ณผ**. ๊ธฐ์กด ๊ฒ€์‚ฌ์™€ ์‹ ๊ทœ V3 ๊ฒ€์‚ฌ๋ฅผ ํ•ฉ์นœ ์ˆ˜์น˜์ด๋ฉฐ V3 ๊ธฐ๋Šฅ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋‹ค.
30
+ - `node --test src/*.test.ts`: ์†Œ์Šค **286๊ฐœ ํ†ต๊ณผ**(2026-09-26, V2ยทV1 ์ œ๊ฑฐ ๋’ค). ์‹œํ—˜ ์ˆ˜์ด๋ฉฐ V3 ๊ธฐ๋Šฅ ์ˆ˜๊ฐ€ ์•„๋‹ˆ๋‹ค.
31
31
  - `node --test docs/prototypes/v3-*.test.mjs`: ์‹คํ—˜ **143๊ฐœ ํ†ต๊ณผ**.
32
32
  - `npm run build`: ํƒ€์ž… ์„ ์–ธยทJS ์ƒ์„ฑ ์„ฑ๊ณต.
33
33
  - `node docs/prototypes/v3-runtime-browser.mjs`: Chrome์—์„œ ๋นŒ๋“œ๋œ ๋ชจ๋“ˆ ์‹คํ–‰, ๋„ค ๋Œ€ํ‘œ ๋ชจ๋ธ(๋“œ๋ผ์ด๋ฃธยท์ปจ๋ฒ ์ด์–ดยท๋กœ๋ด‡์•”ยทํฌํฌ๋ฆฌํ”„ํŠธ)์˜ ๊ณ„์‚ฐ๊ฐ’/ํ˜•์ƒ/์žฌ์งˆ/binding์„ Node์™€ ๋น„๊ต.
@@ -43,8 +43,8 @@
43
43
  4. [์ž์‚ฐ ๊ณ„์•ฝ](v3-asset-persistence.md), [์ €์žฅ ๊ฒ€์ฆ](v3-storage-integration.md).
44
44
  5. [V3 ๋‹จ์ผ ์ „ํ™˜](v3-cutover.md).
45
45
 
46
- ๋‹ค์Œ ์ž‘์—…์€ ๋ชจ๋ธ๋Ÿฌ์˜ ์‚ฌ์šฉ์ž ๋™์ž‘ยทAIยท์‹ค์ œ ์ €์žฅยท๋ Œ๋”๋ง์„ ์ด ๊ณต์šฉ V3 ๊ตฌํ˜„์— ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์™„๋ฃŒํ•œ ๊ณ„์ธต์„ ๋‹ค์‹œ ์ด๊ด€ํ•˜๊ฑฐ๋‚˜ V2 ํ˜ธํ™˜ ๋ถ„๊ธฐ๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค.
46
+ ๋‹ค์Œ ์ž‘์—…์€ ๋ชจ๋ธ๋Ÿฌ์˜ ์‚ฌ์šฉ์ž ๋™์ž‘ยทAIยท์‹ค์ œ ์ €์žฅยท๋ Œ๋”๋ง์„ ์ด ๊ณต์šฉ V3 ๊ตฌํ˜„์— ์—ฐ๊ฒฐํ•˜๋Š” ๊ฒƒ์ด๋‹ค.
47
47
 
48
48
  ## ์ œํ’ˆ ์—ฐ๊ฒฐ ์ž‘์—… ์ถ”๊ฐ€ ๊ธฐ๋ก (2026-09-21)
49
49
 
50
- things-factory์˜ `packages/figure-ui/docs/v3-product-cutover.md`์— ์ œํ’ˆ ์ „ํ™˜ ์ง„ํ–‰ ์ƒํƒœ๋ฅผ ๊ธฐ๋กํ–ˆ๋‹ค. V3 ์ œํ’ˆ ์„ธ์…˜ยท์บ”๋ฒ„์ŠคยทํŽธ์ง‘ ์ปดํฌ๋„ŒํŠธยท์ €์žฅ API์™€ ํŽ˜์ด์ง€๋ฅผ ์ž‘์„ฑํ–ˆ์œผ๋‚˜, ๊ธฐ๋ณธ route๋Š” ์•„์ง ๊ต์ฒดํ•˜์ง€ ์•Š์•˜๋‹ค. ๋กœ์ปฌ ํ™œ์„ฑ ์ž์‚ฐ32๊ฐœ๊ฐ€ ๋ชจ๋‘ V2์ด๋ฉฐ ์ž์‚ฐ ์ „ํ™˜ยทAI ๋„๊ตฌยท๋ฐœํ–‰/์†Œ๋น„์ฒ˜ ์—ฐ๊ฒฐ์ด ๋‚จ์•„ ์žˆ๋‹ค. UI241๊ฐœ ํ…Œ์ŠคํŠธ ๋ฐ ํด๋ผ์ด์–ธํŠธ/์„œ๋น„์Šค ํƒ€์ž… ๊ฒ€์‚ฌ ํ†ต๊ณผ๋Š” V3 ์ œํ’ˆ end-to-end ๊ฒ€์ฆ ์™„๋ฃŒ๋ฅผ ๋œปํ•˜์ง€ ์•Š๋Š”๋‹ค. ์šด์˜ DB ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์ด๋‚˜ ๋ฐฐํฌ๋Š” ํ•˜์ง€ ์•Š์•˜๋‹ค.
50
+ things-factory์˜ `packages/figure-ui/docs/v3-product-cutover.md`์— ์ œํ’ˆ ์ „ํ™˜ ์ง„ํ–‰ ์ƒํƒœ๋ฅผ ๊ธฐ๋กํ–ˆ๋‹ค. V3 ์ œํ’ˆ ์„ธ์…˜ยท์บ”๋ฒ„์ŠคยทํŽธ์ง‘ ์ปดํฌ๋„ŒํŠธยท์ €์žฅ API์™€ ํŽ˜์ด์ง€๋ฅผ ์ž‘์„ฑํ–ˆ์œผ๋‚˜, ๊ธฐ๋ณธ route๋Š” ์•„์ง ๊ต์ฒดํ•˜์ง€ ์•Š์•˜๋‹ค. ๋‹น์‹œ ๋กœ์ปฌ ํ™œ์„ฑ ์ž์‚ฐ 32๊ฐœ๋Š” ์•„์ง V3๋กœ ์ „ํ™˜๋˜์ง€ ์•Š์•˜๊ณ , ์ž์‚ฐ ์ „ํ™˜ยทAI ๋„๊ตฌยท๋ฐœํ–‰/์†Œ๋น„์ฒ˜ ์—ฐ๊ฒฐ์ด ๋‚จ์•„ ์žˆ์—ˆ๋‹ค. UI241๊ฐœ ํ…Œ์ŠคํŠธ ๋ฐ ํด๋ผ์ด์–ธํŠธ/์„œ๋น„์Šค ํƒ€์ž… ๊ฒ€์‚ฌ ํ†ต๊ณผ๋Š” V3 ์ œํ’ˆ end-to-end ๊ฒ€์ฆ ์™„๋ฃŒ๋ฅผ ๋œปํ•˜์ง€ ์•Š๋Š”๋‹ค. ์šด์˜ DB ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ์ด๋‚˜ ๋ฐฐํฌ๋Š” ํ•˜์ง€ ์•Š์•˜๋‹ค.
@@ -12,9 +12,9 @@
12
12
 
13
13
  ## ์™œ ๊ธฐ์กด ์ €์žฅ API์— ๋ฐ”๋กœ ์—ฐ๊ฒฐํ•˜์ง€ ์•Š์•˜๋Š”๊ฐ€
14
14
 
15
- ์ œํ’ˆ figure-service์˜ `figure-source.ts`๋Š” V2 validate/compile/costOf/scoreOf๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค. `figure-mutation.ts`์˜ ์ƒ์„ฑยท์ˆ˜์ •ยท๋˜๋Œ๋ฆฌ๊ธฐ๋Š” ์ด ๊ฒ€์ฆ์„ ์‚ฌ์šฉํ•˜๋ฉฐ ๋ฐœํ–‰์€ V2 ๊ฒ€์‚ฌ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. figure-ui๋„ draft/parts๋ฅผ ์ง์ ‘ ํŽธ์ง‘ํ•œ๋‹ค.
15
+ ๋‹น์‹œ ์ œํ’ˆ figure-service์˜ `figure-source.ts`๋Š” ์ด์ „ ํ˜•์‹์˜ ๊ฒ€์ฆยท์ปดํŒŒ์ผยท๋น„์šฉยท์ ์ˆ˜ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ–ˆ๋‹ค. `figure-mutation.ts`์˜ ์ƒ์„ฑยท์ˆ˜์ •ยท๋˜๋Œ๋ฆฌ๊ธฐ์™€ ๋ฐœํ–‰๋„ ๊ทธ ๊ฒ€์‚ฌ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค. figure-ui๋„ draft/parts๋ฅผ ์ง์ ‘ ํŽธ์ง‘ํ•œ๋‹ค.
16
16
 
17
- ์‹คํ—˜ ํฌ๋งท๋งŒ ํ—ˆ์šฉํ•˜๋ฉด ์ €์žฅ์€ ๋˜์ง€๋งŒ ๊ธฐ์กด ์†Œ๋น„์ž๊ฐ€ ์ฝ์„ ์ˆ˜ ์—†๋Š” ์ž์‚ฐ์ด ๋œ๋‹ค. ๋”ฐ๋ผ์„œ **์ œํ’ˆ V3 ๊ฒฝ๋กœ ์—ฐ๊ฒฐ์€ ์•„์ง ๋ฏธ์™„๋ฃŒ**๋‹ค. ์‹คํ—˜ ์ฝ”๋“œ์˜ ์ง์ ‘ import, package.json ๋ณ€๊ฒฝ, V2 ๊ฒ€์ฆ ์šฐํšŒ๋Š” ํ•˜์ง€ ์•Š์•˜๋‹ค.
17
+ ์‹คํ—˜ ํฌ๋งท๋งŒ ํ—ˆ์šฉํ•˜๋ฉด ์ €์žฅ์€ ๋˜์ง€๋งŒ ๊ธฐ์กด ์†Œ๋น„์ž๊ฐ€ ์ฝ์„ ์ˆ˜ ์—†๋Š” ์ž์‚ฐ์ด ๋œ๋‹ค. ๋”ฐ๋ผ์„œ **์ œํ’ˆ V3 ๊ฒฝ๋กœ ์—ฐ๊ฒฐ์€ ์•„์ง ๋ฏธ์™„๋ฃŒ**๋‹ค. ์‹คํ—˜ ์ฝ”๋“œ์˜ ์ง์ ‘ import, package.json ๋ณ€๊ฒฝ, ๊ธฐ์กด ๊ฒ€์ฆ ์šฐํšŒ๋Š” ํ•˜์ง€ ์•Š์•˜๋‹ค.
18
18
 
19
19
  ## ์ €์žฅ ๊ณ„์•ฝ
20
20
 
@@ -51,8 +51,8 @@ scope/id ์กฐํ•ฉ์„ ํ•ด์‹œํ•œ ํŒŒ์ผ๋ช…์œผ๋กœ ์‚ฌ์šฉํ•ด ์‚ฌ์šฉ์ž ์‹๋ณ„์ž๋ฅผ
51
51
  ## ์ œํ’ˆ ์—ฐ๊ฒฐ ์ˆœ์„œ
52
52
 
53
53
  1. ์ž…๋ ฅยท๊ทธ๋ž˜ํ”„ยทcapabilityยท๋ฌธ์„œยท์ž์‚ฐยทํŽธ์ง‘ workspace์˜ ์ •์‹ ์†Œ์Šค ์ด๊ด€์€ [์™„๋ฃŒ](v3-runtime-extraction.md)ํ–ˆ๋‹ค. ์ด ๋ชจ๋“ˆ๋“ค์„ ์ œํ’ˆ์— ๋ฐ˜์˜ํ•œ๋‹ค.
54
- 2. figure-service์˜ ์ €์žฅยท์กฐํšŒยท๋ฐœํ–‰์„ V3 ๋‹จ์ผ ๊ธฐ์ค€์œผ๋กœ ์ „ํ™˜ํ•˜๊ณ  ์ €์žฅ revision CAS๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค. V2 ๋ณ‘ํ–‰ ์šด์˜์€ ์š”๊ตฌ์‚ฌํ•ญ์ด ์•„๋‹ˆ๋‹ค.
55
- 3. figure-ui์™€ ๋ Œ๋”๋ŸฌยทAI๋ฅผ V3 ๋‹จ์ผ ๊ฒฝ๋กœ์— ์—ฐ๊ฒฐํ•œ๋‹ค. ๊ธฐ์กด ์ž์‚ฐ์€ V3๋กœ ๋ณ€ํ™˜ํ•˜๊ฑฐ๋‚˜ ์žฌ์ž‘์„ฑํ•œ๋‹ค.
54
+ 2. figure-service์˜ ์ €์žฅยท์กฐํšŒยท๋ฐœํ–‰์„ V3 ๋‹จ์ผ ๊ธฐ์ค€์œผ๋กœ ์ „ํ™˜ํ•˜๊ณ  ์ €์žฅ revision CAS๋ฅผ ๊ตฌํ˜„ํ•œ๋‹ค.
55
+ 3. figure-ui์™€ ๋ Œ๋”๋ŸฌยทAI๋ฅผ V3 ๋‹จ์ผ ๊ฒฝ๋กœ์— ์—ฐ๊ฒฐํ•œ๋‹ค. ๊ธฐ์กด ์ž์‚ฐ์€ V3๋กœ ์žฌ์ž‘์„ฑํ•œ๋‹ค.
56
56
  4. ์‹ค์ œ ์ธ์ฆยทDB๋กœ ๋‘ ํŽธ์ง‘ ์„ธ์…˜์˜ ์ถฉ๋Œ, ์ €์žฅ ์‹คํŒจ, ์žฌ์ ‘์†, ๋ชจ๋ธ ์ „ํ™˜, AI ๋Šฆ์€ ์‘๋‹ต์„ ๊ฒ€์ฆํ•œ๋‹ค.
57
57
 
58
58
  ์ด ๋ฌธ์„œ์˜ ์™„๋ฃŒ ๋ฒ”์œ„๋Š” ์ €์žฅ ๊ฒฝ๊ณ„์˜ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ๊ฒ€์ฆ์ด๋ฉฐ, ์ œํ’ˆ ์—ฐ๊ฒฐยท๋ฐฐํฌ ์™„๋ฃŒ๊ฐ€ ์•„๋‹ˆ๋‹ค.
package/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "@hatiolab/figure-model",
3
- "version": "0.1.76",
4
- "description": "Figure ์ €์ž‘ ๊ฒฐ๊ณผ์˜ ์ •๋ณธ ํ˜•์‹๊ณผ ๊ฒ€์ฆ โ€” ์žฌ์งˆ๋ณ„๋กœ ๋ณ‘ํ•ฉ๋˜๊ณ  ์ด๋ฆ„์ด ๋ถ™์€ ๋ถ€ํ’ˆ ๊ทธ๋ž˜ํ”„. 3D ๋กœ ์ €์ž‘ํ•œ ํ˜•์ƒ ํ•˜๋‚˜๊ฐ€ ์”ฌ ์ปดํฌ๋„ŒํŠธ๋กœ ์„œ๋Š” ๋ฐ ํ•„์š”ํ•œ ๊ฒƒ์„ ๋‹ด๋Š”๋‹ค.",
3
+ "version": "0.1.77",
4
+ "description": "The figure format (figure-v3-asset-1): a kernel that evaluates a figure from its declared relations, the authoring commands a modeller and an AI share, the release gate and the score.",
5
5
  "keywords": [
6
6
  "figure",
7
7
  "low-poly",
8
8
  "3d",
9
- "blueprint",
10
9
  "authoring",
11
10
  "things-scene",
12
11
  "digital-twin",
@@ -31,22 +30,6 @@
31
30
  "types": "./dist/index.d.ts",
32
31
  "default": "./dist/index.js"
33
32
  },
34
- "./types": {
35
- "types": "./dist/types.d.ts",
36
- "default": "./dist/types.js"
37
- },
38
- "./validate": {
39
- "types": "./dist/validate.d.ts",
40
- "default": "./dist/validate.js"
41
- },
42
- "./blueprint": {
43
- "types": "./dist/blueprint.d.ts",
44
- "default": "./dist/blueprint.js"
45
- },
46
- "./cost": {
47
- "types": "./dist/cost.d.ts",
48
- "default": "./dist/cost.js"
49
- },
50
33
  "./package.json": "./package.json"
51
34
  },
52
35
  "files": [
@@ -67,7 +50,6 @@
67
50
  "check": "tsc -p tsconfig.json --noEmit",
68
51
  "test": "npm run check && node --test src/*.test.ts",
69
52
  "test:coverage": "node --test --experimental-test-coverage --test-coverage-lines=100 --test-coverage-branches=95 --test-coverage-functions=100 src/*.test.ts",
70
- "bench": "node src/perf.bench.ts",
71
53
  "format": "prettier --write \"src/**/*.ts\" \"docs/**/*.md\" \"*.md\" \"*.json\"",
72
54
  "format:check": "prettier --check \"src/**/*.ts\" \"docs/**/*.md\" \"*.md\" \"*.json\"",
73
55
  "clean": "rm -rf dist",
@@ -1,10 +0,0 @@
1
- /**
2
- * ์ฒญ์‚ฌ์ง„์˜ ํ˜•ํƒœ๋ฅผ ํ™•์ธํ•œ๋‹ค โ€” **์ฝ๊ธฐ ์ „์— ํ•œ ๋ฒˆ**, ๋“ฑ๋ก ์‹œ์ ์—.
3
- *
4
- * ๊ทธ๋ฆฌ๋Š” ์‹œ์ ์ด ์•„๋‹ˆ๋ผ ๋“ฑ๋ก ์‹œ์ ์— ๋ณด๋Š” ์ด์œ ๋Š”, ์ž˜๋ชป๋œ ์ฒญ์‚ฌ์ง„์ด ํ”„๋ ˆ์ž„๋งˆ๋‹ค ์กฐ์šฉํžˆ
5
- * ์‹คํŒจํ•˜๋Š” ๋Œ€์‹  ๋“ฑ๋ก์—์„œ ํ•œ ๋ฒˆ ํฌ๊ฒŒ ์‹คํŒจํ•˜๊ฒŒ ํ•˜๋ ค๋Š” ๊ฒƒ์ด๋‹ค.
6
- *
7
- * ๋ฌธ์ œ๋ฅผ ์ฐพ์œผ๋ฉด ์‚ฌ๋žŒ์ด ์ฝ์„ ์ˆ˜ ์žˆ๋Š” ์‚ฌ์œ  ๋ชฉ๋ก์„ ๋Œ๋ ค์ค€๋‹ค. ๋น„์–ด ์žˆ์œผ๋ฉด ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค.
8
- */
9
- export declare function blueprintProblems(value: unknown): string[];
10
- //# sourceMappingURL=blueprint-shape.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"blueprint-shape.d.ts","sourceRoot":"","sources":["../src/blueprint-shape.ts"],"names":[],"mappings":"AAgCA;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,EAAE,CA+J1D"}