@hatiolab/figure-model 0.1.75 → 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.
- package/CHANGELOG.md +11 -0
- package/README.md +60 -138
- package/dist/index.d.ts +2 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -26
- package/dist/index.js.map +1 -1
- package/dist/v3-asset-types.d.ts +1 -2
- package/dist/v3-asset-types.d.ts.map +1 -1
- package/dist/v3-asset.js +1 -1
- package/dist/v3-asset.js.map +1 -1
- package/dist/v3-authoring-actions.d.ts +9 -12
- package/dist/v3-authoring-actions.d.ts.map +1 -1
- package/dist/v3-authoring-actions.js +4 -5
- package/dist/v3-authoring-actions.js.map +1 -1
- package/dist/v3-capabilities.js +4 -1
- package/dist/v3-capabilities.js.map +1 -1
- package/dist/v3-cost.d.ts.map +1 -1
- package/dist/v3-cost.js +3 -5
- package/dist/v3-cost.js.map +1 -1
- package/dist/v3-create.d.ts +1 -1
- package/dist/v3-create.d.ts.map +1 -1
- package/dist/v3-editor-workspace.d.ts +38 -0
- package/dist/v3-editor-workspace.d.ts.map +1 -1
- package/dist/v3-editor-workspace.js +14 -0
- package/dist/v3-editor-workspace.js.map +1 -1
- package/dist/v3-examples.js +1 -1
- package/dist/v3-gate.d.ts +7 -8
- package/dist/v3-gate.d.ts.map +1 -1
- package/dist/v3-gate.js +11 -14
- package/dist/v3-gate.js.map +1 -1
- package/dist/v3-graph.d.ts +1 -2
- package/dist/v3-graph.d.ts.map +1 -1
- package/dist/v3-graph.js +5 -7
- package/dist/v3-graph.js.map +1 -1
- package/dist/v3-instance-size.d.ts +3 -5
- package/dist/v3-instance-size.d.ts.map +1 -1
- package/dist/v3-instance-size.js +2 -4
- package/dist/v3-instance-size.js.map +1 -1
- package/dist/v3-kernel-version.d.ts +1 -1
- package/dist/v3-kernel-version.js +1 -1
- package/dist/v3-part-edit.d.ts +4 -5
- package/dist/v3-part-edit.d.ts.map +1 -1
- package/dist/v3-part-edit.js +2 -2
- package/dist/v3-part-edit.js.map +1 -1
- package/dist/v3-proposal.d.ts +42 -0
- package/dist/v3-proposal.d.ts.map +1 -0
- package/dist/v3-proposal.js +179 -0
- package/dist/v3-proposal.js.map +1 -0
- package/dist/v3-release-contract.js +1 -1
- package/dist/v3-release-contract.js.map +1 -1
- package/dist/v3-score.d.ts +4 -5
- package/dist/v3-score.d.ts.map +1 -1
- package/dist/v3-score.js +7 -8
- package/dist/v3-score.js.map +1 -1
- package/dist/v3-words.d.ts +87 -0
- package/dist/v3-words.d.ts.map +1 -0
- package/dist/v3-words.js +87 -0
- package/dist/v3-words.js.map +1 -0
- package/docs/assembly-constraints-v3.md +13 -23
- package/docs/v3-asset-persistence.md +4 -4
- package/docs/v3-common-kernel-experiment.md +1 -1
- package/docs/v3-core-semantics.md +3 -3
- package/docs/v3-cutover.md +5 -3
- package/docs/v3-design.md +13 -26
- package/docs/v3-editor-integration.md +2 -2
- package/docs/v3-full-conveyor-validation.md +3 -3
- package/docs/v3-layout-system.md +1 -1
- package/docs/v3-minimal-model.md +0 -1
- package/docs/v3-motion-contract.md +21 -56
- package/docs/v3-runtime-extraction.md +7 -7
- package/docs/v3-sample-validation-expanded.md +1 -1
- package/docs/v3-sample-validation.md +1 -1
- package/docs/v3-shape-dimension-contract.md +23 -57
- package/docs/v3-status.md +5 -5
- package/docs/v3-storage-integration.md +4 -4
- package/package.json +2 -20
- package/dist/blueprint-shape.d.ts +0 -10
- package/dist/blueprint-shape.d.ts.map +0 -1
- package/dist/blueprint-shape.js +0 -194
- package/dist/blueprint-shape.js.map +0 -1
- package/dist/blueprint.d.ts +0 -73
- package/dist/blueprint.d.ts.map +0 -1
- package/dist/blueprint.js +0 -388
- package/dist/blueprint.js.map +0 -1
- package/dist/cost-chart.d.ts +0 -35
- package/dist/cost-chart.d.ts.map +0 -1
- package/dist/cost-chart.js +0 -150
- package/dist/cost-chart.js.map +0 -1
- package/dist/cost.d.ts +0 -162
- package/dist/cost.d.ts.map +0 -1
- package/dist/cost.js +0 -194
- package/dist/cost.js.map +0 -1
- package/dist/gate.d.ts +0 -65
- package/dist/gate.d.ts.map +0 -1
- package/dist/gate.js +0 -284
- package/dist/gate.js.map +0 -1
- package/dist/grouping.d.ts +0 -121
- package/dist/grouping.d.ts.map +0 -1
- package/dist/grouping.js +0 -224
- package/dist/grouping.js.map +0 -1
- package/dist/keys.d.ts +0 -45
- package/dist/keys.d.ts.map +0 -1
- package/dist/keys.js +0 -84
- package/dist/keys.js.map +0 -1
- package/dist/origin.d.ts +0 -33
- package/dist/origin.d.ts.map +0 -1
- package/dist/origin.js +0 -46
- package/dist/origin.js.map +0 -1
- package/dist/release-contract.d.ts +0 -38
- package/dist/release-contract.d.ts.map +0 -1
- package/dist/release-contract.js +0 -246
- package/dist/release-contract.js.map +0 -1
- package/dist/sizing.d.ts +0 -231
- package/dist/sizing.d.ts.map +0 -1
- package/dist/sizing.js +0 -550
- package/dist/sizing.js.map +0 -1
- package/dist/types.d.ts +0 -1233
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -547
- package/dist/types.js.map +0 -1
- package/dist/v3-from-v2.d.ts +0 -203
- package/dist/v3-from-v2.d.ts.map +0 -1
- package/dist/v3-from-v2.js +0 -2053
- package/dist/v3-from-v2.js.map +0 -1
- package/dist/v3-mesh-compare.d.ts +0 -24
- package/dist/v3-mesh-compare.d.ts.map +0 -1
- package/dist/v3-mesh-compare.js +0 -55
- package/dist/v3-mesh-compare.js.map +0 -1
- package/dist/validate.d.ts +0 -7
- package/dist/validate.d.ts.map +0 -1
- package/dist/validate.js +0 -1119
- package/dist/validate.js.map +0 -1
- package/dist/visual-evidence.d.ts +0 -21
- package/dist/visual-evidence.d.ts.map +0 -1
- package/dist/visual-evidence.js +0 -52
- package/dist/visual-evidence.js.map +0 -1
- package/docs/design.md +0 -193
- package/docs/format-survey.md +0 -108
- package/docs/format.md +0 -704
- package/docs/sizing.md +0 -183
- package/docs/validation.md +0 -357
|
@@ -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
|
|
5
|
-
them
|
|
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`.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
49
|
-
|
|
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
|
|
53
|
-
what V2 drew (ruling 2) and reports it.
|
|
49
|
+
declared corner larger than the section is refused at compile.
|
|
54
50
|
|
|
55
|
-
###
|
|
51
|
+
### A round section under non-uniform sizing
|
|
56
52
|
|
|
57
|
-
|
|
58
|
-
|
|
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)
|
|
62
|
-
follows axes radiusX = r₀ · fx, radiusZ = r₀ · fz
|
|
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
|
|
66
|
-
|
|
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
|
|
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.
|
|
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
|
-
##
|
|
125
|
+
## 5. 표시 여부 (visibility) — 안 보이는 것과 작은 것은 다르다
|
|
149
126
|
|
|
150
|
-
**V3 설계자 결정 2026-09-22.**
|
|
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
|
|
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
|
|
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
|
|
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
|
-
- `
|
|
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 구현에 연결하는 것이다.
|
|
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
|
|
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`는
|
|
15
|
+
당시 제품 figure-service의 `figure-source.ts`는 이전 형식의 검증·컴파일·비용·점수 함수를 호출했다. `figure-mutation.ts`의 생성·수정·되돌리기와 발행도 그 검사 경로를 사용했다. figure-ui도 draft/parts를 직접 편집한다.
|
|
16
16
|
|
|
17
|
-
실험 포맷만 허용하면 저장은 되지만 기존 소비자가 읽을 수 없는 자산이 된다. 따라서 **제품 V3 경로 연결은 아직 미완료**다. 실험 코드의 직접 import, package.json 변경,
|
|
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를 구현한다.
|
|
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.
|
|
4
|
-
"description": "
|
|
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"}
|
package/dist/blueprint-shape.js
DELETED
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 이미 **컴파일된 청사진**의 형태를 확인한다.
|
|
3
|
-
*
|
|
4
|
-
* `validate` 는 저작 형식(`FigureSource`)을 본다. 이쪽은 그 결과물인 `FigureBlueprint`
|
|
5
|
-
* 를 본다 — 서버나 파일에서 온 것이 이 형식대로 생겼는지, **읽기 전에 한 번** 묻는
|
|
6
|
-
* 자리다.
|
|
7
|
-
*
|
|
8
|
-
* 그리는 시점이 아니라 등록 시점에 보는 이유는, 잘못된 청사진이 프레임마다 조용히
|
|
9
|
-
* 실패하는 대신 등록에서 한 번 크게 실패하게 하려는 것이다.
|
|
10
|
-
*
|
|
11
|
-
* ## 왜 여기 있나
|
|
12
|
-
*
|
|
13
|
-
* 한동안 things-scene 이 이것을 손으로 들고 있었다. 「청사진이 어떻게 생겨야 하는가」는
|
|
14
|
-
* **형식의 지식**이고, 읽는 쪽이 다시 적으면 형식이 바뀔 때 조용히 어긋난다. 실제로
|
|
15
|
-
* `SEGMENT_PRESETS` 가 그렇게 갈려 있었다.
|
|
16
|
-
*
|
|
17
|
-
* 문제를 찾으면 사람이 읽을 수 있는 사유 목록을 돌려준다. 비어 있으면 읽을 수 있다.
|
|
18
|
-
*/
|
|
19
|
-
import { BLUEPRINT_VERSION, JOINT_TYPES, PART_ROLES } from "./types.js";
|
|
20
|
-
function isFiniteNumber(v) {
|
|
21
|
-
return typeof v === 'number' && Number.isFinite(v);
|
|
22
|
-
}
|
|
23
|
-
function isFiniteVec3(v) {
|
|
24
|
-
if (!v || typeof v !== 'object')
|
|
25
|
-
return false;
|
|
26
|
-
const { x, y, z } = v;
|
|
27
|
-
return isFiniteNumber(x) && isFiniteNumber(y) && isFiniteNumber(z);
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* 청사진의 형태를 확인한다 — **읽기 전에 한 번**, 등록 시점에.
|
|
31
|
-
*
|
|
32
|
-
* 그리는 시점이 아니라 등록 시점에 보는 이유는, 잘못된 청사진이 프레임마다 조용히
|
|
33
|
-
* 실패하는 대신 등록에서 한 번 크게 실패하게 하려는 것이다.
|
|
34
|
-
*
|
|
35
|
-
* 문제를 찾으면 사람이 읽을 수 있는 사유 목록을 돌려준다. 비어 있으면 읽을 수 있다.
|
|
36
|
-
*/
|
|
37
|
-
export function blueprintProblems(value) {
|
|
38
|
-
const problems = [];
|
|
39
|
-
const bp = value;
|
|
40
|
-
if (!bp || typeof bp !== 'object')
|
|
41
|
-
return ['청사진이 객체가 아니다'];
|
|
42
|
-
if (bp.version !== BLUEPRINT_VERSION) {
|
|
43
|
-
problems.push(`읽을 수 없는 판이다 — version ${String(bp.version)}, 이 판올림은 ${BLUEPRINT_VERSION} 만 읽는다`);
|
|
44
|
-
}
|
|
45
|
-
if (typeof bp.type !== 'string' || bp.type.length === 0) {
|
|
46
|
-
problems.push('type 이 없다 — 컴포넌트 타입 이름이 곧 청사진을 찾는 키다');
|
|
47
|
-
}
|
|
48
|
-
const base = bp.base;
|
|
49
|
-
if (!base || !isFiniteNumber(base.x) || !isFiniteNumber(base.y) || !isFiniteNumber(base.z)) {
|
|
50
|
-
problems.push('base 의 x·y·z 가 온전하지 않다');
|
|
51
|
-
}
|
|
52
|
-
else if (!(base.x > 0) || !(base.z > 0)) {
|
|
53
|
-
problems.push('base 의 x·z 는 0 보다 커야 한다 — 평면 배치 비율의 분모다');
|
|
54
|
-
}
|
|
55
|
-
if (!Array.isArray(bp.groups)) {
|
|
56
|
-
problems.push('groups 가 배열이 아니다');
|
|
57
|
-
return problems;
|
|
58
|
-
}
|
|
59
|
-
if (bp.groups.length === 0) {
|
|
60
|
-
problems.push('groups 가 비어 있다 — 그릴 것이 없는 청사진은 등록하지 않는다');
|
|
61
|
-
}
|
|
62
|
-
bp.groups.forEach((group, gi) => {
|
|
63
|
-
if (!group || !Array.isArray(group.members)) {
|
|
64
|
-
problems.push(`groups[${gi}].members 가 배열이 아니다`);
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
if (group.members.length === 0) {
|
|
68
|
-
problems.push(`groups[${gi}] 에 부품이 없다`);
|
|
69
|
-
}
|
|
70
|
-
group.members.forEach((member, mi) => {
|
|
71
|
-
const where = `groups[${gi}].members[${mi}]`;
|
|
72
|
-
if (typeof member?.name !== 'string' || member.name.length === 0) {
|
|
73
|
-
problems.push(`${where}.name 이 없다 — 이름이 바인딩·이벤트·애니메이션이 붙는 자리다`);
|
|
74
|
-
}
|
|
75
|
-
const t = member?.transform;
|
|
76
|
-
if (!t || !isFiniteVec3(t.position) || !isFiniteVec3(t.size)) {
|
|
77
|
-
problems.push(`${where}.transform 의 값이 온전하지 않다`);
|
|
78
|
-
}
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
/*
|
|
82
|
-
자리와 문.
|
|
83
|
-
|
|
84
|
-
`groups` 와 달리 없어도 된다 — 능력을 안 지는 도형이 대부분이다. 있으면 형태를 본다.
|
|
85
|
-
그리지 않는 것이라 **틀려도 화면에는 아무 일도 안 일어나고**, 물건을 앉히려는 순간에야
|
|
86
|
-
프레임마다 조용히 실패한다. 등록에서 한 번 크게 실패하는 편이 낫다.
|
|
87
|
-
*/
|
|
88
|
-
if (bp.anchors !== undefined) {
|
|
89
|
-
if (!Array.isArray(bp.anchors)) {
|
|
90
|
-
problems.push('anchors 가 배열이 아니다');
|
|
91
|
-
}
|
|
92
|
-
else {
|
|
93
|
-
bp.anchors.forEach((at, ai) => {
|
|
94
|
-
const where = `anchors[${ai}]`;
|
|
95
|
-
if (typeof at?.name !== 'string' || at.name.length === 0) {
|
|
96
|
-
problems.push(`${where}.name 이 없다 — 이름이 곧 slot·port 의 id 다`);
|
|
97
|
-
}
|
|
98
|
-
if (!Array.isArray(at?.roles) || at.roles.length === 0) {
|
|
99
|
-
problems.push(`${where}.roles 가 역할 하나 이상의 배열이 아니다`);
|
|
100
|
-
}
|
|
101
|
-
else if (at.roles.some(role => !PART_ROLES.includes(role))) {
|
|
102
|
-
problems.push(`${where}.roles 에 ${PART_ROLES.join(' · ')} 밖의 값이 있다`);
|
|
103
|
-
}
|
|
104
|
-
const t = at?.transform;
|
|
105
|
-
if (!t || !isFiniteVec3(t.position) || !isFiniteVec3(t.size)) {
|
|
106
|
-
problems.push(`${where}.transform 의 값이 온전하지 않다`);
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
/*
|
|
112
|
-
값이 만드는 자세.
|
|
113
|
-
|
|
114
|
-
`anchors` 와 같은 갈래다 — 없어도 되고, **틀려도 세울 때는 아무 일도 안 일어난다.**
|
|
115
|
-
인스턴스가 값을 주는 순간에야 프레임마다 조용히 기본 자세로 돌아간다. 등록에서 한 번
|
|
116
|
-
크게 실패하는 편이 낫다.
|
|
117
|
-
|
|
118
|
-
`range` 를 여기서 보는 이유는 그것이 **런타임의 나누는 수**라서다. `max` 가 `min`
|
|
119
|
-
이하면 런타임이 물리량을 0~1 로 맵할 수 없고, 그러면 준 값이 조용히 버려진다.
|
|
120
|
-
*/
|
|
121
|
-
if (bp.parameters !== undefined) {
|
|
122
|
-
if (!Array.isArray(bp.parameters)) {
|
|
123
|
-
problems.push('parameters 가 배열이 아니다');
|
|
124
|
-
}
|
|
125
|
-
else {
|
|
126
|
-
bp.parameters.forEach((parameter, pi) => {
|
|
127
|
-
const where = `parameters[${pi}]`;
|
|
128
|
-
if (typeof parameter?.name !== 'string' || parameter.name.length === 0) {
|
|
129
|
-
problems.push(`${where}.name 이 없다 — 인스턴스가 이 이름으로 값을 준다`);
|
|
130
|
-
}
|
|
131
|
-
const range = parameter?.range;
|
|
132
|
-
if (!range || !isFiniteNumber(range.min) || !isFiniteNumber(range.max)) {
|
|
133
|
-
problems.push(`${where}.range 의 min·max 가 온전하지 않다`);
|
|
134
|
-
}
|
|
135
|
-
else if (!(range.max > range.min)) {
|
|
136
|
-
problems.push(`${where}.range 의 max 가 min 보다 크지 않다 — 0~1 로 맵할 수 없다`);
|
|
137
|
-
}
|
|
138
|
-
if (!parameter?.clip || !Array.isArray(parameter.clip.channels)) {
|
|
139
|
-
problems.push(`${where}.clip.channels 가 배열이 아니다 — 값이 무엇을 움직이는지 없다`);
|
|
140
|
-
}
|
|
141
|
-
else if (parameter.clip.duration !== undefined &&
|
|
142
|
-
!(isFiniteNumber(parameter.clip.duration) && parameter.clip.duration >= 0)) {
|
|
143
|
-
problems.push(`${where}.clip.duration 이 0 이상의 수가 아니다`);
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
/*
|
|
149
|
-
Joints (ADR-0066). Optional, like anchors. The runtime builds a node per joint and hangs groups from
|
|
150
|
-
the node a group names, so a group or anchor naming a joint that is not there, a zero axis, or a
|
|
151
|
-
parent that comes later would leave parts in no frame or turn them by nothing. Refused at
|
|
152
|
-
registration instead.
|
|
153
|
-
*/
|
|
154
|
-
if (bp.joints !== undefined) {
|
|
155
|
-
if (!Array.isArray(bp.joints)) {
|
|
156
|
-
problems.push('joints 가 배열이 아니다');
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
const placed = new Set();
|
|
160
|
-
bp.joints.forEach((joint, ji) => {
|
|
161
|
-
const where = `joints[${ji}]`;
|
|
162
|
-
if (typeof joint?.name !== 'string' || joint.name.length === 0) {
|
|
163
|
-
problems.push(`${where}.name 이 없다 — channel 이 이 이름으로 관절을 몬다`);
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
if (!JOINT_TYPES.includes(joint.type)) {
|
|
167
|
-
problems.push(`${where}.type 이 ${JOINT_TYPES.join(' · ')} 가 아니다`);
|
|
168
|
-
}
|
|
169
|
-
if (!isFiniteVec3(joint.origin))
|
|
170
|
-
problems.push(`${where}.origin 이 온전하지 않다`);
|
|
171
|
-
if (!isFiniteVec3(joint.axis) || Math.hypot(joint.axis.x, joint.axis.y, joint.axis.z) === 0) {
|
|
172
|
-
problems.push(`${where}.axis 가 0 이 아닌 벡터가 아니다`);
|
|
173
|
-
}
|
|
174
|
-
if (joint.parent !== undefined && !placed.has(joint.parent)) {
|
|
175
|
-
problems.push(`${where}.parent '${joint.parent}' 가 앞에 없다 — 관절은 부모가 먼저 온다`);
|
|
176
|
-
}
|
|
177
|
-
placed.add(joint.name);
|
|
178
|
-
});
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
const frames = new Set(Array.isArray(bp.joints) ? bp.joints.map(joint => joint?.name) : []);
|
|
182
|
-
bp.groups.forEach((group, gi) => {
|
|
183
|
-
if (group?.joint !== undefined && !frames.has(group.joint)) {
|
|
184
|
-
problems.push(`groups[${gi}].joint '${group.joint}' 가 joints 에 없다`);
|
|
185
|
-
}
|
|
186
|
-
});
|
|
187
|
-
(Array.isArray(bp.anchors) ? bp.anchors : []).forEach((at, ai) => {
|
|
188
|
-
if (at?.joint !== undefined && !frames.has(at.joint)) {
|
|
189
|
-
problems.push(`anchors[${ai}].joint '${at.joint}' 가 joints 에 없다`);
|
|
190
|
-
}
|
|
191
|
-
});
|
|
192
|
-
return problems;
|
|
193
|
-
}
|
|
194
|
-
//# sourceMappingURL=blueprint-shape.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"blueprint-shape.js","sourceRoot":"","sources":["../src/blueprint-shape.ts"],"names":[],"mappings":"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"}
|
package/dist/blueprint.d.ts
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { type ValidateResult } from './validate.ts';
|
|
2
|
-
export { geometryKeyOf, emissiveKeyOf, materialKeyOf, usesSegments } from './keys.ts';
|
|
3
|
-
import { type FigureBlueprint, type FigurePart, type Axis, type PartTransform, type Vec3 } from './types.ts';
|
|
4
|
-
/** 컴파일할 수 없을 때 던진다. 오류보고없이 빈 청사진을 돌려주지 않는다. */
|
|
5
|
-
export declare class FigureCompileError extends Error {
|
|
6
|
-
readonly errors: ValidateResult['errors'];
|
|
7
|
-
constructor(errors: ValidateResult['errors']);
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* 삼각형 수 추정.
|
|
11
|
-
*
|
|
12
|
-
* 근거는 things-scene 의 geometry 생성 인자다.
|
|
13
|
-
*
|
|
14
|
-
* cube · wall BoxGeometry 면 6 × 2 = 12
|
|
15
|
-
* cylinder CylinderGeometry(seg) 측면 2·seg + 캡 2·seg = 4·seg
|
|
16
|
-
* 민 것(n 점) ExtrudeGeometry 캡 2·(n−2) + 측면 2·n = 4n − 4
|
|
17
|
-
* 속 판 것 ExtrudeGeometry+구멍 4·(n + m) m 은 안쪽 테의 점 수
|
|
18
|
-
*
|
|
19
|
-
* ## 라운드를 안 세다가 12 배를 놓쳤다
|
|
20
|
-
*
|
|
21
|
-
* 한동안 `rect` 를 라운드와 무관하게 12 로 셌다. 「베벨과 라운드는 세지 않는다」고
|
|
22
|
-
* 적어 두기까지 했다. three 로 실제로 만들어 세어 보면
|
|
23
|
-
*
|
|
24
|
-
* rect 각짐 12 cube 와 같다 — 민다고 비싸지지 않는다
|
|
25
|
-
* rect round=24 140 모서리마다 8 점으로 뽑으므로 테가 36 점이 된다
|
|
26
|
-
* 속 판 rect round=24 160 구멍은 +20 이다. 고리의 캡이 통짜 캡보다 싸다
|
|
27
|
-
*
|
|
28
|
-
* **비싼 것은 미는 것이 아니라 라운드다.** 그리고 라운드는 저작자가 무심코 넣는
|
|
29
|
-
* 값이라, 예산이 12 배 적게 세고 있으면 그 선택의 대가가 화면에 안 나타난다.
|
|
30
|
-
*
|
|
31
|
-
* 그리는 쪽이 테를 몇 점으로 뽑는지(`SEGMENT_PRESETS[0]`)와 **같은 수**를 쓴다.
|
|
32
|
-
* 다르면 재는 값과 그려지는 것이 갈린다.
|
|
33
|
-
*/
|
|
34
|
-
export declare function trianglesOf(part: FigurePart): number;
|
|
35
|
-
/** `sizing` 이 없으면 무엇으로 보나 — 비례 확대가 가장 예측 가능하다. */
|
|
36
|
-
/**
|
|
37
|
-
* 회전까지 반영한 부품의 축별 크기.
|
|
38
|
-
*
|
|
39
|
-
* 회전한 상자의 여덟 꼭짓점을 각 축에 내린 것 — 축에 맞춘 경계다. 회전 행렬은
|
|
40
|
-
* `Rx·Ry·Rz` 이고 three 의 기본 Euler 순서('XYZ')와 같다. 그리는 쪽이 같은 순서로
|
|
41
|
-
* 돌리므로 여기서만 다르면 답이 달라진다.
|
|
42
|
-
*/
|
|
43
|
-
export declare function rotatedExtentOf(part: {
|
|
44
|
-
transform: PartTransform;
|
|
45
|
-
}): Vec3;
|
|
46
|
-
/**
|
|
47
|
-
* `stretch` 일 때 늘어나는 축.
|
|
48
|
-
*
|
|
49
|
-
* 형식에 축을 적는 자리가 없다. 대신 **부품이 가장 길게 뻗은 축**으로 정한다. 문서가
|
|
50
|
-
* 든 예(프레임 · 벨트 · 레일)가 전부 "길어서 그 물건인 것"이라 이 규칙과 맞는다.
|
|
51
|
-
* 정육면체에 가까운 부품에는 뜻이 없는데, 그런 부품은 애초에 `stretch` 를 쓸 자리가 아니다.
|
|
52
|
-
*
|
|
53
|
-
* **회전을 반영해 측정한다.** 크기만 보면 x 로 길게 그린 레일을 y 로 90° 돌려 세워도 여전히
|
|
54
|
-
* x 라고 답한다. 그러면 레일이 길이가 아니라 두께 쪽으로 늘어난다.
|
|
55
|
-
*
|
|
56
|
-
* 두 축의 길이가 같으면 x → z → y 순으로 정한다. 순서를 정해 두지 않으면 같은 부품이
|
|
57
|
-
* 소비처마다 다른 축으로 늘어난다.
|
|
58
|
-
*
|
|
59
|
-
* **소비처가 저마다 계산하면 안 된다.** 3D 와 2D 톱뷰와 속성 편집기가 같은 답을 내야
|
|
60
|
-
* 하므로 여기 한 곳에서만 정한다.
|
|
61
|
-
*/
|
|
62
|
-
export declare function stretchAxisOf(part: {
|
|
63
|
-
transform: PartTransform;
|
|
64
|
-
}): Axis;
|
|
65
|
-
/**
|
|
66
|
-
* 원본 데이터를 청사진으로 컴파일한다.
|
|
67
|
-
*
|
|
68
|
-
* `errors` 가 있으면 던진다 — 세울 수 없는 것을 반쯤 세운 청사진으로 돌려주면
|
|
69
|
-
* 어디서 잘못됐는지 알 수 없다. `violations` 는 청사진에 담아 돌려준다. 정책 위반은
|
|
70
|
-
* 컴파일을 막지 않고 숫자로 보인다.
|
|
71
|
-
*/
|
|
72
|
-
export declare function compile(source: unknown): FigureBlueprint;
|
|
73
|
-
//# sourceMappingURL=blueprint.d.ts.map
|
package/dist/blueprint.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"blueprint.d.ts","sourceRoot":"","sources":["../src/blueprint.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAY,KAAK,cAAc,EAAE,MAAM,eAAe,CAAA;AAM7D,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AACrF,OAAO,EAeL,KAAK,eAAe,EACpB,KAAK,UAAU,EAGf,KAAK,IAAI,EACT,KAAK,aAAa,EAClB,KAAK,IAAI,EACV,MAAM,YAAY,CAAA;AAEnB,+CAA+C;AAC/C,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAA;gBAE7B,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC;CAS7C;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CA0BpD;AAuBD,kDAAkD;AAElD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE;IAAE,SAAS,EAAE,aAAa,CAAA;CAAE,GAAG,IAAI,CAuBxE;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE;IAAE,SAAS,EAAE,aAAa,CAAA;CAAE,GAAG,IAAI,CAKtE;AAyFD;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,OAAO,GAAG,eAAe,CAwHxD"}
|