@things-factory/figure-ui 10.1.44 → 10.1.46
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/client/modeller/figure-v3-links.ts +394 -0
- package/client/modeller/modeller-route.ts +6 -21
- package/client/modeller/v3-editor.ts +47 -5
- package/client/modeller/v3-gizmo.ts +13 -2
- package/client/modeller/v3-links.ts +170 -0
- package/client/pages/figure-v3-modeller-page.ts +2 -5
- package/client/route.ts +2 -6
- package/dist-client/modeller/figure-v3-links.d.ts +47 -0
- package/dist-client/modeller/figure-v3-links.js +379 -0
- package/dist-client/modeller/figure-v3-links.js.map +1 -0
- package/dist-client/modeller/modeller-route.d.ts +4 -11
- package/dist-client/modeller/modeller-route.js +5 -22
- package/dist-client/modeller/modeller-route.js.map +1 -1
- package/dist-client/modeller/v3-editor.d.ts +5 -0
- package/dist-client/modeller/v3-editor.js +49 -4
- package/dist-client/modeller/v3-editor.js.map +1 -1
- package/dist-client/modeller/v3-gizmo.js +11 -1
- package/dist-client/modeller/v3-gizmo.js.map +1 -1
- package/dist-client/modeller/v3-links.d.ts +67 -0
- package/dist-client/modeller/v3-links.js +141 -0
- package/dist-client/modeller/v3-links.js.map +1 -0
- package/dist-client/pages/figure-v3-modeller-page.d.ts +2 -5
- package/dist-client/pages/figure-v3-modeller-page.js +2 -5
- package/dist-client/pages/figure-v3-modeller-page.js.map +1 -1
- package/dist-client/route.d.ts +1 -1
- package/dist-client/route.js +2 -5
- package/dist-client/route.js.map +1 -1
- package/dist-client/tsconfig.scratch-fm.tsbuildinfo +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/test/ai-proposal-contract.test.ts +0 -88
- package/test/figure-source.test.ts +0 -102
- package/test/i18n-prefix-guard.test.ts +0 -24
- package/test/modeller-route.test.ts +14 -25
- package/test/part-edits.test.ts +0 -7
- package/test/scene-budget.test.ts +0 -7
- package/test/v3-gizmo.test.ts +10 -0
- package/test/v3-links.test.ts +163 -0
- package/things-factory.config.js +2 -5
- package/translations/en.json +21 -1
- package/translations/ja.json +21 -1
- package/translations/ko.json +21 -1
- package/translations/ms.json +21 -1
- package/translations/zh.json +21 -1
- package/client/modeller/angle-dial.ts +0 -70
- package/client/modeller/base-box.ts +0 -175
- package/client/modeller/figure-animations.ts +0 -1249
- package/client/modeller/figure-canvas.ts +0 -567
- package/client/modeller/figure-capabilities.ts +0 -379
- package/client/modeller/figure-inspector.ts +0 -2208
- package/client/modeller/figure-parts.ts +0 -479
- package/client/modeller/figure-preview.ts +0 -598
- package/client/modeller/figure-report.ts +0 -966
- package/client/modeller/figure-settings.ts +0 -328
- package/client/modeller/figure-side.ts +0 -272
- package/client/modeller/figure-thumbnail.ts +0 -123
- package/client/modeller/figure-view.ts +0 -152
- package/client/modeller/joint-edits.ts +0 -262
- package/client/modeller/joint-gizmo.ts +0 -180
- package/client/modeller/maturity.ts +0 -288
- package/client/modeller/new-figure-entry.ts +0 -4
- package/client/modeller/pose-defaults.ts +0 -67
- package/client/pages/figure-modeller-page.ts +0 -2082
- package/dist-client/modeller/angle-dial.d.ts +0 -32
- package/dist-client/modeller/angle-dial.js +0 -41
- package/dist-client/modeller/angle-dial.js.map +0 -1
- package/dist-client/modeller/base-box.d.ts +0 -71
- package/dist-client/modeller/base-box.js +0 -110
- package/dist-client/modeller/base-box.js.map +0 -1
- package/dist-client/modeller/figure-animations.d.ts +0 -159
- package/dist-client/modeller/figure-animations.js +0 -1132
- package/dist-client/modeller/figure-animations.js.map +0 -1
- package/dist-client/modeller/figure-canvas.d.ts +0 -150
- package/dist-client/modeller/figure-canvas.js +0 -506
- package/dist-client/modeller/figure-canvas.js.map +0 -1
- package/dist-client/modeller/figure-capabilities.d.ts +0 -42
- package/dist-client/modeller/figure-capabilities.js +0 -349
- package/dist-client/modeller/figure-capabilities.js.map +0 -1
- package/dist-client/modeller/figure-inspector.d.ts +0 -329
- package/dist-client/modeller/figure-inspector.js +0 -2095
- package/dist-client/modeller/figure-inspector.js.map +0 -1
- package/dist-client/modeller/figure-parts.d.ts +0 -64
- package/dist-client/modeller/figure-parts.js +0 -478
- package/dist-client/modeller/figure-parts.js.map +0 -1
- package/dist-client/modeller/figure-preview.d.ts +0 -138
- package/dist-client/modeller/figure-preview.js +0 -549
- package/dist-client/modeller/figure-preview.js.map +0 -1
- package/dist-client/modeller/figure-report.d.ts +0 -165
- package/dist-client/modeller/figure-report.js +0 -952
- package/dist-client/modeller/figure-report.js.map +0 -1
- package/dist-client/modeller/figure-settings.d.ts +0 -39
- package/dist-client/modeller/figure-settings.js +0 -317
- package/dist-client/modeller/figure-settings.js.map +0 -1
- package/dist-client/modeller/figure-side.d.ts +0 -78
- package/dist-client/modeller/figure-side.js +0 -317
- package/dist-client/modeller/figure-side.js.map +0 -1
- package/dist-client/modeller/figure-thumbnail.d.ts +0 -3
- package/dist-client/modeller/figure-thumbnail.js +0 -95
- package/dist-client/modeller/figure-thumbnail.js.map +0 -1
- package/dist-client/modeller/figure-view.d.ts +0 -118
- package/dist-client/modeller/figure-view.js +0 -78
- package/dist-client/modeller/figure-view.js.map +0 -1
- package/dist-client/modeller/joint-edits.d.ts +0 -49
- package/dist-client/modeller/joint-edits.js +0 -223
- package/dist-client/modeller/joint-edits.js.map +0 -1
- package/dist-client/modeller/joint-gizmo.d.ts +0 -34
- package/dist-client/modeller/joint-gizmo.js +0 -158
- package/dist-client/modeller/joint-gizmo.js.map +0 -1
- package/dist-client/modeller/maturity.d.ts +0 -55
- package/dist-client/modeller/maturity.js +0 -212
- package/dist-client/modeller/maturity.js.map +0 -1
- package/dist-client/modeller/new-figure-entry.d.ts +0 -2
- package/dist-client/modeller/new-figure-entry.js +0 -5
- package/dist-client/modeller/new-figure-entry.js.map +0 -1
- package/dist-client/modeller/pose-defaults.d.ts +0 -9
- package/dist-client/modeller/pose-defaults.js +0 -35
- package/dist-client/modeller/pose-defaults.js.map +0 -1
- package/dist-client/pages/figure-modeller-page.d.ts +0 -419
- package/dist-client/pages/figure-modeller-page.js +0 -2060
- package/dist-client/pages/figure-modeller-page.js.map +0 -1
- package/test/angle-dial.test.ts +0 -78
- package/test/base-box.test.ts +0 -235
- package/test/joint-edits.test.ts +0 -165
- package/test/joint-gizmo.test.ts +0 -174
- package/test/joint-needle.test.ts +0 -162
- package/test/modeller-undo-redo.test.ts +0 -33
- package/test/new-figure-entry.test.ts +0 -15
- package/test/pose-defaults.test.ts +0 -71
- package/test/preview-board-depth.test.ts +0 -27
|
@@ -1,317 +0,0 @@
|
|
|
1
|
-
import { __decorate, __metadata } from "tslib";
|
|
2
|
-
import '@material/web/icon/icon.js';
|
|
3
|
-
import './figure-inspector.js';
|
|
4
|
-
import './figure-capabilities.js';
|
|
5
|
-
import './figure-animations.js';
|
|
6
|
-
import './figure-report.js';
|
|
7
|
-
import './figure-settings.js';
|
|
8
|
-
import './figure-history-panel.js';
|
|
9
|
-
import { css, html, LitElement } from 'lit';
|
|
10
|
-
import { customElement, property, state } from 'lit/decorators.js';
|
|
11
|
-
import { i18next, localize } from '@operato/i18n';
|
|
12
|
-
import { DEFAULT_VIEW } from './figure-view.js';
|
|
13
|
-
/**
|
|
14
|
-
* 저작면 오른쪽 칸 — 속성과 판정을 탭으로 겹쳐 둔다.
|
|
15
|
-
*
|
|
16
|
-
* ## 왜 위아래로 나누지 않나
|
|
17
|
-
*
|
|
18
|
-
* 둘 다 세로로 긴 화면이다. 위아래로 나누면 양쪽 다 잘려서, 속성은 재질까지 못
|
|
19
|
-
* 내려가고 판정은 무게까지 못 내려간다. 탭으로 겹치면 각자 칸 전체를 쓴다.
|
|
20
|
-
*
|
|
21
|
-
* ## 그래도 개수는 늘 보인다
|
|
22
|
-
*
|
|
23
|
-
* 성숙도의 축 하나 —「몇 개까지 편한가」— 는 부품을 고칠 때마다 움직이고, 그것이
|
|
24
|
-
* 보여야 저작자가 고칠 수 있다. 탭 뒤로 숨으면 저장하고 나서야 알게 된다. 그래서 그
|
|
25
|
-
* 숫자만 **탭 이름표에 남긴다** — 성숙도를 덮어 두고 속성을 만져도 따라 움직이는
|
|
26
|
-
* 것이 보인다.
|
|
27
|
-
*
|
|
28
|
-
* 판정은 화면에서 감춰도 **DOM 에는 남는다.** 떼었다 붙이면 다시 세느라 값이 잠깐
|
|
29
|
-
* 비고, 펼쳐 둔 추이 그림 같은 상태도 날아간다.
|
|
30
|
-
*/
|
|
31
|
-
let FigureSide = class FigureSide extends localize(i18next)(LitElement) {
|
|
32
|
-
constructor() {
|
|
33
|
-
super(...arguments);
|
|
34
|
-
/*
|
|
35
|
-
두 형태가 이 패널에서 갈린다.
|
|
36
|
-
|
|
37
|
-
속성은 **수정하는** 곳이라 편집 중인 씬 모델을 받는다. 판정은 **저장될 것을 측정하는**
|
|
38
|
-
곳이라 변환된 FigureSource 를 받는다. 변환은 모델러 페이지가 한 번만 해서 내려보낸다.
|
|
39
|
-
*/
|
|
40
|
-
this.figureName = '';
|
|
41
|
-
this.figureVersion = 0;
|
|
42
|
-
this.dirty = false;
|
|
43
|
-
this.parts = [];
|
|
44
|
-
/** 이 고침이 이미 놓인 인스턴스에 무엇을 하나(ADR-0063 결정 3). 발행 전 도형에는 비어 있다. */
|
|
45
|
-
this.contract = [];
|
|
46
|
-
this.selected = -1;
|
|
47
|
-
/** 저작 화면의 보기 설정. 자산이 아니라 작업대다 — 저장되지 않는다. */
|
|
48
|
-
this.view = DEFAULT_VIEW;
|
|
49
|
-
this.tab = 'properties';
|
|
50
|
-
}
|
|
51
|
-
static { this.styles = css `
|
|
52
|
-
:host {
|
|
53
|
-
display: flex;
|
|
54
|
-
flex-direction: column;
|
|
55
|
-
min-height: 0;
|
|
56
|
-
overflow: hidden;
|
|
57
|
-
background-color: var(--md-sys-color-surface-container-lowest);
|
|
58
|
-
border-left: 1px solid var(--md-sys-color-outline-variant);
|
|
59
|
-
color: var(--md-sys-color-on-surface);
|
|
60
|
-
font: var(--label-font, inherit);
|
|
61
|
-
/*
|
|
62
|
-
이 패널의 본문 크기를 여기서 한 번 정한다.
|
|
63
|
-
|
|
64
|
-
전에는 규칙마다 따로 적었다. 그러면 빠뜨린 규칙이 본문 기본 크기(1rem)를
|
|
65
|
-
물려받아 그 줄만 제목처럼 커진다. 오류가 아니라서 화면을 띄워 봐야 안다.
|
|
66
|
-
이 파일에서만 두 번 났다.
|
|
67
|
-
|
|
68
|
-
form 요소(input · select · button)는 글꼴을 물려받지 않으므로 각자 적어야 한다.
|
|
69
|
-
그것 말고는 여기 값을 따른다.
|
|
70
|
-
*/
|
|
71
|
-
font-size: 0.76rem;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
div[tabs] {
|
|
75
|
-
display: flex;
|
|
76
|
-
flex: none;
|
|
77
|
-
border-bottom: 1px solid var(--md-sys-color-outline-variant);
|
|
78
|
-
}
|
|
79
|
-
button[tab] {
|
|
80
|
-
flex: 1;
|
|
81
|
-
/*
|
|
82
|
-
**아이콘 하나가 한 칸을 쓴다.**
|
|
83
|
-
|
|
84
|
-
전에는 이름을 적었는데, 넷이 좁은 칸을 나눠 쓰면서 접혀 「성숙 / 도」가 되었다. 접히면
|
|
85
|
-
그 탭만 두 줄이 되어 높이가 서로 달라진다. 다섯이 되면서 더는 줄여 짜 넣을 수 없어
|
|
86
|
-
아이콘으로 바꿨고, 이름은 title 과 aria-label 로 남는다.
|
|
87
|
-
|
|
88
|
-
배지는 여전히 자리를 차지하지 않고 **아이콘 위에 겹친다**(아래 span[badge]). 개수는
|
|
89
|
-
곁들이는 것이다.
|
|
90
|
-
*/
|
|
91
|
-
position: relative;
|
|
92
|
-
display: flex;
|
|
93
|
-
align-items: center;
|
|
94
|
-
justify-content: center;
|
|
95
|
-
white-space: nowrap;
|
|
96
|
-
padding: 7px 6px;
|
|
97
|
-
color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));
|
|
98
|
-
background: none;
|
|
99
|
-
border: none;
|
|
100
|
-
/* 고른 탭을 밑줄로 말한다 — 칸을 색으로 채우면 아래 내용과 경계가 흐려진다 */
|
|
101
|
-
border-bottom: 2px solid transparent;
|
|
102
|
-
cursor: pointer;
|
|
103
|
-
}
|
|
104
|
-
button[tab]:hover:not([on]) {
|
|
105
|
-
background-color: var(--md-sys-color-surface-container);
|
|
106
|
-
}
|
|
107
|
-
button[tab][on] {
|
|
108
|
-
font-weight: 700;
|
|
109
|
-
color: var(--md-sys-color-primary);
|
|
110
|
-
border-bottom-color: var(--md-sys-color-primary);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/*
|
|
114
|
-
판정을 덮어 두어도 개수는 여기 남는다.
|
|
115
|
-
|
|
116
|
-
자리를 먹지 않게 오른쪽 위에 겹쳐 둔다 — 탭 이름을 밀지 않으므로 이름이 접히지 않는다.
|
|
117
|
-
숫자가 커져도(1,200 같은 것) 이름 위로 넘칠 뿐 줄을 바꾸지 않는다.
|
|
118
|
-
*/
|
|
119
|
-
button[tab] md-icon {
|
|
120
|
-
font-size: 20px;
|
|
121
|
-
width: 20px;
|
|
122
|
-
height: 20px;
|
|
123
|
-
}
|
|
124
|
-
span[badge] {
|
|
125
|
-
position: absolute;
|
|
126
|
-
/* 이름 위에 겹치되 위로 붙지 않게 — 탭 가운데 글자와 눈높이를 조금 맞춘다 */
|
|
127
|
-
top: 5px;
|
|
128
|
-
right: 2px;
|
|
129
|
-
padding: 0 5px;
|
|
130
|
-
font-size: 0.62rem;
|
|
131
|
-
font-weight: 700;
|
|
132
|
-
line-height: 1.5;
|
|
133
|
-
color: var(--md-sys-color-on-primary-container);
|
|
134
|
-
background-color: var(--md-sys-color-primary-container);
|
|
135
|
-
border-radius: 999em;
|
|
136
|
-
pointer-events: none;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
figure-inspector,
|
|
140
|
-
figure-animations,
|
|
141
|
-
figure-report,
|
|
142
|
-
figure-settings {
|
|
143
|
-
flex: 1;
|
|
144
|
-
min-height: 0;
|
|
145
|
-
border-left: none;
|
|
146
|
-
}
|
|
147
|
-
/* 감추되 떼지는 않는다 */
|
|
148
|
-
[off] {
|
|
149
|
-
display: none;
|
|
150
|
-
}
|
|
151
|
-
`; }
|
|
152
|
-
/**
|
|
153
|
-
* 이 도형이 든 clip 수. 탭 아이콘에 붙는다.
|
|
154
|
-
*
|
|
155
|
-
* 아이콘만으로는 「여기에 무언가 있다」를 알 수 없다. 대부분의 도형은 움직이지 않으므로
|
|
156
|
-
* 이 탭은 늘 비어 있을 것이고, 그러면 움직이는 도형을 열었을 때 그 사실이 눈에 걸려야 한다.
|
|
157
|
-
* 0 이면 아무것도 안 붙인다 — 「0」을 붙이면 없는 것이 있는 것처럼 자리를 차지한다.
|
|
158
|
-
*/
|
|
159
|
-
get clipCount() {
|
|
160
|
-
const n = (this.draft?.animations?.length ?? 0) + (this.draft?.parameters?.length ?? 0);
|
|
161
|
-
return n === 0 ? undefined : n;
|
|
162
|
-
}
|
|
163
|
-
render() {
|
|
164
|
-
return html `
|
|
165
|
-
<div tabs>
|
|
166
|
-
${this.renderTab('properties', 'tune', i18next.t('figure.label.properties'))}
|
|
167
|
-
${this.renderTab('capability', 'conveyor_belt', i18next.t('figure.label.tab-capability'))}
|
|
168
|
-
${this.renderTab('animation', 'animation', i18next.t('figure.label.animation'), this.clipCount)}
|
|
169
|
-
${this.renderTab('verdict', 'insights', i18next.t('figure.label.maturity'), this.instances)}
|
|
170
|
-
${this.renderTab('view', 'wb_sunny', i18next.t('figure.label.tab-environment'))}
|
|
171
|
-
${this.renderTab('history', 'history', i18next.t('figure.label.history'))}
|
|
172
|
-
</div>
|
|
173
|
-
|
|
174
|
-
<figure-inspector
|
|
175
|
-
?off=${this.tab !== 'properties'}
|
|
176
|
-
.figureId=${this.figureId}
|
|
177
|
-
.figureVersion=${this.figureVersion}
|
|
178
|
-
.figureName=${this.figureName}
|
|
179
|
-
.figureCategory=${this.figureCategory}
|
|
180
|
-
.figureTags=${this.figureTags}
|
|
181
|
-
.draft=${this.draft}
|
|
182
|
-
.parts=${this.parts}
|
|
183
|
-
.contract=${this.contract}
|
|
184
|
-
.contractFailure=${this.contractFailure}
|
|
185
|
-
.selected=${this.selected}
|
|
186
|
-
></figure-inspector>
|
|
187
|
-
|
|
188
|
-
<figure-capabilities
|
|
189
|
-
?off=${this.tab !== 'capability'}
|
|
190
|
-
.draft=${this.draft}
|
|
191
|
-
.parts=${this.parts}
|
|
192
|
-
></figure-capabilities>
|
|
193
|
-
|
|
194
|
-
<figure-animations
|
|
195
|
-
?off=${this.tab !== 'animation'}
|
|
196
|
-
.draft=${this.draft}
|
|
197
|
-
.parts=${this.parts}
|
|
198
|
-
></figure-animations>
|
|
199
|
-
|
|
200
|
-
<figure-report
|
|
201
|
-
?off=${this.tab !== 'verdict'}
|
|
202
|
-
.source=${this.source}
|
|
203
|
-
@verdict-changed=${(e) => (this.instances = e.detail.instances)}
|
|
204
|
-
></figure-report>
|
|
205
|
-
|
|
206
|
-
<figure-settings ?off=${this.tab !== 'view'} .view=${this.view}></figure-settings>
|
|
207
|
-
|
|
208
|
-
<!--
|
|
209
|
-
이력은 감춰도 DOM 에 남긴다 — 다른 탭들과 같은 규칙이다. 떼었다 붙이면 판본을 다시 부른다.
|
|
210
|
-
-->
|
|
211
|
-
<figure-history-panel
|
|
212
|
-
?off=${this.tab !== 'history'}
|
|
213
|
-
.figureId=${this.figureId}
|
|
214
|
-
.figureState=${this.figureState}
|
|
215
|
-
.figureVersion=${this.figureVersion}
|
|
216
|
-
.dirty=${this.dirty}
|
|
217
|
-
.releasedBase=${this.releasedBase}
|
|
218
|
-
></figure-history-panel>
|
|
219
|
-
`;
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* 탭 하나 — **아이콘이 이름을 대신한다.**
|
|
223
|
-
*
|
|
224
|
-
* 탭이 다섯이 되면서 이름이 좁은 칸을 나눠 쓰다 접혔다. 앞으로 더 늘어날 자리이므로 이름을
|
|
225
|
-
* 줄여 짜 넣는 대신 아이콘으로 바꾼다.
|
|
226
|
-
*
|
|
227
|
-
* **이름을 버리지는 않는다.** 아이콘만으로는 무엇인지 모르는 사람이 있고, 특히 「능력」처럼
|
|
228
|
-
* 이 도구에만 있는 개념이 그렇다. 그래서 이름은 `title` 로 남아 마우스를 올리면 나오고,
|
|
229
|
-
* `aria-label` 로 읽는 기계에도 그대로 간다.
|
|
230
|
-
*/
|
|
231
|
-
renderTab(tab, icon, label, badge) {
|
|
232
|
-
return html `
|
|
233
|
-
<button
|
|
234
|
-
tab
|
|
235
|
-
?on=${this.tab === tab}
|
|
236
|
-
title=${label}
|
|
237
|
-
aria-label=${label}
|
|
238
|
-
@click=${() => (this.tab = tab)}
|
|
239
|
-
>
|
|
240
|
-
<md-icon>${icon}</md-icon>${badge == null ? '' : html `<span badge>${badge.toLocaleString()}</span>`}
|
|
241
|
-
</button>
|
|
242
|
-
`;
|
|
243
|
-
}
|
|
244
|
-
};
|
|
245
|
-
__decorate([
|
|
246
|
-
property({ type: String }),
|
|
247
|
-
__metadata("design:type", Object)
|
|
248
|
-
], FigureSide.prototype, "figureName", void 0);
|
|
249
|
-
__decorate([
|
|
250
|
-
property({ type: String }),
|
|
251
|
-
__metadata("design:type", String)
|
|
252
|
-
], FigureSide.prototype, "figureCategory", void 0);
|
|
253
|
-
__decorate([
|
|
254
|
-
property({ type: Array }),
|
|
255
|
-
__metadata("design:type", Array)
|
|
256
|
-
], FigureSide.prototype, "figureTags", void 0);
|
|
257
|
-
__decorate([
|
|
258
|
-
property({ type: String }),
|
|
259
|
-
__metadata("design:type", String)
|
|
260
|
-
], FigureSide.prototype, "figureId", void 0);
|
|
261
|
-
__decorate([
|
|
262
|
-
property({ type: String }),
|
|
263
|
-
__metadata("design:type", String)
|
|
264
|
-
], FigureSide.prototype, "figureState", void 0);
|
|
265
|
-
__decorate([
|
|
266
|
-
property({ type: Number }),
|
|
267
|
-
__metadata("design:type", Object)
|
|
268
|
-
], FigureSide.prototype, "figureVersion", void 0);
|
|
269
|
-
__decorate([
|
|
270
|
-
property({ type: Boolean }),
|
|
271
|
-
__metadata("design:type", Object)
|
|
272
|
-
], FigureSide.prototype, "dirty", void 0);
|
|
273
|
-
__decorate([
|
|
274
|
-
property({ type: Object }),
|
|
275
|
-
__metadata("design:type", Object)
|
|
276
|
-
], FigureSide.prototype, "draft", void 0);
|
|
277
|
-
__decorate([
|
|
278
|
-
property({ type: Array }),
|
|
279
|
-
__metadata("design:type", Array)
|
|
280
|
-
], FigureSide.prototype, "parts", void 0);
|
|
281
|
-
__decorate([
|
|
282
|
-
property({ type: Object }),
|
|
283
|
-
__metadata("design:type", Object)
|
|
284
|
-
], FigureSide.prototype, "source", void 0);
|
|
285
|
-
__decorate([
|
|
286
|
-
property({ type: Array }),
|
|
287
|
-
__metadata("design:type", Array)
|
|
288
|
-
], FigureSide.prototype, "contract", void 0);
|
|
289
|
-
__decorate([
|
|
290
|
-
property({ type: Object }),
|
|
291
|
-
__metadata("design:type", Object)
|
|
292
|
-
], FigureSide.prototype, "releasedBase", void 0);
|
|
293
|
-
__decorate([
|
|
294
|
-
property({ type: String }),
|
|
295
|
-
__metadata("design:type", String)
|
|
296
|
-
], FigureSide.prototype, "contractFailure", void 0);
|
|
297
|
-
__decorate([
|
|
298
|
-
property({ type: Number }),
|
|
299
|
-
__metadata("design:type", Object)
|
|
300
|
-
], FigureSide.prototype, "selected", void 0);
|
|
301
|
-
__decorate([
|
|
302
|
-
property({ type: Object }),
|
|
303
|
-
__metadata("design:type", Object)
|
|
304
|
-
], FigureSide.prototype, "view", void 0);
|
|
305
|
-
__decorate([
|
|
306
|
-
state(),
|
|
307
|
-
__metadata("design:type", String)
|
|
308
|
-
], FigureSide.prototype, "tab", void 0);
|
|
309
|
-
__decorate([
|
|
310
|
-
state(),
|
|
311
|
-
__metadata("design:type", Number)
|
|
312
|
-
], FigureSide.prototype, "instances", void 0);
|
|
313
|
-
FigureSide = __decorate([
|
|
314
|
-
customElement('figure-side')
|
|
315
|
-
], FigureSide);
|
|
316
|
-
export { FigureSide };
|
|
317
|
-
//# sourceMappingURL=figure-side.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"figure-side.js","sourceRoot":"","sources":["../../client/modeller/figure-side.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport './figure-inspector.js'\nimport './figure-capabilities.js'\nimport './figure-animations.js'\nimport './figure-report.js'\nimport './figure-settings.js'\nimport './figure-history-panel.js'\n\nimport { css, html, LitElement } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport type { ContractChange, FigureSource } from '@hatiolab/figure-model'\n\nimport type { FigureDraft, PartModel } from './figure-source.js'\nimport { DEFAULT_VIEW } from './figure-view.js'\nimport type { ViewSettings } from './figure-view.js'\n\ntype Tab = 'properties' | 'capability' | 'animation' | 'verdict' | 'view' | 'history'\n\n/**\n * 저작면 오른쪽 칸 — 속성과 판정을 탭으로 겹쳐 둔다.\n *\n * ## 왜 위아래로 나누지 않나\n *\n * 둘 다 세로로 긴 화면이다. 위아래로 나누면 양쪽 다 잘려서, 속성은 재질까지 못\n * 내려가고 판정은 무게까지 못 내려간다. 탭으로 겹치면 각자 칸 전체를 쓴다.\n *\n * ## 그래도 개수는 늘 보인다\n *\n * 성숙도의 축 하나 —「몇 개까지 편한가」— 는 부품을 고칠 때마다 움직이고, 그것이\n * 보여야 저작자가 고칠 수 있다. 탭 뒤로 숨으면 저장하고 나서야 알게 된다. 그래서 그\n * 숫자만 **탭 이름표에 남긴다** — 성숙도를 덮어 두고 속성을 만져도 따라 움직이는\n * 것이 보인다.\n *\n * 판정은 화면에서 감춰도 **DOM 에는 남는다.** 떼었다 붙이면 다시 세느라 값이 잠깐\n * 비고, 펼쳐 둔 추이 그림 같은 상태도 날아간다.\n */\n@customElement('figure-side')\nexport class FigureSide extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow: hidden;\n background-color: var(--md-sys-color-surface-container-lowest);\n border-left: 1px solid var(--md-sys-color-outline-variant);\n color: var(--md-sys-color-on-surface);\n font: var(--label-font, inherit);\n /*\n 이 패널의 본문 크기를 여기서 한 번 정한다.\n\n 전에는 규칙마다 따로 적었다. 그러면 빠뜨린 규칙이 본문 기본 크기(1rem)를\n 물려받아 그 줄만 제목처럼 커진다. 오류가 아니라서 화면을 띄워 봐야 안다.\n 이 파일에서만 두 번 났다.\n\n form 요소(input · select · button)는 글꼴을 물려받지 않으므로 각자 적어야 한다.\n 그것 말고는 여기 값을 따른다.\n */\n font-size: 0.76rem;\n }\n\n div[tabs] {\n display: flex;\n flex: none;\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n button[tab] {\n flex: 1;\n /*\n **아이콘 하나가 한 칸을 쓴다.**\n\n 전에는 이름을 적었는데, 넷이 좁은 칸을 나눠 쓰면서 접혀 「성숙 / 도」가 되었다. 접히면\n 그 탭만 두 줄이 되어 높이가 서로 달라진다. 다섯이 되면서 더는 줄여 짜 넣을 수 없어\n 아이콘으로 바꿨고, 이름은 title 과 aria-label 로 남는다.\n\n 배지는 여전히 자리를 차지하지 않고 **아이콘 위에 겹친다**(아래 span[badge]). 개수는\n 곁들이는 것이다.\n */\n position: relative;\n display: flex;\n align-items: center;\n justify-content: center;\n white-space: nowrap;\n padding: 7px 6px;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n background: none;\n border: none;\n /* 고른 탭을 밑줄로 말한다 — 칸을 색으로 채우면 아래 내용과 경계가 흐려진다 */\n border-bottom: 2px solid transparent;\n cursor: pointer;\n }\n button[tab]:hover:not([on]) {\n background-color: var(--md-sys-color-surface-container);\n }\n button[tab][on] {\n font-weight: 700;\n color: var(--md-sys-color-primary);\n border-bottom-color: var(--md-sys-color-primary);\n }\n\n /*\n 판정을 덮어 두어도 개수는 여기 남는다.\n\n 자리를 먹지 않게 오른쪽 위에 겹쳐 둔다 — 탭 이름을 밀지 않으므로 이름이 접히지 않는다.\n 숫자가 커져도(1,200 같은 것) 이름 위로 넘칠 뿐 줄을 바꾸지 않는다.\n */\n button[tab] md-icon {\n font-size: 20px;\n width: 20px;\n height: 20px;\n }\n span[badge] {\n position: absolute;\n /* 이름 위에 겹치되 위로 붙지 않게 — 탭 가운데 글자와 눈높이를 조금 맞춘다 */\n top: 5px;\n right: 2px;\n padding: 0 5px;\n font-size: 0.62rem;\n font-weight: 700;\n line-height: 1.5;\n color: var(--md-sys-color-on-primary-container);\n background-color: var(--md-sys-color-primary-container);\n border-radius: 999em;\n pointer-events: none;\n }\n\n figure-inspector,\n figure-animations,\n figure-report,\n figure-settings {\n flex: 1;\n min-height: 0;\n border-left: none;\n }\n /* 감추되 떼지는 않는다 */\n [off] {\n display: none;\n }\n `\n\n /*\n 두 형태가 이 패널에서 갈린다.\n\n 속성은 **수정하는** 곳이라 편집 중인 씬 모델을 받는다. 판정은 **저장될 것을 측정하는**\n 곳이라 변환된 FigureSource 를 받는다. 변환은 모델러 페이지가 한 번만 해서 내려보낸다.\n */\n @property({ type: String }) figureName = ''\n /** 카탈로그 분류·태그. 속성 탭이 보여 주고 바꾼다. */\n @property({ type: String }) figureCategory?: string\n @property({ type: Array }) figureTags?: string[]\n /** 이력 탭이 발행하고 되돌리는 데 필요한 것들. 정본은 저작면이 든다. */\n @property({ type: String }) figureId?: string\n @property({ type: String }) figureState?: 'draft' | 'released'\n @property({ type: Number }) figureVersion = 0\n @property({ type: Boolean }) dirty = false\n\n @property({ type: Object }) draft?: FigureDraft\n @property({ type: Array }) parts: PartModel[] = []\n @property({ type: Object }) source?: FigureSource\n\n /** 이 고침이 이미 놓인 인스턴스에 무엇을 하나(ADR-0063 결정 3). 발행 전 도형에는 비어 있다. */\n @property({ type: Array }) contract: ContractChange[] = []\n /** 직전 발행 기준 상자. 외형 변화 안내의 X·Z 복원 선택지에만 쓴다. */\n @property({ type: Object }) releasedBase?: FigureSource['base']\n\n /** 견주지 못한 까닭. 있으면 화면이 「확인하지 못했다」로 말한다. */\n @property({ type: String }) contractFailure?: string\n @property({ type: Number }) selected = -1\n /** 저작 화면의 보기 설정. 자산이 아니라 작업대다 — 저장되지 않는다. */\n @property({ type: Object }) view: ViewSettings = DEFAULT_VIEW\n\n @state() private tab: Tab = 'properties'\n /** 판정이 알려 준 개수. 탭 이름표에 붙는다. */\n @state() private instances?: number\n\n /**\n * 이 도형이 든 clip 수. 탭 아이콘에 붙는다.\n *\n * 아이콘만으로는 「여기에 무언가 있다」를 알 수 없다. 대부분의 도형은 움직이지 않으므로\n * 이 탭은 늘 비어 있을 것이고, 그러면 움직이는 도형을 열었을 때 그 사실이 눈에 걸려야 한다.\n * 0 이면 아무것도 안 붙인다 — 「0」을 붙이면 없는 것이 있는 것처럼 자리를 차지한다.\n */\n private get clipCount(): number | undefined {\n const n = (this.draft?.animations?.length ?? 0) + (this.draft?.parameters?.length ?? 0)\n return n === 0 ? undefined : n\n }\n\n render() {\n return html`\n <div tabs>\n ${this.renderTab('properties', 'tune', i18next.t('figure.label.properties'))}\n ${this.renderTab('capability', 'conveyor_belt', i18next.t('figure.label.tab-capability'))}\n ${this.renderTab('animation', 'animation', i18next.t('figure.label.animation'), this.clipCount)}\n ${this.renderTab('verdict', 'insights', i18next.t('figure.label.maturity'), this.instances)}\n ${this.renderTab('view', 'wb_sunny', i18next.t('figure.label.tab-environment'))}\n ${this.renderTab('history', 'history', i18next.t('figure.label.history'))}\n </div>\n\n <figure-inspector\n ?off=${this.tab !== 'properties'}\n .figureId=${this.figureId}\n .figureVersion=${this.figureVersion}\n .figureName=${this.figureName}\n .figureCategory=${this.figureCategory}\n .figureTags=${this.figureTags}\n .draft=${this.draft}\n .parts=${this.parts}\n .contract=${this.contract}\n .contractFailure=${this.contractFailure}\n .selected=${this.selected}\n ></figure-inspector>\n\n <figure-capabilities\n ?off=${this.tab !== 'capability'}\n .draft=${this.draft}\n .parts=${this.parts}\n ></figure-capabilities>\n\n <figure-animations\n ?off=${this.tab !== 'animation'}\n .draft=${this.draft}\n .parts=${this.parts}\n ></figure-animations>\n\n <figure-report\n ?off=${this.tab !== 'verdict'}\n .source=${this.source}\n @verdict-changed=${(e: CustomEvent) => (this.instances = e.detail.instances)}\n ></figure-report>\n\n <figure-settings ?off=${this.tab !== 'view'} .view=${this.view}></figure-settings>\n\n <!--\n 이력은 감춰도 DOM 에 남긴다 — 다른 탭들과 같은 규칙이다. 떼었다 붙이면 판본을 다시 부른다.\n -->\n <figure-history-panel\n ?off=${this.tab !== 'history'}\n .figureId=${this.figureId}\n .figureState=${this.figureState}\n .figureVersion=${this.figureVersion}\n .dirty=${this.dirty}\n .releasedBase=${this.releasedBase}\n ></figure-history-panel>\n `\n }\n\n /**\n * 탭 하나 — **아이콘이 이름을 대신한다.**\n *\n * 탭이 다섯이 되면서 이름이 좁은 칸을 나눠 쓰다 접혔다. 앞으로 더 늘어날 자리이므로 이름을\n * 줄여 짜 넣는 대신 아이콘으로 바꾼다.\n *\n * **이름을 버리지는 않는다.** 아이콘만으로는 무엇인지 모르는 사람이 있고, 특히 「능력」처럼\n * 이 도구에만 있는 개념이 그렇다. 그래서 이름은 `title` 로 남아 마우스를 올리면 나오고,\n * `aria-label` 로 읽는 기계에도 그대로 간다.\n */\n private renderTab(tab: Tab, icon: string, label: string, badge?: number) {\n return html`\n <button\n tab\n ?on=${this.tab === tab}\n title=${label}\n aria-label=${label}\n @click=${() => (this.tab = tab)}\n >\n <md-icon>${icon}</md-icon>${badge == null ? '' : html`<span badge>${badge.toLocaleString()}</span>`}\n </button>\n `\n }\n}\n"]}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import './figure-canvas.js';
|
|
2
|
-
/**
|
|
3
|
-
* 카드에 쓸 그림을 찍는다 — **숨은 자리에 저작 캔버스를 하나 더 세워서.**
|
|
4
|
-
*
|
|
5
|
-
* ## 왜 보이는 캔버스를 찍지 않나
|
|
6
|
-
*
|
|
7
|
-
* 저작면의 캔버스는 저작자가 돌려 둔 각도와 확대로 서 있고, 칸의 비율도 창 크기와 접힌 패널에 따라
|
|
8
|
-
* 다르다. 그것을 찍으면 카드마다 프레임이 달라지고, 방금 확대해 보던 나사 하나가 그 자산의 얼굴이
|
|
9
|
-
* 된다. 목록은 견주는 자리이므로 그림은 **정해진 크기와 정해진 카메라**로 찍는다.
|
|
10
|
-
*
|
|
11
|
-
* ## 왜 씬을 여기서 세우지 않고 부품을 세우나
|
|
12
|
-
*
|
|
13
|
-
* 씬 값(환경 · 하늘 · 조명 · 픽셀 비율 · 좌표 바탕)은 `figure-canvas` 가 든다. 여기서 다시 적으면
|
|
14
|
-
* 두 벌이 되고, 그러면 **카드에 보이는 그림과 저작면에서 보던 것이 아무 오류 없이 갈린다.** 그래서
|
|
15
|
-
* 같은 부품을 `viewOnly` 로 하나 더 세워 그 부품이 자기 씬을 세우게 하고, 찍은 뒤 버린다.
|
|
16
|
-
*
|
|
17
|
-
* ## 왜 서버가 아니라 브라우저인가
|
|
18
|
-
*
|
|
19
|
-
* 도면은 저장할 때 서버가 찍는데, 백엔드에 GPU 가 없는 배포가 많아 헤드리스로 3D 를 찍는 것이 자주
|
|
20
|
-
* 실패한다. 도형을 그릴 GPU 는 이미 보는 사람 손에 있다.
|
|
21
|
-
*/
|
|
22
|
-
/** 카드는 4:3 이다. */
|
|
23
|
-
const WIDTH = 480;
|
|
24
|
-
const HEIGHT = 360;
|
|
25
|
-
/**
|
|
26
|
-
* 씬이 서고 카메라가 자리를 잡을 틈 — 프레임 두 장 뒤에 한 번 더 쉰다. 씬에 그 신호가 없다.
|
|
27
|
-
*
|
|
28
|
-
* **rAF 만 기다리면 안 된다.** 탭이 뒤로 가거나 창이 가려지면 브라우저가 rAF 를 멈추고, 그러면
|
|
29
|
-
* 이 약속이 영원히 안 풀린다. 그 위에 저장이 얹혀 있어서 저장이 통째로 멈췄다 — 단추는 잠긴 채로,
|
|
30
|
-
* 아무 말도 없이. [확인함] 2026-09-10 포커스 없는 탭에서 `saving: true` 로 고정.
|
|
31
|
-
*
|
|
32
|
-
* 그래서 시계와 함께 경주시킨다. 늦게 깨어난 쪽은 버려지고, 화면이 안 그려지는 상황이면 아래
|
|
33
|
-
* `snapshot` 이 빈 것을 돌려주거나 시간이 다 된다 — 어느 쪽이든 **저장은 계속 간다.**
|
|
34
|
-
*/
|
|
35
|
-
function settle() {
|
|
36
|
-
const frames = new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(() => setTimeout(resolve, 150))));
|
|
37
|
-
return Promise.race([frames, delay(600)]);
|
|
38
|
-
}
|
|
39
|
-
function delay(ms) {
|
|
40
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
41
|
-
}
|
|
42
|
-
/**
|
|
43
|
-
* 그림을 기다리는 시간의 한도.
|
|
44
|
-
*
|
|
45
|
-
* 3D 를 세워 한 장 찍는 데 걸리는 시간은 형상과 기계에 따라 다르지만, 이 한도의 목적은 빠르기가
|
|
46
|
-
* 아니라 **저장이 멈추지 않는 것**이다. 넘으면 그림 없이 저장한다 — 정본이 그림보다 중하고,
|
|
47
|
-
* 그림은 다음에 저작면을 열 때 다시 채운다(`figure-modeller-page` 의 fillThumbnail).
|
|
48
|
-
*/
|
|
49
|
-
const PATIENCE = 5000;
|
|
50
|
-
/** 시간이 다 되면 없는 것으로 답한다. 던지지 않는다 — 그림이 없는 것은 실패가 아니다. */
|
|
51
|
-
function within(work, ms) {
|
|
52
|
-
return Promise.race([work, delay(ms).then(() => undefined)]);
|
|
53
|
-
}
|
|
54
|
-
export async function captureThumbnail(draft, parts) {
|
|
55
|
-
if (!draft || !parts.length) {
|
|
56
|
-
return undefined;
|
|
57
|
-
}
|
|
58
|
-
/*
|
|
59
|
-
화면 밖에 둔다. `display: none` 이면 캔버스가 크기를 못 얻어 아무것도 그리지 못한다.
|
|
60
|
-
WebGL context 는 브라우저가 8~16개에서 끊으므로 찍은 뒤 반드시 버린다(아래 finally).
|
|
61
|
-
*/
|
|
62
|
-
const host = document.createElement('div');
|
|
63
|
-
host.setAttribute('figure-thumbnail-stage', '');
|
|
64
|
-
host.style.cssText = `position: fixed; left: -10000px; top: 0; width: ${WIDTH}px; height: ${HEIGHT}px; pointer-events: none;`;
|
|
65
|
-
document.body.appendChild(host);
|
|
66
|
-
const shooter = document.createElement('figure-canvas');
|
|
67
|
-
shooter.viewOnly = true;
|
|
68
|
-
shooter.draft = draft;
|
|
69
|
-
shooter.parts = parts;
|
|
70
|
-
shooter.style.cssText = 'display: block; width: 100%; height: 100%;';
|
|
71
|
-
try {
|
|
72
|
-
host.appendChild(shooter);
|
|
73
|
-
/*
|
|
74
|
-
**한도 안에 못 찍으면 그림 없이 간다.** 이 함수를 부르는 자리가 저장이고, 저장은 그림을
|
|
75
|
-
기다리다 멈춰서는 안 된다. 못 찍은 것은 조용히 넘기지 않고 콘솔에 남긴다 — 그림이 계속
|
|
76
|
-
안 생기면 그 줄이 단서가 된다.
|
|
77
|
-
*/
|
|
78
|
-
const shot = await within((async () => {
|
|
79
|
-
await settle();
|
|
80
|
-
return shooter.snapshot ? await shooter.snapshot(WIDTH, HEIGHT) : undefined;
|
|
81
|
-
})(), PATIENCE);
|
|
82
|
-
if (!shot) {
|
|
83
|
-
console.warn(`[thumbnail] ${PATIENCE}ms 안에 못 찍었습니다 — 그림 없이 저장합니다`);
|
|
84
|
-
}
|
|
85
|
-
return shot;
|
|
86
|
-
}
|
|
87
|
-
catch (e) {
|
|
88
|
-
console.warn(`[thumbnail] 세우지 못했습니다 — ${e.message}`);
|
|
89
|
-
return undefined;
|
|
90
|
-
}
|
|
91
|
-
finally {
|
|
92
|
-
host.remove();
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
//# sourceMappingURL=figure-thumbnail.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"figure-thumbnail.js","sourceRoot":"","sources":["../../client/modeller/figure-thumbnail.ts"],"names":[],"mappings":"AAAA,OAAO,oBAAoB,CAAA;AAI3B;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,kBAAkB;AAClB,MAAM,KAAK,GAAG,GAAG,CAAA;AACjB,MAAM,MAAM,GAAG,GAAG,CAAA;AASlB;;;;;;;;;GASG;AACH,SAAS,MAAM;IACb,MAAM,MAAM,GAAG,IAAI,OAAO,CAAO,OAAO,CAAC,EAAE,CACzC,qBAAqB,CAAC,GAAG,EAAE,CAAC,qBAAqB,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,CACnF,CAAA;IAED,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;AAC3C,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAA;AACxD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,QAAQ,GAAG,IAAI,CAAA;AAErB,wDAAwD;AACxD,SAAS,MAAM,CAAI,IAAgB,EAAE,EAAU;IAC7C,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;AAC9D,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,KAA8B,EAC9B,KAAkB;IAElB,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QAC5B,OAAO,SAAS,CAAA;IAClB,CAAC;IAED;;;MAGE;IACF,MAAM,IAAI,GAAG,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAA;IAC1C,IAAI,CAAC,YAAY,CAAC,wBAAwB,EAAE,EAAE,CAAC,CAAA;IAC/C,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,mDAAmD,KAAK,eAAe,MAAM,2BAA2B,CAAA;IAC7H,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAA;IAE/B,MAAM,OAAO,GAAG,QAAQ,CAAC,aAAa,CAAC,eAAe,CAAY,CAAA;IAClE,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAA;IACvB,OAAO,CAAC,KAAK,GAAG,KAAK,CAAA;IACrB,OAAO,CAAC,KAAK,GAAG,KAAK,CAAA;IACrB,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG,4CAA4C,CAAA;IAEpE,IAAI,CAAC;QACH,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;QAEzB;;;;UAIE;QACF,MAAM,IAAI,GAAG,MAAM,MAAM,CACvB,CAAC,KAAK,IAAI,EAAE;YACV,MAAM,MAAM,EAAE,CAAA;YACd,OAAO,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;QAC7E,CAAC,CAAC,EAAE,EACJ,QAAQ,CACT,CAAA;QAED,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,CAAC,IAAI,CAAC,eAAe,QAAQ,6BAA6B,CAAC,CAAA;QACpE,CAAC;QAED,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,IAAI,CAAC,2BAA4B,CAAW,CAAC,OAAO,EAAE,CAAC,CAAA;QAC/D,OAAO,SAAS,CAAA;IAClB,CAAC;YAAS,CAAC;QACT,IAAI,CAAC,MAAM,EAAE,CAAA;IACf,CAAC;AACH,CAAC","sourcesContent":["import './figure-canvas.js'\n\nimport type { FigureDraft, PartModel } from './figure-source.js'\n\n/**\n * 카드에 쓸 그림을 찍는다 — **숨은 자리에 저작 캔버스를 하나 더 세워서.**\n *\n * ## 왜 보이는 캔버스를 찍지 않나\n *\n * 저작면의 캔버스는 저작자가 돌려 둔 각도와 확대로 서 있고, 칸의 비율도 창 크기와 접힌 패널에 따라\n * 다르다. 그것을 찍으면 카드마다 프레임이 달라지고, 방금 확대해 보던 나사 하나가 그 자산의 얼굴이\n * 된다. 목록은 견주는 자리이므로 그림은 **정해진 크기와 정해진 카메라**로 찍는다.\n *\n * ## 왜 씬을 여기서 세우지 않고 부품을 세우나\n *\n * 씬 값(환경 · 하늘 · 조명 · 픽셀 비율 · 좌표 바탕)은 `figure-canvas` 가 든다. 여기서 다시 적으면\n * 두 벌이 되고, 그러면 **카드에 보이는 그림과 저작면에서 보던 것이 아무 오류 없이 갈린다.** 그래서\n * 같은 부품을 `viewOnly` 로 하나 더 세워 그 부품이 자기 씬을 세우게 하고, 찍은 뒤 버린다.\n *\n * ## 왜 서버가 아니라 브라우저인가\n *\n * 도면은 저장할 때 서버가 찍는데, 백엔드에 GPU 가 없는 배포가 많아 헤드리스로 3D 를 찍는 것이 자주\n * 실패한다. 도형을 그릴 GPU 는 이미 보는 사람 손에 있다.\n */\n\n/** 카드는 4:3 이다. */\nconst WIDTH = 480\nconst HEIGHT = 360\n\ninterface Shooter extends HTMLElement {\n draft?: FigureDraft\n parts?: PartModel[]\n viewOnly?: boolean\n snapshot?: (width?: number, height?: number) => Promise<string | undefined>\n}\n\n/**\n * 씬이 서고 카메라가 자리를 잡을 틈 — 프레임 두 장 뒤에 한 번 더 쉰다. 씬에 그 신호가 없다.\n *\n * **rAF 만 기다리면 안 된다.** 탭이 뒤로 가거나 창이 가려지면 브라우저가 rAF 를 멈추고, 그러면\n * 이 약속이 영원히 안 풀린다. 그 위에 저장이 얹혀 있어서 저장이 통째로 멈췄다 — 단추는 잠긴 채로,\n * 아무 말도 없이. [확인함] 2026-09-10 포커스 없는 탭에서 `saving: true` 로 고정.\n *\n * 그래서 시계와 함께 경주시킨다. 늦게 깨어난 쪽은 버려지고, 화면이 안 그려지는 상황이면 아래\n * `snapshot` 이 빈 것을 돌려주거나 시간이 다 된다 — 어느 쪽이든 **저장은 계속 간다.**\n */\nfunction settle(): Promise<void> {\n const frames = new Promise<void>(resolve =>\n requestAnimationFrame(() => requestAnimationFrame(() => setTimeout(resolve, 150)))\n )\n\n return Promise.race([frames, delay(600)])\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms))\n}\n\n/**\n * 그림을 기다리는 시간의 한도.\n *\n * 3D 를 세워 한 장 찍는 데 걸리는 시간은 형상과 기계에 따라 다르지만, 이 한도의 목적은 빠르기가\n * 아니라 **저장이 멈추지 않는 것**이다. 넘으면 그림 없이 저장한다 — 정본이 그림보다 중하고,\n * 그림은 다음에 저작면을 열 때 다시 채운다(`figure-modeller-page` 의 fillThumbnail).\n */\nconst PATIENCE = 5000\n\n/** 시간이 다 되면 없는 것으로 답한다. 던지지 않는다 — 그림이 없는 것은 실패가 아니다. */\nfunction within<T>(work: Promise<T>, ms: number): Promise<T | undefined> {\n return Promise.race([work, delay(ms).then(() => undefined)])\n}\n\nexport async function captureThumbnail(\n draft: FigureDraft | undefined,\n parts: PartModel[]\n): Promise<string | undefined> {\n if (!draft || !parts.length) {\n return undefined\n }\n\n /*\n 화면 밖에 둔다. `display: none` 이면 캔버스가 크기를 못 얻어 아무것도 그리지 못한다.\n WebGL context 는 브라우저가 8~16개에서 끊으므로 찍은 뒤 반드시 버린다(아래 finally).\n */\n const host = document.createElement('div')\n host.setAttribute('figure-thumbnail-stage', '')\n host.style.cssText = `position: fixed; left: -10000px; top: 0; width: ${WIDTH}px; height: ${HEIGHT}px; pointer-events: none;`\n document.body.appendChild(host)\n\n const shooter = document.createElement('figure-canvas') as Shooter\n shooter.viewOnly = true\n shooter.draft = draft\n shooter.parts = parts\n shooter.style.cssText = 'display: block; width: 100%; height: 100%;'\n\n try {\n host.appendChild(shooter)\n\n /*\n **한도 안에 못 찍으면 그림 없이 간다.** 이 함수를 부르는 자리가 저장이고, 저장은 그림을\n 기다리다 멈춰서는 안 된다. 못 찍은 것은 조용히 넘기지 않고 콘솔에 남긴다 — 그림이 계속\n 안 생기면 그 줄이 단서가 된다.\n */\n const shot = await within(\n (async () => {\n await settle()\n return shooter.snapshot ? await shooter.snapshot(WIDTH, HEIGHT) : undefined\n })(),\n PATIENCE\n )\n\n if (!shot) {\n console.warn(`[thumbnail] ${PATIENCE}ms 안에 못 찍었습니다 — 그림 없이 저장합니다`)\n }\n\n return shot\n } catch (e) {\n console.warn(`[thumbnail] 세우지 못했습니다 — ${(e as Error).message}`)\n return undefined\n } finally {\n host.remove()\n }\n}\n"]}
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 저작 화면의 **보기 설정**.
|
|
3
|
-
*
|
|
4
|
-
* ## 저장되지 않는다
|
|
5
|
-
*
|
|
6
|
-
* 이것은 자산이 아니라 **작업대**다. 조명을 밝게 하고 바닥을 켠 것은 그 사람이 지금
|
|
7
|
-
* 보기 편한 상태일 뿐, 그 자산의 성질이 아니다. 그래서 `FigureSource` 에 안 들어간다 —
|
|
8
|
-
* `toFigureSource` 는 판에서 `width` · `height` · `depth` 와 몇 가지만 집어 가고 나머지는
|
|
9
|
-
* 버린다.
|
|
10
|
-
*
|
|
11
|
-
* 다른 사람이 같은 자산을 열면 자기 설정으로 본다. 그것이 맞다.
|
|
12
|
-
*
|
|
13
|
-
* ## 씬이 아는 이름을 그대로 쓴다
|
|
14
|
-
*
|
|
15
|
-
* 여기 이름은 전부 `model-layer` 의 상태 이름이다. 옮겨 적는 표를 두지 않는다 — 표를
|
|
16
|
-
* 두면 씬이 새 설정을 받아도 이쪽이 모른다.
|
|
17
|
-
*
|
|
18
|
-
* 값이 바뀌면 씬이 스스로 반영한다(`three-capability` 의 `onchange`). 다만 `grid` 는
|
|
19
|
-
* 한동안 3D 를 세울 때만 읽혔다 — things-scene 10.1.5 에서 고쳤다.
|
|
20
|
-
*/
|
|
21
|
-
export interface ViewSettings {
|
|
22
|
-
/**
|
|
23
|
-
* 어떤 도면에 놓인 것으로 보나 — 씬 전체의 좌표 모드.
|
|
24
|
-
*
|
|
25
|
-
* **도형의 `placement` 와 다른 것이다.** 도형의 것은 「이 종류는 바닥에 서나, 천장에
|
|
26
|
-
* 매달리나」이고, 이것은 「지금 보고 있는 도면이 어느 쪽을 기준으로 재나」다. 바닥
|
|
27
|
-
* 기준 도면에 천정 기반 OHT 를 놓으면 도면은 안 뒤집히고 OHT 가 천장 높이에 매달린다.
|
|
28
|
-
*
|
|
29
|
-
* 한동안 도형의 `placement` 를 이 자리에 흘려 넣었다. 모델러에 도형이 하나뿐이라
|
|
30
|
-
* 그럴듯해 보였지만, 그러면 도형의 성질이 씬 전체를 뒤집는다 — 도면에서는 성립할 수가
|
|
31
|
-
* 없고(도면에는 도형이 여럿이다), 저작 중에는 배치를 고를 때마다 저작자가 적어 둔
|
|
32
|
-
* 높이가 전부 다른 숫자로 보였다.
|
|
33
|
-
*
|
|
34
|
-
* 씬의 낱말 그대로다: `floor` 바닥 기준 · `space` 중심 기준(바닥 없음) · `inverted`
|
|
35
|
-
* 천장 기준. **미리보기에만 먹인다** — 편집 캔버스의 `zPos` 는 저작자가 직접 적는
|
|
36
|
-
* 숫자라 그 뜻이 보기 설정에 따라 바뀌면 안 된다.
|
|
37
|
-
*/
|
|
38
|
-
placement: 'floor' | 'space' | 'inverted';
|
|
39
|
-
/**
|
|
40
|
-
* 천장 높이 (mm). 천정 기반 도형을 미리보기에서 어디에 매달 것인가.
|
|
41
|
-
*
|
|
42
|
-
* 도형은 제가 놓일 방의 높이를 모른다. 도면은 알지만 미리보기에는 도면이 없으므로,
|
|
43
|
-
* 저작자가 가정할 값을 여기서 정한다.
|
|
44
|
-
*/
|
|
45
|
-
ceilingHeight: number;
|
|
46
|
-
/** 좌표 바탕(축 가이드). 원점과 눈금을 보인다. */
|
|
47
|
-
grid: boolean;
|
|
48
|
-
/** 축 이름표(X · Y · Z). 눈금만 두고 글자를 끌 수 있다. */
|
|
49
|
-
gridLabels: boolean;
|
|
50
|
-
/** 판의 바닥면. 좌표 바탕과 겹치므로 기본은 끈다. */
|
|
51
|
-
floor: boolean;
|
|
52
|
-
/** Environment — 반사(IBL). 금속 재질이 무엇을 비출지 정한다. */
|
|
53
|
-
environment: EnvironmentName;
|
|
54
|
-
/** Sky Color — 배경색. */
|
|
55
|
-
skyColor: string;
|
|
56
|
-
/** Key Light Intensity. */
|
|
57
|
-
dirLightIntensity: number;
|
|
58
|
-
/** Key Light — Follow Camera. 끄면 그림자 방향이 고정된다. */
|
|
59
|
-
dirLightFollowCamera: boolean;
|
|
60
|
-
/** Key Light — Cast Shadow. */
|
|
61
|
-
dirShadowEnabled: boolean;
|
|
62
|
-
/** Hemisphere Light Intensity — 그늘진 면을 들어올린다. */
|
|
63
|
-
hemiIntensity: number;
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* 환경 프리셋 — **`scene-manager` 의 `SkyPreset` 과 같은 여덟이다.**
|
|
67
|
-
*
|
|
68
|
-
* 한동안 다섯만 적었다. 씬은 여덟을 다 받는데 이쪽이 셋을 몰라서 고를 수 없었다.
|
|
69
|
-
* operato-board 의 3D 씬 속성 패널도 같은 여덟을 보인다.
|
|
70
|
-
*/
|
|
71
|
-
export declare const ENVIRONMENTS: readonly ["studio", "warehouse", "factory", "office", "home", "sunny", "cloudy", "rainy"];
|
|
72
|
-
export type EnvironmentName = (typeof ENVIRONMENTS)[number];
|
|
73
|
-
/**
|
|
74
|
-
* 씬에 그대로 넣는 보기 설정 — **좌표 기준과 천장 높이는 빼고.**
|
|
75
|
-
*
|
|
76
|
-
* 나머지는 전부 `model-layer` 의 상태 이름이라 그대로 넣으면 씬이 알아서 반응한다.
|
|
77
|
-
* 그런데 `placement` 는 편집 캔버스에 들어가면 안 되고(거기는 늘 상자 기준이다),
|
|
78
|
-
* `ceilingHeight` 는 씬이 모르는 이름이다.
|
|
79
|
-
*
|
|
80
|
-
* **rest spread 로 넘기지 않으려고 이 함수가 있다.** 캔버스가 한동안
|
|
81
|
-
* `const { grid, ..., ...light } = view` 로 나머지를 통째로 넘겼는데, 그러면 설정을
|
|
82
|
-
* 하나 더할 때마다 그것이 두 화면에 **말없이** 실린다. 새로 더한 좌표 기준이 바로
|
|
83
|
-
* 그 길로 캔버스에 들어갈 뻔했다.
|
|
84
|
-
*/
|
|
85
|
-
export declare function sceneLook(view: ViewSettings): Record<string, unknown>;
|
|
86
|
-
/**
|
|
87
|
-
* 씬의 좌표 기준 — **씬의 낱말 그대로 셋이다.**
|
|
88
|
-
*
|
|
89
|
-
* 형식의 `floor` · `center` · `ceiling` 과 짝이 맞지만 철자가 다르다. 옮겨 적는 표를 두지
|
|
90
|
-
* 않는 것이 이 파일의 규칙이므로 씬 쪽을 쓴다. 화면에는 둘 다 보인다 — 「천장 기준
|
|
91
|
-
* (inverted)」.
|
|
92
|
-
*/
|
|
93
|
-
export declare const SCENE_REFERENCES: readonly ["floor", "space", "inverted"];
|
|
94
|
-
/** 배경색 기본값. 회색이라 부품 색이 제 색으로 보인다. */
|
|
95
|
-
export declare const WORKBENCH = "#7c7c7c";
|
|
96
|
-
/**
|
|
97
|
-
* 처음 값.
|
|
98
|
-
*
|
|
99
|
-
* **지금 저작 화면이 실제로 쓰던 값 그대로다.** 설정을 만들면서 화면이 달라지면
|
|
100
|
-
* 무엇이 설정 때문이고 무엇이 원래 그랬는지 갈리지 않는다.
|
|
101
|
-
*/
|
|
102
|
-
export declare const DEFAULT_VIEW: ViewSettings;
|
|
103
|
-
/**
|
|
104
|
-
* How tall the preview board is: enough room for the tallest instance where the figure actually stands.
|
|
105
|
-
*
|
|
106
|
-
* A floor or center figure stands on the floor, so the tallest instance is the whole height. Only a
|
|
107
|
-
* ceiling figure needs the room up to the ceiling. The board used to reach the ceiling for every figure,
|
|
108
|
-
* which made a 920 tall AGV preview 4400 tall.
|
|
109
|
-
*
|
|
110
|
-
* This is an envelope, not a placement rule: where each instance goes is still the scene's
|
|
111
|
-
* (`FigureRealObject.effectiveZPos`), and the camera fits what the scene drew.
|
|
112
|
-
*/
|
|
113
|
-
export declare function previewBoardDepth(figure: {
|
|
114
|
-
placement?: 'floor' | 'ceiling' | 'center';
|
|
115
|
-
base: {
|
|
116
|
-
y: number;
|
|
117
|
-
};
|
|
118
|
-
}, ceilingHeight: number, factor: number): number;
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 환경 프리셋 — **`scene-manager` 의 `SkyPreset` 과 같은 여덟이다.**
|
|
3
|
-
*
|
|
4
|
-
* 한동안 다섯만 적었다. 씬은 여덟을 다 받는데 이쪽이 셋을 몰라서 고를 수 없었다.
|
|
5
|
-
* operato-board 의 3D 씬 속성 패널도 같은 여덟을 보인다.
|
|
6
|
-
*/
|
|
7
|
-
export const ENVIRONMENTS = [
|
|
8
|
-
'studio',
|
|
9
|
-
'warehouse',
|
|
10
|
-
'factory',
|
|
11
|
-
'office',
|
|
12
|
-
'home',
|
|
13
|
-
'sunny',
|
|
14
|
-
'cloudy',
|
|
15
|
-
'rainy'
|
|
16
|
-
];
|
|
17
|
-
/**
|
|
18
|
-
* 씬에 그대로 넣는 보기 설정 — **좌표 기준과 천장 높이는 빼고.**
|
|
19
|
-
*
|
|
20
|
-
* 나머지는 전부 `model-layer` 의 상태 이름이라 그대로 넣으면 씬이 알아서 반응한다.
|
|
21
|
-
* 그런데 `placement` 는 편집 캔버스에 들어가면 안 되고(거기는 늘 상자 기준이다),
|
|
22
|
-
* `ceilingHeight` 는 씬이 모르는 이름이다.
|
|
23
|
-
*
|
|
24
|
-
* **rest spread 로 넘기지 않으려고 이 함수가 있다.** 캔버스가 한동안
|
|
25
|
-
* `const { grid, ..., ...light } = view` 로 나머지를 통째로 넘겼는데, 그러면 설정을
|
|
26
|
-
* 하나 더할 때마다 그것이 두 화면에 **말없이** 실린다. 새로 더한 좌표 기준이 바로
|
|
27
|
-
* 그 길로 캔버스에 들어갈 뻔했다.
|
|
28
|
-
*/
|
|
29
|
-
export function sceneLook(view) {
|
|
30
|
-
const { placement, ceilingHeight, ...look } = view;
|
|
31
|
-
return look;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* 씬의 좌표 기준 — **씬의 낱말 그대로 셋이다.**
|
|
35
|
-
*
|
|
36
|
-
* 형식의 `floor` · `center` · `ceiling` 과 짝이 맞지만 철자가 다르다. 옮겨 적는 표를 두지
|
|
37
|
-
* 않는 것이 이 파일의 규칙이므로 씬 쪽을 쓴다. 화면에는 둘 다 보인다 — 「천장 기준
|
|
38
|
-
* (inverted)」.
|
|
39
|
-
*/
|
|
40
|
-
export const SCENE_REFERENCES = ['floor', 'space', 'inverted'];
|
|
41
|
-
/** 배경색 기본값. 회색이라 부품 색이 제 색으로 보인다. */
|
|
42
|
-
export const WORKBENCH = '#7c7c7c';
|
|
43
|
-
/**
|
|
44
|
-
* 처음 값.
|
|
45
|
-
*
|
|
46
|
-
* **지금 저작 화면이 실제로 쓰던 값 그대로다.** 설정을 만들면서 화면이 달라지면
|
|
47
|
-
* 무엇이 설정 때문이고 무엇이 원래 그랬는지 갈리지 않는다.
|
|
48
|
-
*/
|
|
49
|
-
export const DEFAULT_VIEW = {
|
|
50
|
-
placement: 'floor',
|
|
51
|
-
/* 공장 천장의 흔한 높이. 반도체 fab 의 OHT 레일이 대체로 이 언저리다. */
|
|
52
|
-
ceilingHeight: 4000,
|
|
53
|
-
grid: true,
|
|
54
|
-
gridLabels: true,
|
|
55
|
-
floor: false,
|
|
56
|
-
environment: 'studio',
|
|
57
|
-
skyColor: WORKBENCH,
|
|
58
|
-
dirLightIntensity: 2.0,
|
|
59
|
-
dirLightFollowCamera: true,
|
|
60
|
-
dirShadowEnabled: true,
|
|
61
|
-
hemiIntensity: 4.0
|
|
62
|
-
};
|
|
63
|
-
/**
|
|
64
|
-
* How tall the preview board is: enough room for the tallest instance where the figure actually stands.
|
|
65
|
-
*
|
|
66
|
-
* A floor or center figure stands on the floor, so the tallest instance is the whole height. Only a
|
|
67
|
-
* ceiling figure needs the room up to the ceiling. The board used to reach the ceiling for every figure,
|
|
68
|
-
* which made a 920 tall AGV preview 4400 tall.
|
|
69
|
-
*
|
|
70
|
-
* This is an envelope, not a placement rule: where each instance goes is still the scene's
|
|
71
|
-
* (`FigureRealObject.effectiveZPos`), and the camera fits what the scene drew.
|
|
72
|
-
*/
|
|
73
|
-
export function previewBoardDepth(figure, ceilingHeight, factor) {
|
|
74
|
-
const tallest = figure.base.y * factor;
|
|
75
|
-
const reach = figure.placement === 'ceiling' ? Math.max(ceilingHeight, tallest) : tallest;
|
|
76
|
-
return Math.round(reach * 1.1);
|
|
77
|
-
}
|
|
78
|
-
//# sourceMappingURL=figure-view.js.map
|