@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.
- package/CHANGELOG.md +11 -0
- package/README.md +60 -138
- package/dist/index.d.ts +1 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -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-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.js +1 -1
- package/dist/v3-proposal.js.map +1 -1
- 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
package/dist/types.d.ts
DELETED
|
@@ -1,1233 +0,0 @@
|
|
|
1
|
-
/** 저작에 쓰는 프리미티브. mesh 계열과 extrude 계열로 나뉜다. */
|
|
2
|
-
export declare const PRIMITIVE_KINDS: readonly ["cube", "wall", "cylinder", "sphere", "rect", "polygon"];
|
|
3
|
-
export type PrimitiveKind = (typeof PRIMITIVE_KINDS)[number];
|
|
4
|
-
/** extrude 계열은 2D 단면이 필요하다. */
|
|
5
|
-
export declare const EXTRUDE_PRIMITIVES: readonly PrimitiveKind[];
|
|
6
|
-
/** mesh 계열은 치수만으로 선다. 분할 수를 갖는다. */
|
|
7
|
-
export declare const MESH_PRIMITIVES: readonly PrimitiveKind[];
|
|
8
|
-
/** 분할 수를 갖는 프리미티브 — 곡면이 있는 것만. */
|
|
9
|
-
export declare const SEGMENTED_PRIMITIVES: readonly PrimitiveKind[];
|
|
10
|
-
/**
|
|
11
|
-
* 단면이 **원**인 프리미티브.
|
|
12
|
-
*
|
|
13
|
-
* 축마다 다른 배율을 받으면 타원이 된다. 그래서 이것들은 합친 묶음에 들지 못한다 —
|
|
14
|
-
* 합친 형상은 변환을 하나만 받는다. 곡면 부품 하나가 draw call 하나다.
|
|
15
|
-
*/
|
|
16
|
-
export declare const CURVED_PRIMITIVES: readonly PrimitiveKind[];
|
|
17
|
-
/**
|
|
18
|
-
* 재질 슬롯. extrude 계열의 재질 인덱스가 둘로 정해져 있다.
|
|
19
|
-
* `threed/real-object-extrude.ts:105-111` — 0 = cap(fillStyle), 1 = side(strokeStyle)
|
|
20
|
-
*/
|
|
21
|
-
export declare const MATERIAL_SLOTS: readonly ["cap", "side"];
|
|
22
|
-
export type MaterialSlot = (typeof MATERIAL_SLOTS)[number];
|
|
23
|
-
/** 재질 프리셋. `threed/material-3d.ts:9` 의 preset 과 같은 집합. */
|
|
24
|
-
export declare const MATERIAL_PRESETS: readonly ["default", "metal", "glass", "plastic", "wood", "ceramic", "rubber"];
|
|
25
|
-
export type MaterialPreset = (typeof MATERIAL_PRESETS)[number];
|
|
26
|
-
/**
|
|
27
|
-
* 저작이 고를 수 있는 능력 — **씬이 실제로 조립할 수 있는 것만 있다.**
|
|
28
|
-
*
|
|
29
|
-
* `MATERIAL_PRESETS` 와 같은 갈래다. 형식이 목록을 선언하고 씬이 그것을 소비한다.
|
|
30
|
-
*
|
|
31
|
-
* ## 왜 목록이 형식에 있나
|
|
32
|
-
*
|
|
33
|
-
* 한동안 things-scene 에만 있었다. 그래서 `validate` 가 이름을 못 봤고, AI 가 낸
|
|
34
|
-
* `capabilities: ['hoist']` 가 **검증을 지나고 발행을 지나** 렌더링에서 죽었다. 게이트는
|
|
35
|
-
* 사실이 사는 곳에 있어야 한다 — 형식이 무엇이 성립하는 도형인지 판정하는 자리이므로
|
|
36
|
-
* 여기다(ADR-0051 ④).
|
|
37
|
-
*
|
|
38
|
-
* `PlacementSurface`·`CarrierLine` 같은 이름은 씬에 metadata 는 있어도 mixin factory 가
|
|
39
|
-
* 없다. 구현이 있어야 성립하는 계약이라, 이름만 적어 지게 하면 「선언은 있는데 동작이
|
|
40
|
-
* 없는」 것이 된다. **여기 있는 넷은 씬에 조립할 것이 있다.**
|
|
41
|
-
*
|
|
42
|
-
* ## 사다리
|
|
43
|
-
*
|
|
44
|
-
* Capacity 자리를 갖는다
|
|
45
|
-
* Holdable 담긴 것을 함께 들고 그린다
|
|
46
|
-
* Transferable 자리를 잡아 두고 넘겨받는다 — `Capacity` 가 있어야 자리를 찾는다
|
|
47
|
-
* FlowNode 흐름의 마디다. 위의 셋을 스스로 포함한다
|
|
48
|
-
*/
|
|
49
|
-
export declare const FIGURE_CAPABILITIES: readonly ["Capacity", "Holdable", "Transferable", "FlowNode"];
|
|
50
|
-
export type FigureCapability = (typeof FIGURE_CAPABILITIES)[number];
|
|
51
|
-
/**
|
|
52
|
-
* 혼자 설 수 없는 능력 — 이름 → 그 중 **하나라도** 함께 있어야 하는 것들.
|
|
53
|
-
*
|
|
54
|
-
* `Transferable` 은 자리를 찾는 일을 `Capacity` 에게 맡긴다. 혼자 적으면 씬이 조립할 때
|
|
55
|
-
* 던지는데, 그때는 이미 발행된 뒤다. 모르는 이름과 같은 갈래라 같은 자리에서 본다.
|
|
56
|
-
*/
|
|
57
|
-
export declare const CAPABILITY_NEEDS: Readonly<Record<string, readonly FigureCapability[]>>;
|
|
58
|
-
/**
|
|
59
|
-
* 크기 반응 규칙 — 인스턴스 크기가 바뀔 때 부품이 어떻게 변하는가.
|
|
60
|
-
*
|
|
61
|
-
* scale 비례 확대. 탱크 몸체 같은 단일 덩어리
|
|
62
|
-
* fixed 크기는 그대로, 자리만 따라간다. 모터·계기·노즐
|
|
63
|
-
* stretch 한 축만 늘어난다. 프레임·벨트·레일
|
|
64
|
-
* repeat 개수가 늘어난다. 롤러·선반 단 ← 새 geometry 가 생기지 않는다
|
|
65
|
-
*/
|
|
66
|
-
/** What `sizing` means when a part does not say. */
|
|
67
|
-
export declare const DEFAULT_SIZING: "scale";
|
|
68
|
-
/**
|
|
69
|
-
* How many copies one repeat part may expand to.
|
|
70
|
-
*
|
|
71
|
-
* Every copy is a draw call, so an instance stretched far enough would grow
|
|
72
|
-
* without bound and one asset would eat the frame. Past this point the copies
|
|
73
|
-
* are too small to count anyway, so more of them changes nothing on screen.
|
|
74
|
-
*
|
|
75
|
-
* The renderer enforces the same number. It lives here because the report has
|
|
76
|
-
* to predict what the renderer will do -- things-scene used to keep its own
|
|
77
|
-
* copy of it.
|
|
78
|
-
*/
|
|
79
|
-
export declare const REPEAT_LIMIT = 100;
|
|
80
|
-
export declare const SIZING_RULES: readonly ["scale", "fixed", "stretch", "repeat"];
|
|
81
|
-
export type SizingRule = (typeof SIZING_RULES)[number];
|
|
82
|
-
/**
|
|
83
|
-
* 3D 배치 기준면.
|
|
84
|
-
*
|
|
85
|
-
* floor 바닥 기준 (y=0 위에 서 있음. AGV, 로봇, 컨베이어, 파렛트 등)
|
|
86
|
-
* ceiling 천정 기준 (상단 레일/천정에 매달림. OHT, 호이스트 등)
|
|
87
|
-
* center 중심 기준 (공간 부유/중심 기준. 드론, 센서, 부유물 등)
|
|
88
|
-
*/
|
|
89
|
-
export declare const FIGURE_PLACEMENTS: readonly ["floor", "ceiling", "center"];
|
|
90
|
-
export type FigurePlacement = (typeof FIGURE_PLACEMENTS)[number];
|
|
91
|
-
/**
|
|
92
|
-
* 부품이 한 축에서 기준 상자의 **어느 면을 붙잡나**. 축마다 따로 정한다.
|
|
93
|
-
*
|
|
94
|
-
* scale **아무 면도 안 붙잡는다.** 상자와 함께 비례로 커진다
|
|
95
|
-
* min 아래(또는 왼쪽·뒤) 면에서 잰 거리를 지킨다
|
|
96
|
-
* center 자리는 비례로 따라가고 **크기는 지킨다**
|
|
97
|
-
* max 위(또는 오른쪽·앞) 면에서 잰 거리를 지킨다
|
|
98
|
-
* span **양쪽을 다 붙잡는다.** 가운데가 늘어나 사이를 채운다
|
|
99
|
-
*
|
|
100
|
-
* 붙잡는 면의 수로 읽으면 하나다 — 0 개면 상자와 함께 커지고, 1 개면 그 면에서 잰
|
|
101
|
-
* 거리를 지키고, 2 개면 사이를 채운다. 3D 도구의 나인슬라이스가 하는 일이고 여기서는
|
|
102
|
-
* 그것이 세 축으로 있다.
|
|
103
|
-
*
|
|
104
|
-
* ## `repeat` 의 축에서는 **줄이 어떻게 되는가**를 말한다
|
|
105
|
-
*
|
|
106
|
-
* 같은 「반복」이 두 가지다.
|
|
107
|
-
*
|
|
108
|
-
* 컨베이어의 롤러 길어지면 롤러가 **는다.** 한 칸 간격은 그대로다
|
|
109
|
-
* 셀트레이의 셀 커지면 셀이 **커진다.** 개수는 그 트레이가 몇 셀짜리냐이지
|
|
110
|
-
* 화면에 얼마나 크게 그렸느냐가 아니다
|
|
111
|
-
*
|
|
112
|
-
* 앞의 것이 `center`(줄이 상자를 채운다), 뒤의 것이 `scale`(줄이 상자와 함께 큰다)이다.
|
|
113
|
-
*
|
|
114
|
-
* ## 없던 것을 왜 더하나
|
|
115
|
-
*
|
|
116
|
-
* `sizing` 은 부품의 **크기**가 인스턴스를 어떻게 따라가는지만 말했다. **자리**는
|
|
117
|
-
* 언제나 비례였다. 그래서 시그널 타워를 3 배로 세우면 기둥은 늘어나는데 램프들은
|
|
118
|
-
* 기둥 위 공중으로 흩어졌다 — 저작한 자리 512 가 1536 이 되고, 그 사이의 틈 100 이
|
|
119
|
-
* 300 이 되기 때문이다.
|
|
120
|
-
*
|
|
121
|
-
* 1× foot 0..90 · pole 85..705 · bracket 703..747 · … · cap 1037..1087
|
|
122
|
-
* 3× foot 90..180 · pole 255..2115 · bracket 2153..2197 · … · cap 3161..3211
|
|
123
|
-
*
|
|
124
|
-
* 램프는 상자 안 어디쯤이 아니라 **기둥 꼭대기**에 붙어 있다. 형식에 그 말을 적을
|
|
125
|
-
* 자리가 없었다.
|
|
126
|
-
*
|
|
127
|
-
* ## 적지 않으면 **가까운 면**을 붙잡는다
|
|
128
|
-
*
|
|
129
|
-
* 상자의 위 절반에 저작한 것은 위를, 아래 절반에 저작한 것은 아래를 붙잡는다.
|
|
130
|
-
* 정확히 가운데면 `center` 다. 사람이 램프를 꼭대기 근처에 놓을 때 뜻하는 것이
|
|
131
|
-
* 그것이고, 그래서 표본 열넷 중 어느 것도 이 값을 적지 않고 제대로 선다.
|
|
132
|
-
*
|
|
133
|
-
* **적어 두면 `sizing` 을 이긴다 — `'scale'` 이어도 그렇다.** `sizing: 'scale'` 인 부품은
|
|
134
|
-
* *적지 않았을 때* 상자와 함께 커진다는 뜻이고, 축 하나에 `max` 를 적으면 그 축에서는 위 면에서
|
|
135
|
-
* 잰 거리를 지킨다. 한동안 이 자리에 「`scale` 인 부품에는 뜻이 없다」고 적혀 있었는데 코드와
|
|
136
|
-
* 달랐고(`anchorOf` 는 적힌 값을 먼저 돌려준다), 그 주석 때문에 저작 화면의 편집기가 잘못된 것
|
|
137
|
-
* 아니냐는 의심을 받았다.
|
|
138
|
-
*/
|
|
139
|
-
export declare const ANCHOR_RULES: readonly ["scale", "min", "center", "max", "span", "aspect-x", "aspect-y", "aspect-z"];
|
|
140
|
-
export type AnchorRule = (typeof ANCHOR_RULES)[number];
|
|
141
|
-
/**
|
|
142
|
-
* 축별 앵커. 적지 않은 축은 `sizing` 이 정한 것을 따른다.
|
|
143
|
-
*
|
|
144
|
-
* **`sizing` 하나로는 못 하는 말이 있어서 있다.** 컨베이어의 데크가 그렇다 —
|
|
145
|
-
* 길이(x)와 폭(z)은 상자를 채우고 두께(y)는 24 mm 그대로여야 한다. `sizing` 은
|
|
146
|
-
* 부품당 하나라 「x 는 채우고 y 는 붙잡는다」를 적을 자리가 없었다.
|
|
147
|
-
*
|
|
148
|
-
* sizing: 'fixed', anchor: { x: 'span', y: 'max', z: 'span' }
|
|
149
|
-
*/
|
|
150
|
-
export interface PartAnchor {
|
|
151
|
-
x?: AnchorRule;
|
|
152
|
-
y?: AnchorRule;
|
|
153
|
-
z?: AnchorRule;
|
|
154
|
-
}
|
|
155
|
-
/**
|
|
156
|
-
* 디테일 등급 — 이 형상을 얼마나 상세하게 만들 것인지 저작자가 밝히는 값.
|
|
157
|
-
*
|
|
158
|
-
* S 단순 표지 · 기둥처럼 형태가 단순한 것
|
|
159
|
-
* M 보통 대부분의 설비
|
|
160
|
-
* L 상세 화면의 주역이 되는 큰 설비
|
|
161
|
-
*
|
|
162
|
-
* 밝힌 등급이 부품 수 상한을 정한다. 그리고 성숙도가 그 등급에 걸맞게 만들어졌는지
|
|
163
|
-
* 본다. 등급만 L 로 올려 놓고 부품 셋으로 끝내면 밝힌 것과 만든 것이 다르다.
|
|
164
|
-
*
|
|
165
|
-
* **뜻을 여기 적어 두는 이유가 있다.** 한동안 이 값의 내용물이 부품 수 상한 하나뿐이었다.
|
|
166
|
-
* 그래서 "왜 L 인가" 에 답할 수가 없었고, 저작 화면도 등급이라는 글자만 보여 주었다.
|
|
167
|
-
*/
|
|
168
|
-
export declare const DETAIL_LEVELS: readonly ["S", "M", "L"];
|
|
169
|
-
export type DetailLevel = (typeof DETAIL_LEVELS)[number];
|
|
170
|
-
/** 등급별 부품 수 상한. */
|
|
171
|
-
export declare const PART_LIMIT: Record<DetailLevel, number>;
|
|
172
|
-
/**
|
|
173
|
-
* 채널이 무엇을 움직이나. **glTF 의 `target.path` 그대로다.**
|
|
174
|
-
*
|
|
175
|
-
* `weights` 는 없다 — 모프 타깃이 없는 형식이다.
|
|
176
|
-
*/
|
|
177
|
-
export declare const CHANNEL_PATHS: readonly ["translation", "rotation", "scale"];
|
|
178
|
-
export type ChannelPath = (typeof CHANNEL_PATHS)[number];
|
|
179
|
-
/** 키프레임 사이를 어떻게 잇나. glTF 의 `CUBICSPLINE` 은 없다 — 접선을 손으로 적을 형식이 아니다. */
|
|
180
|
-
export declare const INTERPOLATIONS: readonly ["linear", "step"];
|
|
181
|
-
export type Interpolation = (typeof INTERPOLATIONS)[number];
|
|
182
|
-
export declare const AXES: readonly ["x", "y", "z"];
|
|
183
|
-
export type Axis = (typeof AXES)[number];
|
|
184
|
-
/**
|
|
185
|
-
* How a joint moves its child part relative to the parent (ADR-0066).
|
|
186
|
-
*
|
|
187
|
-
* revolute turns about `axis` within `limits`, in degrees
|
|
188
|
-
* prismatic slides along `axis` within `limits`, in millimetres
|
|
189
|
-
* continuous turns about `axis` without limits, in degrees
|
|
190
|
-
*
|
|
191
|
-
* These are URDF's three moving joint types. A fixed attachment is not a joint: a part names its parent
|
|
192
|
-
* with `FigurePart.parent` and moves with it.
|
|
193
|
-
*/
|
|
194
|
-
export declare const JOINT_TYPES: readonly ["revolute", "prismatic", "continuous"];
|
|
195
|
-
export type JointType = (typeof JOINT_TYPES)[number];
|
|
196
|
-
/** 텍스트를 언제 보이나. 표현 수단(sprite·overlay)은 런타임이 고른다. */
|
|
197
|
-
export declare const LABEL_WHENS: readonly ["always", "zoomed", "selected", "abnormal"];
|
|
198
|
-
export type LabelWhen = (typeof LABEL_WHENS)[number];
|
|
199
|
-
export interface Vec3 {
|
|
200
|
-
x: number;
|
|
201
|
-
y: number;
|
|
202
|
-
z: number;
|
|
203
|
-
}
|
|
204
|
-
export interface Point2 {
|
|
205
|
-
x: number;
|
|
206
|
-
y: number;
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* 부품의 자리와 크기.
|
|
210
|
-
*
|
|
211
|
-
* ## 축은 3D 도구들이 쓰는 그대로다
|
|
212
|
-
*
|
|
213
|
-
* **`x` 오른쪽, `y` 위, `z` 앞(보는 쪽).** glTF·three.js·Unity 와 같다.
|
|
214
|
-
*
|
|
215
|
-
* 전에는 things-scene 컴포넌트 state 의 용어를 그대로 가져와 `z` 를 위로 두었다. 그
|
|
216
|
-
* 용어는 2D 캔버스에서 온 것이지 3D 규약이 아니다. things-scene 의 3D 세계는 y 가
|
|
217
|
-
* 위이고, 불러온 glTF 모델도 축을 돌리지 않고 그대로 쓴다. 도형 안쪽 좌표까지 캔버스
|
|
218
|
-
* 용어를 따를 이유가 없어서 되돌렸다.
|
|
219
|
-
*
|
|
220
|
-
* ## 용어도 모델러가 쓰는 그대로다
|
|
221
|
-
*
|
|
222
|
-
* `position`·`rotation`·`size` 셋이고 저마다 X·Y·Z 를 갖는다. Blender 의
|
|
223
|
-
* Location·Rotation·Dimensions, Godot 의 Position·Rotation·Size, glTF 의
|
|
224
|
-
* translation·rotation·scale 과 같은 짜임이다.
|
|
225
|
-
*
|
|
226
|
-
* `width`·`height`·`depth` 는 쓰지 않는다. 그 용어들은 **어느 축인지를 따로 외워야
|
|
227
|
-
* 한다.** 축을 되돌린 원인이 바로 그것이었다.
|
|
228
|
-
*
|
|
229
|
-
* 씬 컴포넌트의 state 는 여전히 `width`·`height`·`depth` 이고 축 배정도 다르다.
|
|
230
|
-
* 그 환산은 그리는 쪽 경계 한 곳에서 한다. 형식 안에서는 축이 한 뜻이다.
|
|
231
|
-
*
|
|
232
|
-
* ## 자리는 부품의 중심이다
|
|
233
|
-
*
|
|
234
|
-
* 여느 모델러와 같이 **원점은 부품의 중심**이고 `position` 은 그 원점의 자리다.
|
|
235
|
-
*
|
|
236
|
-
* The frame it is measured in has its origin at the bottom centre of the `base` box: `x` and `z` from
|
|
237
|
-
* the box centre, `y` up from the bottom face (source edition 2, ADR-0065). A part standing on the
|
|
238
|
-
* floor of the box has `position.y` equal to half its height, and changing `base.y` leaves every part's
|
|
239
|
-
* numbers where they were. Edition 1 measured `y` from the box centre as well; the compiled blueprint
|
|
240
|
-
* still does, and `origin.ts` is the one place a source is turned into that frame.
|
|
241
|
-
*
|
|
242
|
-
* 전에는 최소 모서리를 자리로 뒀다. 격자 스냅 때문이라고 적혀 있었는데, 모델러들은
|
|
243
|
-
* 모두 원점을 격자에 붙이고 크기는 따로 스냅한다. 우리만 다르게 둘 이유가 없다.
|
|
244
|
-
*/
|
|
245
|
-
export interface PartTransform {
|
|
246
|
-
/** 부품 중심의 자리 [단위: mm]. */
|
|
247
|
-
position: Vec3;
|
|
248
|
-
/** 축별 크기 [단위: mm]. `size.y` 가 0 이면 바닥에 깔린 평면이다(extrude 단면). */
|
|
249
|
-
size: Vec3;
|
|
250
|
-
/** 축별 회전(도, degree). 오일러 각 회전 순서는 Three.js/glTF 표준인 'XYZ' (Rx -> Ry -> Rz) 순서를 따른다. */
|
|
251
|
-
rotation?: Partial<Vec3>;
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* 부품 재질.
|
|
255
|
-
*
|
|
256
|
-
* 색은 **팔레트 토큰**으로 둔다(`token`). 값을 굽으면 StyleKit 을 바꿔도 따라오지
|
|
257
|
-
* 않는다. 토큰 해석은 그리는 시점에 한다.
|
|
258
|
-
*/
|
|
259
|
-
/**
|
|
260
|
-
* 팔레트 밖 표면의 종류.
|
|
261
|
-
*
|
|
262
|
-
* 둘 다 **이름으로 가리키는 자산**이다. 같은 이름이면 같은 텍스처이고, 따라서 재질도
|
|
263
|
-
* 나눠 쓴다 — `MaterialBank` 가 텍스처를 spec 서명에 넣기 때문이다.
|
|
264
|
-
*/
|
|
265
|
-
export declare const SURFACE_KINDS: readonly ["gradient", "pattern"];
|
|
266
|
-
export type SurfaceKind = (typeof SURFACE_KINDS)[number];
|
|
267
|
-
/**
|
|
268
|
-
* 팔레트 밖의 표면 — **미감의 예외다.**
|
|
269
|
-
*
|
|
270
|
-
* 라벨 판이나 표시창처럼 단색으로는 안 되는 자리에 쓴다.
|
|
271
|
-
*
|
|
272
|
-
* ## 재질은 나눠 쓴다
|
|
273
|
-
*
|
|
274
|
-
* 이름으로 가리키는 자산이므로 같은 `ref` 를 쓰는 부품끼리 텍스처와 재질을 나눠 쓴다.
|
|
275
|
-
* **인스턴스가 늘어도 재질이 늘지 않는다.**
|
|
276
|
-
*
|
|
277
|
-
* 처음에 이것을 `unsharedSurface` 라 부르고 「재질을 나눠 쓸 수 없다」고 셌는데
|
|
278
|
-
* 틀렸다. things-scene 의 컴포넌트는 텍스처를 **자기 bounds 와 상태로부터** 만들어
|
|
279
|
-
* 인스턴스마다 다르지만, 이 형식의 것은 이름으로 가리키는 고정 자산이다.
|
|
280
|
-
*
|
|
281
|
-
* ## 그래도 한도를 둔다
|
|
282
|
-
*
|
|
283
|
-
* 이유가 재질 공유가 아니라 둘이다.
|
|
284
|
-
*
|
|
285
|
-
* 미감 단색 규칙의 예외다. 늘어나면 로우폴리가 무너진다
|
|
286
|
-
* 메모리 텍스처마다 GPU 메모리와 샘플러를 쓴다
|
|
287
|
-
*/
|
|
288
|
-
export interface PartSurface {
|
|
289
|
-
kind: SurfaceKind;
|
|
290
|
-
/** 무엇을 쓰나. 텍스처 이름·이미지 키. 해석은 그리는 쪽이 한다. */
|
|
291
|
-
ref: string;
|
|
292
|
-
}
|
|
293
|
-
/** 램프가 켜졌을 때의 모습. */
|
|
294
|
-
export interface EmissiveSpec {
|
|
295
|
-
/**
|
|
296
|
-
* 켜졌을 때의 색. 없으면 꺼졌을 때와 같은 색이다.
|
|
297
|
-
*
|
|
298
|
-
* 팔레트 토큰이다. `palette.status-*` 넷이 이 자리에 쓰라고 있는 색이다.
|
|
299
|
-
*/
|
|
300
|
-
token?: string;
|
|
301
|
-
/**
|
|
302
|
-
* 스스로 빛나는 세기. 0~1.
|
|
303
|
-
*
|
|
304
|
-
* 그리는 쪽에서 `MeshStandardMaterial.emissiveIntensity` 가 된다. **그 면이 밝아지는
|
|
305
|
-
* 것**이지 주변을 물들이거나 번지지 않는다. 진짜 번짐(bloom)은 후처리 패스가 필요하고
|
|
306
|
-
* 그것은 이 형식 밖이다.
|
|
307
|
-
*/
|
|
308
|
-
intensity: number;
|
|
309
|
-
/**
|
|
310
|
-
* 기본 상태. 없으면 꺼진 채로 그린다.
|
|
311
|
-
*
|
|
312
|
-
* 「지금 켜져 있다」가 아니라 **「아무도 말해 주지 않으면 이렇다」**이다. 인스턴스가
|
|
313
|
-
* 말하면 그것이 이긴다.
|
|
314
|
-
*/
|
|
315
|
-
on?: boolean;
|
|
316
|
-
}
|
|
317
|
-
export interface PartMaterial {
|
|
318
|
-
/** 팔레트 토큰. 예: 'palette.primary' */
|
|
319
|
-
token?: string;
|
|
320
|
-
preset?: MaterialPreset;
|
|
321
|
-
/**
|
|
322
|
-
* 면을 각지게 그리나. **없으면 각지게 그린다(`true`).**
|
|
323
|
-
*
|
|
324
|
-
* 기본값을 여기에 정해 둔다. 전에는 형식에 기본값이 없고 그리는 쪽만 `?? true` 로
|
|
325
|
-
* 두었는데, 저작 화면의 체크상자는 값이 없으면 꺼진 것으로 보였다. **적힌 것과
|
|
326
|
-
* 보이는 것이 달랐다.**
|
|
327
|
-
*
|
|
328
|
-
* 각진 것이 기본인 이유는 저폴리의 생김새가 거기서 나오기 때문이다. 12 분할 원기둥을
|
|
329
|
-
* 매끄럽게 칠하면 분할 수를 줄인 뜻이 없어진다.
|
|
330
|
-
*/
|
|
331
|
-
flatShading?: boolean;
|
|
332
|
-
transparent?: boolean;
|
|
333
|
-
/**
|
|
334
|
-
* 켜진 모습. **없으면 램프가 아니다.**
|
|
335
|
-
*
|
|
336
|
-
* ## 한 부품이 두 모습을 갖는다
|
|
337
|
-
*
|
|
338
|
-
* 꺼진 전구는 빨갛지 않다. 어두운 플라스틱이다. 그래서 `token` 은 **꺼진 모습**이고
|
|
339
|
-
* 여기 적는 것이 **켜진 모습**이다.
|
|
340
|
-
*
|
|
341
|
-
* 한동안 `material.emissive` 하나만 두었다. 그러면 발광을 꺼도 색은 빨간 채로 남아
|
|
342
|
-
* 「꺼진 램프」가 안 된다 — 실제로 화면에서 그랬다.
|
|
343
|
-
*
|
|
344
|
-
* ## 켜고 끄는 것은 인스턴스가 한다
|
|
345
|
-
*
|
|
346
|
-
* 자산 하나가 도면에 열 개 놓이면 각각 다른 등이 켜진다. `on` 은 **기본 상태**일
|
|
347
|
-
* 뿐이고, 인스턴스가 말하면 그것이 이긴다.
|
|
348
|
-
*
|
|
349
|
-
* ## 비용
|
|
350
|
-
*
|
|
351
|
-
* 재질은 둘이 되지만 **동시에 그려지지 않는다.** 부품 하나는 어느 쪽을 입든 묶음
|
|
352
|
-
* 하나다 — draw call 이 늘지 않는다.
|
|
353
|
-
*
|
|
354
|
-
* ## 밝은 곳에서는 발광이 잘 안 보인다
|
|
355
|
-
*
|
|
356
|
-
* [확인함] 저작 화면 기본 조명(하늘빛 4.0 · 키 라이트 2.0)에서 `emissive` 를 0.9 로
|
|
357
|
-
* 켜고 끈 화면이 눈으로 구별되지 않았다. ACES 톤 매핑이 밝은 쪽을 눌러 버린다.
|
|
358
|
-
* 그래서 **색이 같이 바뀌어야** 점등이 읽힌다. `token` 을 두 벌 두는 이유가 이것이다.
|
|
359
|
-
*/
|
|
360
|
-
emissive?: EmissiveSpec;
|
|
361
|
-
/**
|
|
362
|
-
* 팔레트 밖의 표면. **미감의 예외다.**
|
|
363
|
-
*
|
|
364
|
-
* 없는 것이 정상이다. 재질은 나눠 쓰지만 텍스처 메모리를 쓰고 단색 규칙을 벗어나므로
|
|
365
|
-
* 셈에 들어간다.
|
|
366
|
-
*/
|
|
367
|
-
surface?: PartSurface;
|
|
368
|
-
}
|
|
369
|
-
/** `sizing === 'repeat'` 일 때 늘어나는 축과 간격. */
|
|
370
|
-
export interface RepeatSpec {
|
|
371
|
-
axis: Axis;
|
|
372
|
-
/**
|
|
373
|
-
* 한 칸 — **중심에서 다음 중심까지의 거리**다. 부품 크기와 무관하다.
|
|
374
|
-
*
|
|
375
|
-
* 전에는 "부품 사이 빈 틈" 이었다. 그러면 한 칸이 `부품 크기 + 틈` 이 되어, 부품을
|
|
376
|
-
* 굵게 하거나 돌릴 때마다 줄 전체가 다시 깔린다. 롤러를 30° 기울였더니 축 방향
|
|
377
|
-
* 경계상자가 96 에서 343 으로 늘어 개수가 16 에서 6 으로 무너졌다. 기울어진 롤러
|
|
378
|
-
* 둘은 빗살처럼 나란히 놓이므로 그렇게 벌릴 이유가 없는데도 그랬다.
|
|
379
|
-
*
|
|
380
|
-
* 현장이 말하는 방식이기도 하다 — 컨베이어는 "롤러 피치 150", 선반은 "단 피치" 다.
|
|
381
|
-
* 틈으로 말하는 경우가 없다.
|
|
382
|
-
*
|
|
383
|
-
* 부품 크기보다 작게 두면 사본이 겹친다. 막지 않는다 — 빗살처럼 겹쳐 까는 것이
|
|
384
|
-
* 그 자체로 쓰임이다.
|
|
385
|
-
*/
|
|
386
|
-
pitch: number;
|
|
387
|
-
}
|
|
388
|
-
/** 한 시각의 값. glTF sampler 의 input 한 칸과 output 한 칸이다. */
|
|
389
|
-
export interface Keyframe {
|
|
390
|
-
/** 시각(초). 0 이상이고 **오름차순**이어야 한다. */
|
|
391
|
-
at: number;
|
|
392
|
-
/**
|
|
393
|
-
* 그 시각의 값. 경로마다 뜻이 다르다.
|
|
394
|
-
*
|
|
395
|
-
* translation 부품 기준 옮김
|
|
396
|
-
* rotation **오일러 도(°)** — `transform.rotation` 과 같은 약속
|
|
397
|
-
* scale 배율. 1 이 제 크기
|
|
398
|
-
*/
|
|
399
|
-
value: Vec3;
|
|
400
|
-
}
|
|
401
|
-
/**
|
|
402
|
-
* A key on a channel that drives a joint: the joint's coordinate at that position.
|
|
403
|
-
*
|
|
404
|
-
* The value is one number because the joint already says the axis and the centre. A revolute or
|
|
405
|
-
* continuous joint reads degrees, a prismatic joint millimetres (ADR-0066 decision 2).
|
|
406
|
-
*/
|
|
407
|
-
export interface JointKeyframe {
|
|
408
|
-
at: number;
|
|
409
|
-
value: number;
|
|
410
|
-
}
|
|
411
|
-
/**
|
|
412
|
-
* A channel that drives a joint. `target` is a joint name.
|
|
413
|
-
*
|
|
414
|
-
* It carries no `path` and no `pivot`: the joint's `type`, `axis` and `origin` already say what moves
|
|
415
|
-
* and about which point. Writing a rotation vector here would state the axis a second time, and the two
|
|
416
|
-
* could disagree. The node transform, and a quaternion when exporting to glTF, come from the joint.
|
|
417
|
-
*/
|
|
418
|
-
export interface JointChannel {
|
|
419
|
-
target: string;
|
|
420
|
-
path?: undefined;
|
|
421
|
-
pivot?: undefined;
|
|
422
|
-
/** Defaults to `linear`. */
|
|
423
|
-
interpolation?: Interpolation;
|
|
424
|
-
/** At least two. */
|
|
425
|
-
keys: JointKeyframe[];
|
|
426
|
-
}
|
|
427
|
-
/**
|
|
428
|
-
* What a clip or a parameter moves: a part property (`PartChannel`) or a joint (`JointChannel`).
|
|
429
|
-
*
|
|
430
|
-
* The two are told apart by what `target` names. Part and joint names share one name space, so a name
|
|
431
|
-
* never means both.
|
|
432
|
-
*/
|
|
433
|
-
export type AnimationChannel = PartChannel | JointChannel;
|
|
434
|
-
/**
|
|
435
|
-
* 한 부품의 한 속성을 시간에 따라 움직인다. **glTF 의 channel + sampler 를 합친 것.**
|
|
436
|
-
*
|
|
437
|
-
* glTF 는 채널과 샘플러를 나누어 여러 채널이 한 샘플러를 나눠 쓸 수 있게 한다. 그건
|
|
438
|
-
* 정점 데이터를 아끼려는 장치고, 손으로 적는 형식에서는 한 겹 더 들어갈 뿐이라 합쳤다.
|
|
439
|
-
*
|
|
440
|
-
* When the part is a descendant of a joint's child, the channel applies in that joint's frame.
|
|
441
|
-
*/
|
|
442
|
-
export interface PartChannel {
|
|
443
|
-
/** 어느 부품인가. `FigurePart.name`. **노드 인덱스가 아니다** — 이 형식은 이름으로 가리킨다. */
|
|
444
|
-
target: string;
|
|
445
|
-
path: ChannelPath;
|
|
446
|
-
/**
|
|
447
|
-
* 회전 중심. `rotation` 에서만 뜻이 있고, 부품 기준 로컬이다.
|
|
448
|
-
*
|
|
449
|
-
* **glTF 에는 없다.** 거기서는 부모 노드를 하나 끼워서 중심을 옮긴다. 이 형식의 부품은
|
|
450
|
-
* 겹치지 않으므로 끼울 노드가 없어 여기 둔다. 안 적으면 부품 제 중심이다.
|
|
451
|
-
*/
|
|
452
|
-
pivot?: Vec3;
|
|
453
|
-
/** 안 적으면 `linear`. */
|
|
454
|
-
interpolation?: Interpolation;
|
|
455
|
-
/** **둘 이상**이어야 한다. 하나뿐이면 움직이는 것이 아니라 자세 하나다. */
|
|
456
|
-
keys: Keyframe[];
|
|
457
|
-
}
|
|
458
|
-
/**
|
|
459
|
-
* 움직임 한 벌. **glTF 의 `animations[]` 한 칸이다.**
|
|
460
|
-
*
|
|
461
|
-
* 길이는 적지 않는다 — 마지막 키의 시각이 곧 길이다. 따로 적으면 어긋날 수 있고,
|
|
462
|
-
* 어긋나면 어느 쪽이 맞는지 알 방법이 없다.
|
|
463
|
-
*/
|
|
464
|
-
export interface AnimationClip {
|
|
465
|
-
/** **저장되는 식별자다.** 인스턴스가 이 이름으로 구동한다. */
|
|
466
|
-
name: string;
|
|
467
|
-
channels: AnimationChannel[];
|
|
468
|
-
}
|
|
469
|
-
/**
|
|
470
|
-
* 값이 만드는 자세 — **애니메이션이 아니다.**
|
|
471
|
-
*
|
|
472
|
-
* 호이스트가 얼마나 내려왔나, 포크가 얼마나 올라갔나, 닙이 얼마나 닫혔나. 이것들은
|
|
473
|
-
* 재생되는 것이 아니라 **지금 그만큼인 것**이다. 트윈은 「클립을 재생하라」가 아니라
|
|
474
|
-
* 「지금 1200mm 내려와 있다」를 준다.
|
|
475
|
-
*
|
|
476
|
-
* 한동안 이것이 `animations` 안에 `drive: 'hold'` 로 있었다. 형식의 판단은 맞았는데
|
|
477
|
-
* **자리와 이름이 틀려서**, 저작자도 AI 도 「값을 변수로 노출하려면」을 물었을 때 이것을
|
|
478
|
-
* 못 찾았다 — 애니메이션 칸에 있을 거라고 생각하지 않는다. 업계도 둘을 가른다: Unity 의
|
|
479
|
-
* Animation Clip 과 Blend Tree 파라미터, Blender 의 Action 과 Driver.
|
|
480
|
-
* ADR-0051(`operato-twin/design/04-decisions.md`).
|
|
481
|
-
*
|
|
482
|
-
* ## 두 층으로 되어 있다 — 아래는 표준, 위는 우리 것
|
|
483
|
-
*
|
|
484
|
-
* `clip` has the shape of a glTF animation: channels, keys and TRS paths. The one difference is that
|
|
485
|
-
* a key's `at` is a position on the 0..1 value span rather than a time, and the two convert without
|
|
486
|
-
* loss. See `ParameterClip`.
|
|
487
|
-
*
|
|
488
|
-
* 그 위에 얹는 `range` 가 우리 것이다 — 「이 곡선은 재생되는 것이 아니라 값이 몬다」와
|
|
489
|
-
* 「그 값은 mm 로 몇부터 몇까지다」. glTF 에 그것을 적을 자리가 없으므로, 못 받는 쪽은
|
|
490
|
-
* **선언만 잃고 형상은 잃지 않는다.**
|
|
491
|
-
*
|
|
492
|
-
* ## 값 축은 0~1 이고 물리량은 그 위에서 맵된다
|
|
493
|
-
*
|
|
494
|
-
* 곡선의 값 축이 0~1 인 것은 glTF 의 morph target `weights` · Unity 파라미터와 같은
|
|
495
|
-
* 모양이라서다. 저작자와 **인스턴스**가 주고받는 것은 `range` 의 단위(mm)이고, 런타임이 그 사이를
|
|
496
|
-
* 맵한다. 「길이값을 변수로 노출한다」는 그 API 에서 성립하고, 형식의 곡선은 표준 모양으로
|
|
497
|
-
* 남는다.
|
|
498
|
-
*
|
|
499
|
-
* ## The transition time is `clip.duration`
|
|
500
|
-
*
|
|
501
|
-
* `clip.duration` is the number of seconds a full move from 0 to 1 takes. When the value changes from
|
|
502
|
-
* v₁ to v₂ the pose moves in a straight line over `|v₂ − v₁| × duration`, which is the machine's
|
|
503
|
-
* speed. How fast a hoist lowers is a fact about the figure; when one installation differs, the
|
|
504
|
-
* instance overrides it.
|
|
505
|
-
*
|
|
506
|
-
* **ease 는 없다.** 기계는 연출하지 않는다.
|
|
507
|
-
*
|
|
508
|
-
* With no `duration`, or `0`, the move is instant: a new value goes straight to its pose.
|
|
509
|
-
*
|
|
510
|
-
* For a while the last key's time served as both the end of the value span and the transition time.
|
|
511
|
-
* A figure could then not declare several poses together with an instant move, since instant meant
|
|
512
|
-
* every key at 0, and legacy keys that happened to sit at 0 and 1 turned into a one-second move
|
|
513
|
-
* nobody chose. That is why the two facts have separate fields.
|
|
514
|
-
*/
|
|
515
|
-
export interface FigureParameter {
|
|
516
|
-
/** **저장되는 식별자다.** 인스턴스가 이 이름으로 값을 준다. */
|
|
517
|
-
name: string;
|
|
518
|
-
/** 화면에 보일 이름. 없으면 `name` 을 쓴다. */
|
|
519
|
-
label?: string;
|
|
520
|
-
/** 저작자와 인스턴스가 주고받는 물리량. */
|
|
521
|
-
range: ParameterRange;
|
|
522
|
-
/** 아무도 값을 안 줬을 때. 없으면 `range.min`. */
|
|
523
|
-
default?: number;
|
|
524
|
-
/** 자세. **glTF 꼴 그대로다.** */
|
|
525
|
-
clip: ParameterClip;
|
|
526
|
-
}
|
|
527
|
-
/**
|
|
528
|
-
* 파라미터가 오가는 범위 — **물리량이다.**
|
|
529
|
-
*
|
|
530
|
-
* `unit` 은 형식이 해석하지 않는다. 화면이 보이고 인스턴스가 받는 낱말이다 — `mm` · `deg` ·
|
|
531
|
-
* `%` 처럼. 형식이 단위를 판정하려 들면 단위 표를 형식이 갖게 되고, 그것은 형식의 일이 아니다.
|
|
532
|
-
*/
|
|
533
|
-
export interface ParameterRange {
|
|
534
|
-
unit: string;
|
|
535
|
-
min: number;
|
|
536
|
-
max: number;
|
|
537
|
-
}
|
|
538
|
-
/**
|
|
539
|
-
* 파라미터의 자세 — `AnimationClip` 과 **같은 모양이되 이름이 없다.**
|
|
540
|
-
*
|
|
541
|
-
* 이름은 파라미터가 갖는다. 클립에 또 두면 둘이 갈릴 수 있고, 갈리면 인스턴스가 어느 이름으로
|
|
542
|
-
* 값을 주는지 알 수 없다.
|
|
543
|
-
*
|
|
544
|
-
* A key's `at` is a position on the value span, from `0` to `1`: `0` is the pose at `range.min` and
|
|
545
|
-
* `1` the pose at `range.max`. Keys need not cover the whole span; before the first key and after the
|
|
546
|
-
* last one the pose holds at the end key, the same clamping glTF applies outside a clip.
|
|
547
|
-
*
|
|
548
|
-
* Time lives in `duration`. Keys sit on the value axis and `duration` on the time axis, so the two
|
|
549
|
-
* cannot disagree.
|
|
550
|
-
*
|
|
551
|
-
* ## Converting to and from glTF loses nothing
|
|
552
|
-
*
|
|
553
|
-
* - Export: glTF key time = `at × (duration || 1)`. The curve goes out unchanged and its length is the
|
|
554
|
-
* transition time.
|
|
555
|
-
* - Import: divide every key time by the latest one to get `at`, and keep that latest time as `duration`.
|
|
556
|
-
*
|
|
557
|
-
* So `at` not being seconds does not break compatibility; the seconds are gathered into `duration`.
|
|
558
|
-
*/
|
|
559
|
-
export interface ParameterClip {
|
|
560
|
-
/** Seconds for a full move from 0 to 1. Missing or `0` means instant. */
|
|
561
|
-
duration?: number;
|
|
562
|
-
channels: AnimationChannel[];
|
|
563
|
-
}
|
|
564
|
-
/** 텍스트 표현 자리. 무엇을·언제만 정하고 수단은 런타임이 고른다. */
|
|
565
|
-
export interface LabelSpec {
|
|
566
|
-
name: string;
|
|
567
|
-
/** 태그의 어느 값을 보이나. */
|
|
568
|
-
source: string;
|
|
569
|
-
when: LabelWhen;
|
|
570
|
-
}
|
|
571
|
-
/** extrude 계열의 2D 단면. */
|
|
572
|
-
export interface PartShape {
|
|
573
|
-
/** `polygon` 에 필요. 3 점 이상. */
|
|
574
|
-
path?: Point2[];
|
|
575
|
-
/** 코너 라운드. `rect` · `polygon` 공통. */
|
|
576
|
-
round?: number;
|
|
577
|
-
/** 속을 판다. `HollowSpec` 참고. */
|
|
578
|
-
hollow?: HollowSpec;
|
|
579
|
-
}
|
|
580
|
-
/**
|
|
581
|
-
* 민 단면의 **속을 판다** — 트레이 · 토트 · 통 · 케이스 · 프레임이 전부 이 모양이다.
|
|
582
|
-
*
|
|
583
|
-
* 없을 때는 바닥판 하나에 벽 넷을 세워 만들었다. 다섯 부품이 드는 것도 문제지만 더
|
|
584
|
-
* 나쁜 것은 **모양이 안 맞는다**는 것이다. 셀트레이의 바닥판은 모서리를 둥글게 깎았는데
|
|
585
|
-
* 벽 넷은 각진 상자라, 네 귀퉁이에서 둥근 것과 각진 것이 만난다.
|
|
586
|
-
*
|
|
587
|
-
* 한 덩어리로 밀면 바깥 테가 한 바퀴 이어지고, 안쪽 테도 같은 반경에서 두께만큼 줄어든
|
|
588
|
-
* 채 따라온다. 벽과 바닥이 맞닿는 자리가 없어져 z-fighting 이 날 자리도 하나 준다.
|
|
589
|
-
*
|
|
590
|
-
* `size` 는 **바깥 치수**다. 판 자리는 그 안쪽이다.
|
|
591
|
-
*
|
|
592
|
-
* ## 왜 프리미티브를 새로 만들지 않았나
|
|
593
|
-
*
|
|
594
|
-
* 「속을 판다」는 상자만의 성질이 아니다. `polygon` 을 파면 U 자 가드 · ㄷ 자 프레임이
|
|
595
|
-
* 같은 규칙으로 나온다. 새 프리미티브를 두면 그 둘이 서로 모르는 두 벌이 된다.
|
|
596
|
-
*/
|
|
597
|
-
export interface HollowSpec {
|
|
598
|
-
/** 벽 두께. 안쪽 테는 바깥 테에서 이만큼 들어온다. */
|
|
599
|
-
wall: number;
|
|
600
|
-
/**
|
|
601
|
-
* 바닥 두께. 없으면 벽과 같다.
|
|
602
|
-
*
|
|
603
|
-
* `0` 이면 **위아래가 다 뚫린다** — 통이 아니라 테두리다. 프레임 · 덕트가 그렇다.
|
|
604
|
-
*/
|
|
605
|
-
floor?: number;
|
|
606
|
-
}
|
|
607
|
-
export interface FigurePart {
|
|
608
|
-
/**
|
|
609
|
-
* 부품 이름. **저장되는 식별자다** — 바인딩·애니메이션·슬롯이 이 이름을 가리킨다.
|
|
610
|
-
* 바꾸면 인스턴스의 바인딩이 오류보고없이 끊긴다.
|
|
611
|
-
*/
|
|
612
|
-
name: string;
|
|
613
|
-
primitive: PrimitiveKind;
|
|
614
|
-
transform: PartTransform;
|
|
615
|
-
/** mesh 계열 곡면의 분할 수. 프리셋은 `SEGMENT_PRESETS`. */
|
|
616
|
-
segments?: number;
|
|
617
|
-
/** extrude 계열의 단면. */
|
|
618
|
-
shape?: PartShape;
|
|
619
|
-
material: PartMaterial;
|
|
620
|
-
/**
|
|
621
|
-
* 상태 색이 연동될 재질 슬롯. 없으면 상태를 표현하지 않는다.
|
|
622
|
-
*
|
|
623
|
-
* **`slot` 이 아니라 `materialSlot` 이다.** 이 낱말은 스택에서 이미 임자가 있다 —
|
|
624
|
-
* operato-scene 의 `SlotDef` 는 **보유물이 앉는 자리**이고, 그것이 언젠가 이 형식에도
|
|
625
|
-
* 들어온다(`Capacity.get slots()`). 그때 한 형식 안에서 `slot` 이 「재질 인덱스」와
|
|
626
|
-
* 「자재가 앉는 자리」 둘을 뜻하게 된다. 여기는 재질 쪽이므로 그렇게 부른다.
|
|
627
|
-
*/
|
|
628
|
-
materialSlot?: MaterialSlot;
|
|
629
|
-
/**
|
|
630
|
-
* 단면을 **원으로 지킬 것인가.** 곡면 프리미티브만 뜻이 있고, 기본은 지키는 것이다.
|
|
631
|
-
*
|
|
632
|
-
* 인스턴스가 축마다 다른 배율이면 원기둥이 타원 기둥이 된다. AGV 를 길게 늘이면
|
|
633
|
-
* 바퀴가 찌그러지고, 크레들을 높이면 롤이 납작해진다. 원기둥이라고 적어 놓고 원기둥이
|
|
634
|
-
* 아닌 것을 그리는 것이므로 기본을 「지킨다」로 둔다.
|
|
635
|
-
*
|
|
636
|
-
* **값을 치른다.** 지키려면 제 변환이 있어야 하고, 합친 묶음은 변환을 하나만 받는다 —
|
|
637
|
-
* 그래서 지키는 곡면 부품은 **하나가 draw call 하나**다. 표본 열넷에서 139 가 168 이
|
|
638
|
-
* 되었다.
|
|
639
|
-
*
|
|
640
|
-
* 끄면 합쳐진다. 끌 만한 것들이 있다 — 볼트 머리 · 작은 스터드처럼 찌그러져도 아무도
|
|
641
|
-
* 모를 것들이다. 화면의 주역이 되는 롤 · 바퀴 · 탱크는 켜 둔다.
|
|
642
|
-
*/
|
|
643
|
-
keepRound?: boolean;
|
|
644
|
-
sizing?: SizingRule;
|
|
645
|
-
/**
|
|
646
|
-
* 어느 면을 붙잡나. 적지 않은 축은 **가까운 면**이다(`ANCHOR_ENDS` 참고).
|
|
647
|
-
*
|
|
648
|
-
* `sizing` 이 정한 것을 축마다 덮어쓴다. `sizing: 'stretch'` 는 가장 긴 축에
|
|
649
|
-
* `'span'` 을 넣는 짧은 표기이고, 여기 적으면 그것이 이긴다.
|
|
650
|
-
*/
|
|
651
|
-
anchor?: PartAnchor;
|
|
652
|
-
repeat?: RepeatSpec;
|
|
653
|
-
label?: LabelSpec;
|
|
654
|
-
/**
|
|
655
|
-
* 이 부품이 **능력을 받쳐 주는 자리**라는 선언.
|
|
656
|
-
*
|
|
657
|
-
* 형상 수준의 `FigureSource.capabilities` 가 「이 도형이 무엇을 할 수 있나」를 말하고,
|
|
658
|
-
* 이 칸이 「그것을 어느 부품이 받쳐 주나」를 말한다. 둘이 같은 낱말로 읽히도록 묶어 둔다 —
|
|
659
|
-
* `sizing`·`material` 옆에 `role`·`accepts` 를 흩어 놓으면 한 주제인 줄 모른다.
|
|
660
|
-
*
|
|
661
|
-
* ## 왜 자리를 부품으로 두나
|
|
662
|
-
*
|
|
663
|
-
* 자리는 **위치·회전·크기 반응**이 필요하다. 부품이 그 셋을 이미 답한다(`transform` ·
|
|
664
|
-
* `anchor` · `repeat`). 목록을 따로 두면 「크기를 바꾸면 자리가 어디로 가나」를 슬롯용으로 한 벌
|
|
665
|
-
* 더 써야 하고, 그 두 벌은 반드시 어긋난다.
|
|
666
|
-
*
|
|
667
|
-
* ## 개수는 여기 없다
|
|
668
|
-
*
|
|
669
|
-
* `repeat` 인 자리는 **인스턴스 배율에 따라 칸 수가 달라진다** — 컨베이어를 늘이면 는다
|
|
670
|
-
* (`repeatPlan` 이 배율을 받는다). 그래서 청사진에 굽지 않고 씬이 인스턴스에서 센다.
|
|
671
|
-
* 크기와 무관하게 고정하려면 `capacity` 를 적는다.
|
|
672
|
-
*
|
|
673
|
-
* 점유자는 씬에서 `{ slotId, index }` 로 가리킨다 — 자리 하나에 칸이 여럿이다.
|
|
674
|
-
*/
|
|
675
|
-
capability?: PartCapability;
|
|
676
|
-
/**
|
|
677
|
-
* The part this one is attached to (ADR-0066 decision 1).
|
|
678
|
-
*
|
|
679
|
-
* This is the only place a parent is written. A part without one hangs from the figure frame. A part
|
|
680
|
-
* that is a joint's `child` moves relative to this parent as the joint says; any other part moves
|
|
681
|
-
* rigidly with it. The parent chain must end at the figure frame: a cycle is an error.
|
|
682
|
-
*
|
|
683
|
-
* `transform` stays the rest pose in figure coordinates. The hierarchy is built by compile, so
|
|
684
|
-
* sizing rules and existing sources read the same numbers as before.
|
|
685
|
-
*/
|
|
686
|
-
parent?: string;
|
|
687
|
-
}
|
|
688
|
-
/**
|
|
689
|
-
* A joint: how a part moves relative to its parent (ADR-0066).
|
|
690
|
-
*
|
|
691
|
-
* The joint has no `parent` field. Its parent is the `child` part's `FigurePart.parent`, so the parent is
|
|
692
|
-
* written in one place only. A part is the child of at most one joint.
|
|
693
|
-
*
|
|
694
|
-
* The rest pose, the pose every part's `transform` describes, is joint value 0. That is URDF's
|
|
695
|
-
* convention, and it is why `limits` must contain 0: the pose the figure was drawn in has to be one the
|
|
696
|
-
* machine can take.
|
|
697
|
-
*
|
|
698
|
-
* Values come through `parameters` (or a loop clip) with a `JointChannel` whose `target` is this joint's
|
|
699
|
-
* name. There is no second way to set a joint.
|
|
700
|
-
*/
|
|
701
|
-
export interface FigureJoint {
|
|
702
|
-
/** Stored identifier. Channels target it. Shares the name space with part names. */
|
|
703
|
-
name: string;
|
|
704
|
-
/** The part this joint moves. */
|
|
705
|
-
child: string;
|
|
706
|
-
type: JointType;
|
|
707
|
-
/** The point the joint turns about or slides from, in figure coordinates (edition 2: y from the base bottom). */
|
|
708
|
-
origin: Vec3;
|
|
709
|
-
/** Direction of turning (right-hand rule) or sliding. Need not be unit length; must not be zero. */
|
|
710
|
-
axis: Vec3;
|
|
711
|
-
/** Degrees for revolute, millimetres for prismatic. Must contain 0. Not allowed on continuous. */
|
|
712
|
-
limits?: JointLimits;
|
|
713
|
-
}
|
|
714
|
-
export interface JointLimits {
|
|
715
|
-
min: number;
|
|
716
|
-
max: number;
|
|
717
|
-
}
|
|
718
|
-
/**
|
|
719
|
-
* 부품이 맡는 역할.
|
|
720
|
-
*
|
|
721
|
-
* slot 보유물이 앉는 자리 (`Capacity.slots`)
|
|
722
|
-
* port-in 흐름이 들어오는 문 (`FlowNode.inboundPorts`)
|
|
723
|
-
* port-out 흐름이 나가는 문 (`FlowNode.outboundPorts`)
|
|
724
|
-
*/
|
|
725
|
-
export declare const PART_ROLES: readonly ["slot", "port-in", "port-out"];
|
|
726
|
-
export type PartRole = (typeof PART_ROLES)[number];
|
|
727
|
-
export interface PartCapability {
|
|
728
|
-
/**
|
|
729
|
-
* 이 부품이 맡는 역할. **여럿일 수 있다.**
|
|
730
|
-
*
|
|
731
|
-
* AGV 의 상판이 그렇다 — 물건을 놓는 자리이면서, 그 자리에서 물건이 들어오고 나간다.
|
|
732
|
-
* 역할을 하나만 받으면 저작자는 같은 위치에 부품을 두 개 만들어야 하고, 그것은 실물에 없는
|
|
733
|
-
* 구조를 형식이 만들어 내는 것이다.
|
|
734
|
-
*
|
|
735
|
-
* 비어 있을 수 없다. 역할이 없으면 그냥 그리는 부품이므로 `capability` 를 적지 않는다.
|
|
736
|
-
*/
|
|
737
|
-
roles: PartRole[];
|
|
738
|
-
/** 무엇이 들어올 수 있나. 비었으면 아무거나 — `SlotDef.allowedTypes` 와 같다. */
|
|
739
|
-
accepts?: string[];
|
|
740
|
-
/**
|
|
741
|
-
* 칸 수. **`repeat` 인 자리에는 적지 않는다** — 그때는 배율이 정한다.
|
|
742
|
-
* 크기와 무관하게 넷이면 여기 4 를 적는다.
|
|
743
|
-
*/
|
|
744
|
-
capacity?: number;
|
|
745
|
-
/**
|
|
746
|
-
* 포트(port-in, port-out)의 법선/진출입 진행 방향 벡터.
|
|
747
|
-
*
|
|
748
|
-
* 기본값은 부품 로컬 좌표계의 +z 방향인 `{ x: 0, y: 0, z: 1 }` 이다.
|
|
749
|
-
* 부품의 `transform.rotation` 이 적용되어 최종 월드 진출입 방향이 결정된다.
|
|
750
|
-
*/
|
|
751
|
-
direction?: Vec3;
|
|
752
|
-
}
|
|
753
|
-
/**
|
|
754
|
-
* The source edition this format reads.
|
|
755
|
-
*
|
|
756
|
-
* - 1: `position.y` measured from the centre of the base box. Sources saved before the `version`
|
|
757
|
-
* field existed are edition 1 as well.
|
|
758
|
-
* - 2: `position.y` measured from the bottom face of the base box (ADR-0065).
|
|
759
|
-
*
|
|
760
|
-
* Only edition 2 is read. Older sources are refused with `source-version-unsupported` rather than
|
|
761
|
-
* read by the old rule, so a value never lives in two shapes at once.
|
|
762
|
-
*/
|
|
763
|
-
export declare const FIGURE_SOURCE_VERSION = 2;
|
|
764
|
-
/** 저작 결과. 편집 가능한 원본 데이터. */
|
|
765
|
-
export interface FigureSource {
|
|
766
|
-
/**
|
|
767
|
-
* Source edition. Must be `FIGURE_SOURCE_VERSION`; a missing value is refused, because every
|
|
768
|
-
* source saved without one was written in edition 1 coordinates.
|
|
769
|
-
*/
|
|
770
|
-
version?: number;
|
|
771
|
-
/** 컴포넌트 타입 이름. **저장되는 식별자다.** */
|
|
772
|
-
type: string;
|
|
773
|
-
/**
|
|
774
|
-
* 기준 크기 [단위: mm]. 배치 크기는 이 비율에서 산출된다.
|
|
775
|
-
*
|
|
776
|
-
* 부품과 같은 축이다. `base.y` 가 높이다. 씬 컴포넌트의 state 는 용어도 축
|
|
777
|
-
* 배정도 달라서, 그리는 쪽 경계에서 한 번 변환해 받는다.
|
|
778
|
-
*/
|
|
779
|
-
base: Vec3;
|
|
780
|
-
/**
|
|
781
|
-
* 3D 배치 기준면.
|
|
782
|
-
*
|
|
783
|
-
* 'floor' (기본): 바닥 위에 서 있음 (y=0 기준)
|
|
784
|
-
* 'ceiling': 천정에 매달림 (상단 기준, OHT 등)
|
|
785
|
-
* 'center': 중심 기준 부유 (드론, 센서 등)
|
|
786
|
-
*/
|
|
787
|
-
placement?: FigurePlacement;
|
|
788
|
-
detailLevel?: DetailLevel;
|
|
789
|
-
/** StyleKit 참조. 팔레트·분할 수·그리드·등급을 한 번에 받는다. */
|
|
790
|
-
styleKit?: string;
|
|
791
|
-
parts: FigurePart[];
|
|
792
|
-
/**
|
|
793
|
-
* 움직임. **glTF 처럼 부품 바깥에 둔다.**
|
|
794
|
-
*
|
|
795
|
-
* 한 clip 이 부품 여럿을 같이 움직이기 때문이다 — 문 두 짝이 같이 열리는 것이 clip
|
|
796
|
-
* 하나다. 부품 안에 넣으면 그 「같이」를 적을 자리가 없다.
|
|
797
|
-
*/
|
|
798
|
-
animations?: AnimationClip[];
|
|
799
|
-
/**
|
|
800
|
-
* 값이 만드는 자세 — 호이스트 연장 · 포크 높이 · 닙 닫힘. `FigureParameter` 참고.
|
|
801
|
-
*
|
|
802
|
-
* `animations` 와 **다른 칸인 것이 요점이다.** 저것은 시각이 흐르는 것이고 이것은 지금
|
|
803
|
-
* 값이 그만큼인 것이다.
|
|
804
|
-
*/
|
|
805
|
-
parameters?: FigureParameter[];
|
|
806
|
-
/**
|
|
807
|
-
* 이 형상이 씬 컴포넌트로서 **부여받는 능력.**
|
|
808
|
-
*
|
|
809
|
-
* ## 왜 형식이 지나
|
|
810
|
-
*
|
|
811
|
-
* 배치된 도형이 무엇을 할 수 있나는 형상마다 다르다 — 파렛트는 물건을 **담고**(Holdable ·
|
|
812
|
-
* Capacity), 컨베이어는 **흘리고**(FlowNode · Transferable), 신호탑은 아무것도 담지 않는다.
|
|
813
|
-
* 그 답은 저작의 결과이므로 정본이 지고 다녀야 한다. 그리는 쪽이 타입 이름으로 짐작하면
|
|
814
|
-
* 이름 규칙에 능력이 숨는다.
|
|
815
|
-
*
|
|
816
|
-
* ## 이름의 정본도 여기다 — 한동안 아니었다
|
|
817
|
-
*
|
|
818
|
-
* 「목록은 씬의 것이고 여기서는 문자열만 진다」였다. 의존 방향 때문이었는데, 그 대가가
|
|
819
|
-
* **게이트가 사실이 사는 곳에 없는 것**이었다. AI 가 낸 `capabilities: ['hoist']` 가
|
|
820
|
-
* 검증을 지나고 **발행까지 지난 뒤** 렌더링에서 죽었다 — 저작자는 자산을 내보내고 나서야
|
|
821
|
-
* 그것이 안 선다는 것을 알았다. `base` 상자 때와 같은 구멍이다(ADR-0044 · ADR-0051 ④).
|
|
822
|
-
*
|
|
823
|
-
* 그래서 목록은 `FIGURE_CAPABILITIES` 로 여기 서고, 씬은 **그것을 소비해** mixin 을
|
|
824
|
-
* 붙인다. 계약이 두 벌이 되지 않게 씬 쪽에 양방향 시험이 있다 — 선언된 능력마다 mixin 이
|
|
825
|
-
* 있고, mixin 마다 선언이 있다.
|
|
826
|
-
*/
|
|
827
|
-
capabilities?: readonly FigureCapability[];
|
|
828
|
-
/** How parts move relative to their parents (ADR-0066). See `FigureJoint`. */
|
|
829
|
-
joints?: FigureJoint[];
|
|
830
|
-
}
|
|
831
|
-
/** 청사진 스키마 버전. 형식이 바뀌면 올린다. */
|
|
832
|
-
export declare const BLUEPRINT_VERSION = 1;
|
|
833
|
-
/**
|
|
834
|
-
* 크기 반응 계산이 **실제로 읽는 것.**
|
|
835
|
-
*
|
|
836
|
-
* `sizingPosition`·`sizingScale` 은 기하를 안 본다 — 자리와 치수와 규칙만 본다. 그리는 부품과
|
|
837
|
-
* 그리지 않는 닻이 둘 다 이 모양을 만족하므로, 「이 배율에서 어디에 있나」를 **한 벌의 셈**으로
|
|
838
|
-
* 답할 수 있다.
|
|
839
|
-
*
|
|
840
|
-
* 이름을 따로 두는 뜻이 있다. 닻을 `BlueprintMember` 로 억지로 맞추려면 없는 `geometryKey` 와
|
|
841
|
-
* `triangles` 를 지어내야 하고, 그 순간 그리는 목록에 섞여 들어갈 길이 생긴다.
|
|
842
|
-
*/
|
|
843
|
-
declare const CENTRED: unique symbol;
|
|
844
|
-
/**
|
|
845
|
-
* Marks a value whose positions are measured from the centre of the base box.
|
|
846
|
-
*
|
|
847
|
-
* A source measures y from the box bottom (edition 2); the blueprint, sizing, the release gate and the
|
|
848
|
-
* policy checks read box-centred positions. The brand exists only in the type system. Values get it in
|
|
849
|
-
* `origin.ts`, so a caller that hands a source part straight to a centred-only function fails to compile
|
|
850
|
-
* instead of reading every y half a box too high (ADR-0065).
|
|
851
|
-
*/
|
|
852
|
-
export type Centred<T> = T & {
|
|
853
|
-
readonly [CENTRED]: true;
|
|
854
|
-
};
|
|
855
|
-
/** A source whose parts have been moved into box-centred coordinates by `centredSource`. */
|
|
856
|
-
export type CentredSource = Centred<Omit<FigureSource, 'parts' | 'joints'> & {
|
|
857
|
-
parts: Centred<FigurePart>[];
|
|
858
|
-
joints?: Centred<FigureJoint>[];
|
|
859
|
-
}>;
|
|
860
|
-
interface SizingSubjectShape {
|
|
861
|
-
name: string;
|
|
862
|
-
transform: PartTransform;
|
|
863
|
-
sizing: SizingRule;
|
|
864
|
-
/** 어느 면을 붙잡나. */
|
|
865
|
-
anchor?: PartAnchor;
|
|
866
|
-
repeat?: RepeatSpec;
|
|
867
|
-
/** 곡면 판단용. 그리지 않는 닻에는 없다. */
|
|
868
|
-
primitive?: PrimitiveKind;
|
|
869
|
-
keepRound?: boolean;
|
|
870
|
-
}
|
|
871
|
-
/** What the sizing rules read: a part in box-centred coordinates. */
|
|
872
|
-
export type SizingSubject = Centred<SizingSubjectShape>;
|
|
873
|
-
export interface BlueprintMember extends SizingSubject {
|
|
874
|
-
name: string;
|
|
875
|
-
primitive: PrimitiveKind;
|
|
876
|
-
/** GeometryBank 키. 실체가 아니라 참조다. */
|
|
877
|
-
geometryKey: string;
|
|
878
|
-
transform: PartTransform;
|
|
879
|
-
/**
|
|
880
|
-
* 곡면의 분할 수. `SEGMENTED_PRIMITIVES` 인 부품에만 있다.
|
|
881
|
-
*
|
|
882
|
-
* `geometryKey` 안에도 들어 있지만 키는 문자열이라 다시 파싱해야 한다. 그리는 쪽이
|
|
883
|
-
* 2D 톱뷰를 3D 와 **같은 분할 수**로 근사하려면 이 값이 필요하므로 따로 제공한다.
|
|
884
|
-
*/
|
|
885
|
-
segments?: number;
|
|
886
|
-
/** 단면을 원으로 지킬 것인가. 곡면만 뜻이 있고 기본은 지키는 것이다. */
|
|
887
|
-
keepRound?: boolean;
|
|
888
|
-
sizing: SizingRule;
|
|
889
|
-
/** 어느 면을 붙잡나. 원본에 적힌 것만 실린다 — 적지 않은 축은 그리는 쪽이 센다. */
|
|
890
|
-
anchor?: PartAnchor;
|
|
891
|
-
repeat?: RepeatSpec;
|
|
892
|
-
shape?: PartShape;
|
|
893
|
-
/** 이 부품의 삼각형 수 추정. */
|
|
894
|
-
triangles: number;
|
|
895
|
-
}
|
|
896
|
-
/**
|
|
897
|
-
* 능력의 닻 하나 — 자리(slot)나 문(port).
|
|
898
|
-
*
|
|
899
|
-
* 씬이 이것으로 `SlotDef`·`Port` 를 만든다. 기하 정보(geometryKey · triangles)가 없는 이유는
|
|
900
|
-
* **그리지 않기 때문**이고, 대신 자리 계산에 필요한 것은 다 있다 — `sizingPosition`·`repeatPlan` 이
|
|
901
|
-
* 읽는 것이 `transform`·`sizing`·`anchor`·`repeat` 넷이다.
|
|
902
|
-
*/
|
|
903
|
-
export interface BlueprintAnchor extends SizingSubject {
|
|
904
|
-
/** 씬에서 `SlotDef.id` 가 된다. 부품 이름이므로 형식이 이미 유일성을 지킨다. */
|
|
905
|
-
name: string;
|
|
906
|
-
/** 하나가 여럿을 맡을 수 있다 — AGV 의 상판은 자리이자 문이다. */
|
|
907
|
-
roles: PartRole[];
|
|
908
|
-
accepts?: string[];
|
|
909
|
-
capacity?: number;
|
|
910
|
-
/** 포트(port-in, port-out)의 법선/진출입 진행 방향 벡터. 기본값 `{ x: 0, y: 0, z: 1 }`. */
|
|
911
|
-
direction?: Vec3;
|
|
912
|
-
/** The joint whose frame the anchor moves in. Missing means the figure frame. */
|
|
913
|
-
joint?: string;
|
|
914
|
-
}
|
|
915
|
-
/**
|
|
916
|
-
* 재질별로 병합된 묶음. 2D · 3D 공통.
|
|
917
|
-
*
|
|
918
|
-
* `members` 가 병합 대상이다 — 3D 는 geometry 를 합치고, 2D 는 윤곽을 한 path 로
|
|
919
|
-
* 합쳐 한 번에 채운다.
|
|
920
|
-
*/
|
|
921
|
-
export interface BlueprintGroup {
|
|
922
|
-
/** MaterialBank 키. */
|
|
923
|
-
materialKey: string;
|
|
924
|
-
material: PartMaterial;
|
|
925
|
-
materialSlot?: MaterialSlot;
|
|
926
|
-
/** 움직이는 부품이 든 그룹인지. 그런 그룹은 부품을 하나만 갖는다. */
|
|
927
|
-
animated: boolean;
|
|
928
|
-
members: BlueprintMember[];
|
|
929
|
-
/**
|
|
930
|
-
* The joint whose frame this group moves in: the nearest joint on the members' parent chain. Missing
|
|
931
|
-
* means the figure frame. Groups merge only within one joint's frame, so the key is (joint, material).
|
|
932
|
-
*/
|
|
933
|
-
joint?: string;
|
|
934
|
-
}
|
|
935
|
-
/**
|
|
936
|
-
* A joint as the runtime builds it: a node in the figure's hierarchy.
|
|
937
|
-
*
|
|
938
|
-
* Positions are box-centred, like every other blueprint position.
|
|
939
|
-
*/
|
|
940
|
-
export interface BlueprintJoint {
|
|
941
|
-
name: string;
|
|
942
|
-
type: JointType;
|
|
943
|
-
/** The part the joint moves. */
|
|
944
|
-
child: string;
|
|
945
|
-
/** Box-centred rest position of the point the joint turns about or slides from. */
|
|
946
|
-
origin: Vec3;
|
|
947
|
-
/** Unit length. */
|
|
948
|
-
axis: Vec3;
|
|
949
|
-
limits?: JointLimits;
|
|
950
|
-
/** The joint whose frame this joint sits in. Missing means the figure frame. */
|
|
951
|
-
parent?: string;
|
|
952
|
-
/**
|
|
953
|
-
* The child's parent part. The origin follows that part under sizing (ADR-0066 decision 3). Missing when
|
|
954
|
-
* the child hangs from the figure frame.
|
|
955
|
-
*/
|
|
956
|
-
attach?: string;
|
|
957
|
-
}
|
|
958
|
-
/** 청사진의 clip. 원본에 적은 것 그대로다. */
|
|
959
|
-
export type BlueprintClip = AnimationClip;
|
|
960
|
-
export type BlueprintParameter = FigureParameter;
|
|
961
|
-
export interface BlueprintLabel extends LabelSpec {
|
|
962
|
-
/** 어느 부품에 붙나. `FigurePart.name`. */
|
|
963
|
-
at: string;
|
|
964
|
-
}
|
|
965
|
-
/** 형식은 맞으나 정책을 넘은 것. 컴파일을 막지 않는다. */
|
|
966
|
-
export interface Violation {
|
|
967
|
-
code: ViolationCode;
|
|
968
|
-
message: string;
|
|
969
|
-
/** 넘은 값과 한도. */
|
|
970
|
-
actual?: number;
|
|
971
|
-
limit?: number;
|
|
972
|
-
/**
|
|
973
|
-
* **왜 그것이 문제인가.** 잰 것만 보여 주면 읽는 사람이 「그래서?」에서 멈춘다.
|
|
974
|
-
*
|
|
975
|
-
* 크기 반응 판정(`sizing.ts`)은 처음부터 이 둘을 실었고, 발행을 막는 위반은 싣지 않았다. 그래서
|
|
976
|
-
* 저작자가 손댈 수 있는 결함이 가장 드문 것이었다 — 표본 47 개를 게이트에 넣었을 때 막는 판정
|
|
977
|
-
* 99 건 중 셋을 다 가진 것이 2 건이었다(2026-09-19).
|
|
978
|
-
*/
|
|
979
|
-
why?: string;
|
|
980
|
-
/** **무엇을 바꾸면 되나.** 부품 이름과 값으로. 고를 길이 둘이면 둘 다 적는다. */
|
|
981
|
-
how?: string;
|
|
982
|
-
}
|
|
983
|
-
/**
|
|
984
|
-
* 오류 코드 전부. **여기 없는 코드는 낼 수 없다** — `FigureError.code` 가 이 목록의
|
|
985
|
-
* 값으로 좁혀져 있어, 코드를 새로 쓰면 타입 검사가 막는다.
|
|
986
|
-
*
|
|
987
|
-
* 목록을 두는 이유는 소비처 때문이다. 오류를 사용자에게 보이는 쪽은 코드마다 문구와
|
|
988
|
-
* 처리를 정해야 하는데, 코드가 늘어난 것이 알려지지 않으면 그 대응이 빠진다. 뜻은
|
|
989
|
-
* `docs/validation.md` 에 있고, 문서와 이 목록이 어긋나면 테스트가 실패한다.
|
|
990
|
-
*/
|
|
991
|
-
export declare const ERROR_CODES: readonly ["not-object", "not-finite", "not-positive", "out-of-range", "not-integer", "not-boolean", "not-allowed", "missing-type", "source-version-unsupported", "missing-base", "missing-parts", "bad-style-kit", "missing-name", "duplicate-name", "missing-transform", "missing-position", "missing-size", "too-few-segments", "missing-shape-path", "bad-shape-point", "hollow-too-thick", "hollow-not-convex", "bad-aspect-axis", "missing-material", "material-unresolvable", "missing-repeat", "missing-channels", "unknown-channel-target", "too-few-keys", "keys-out-of-order", "missing-surface-ref", "missing-label-name", "missing-label-source", "bad-capability", "duplicate-capability", "bad-part-capability", "missing-range", "bad-range", "unknown-parent", "parent-cycle", "unknown-joint-child", "joint-child-taken", "bad-joint-axis"];
|
|
992
|
-
export type ErrorCode = (typeof ERROR_CODES)[number];
|
|
993
|
-
/**
|
|
994
|
-
* 위반 코드 전부. 위반은 컴파일을 막지 않는다 — 저작 화면이 알려 주는 데 쓴다.
|
|
995
|
-
* 뜻과 한도는 `docs/validation.md` 에 있다.
|
|
996
|
-
*/
|
|
997
|
-
export declare const VIOLATION_CODES: readonly ["segments-off-preset", "segments-ignored", "repeat-ignored", "keep-round-ignored", "hollow-ignored", "pivot-ignored", "detail-level-missing", "too-many-parts", "too-many-independent-parts", "too-many-material-groups", "too-many-transparent", "too-many-surface-textures", "capacity-with-repeat", "too-many-always-labels", "part-outside-base", "parts-off-placement-face", "type-not-identifier", "type-is-placeholder"];
|
|
998
|
-
export type ViolationCode = (typeof VIOLATION_CODES)[number];
|
|
999
|
-
/**
|
|
1000
|
-
* 발행을 막는 위반 — ADR-0044 결정 ② (`operato-twin/design/04-decisions.md`).
|
|
1001
|
-
*
|
|
1002
|
-
* 나머지 위반은 알리기만 한다. 막으면 저작자가 우회하고, 숫자로 보여 주면 아낀다.
|
|
1003
|
-
* 이 둘이 다른 것은 **소비처에게 하는 약속을 깨기 때문**이다 — `base` 가 배치 배율의 나누는
|
|
1004
|
-
* 수라, 상자가 부피와 어긋난 도형은 도면에 놓이는 순간 크기와 높이가 둘 다 틀린다.
|
|
1005
|
-
*
|
|
1006
|
-
* **목록이 여기 있는 이유.** 이 사실을 두 곳이 쓴다 — 발행 관문이 거절할 때, 그리고 저작
|
|
1007
|
-
* 화면이 「이건 고쳐야 나간다」를 뜻으로 보여 줄 때. 서버가 제 목록을 들면 화면은 그것을
|
|
1008
|
-
* 알 길이 없어 전부 같은 「알림」으로 그리고, 저작자는 발행이 막힌 것을 **눌러 보고 나서야**
|
|
1009
|
-
* 안다. 코드를 소유한 자리가 등급도 소유한다.
|
|
1010
|
-
*
|
|
1011
|
-
* The two type-name codes belong here for the same reason: a drawing records the type, so a released
|
|
1012
|
-
* name is a promise to consumers.
|
|
1013
|
-
*/
|
|
1014
|
-
export declare const RELEASE_BLOCKING_VIOLATIONS: readonly ViolationCode[];
|
|
1015
|
-
/**
|
|
1016
|
-
* The shape of a `type`: `SCREAMING_SNAKE_CASE` starting with a capital, 3 to 32 characters.
|
|
1017
|
-
*
|
|
1018
|
-
* Capitals are the figure namespace. Built-in scene components use lower-case kebab names, so a figure
|
|
1019
|
-
* that follows this shape cannot share a name with one.
|
|
1020
|
-
*/
|
|
1021
|
-
export declare const TYPE_PATTERN: RegExp;
|
|
1022
|
-
export declare const TYPE_LENGTH: {
|
|
1023
|
-
readonly min: 3;
|
|
1024
|
-
readonly max: 32;
|
|
1025
|
-
};
|
|
1026
|
-
/**
|
|
1027
|
-
* The temporary type a figure carries before anyone names it. The format owns it so that the code
|
|
1028
|
-
* making it and the code recognising it follow one rule: the authoring screen makes it, the release
|
|
1029
|
-
* gate and the AI tools recognise it.
|
|
1030
|
-
*
|
|
1031
|
-
* It passes the identifier pattern (`FIGURE_MTU10FWR`), so the shape check alone would not catch it.
|
|
1032
|
-
*/
|
|
1033
|
-
export declare function placeholderType(now?: number): string;
|
|
1034
|
-
/** Whether a type is the temporary name given before anyone names the figure. */
|
|
1035
|
-
export declare function isPlaceholderType(type: string): boolean;
|
|
1036
|
-
/** 이 위반이 발행을 막나. */
|
|
1037
|
-
export declare function blocksRelease(code: string): boolean;
|
|
1038
|
-
/** 형식·정합성 오류. 이것이 있으면 컴파일할 수 없다. */
|
|
1039
|
-
export interface FigureError {
|
|
1040
|
-
code: ErrorCode;
|
|
1041
|
-
/** 어디서 났나. 예: `parts[2].transform.size.x` */
|
|
1042
|
-
path: string;
|
|
1043
|
-
message: string;
|
|
1044
|
-
}
|
|
1045
|
-
export interface FigureBlueprint {
|
|
1046
|
-
version: number;
|
|
1047
|
-
/**
|
|
1048
|
-
* The source format edition this blueprint was compiled from.
|
|
1049
|
-
*
|
|
1050
|
-
* `version` above is the blueprint's own schema number and moves when the compiled shape
|
|
1051
|
-
* changes. This one reports `FigureSource.version` — which edition of the authored format the
|
|
1052
|
-
* document was written in. A consumer deciding whether it can handle a figure needs this one,
|
|
1053
|
-
* and the blueprint is all a consumer receives: `figureBlueprint(type)` hands over the compiled
|
|
1054
|
-
* result, never the source.
|
|
1055
|
-
*
|
|
1056
|
-
* `compile` fills in `FIGURE_SOURCE_VERSION` when the source carries no version, so this is
|
|
1057
|
-
* always a number. Leaving the default to each consumer was tried once with `flatShading`: the
|
|
1058
|
-
* renderer read an absent value as `true` while the authoring checkbox drew it as off.
|
|
1059
|
-
*/
|
|
1060
|
-
sourceVersion: number;
|
|
1061
|
-
type: string;
|
|
1062
|
-
base: Vec3;
|
|
1063
|
-
/** 3D 배치 기준면 ('floor' | 'ceiling' | 'center'). */
|
|
1064
|
-
placement?: FigurePlacement;
|
|
1065
|
-
/**
|
|
1066
|
-
* 디테일 등급. **부품 수 한도가 여기서 나온다** — 소비처가 「이 Figure 가 예산 안에
|
|
1067
|
-
* 있나」를 판단하려면 등급을 알아야 한다. 원본에 지정되지 않았으면 없다.
|
|
1068
|
-
*/
|
|
1069
|
-
detailLevel?: DetailLevel;
|
|
1070
|
-
budget: {
|
|
1071
|
-
triangles: number;
|
|
1072
|
-
/** 묶음 수 = 재질·슬롯 조합 수 + 움직이는 부품 수. **재는 것은 이것이다.** */
|
|
1073
|
-
groups: number;
|
|
1074
|
-
};
|
|
1075
|
-
groups: BlueprintGroup[];
|
|
1076
|
-
/**
|
|
1077
|
-
* 능력을 받쳐 주는 자리들 — **그리는 것과 섞지 않는다.**
|
|
1078
|
-
*
|
|
1079
|
-
* 자리는 그려지지 않고 삼각형·묶음·부품 수에도 들어가지 않는다. `groups` 안에 두면 `costOf` 가
|
|
1080
|
-
* 세어 버려서, 셀 24칸짜리 트레이가 묶음 한도(3)를 자리만으로 넘긴다. 그리는 것과 세는 것이
|
|
1081
|
-
* 같은 목록을 보므로 **목록을 가르는 것**이 표시를 다는 것보다 안전하다.
|
|
1082
|
-
*/
|
|
1083
|
-
anchors: BlueprintAnchor[];
|
|
1084
|
-
animations: BlueprintClip[];
|
|
1085
|
-
/**
|
|
1086
|
-
* 값이 모는 자세. 인스턴스가 이름으로 값을 준다.
|
|
1087
|
-
*/
|
|
1088
|
-
parameters: BlueprintParameter[];
|
|
1089
|
-
labels: BlueprintLabel[];
|
|
1090
|
-
/**
|
|
1091
|
-
* 정본이 선언한 능력 — **그대로 실어 나른다.**
|
|
1092
|
-
*
|
|
1093
|
-
* 청사진을 받는 쪽(`registerFigure`)이 타입별 클래스를 만들 때 이것으로 mixin 을 얹는다.
|
|
1094
|
-
* 형식은 이름의 뜻을 모르고 판정하지도 않는다(`FigureSource.capabilities` 주석 참고).
|
|
1095
|
-
*/
|
|
1096
|
-
capabilities: readonly string[];
|
|
1097
|
-
/**
|
|
1098
|
-
* Joints, parents before children. Missing or empty means every part is fixed to the figure frame, which
|
|
1099
|
-
* is every blueprint compiled before joints existed.
|
|
1100
|
-
*/
|
|
1101
|
-
joints?: BlueprintJoint[];
|
|
1102
|
-
violations: Violation[];
|
|
1103
|
-
}
|
|
1104
|
-
/**
|
|
1105
|
-
* 맞대어 놓은 면은 정확히 0 만큼 떨어져 있다. 부동소수 나머지를 「닿았다」로 친다.
|
|
1106
|
-
*
|
|
1107
|
-
* 이 값을 키우면 실제로 떨어진 것도 붙은 것으로 읽히고, 줄이면 맞댄 면이 갈라진 것으로 읽힌다.
|
|
1108
|
-
*
|
|
1109
|
-
* **오차 상수는 하나여야 한다.** 발행 관문이 「덩어리가 갈라졌나」를 이 값으로 재고
|
|
1110
|
-
* (`gate.ts`), 판정이 「부품이 상자를 벗어났나」와 「기준면에 닿았나」를 같은 값으로 잰다
|
|
1111
|
-
* (`validate.ts`). 둘이 갈리면 한쪽이 닿았다고 한 면을 다른 쪽이 떨어졌다고 한다.
|
|
1112
|
-
*/
|
|
1113
|
-
export declare const SKIN = 0.5;
|
|
1114
|
-
/**
|
|
1115
|
-
* 성능을 담보하는 한도.
|
|
1116
|
-
*
|
|
1117
|
-
* 로우폴리에서 병목은 삼각형이 아니라 **묶음 수**다. 값을 치르는 것은 놓은 개수가 아니라
|
|
1118
|
-
* **한 화면에 보이는 개수 × 그 도형의 묶음 수**이고, 그 합이 4,000 쯤에서 60fps 가 깨진다
|
|
1119
|
-
* (실측 2026-09-18 · Apple M5 · things-scene `test/browser/measure-figure-frames.mjs`).
|
|
1120
|
-
*
|
|
1121
|
-
* 도형 하나의 묶음은 이렇게 센다 — 두 칸이 그 둘을 각각 본다.
|
|
1122
|
-
*
|
|
1123
|
-
* 따로 변환되는 부품 `movingNames` → independentParts
|
|
1124
|
-
* 실제로 그리는 횟수 `drawCallsOf` → materialGroups
|
|
1125
|
-
*
|
|
1126
|
-
* ⚠ 아래 `materialGroups` 는 **재는 것이 바뀌었는데 값이 안 바뀐 한도**다. 「재질·슬롯 조합 수」
|
|
1127
|
-
* 로 정해진 3 인데, 지금 그 값과 견주는 것은 `drawCallsOf` 가 내는 실제 draw call 이고 그것은 더
|
|
1128
|
-
* 큰 수다(`validate.ts` 의 `checkBudgets` 주석이 그 교체를 적어 두었다). 그래서 표본 47 개 중
|
|
1129
|
-
* **35 개가 이 한도를 넘는다**(중간 6 · 상위 25% 12 · 최대 32). 막지는 않으므로 발행은 되지만,
|
|
1130
|
-
* 거의 모든 도형에 붙는 알림은 정보가 아니다. 다시 재든 없애든 수석 아키텍트 판정을 기다리는
|
|
1131
|
-
* 중이다(2026-09-19). `independentParts` 가 2 → 12 로 겪은 것과 같은 부류다.
|
|
1132
|
-
*/
|
|
1133
|
-
export declare const LIMITS: {
|
|
1134
|
-
/**
|
|
1135
|
-
* **V2 만 읽는다.** 실제 draw call 수와 견주던 옛 한도다(위 ⚠). V3 는 이것을 읽지 않는다 — draw call 은 숫자로만
|
|
1136
|
-
* 보이고 한도에 대지 않으며(ADR-0051 보탬 09-19 판정 2), 값을 치르는 것은 한 화면의 총 묶음이라 그것은
|
|
1137
|
-
* `screenInstances` 가 말한다(판정 1).
|
|
1138
|
-
*/
|
|
1139
|
-
readonly materialGroups: 3;
|
|
1140
|
-
/**
|
|
1141
|
-
* **서로 다른 재질 수** — 팔레트 쪽 뜻(ADR-0051 보탬 09-19 판정 3). 그림의 가독성과 팔레트 규칙을 재는 천장이고,
|
|
1142
|
-
* draw call 과 무관하다. `materialGroups` 가 두 뜻으로 읽히던 것 중 팔레트 쪽이 이 이름을 갖는다.
|
|
1143
|
-
*/
|
|
1144
|
-
readonly distinctMaterials: 3;
|
|
1145
|
-
/**
|
|
1146
|
-
* 한 화면에 보이는 묶음 — 60fps 가 꺾이는 지점, **실측**(2026-09-18 · Apple M5 · things-scene
|
|
1147
|
-
* `test/browser/measure-figure-frames.mjs`). 한 화면에 몇 대 들어가나는 이것을 도형 하나의 묶음 수로 나눈 값이다.
|
|
1148
|
-
*/
|
|
1149
|
-
readonly groupsOnScreen: 4000;
|
|
1150
|
-
/** 한 화면의 삼각형. **아직 안 쟀다** — 설계 문서의 목표치다. */
|
|
1151
|
-
readonly trianglesOnScreen: 500000;
|
|
1152
|
-
/**
|
|
1153
|
-
* **한 화면에 같은 도형을 몇 대 놓을 수 있어야 하나** — V3 등급의 기준(수석 아키텍트 판정 2026-09-24, ADR-0051 보탬
|
|
1154
|
-
* 09-19 판정 1 · 4). 따로 움직이는 부품 12 에 몸체 12 를 더한 도형(묶음 24)이 실측으로 166 대까지 60fps 로 돈다;
|
|
1155
|
-
* 그만큼 놓을 수 있는 도형이 한도 안(C)이고, 두 배 넘게 놓이면 A 다. 고정된 draw call 한도는 도형이 커지면 다시
|
|
1156
|
-
* 낡으므로 두지 않는다.
|
|
1157
|
-
*/
|
|
1158
|
-
readonly screenInstances: 166;
|
|
1159
|
-
/**
|
|
1160
|
-
* **따로 변환되는 부품 수.** 구동 방식과 무관하다 — 값이 몰든 시각이 몰든, 제 변환을 지는
|
|
1161
|
-
* 부품은 제 묶음으로 그린다(ADR-0051 결정 ③).
|
|
1162
|
-
*
|
|
1163
|
-
* 12 인 근거는 실측이다(2026-09-18, Apple M5, things-scene `test/browser/measure-figure-frames.mjs`).
|
|
1164
|
-
* 놓는 개수가 값을 치르는 것이 아니라 **한 화면에 보이는 개수 × 그 도형의 묶음 수**가 치르고,
|
|
1165
|
-
* 그 합이 4,000 쯤에서 60fps 가 깨진다. 독립 부품 12 에 몸체 묶음 12 를 더하면 도형 하나가
|
|
1166
|
-
* 24 묶음이고, 한 화면에 166 대쯤까지 60fps 로 돈다(ADR-0051 보탬 09-19 판정 4 가 옛 「12 + 3 = 15
|
|
1167
|
-
* 묶음, 260 대」를 고쳤다 — 몸체 묶음은 3 이 아니었다). 그만큼이면 현장 한 장면에 같은 종류를
|
|
1168
|
-
* 늘어놓는 수를 담는다 — `screenInstances` 가 그 목표치다.
|
|
1169
|
-
*
|
|
1170
|
-
* 옛 이름은 `animatedParts` 였고 값이 2 였다 — 셈이 아니라 짐작이었다. 포크리프트의 `lift` 가
|
|
1171
|
-
* 11 채널인 것이 현실이라, 2 는 실제로 쓰는 도형을 위반으로 만들었다.
|
|
1172
|
-
*/
|
|
1173
|
-
readonly independentParts: 12;
|
|
1174
|
-
/** 투명 재질. 정렬 비용이 크다. */
|
|
1175
|
-
readonly transparentMaterials: 1;
|
|
1176
|
-
/**
|
|
1177
|
-
* 팔레트 밖 표면(무늬·그라디언트)의 종류 수.
|
|
1178
|
-
*
|
|
1179
|
-
* 1 인 이유 — 라벨 판이나 표시창처럼 정말 그것이어야 하는 자리가 한 군데쯤은 있을 수
|
|
1180
|
-
* 있다. 둘을 넘으면 단색 규칙과 싸우는 것이고, 텍스처마다 GPU 메모리를 쓴다.
|
|
1181
|
-
*
|
|
1182
|
-
* **재질 공유 때문이 아니다** — 이름으로 가리키는 자산이라 재질은 나눠 쓴다.
|
|
1183
|
-
*/
|
|
1184
|
-
readonly surfaceTextures: 1;
|
|
1185
|
-
/** 분할 수 하한 — 이보다 낮으면 형상이 아니다. */
|
|
1186
|
-
readonly minSegments: 3;
|
|
1187
|
-
};
|
|
1188
|
-
/**
|
|
1189
|
-
* 로우폴리 분할 수 프리셋. 자유 입력보다 이 중 하나를 권한다.
|
|
1190
|
-
*
|
|
1191
|
-
* ## 왜 목록을 좁게 두나
|
|
1192
|
-
*
|
|
1193
|
-
* **삼각형 때문이 아니다.** 삼각형은 사실상 공짜다 — 같은 draw call 에서 81만과
|
|
1194
|
-
* 7,305만이 15.2ms 대 15.7ms 였다 [재봤음]. 좁게 두는 이유는 **형상 공유**다.
|
|
1195
|
-
* 단위 곡면은 분할 수마다 하나씩 창고에 남으므로, 모두가 같은 몇 개만 쓰면 전체
|
|
1196
|
-
* 자산이 그 몇 개를 나눠 쓴다.
|
|
1197
|
-
*
|
|
1198
|
-
* ## 24 · 32 를 더한 까닭
|
|
1199
|
-
*
|
|
1200
|
-
* 한동안 8 · 12 · 16 이었다. 근거는 도면 배율에서 잰 톱뷰 실루엣이었다 —
|
|
1201
|
-
* 24 · 48 · 96px 에서 16 → 32 의 차이가 1.9 ~ 2.2% 로 거의 안 보였다.
|
|
1202
|
-
*
|
|
1203
|
-
* 그 측정이 덮지 못하는 자리가 있다. **저작면은 자산을 크게 띄우고, 바퀴처럼 둥근
|
|
1204
|
-
* 면이 옆을 보는 부품이 있다.** n각형이 원에서 벗어나는 최대 거리는
|
|
1205
|
-
* `r(1 − cos(π/n))` 이므로, 같은 다각형이 배율에 따라 정반대로 읽힌다.
|
|
1206
|
-
*
|
|
1207
|
-
* 분할 벗어남 도면(반지름 5px) 저작면(반지름 120px)
|
|
1208
|
-
* 8 7.61% 0.38px 9.1px
|
|
1209
|
-
* 12 3.41% 0.17px 4.1px
|
|
1210
|
-
* 16 1.92% 0.10px 2.3px
|
|
1211
|
-
* 24 0.86% 0.04px 1.0px
|
|
1212
|
-
* 32 0.48% 0.02px 0.6px
|
|
1213
|
-
*
|
|
1214
|
-
* 저작면에서 2.3px 는 면이 또렷이 보이는 크기다. 한 단계마다 벗어남이 대략 반씩
|
|
1215
|
-
* 줄어드는 사다리로 두면, 저작자가 「조금 더 둥글게」를 한 칸씩 고를 수 있다.
|
|
1216
|
-
*
|
|
1217
|
-
* 값 둘을 더해도 창고의 단위 곡면이 셋에서 다섯이 되는 것뿐이다.
|
|
1218
|
-
*
|
|
1219
|
-
* ## 48 을 더한 까닭
|
|
1220
|
-
*
|
|
1221
|
-
* **저작면이 자산을 크게 띄우기 때문**이다 — 렌즈나 축처럼 작고 둥근 것을 화면 절반만
|
|
1222
|
-
* 하게 확대해 놓고 보면 32 에서도 각이 읽힌다. 지름 600px 에서 32 는 2.89px 벗어난다.
|
|
1223
|
-
*
|
|
1224
|
-
* 64 가 아니라 48 인 이유는 **사다리를 건너뛰지 않으려는 것**이다. 이 목록은 벗어남이
|
|
1225
|
-
* 2.25배 · 1.78배로 번갈아 줄어드는 사다리이고, 32 다음 칸이 48 이다. 64 를 넣으면 거기서만
|
|
1226
|
-
* 두 칸이 되어 「한 칸씩 더 둥글게」가 깨진다.
|
|
1227
|
-
*
|
|
1228
|
-
* 그리고 64 는 보이지 않는다 — 지름 600px 에서 48 이 1.28px, 64 가 0.72px 다. 1px 아래는
|
|
1229
|
-
* 화면이 표현하지 못한다. 삼각형만 192 에서 256 으로 는다.
|
|
1230
|
-
*/
|
|
1231
|
-
export declare const SEGMENT_PRESETS: readonly number[];
|
|
1232
|
-
export {};
|
|
1233
|
-
//# sourceMappingURL=types.d.ts.map
|