@things-factory/figure-ui 10.1.26 โ†’ 10.1.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/client/graphql/index.ts +23 -0
  2. package/client/modeller/base-box.ts +104 -0
  3. package/client/modeller/figure-animations.ts +253 -32
  4. package/client/modeller/figure-canvas.ts +18 -3
  5. package/client/modeller/figure-inspector.ts +292 -3
  6. package/client/modeller/figure-preview.ts +57 -2
  7. package/client/modeller/figure-report.ts +9 -4
  8. package/client/modeller/figure-side.ts +9 -1
  9. package/client/modeller/figure-source.ts +24 -4
  10. package/client/modeller/figure-view.ts +20 -0
  11. package/client/modeller/joint-edits.ts +262 -0
  12. package/client/modeller/joint-gizmo.ts +118 -0
  13. package/client/modeller/pose-defaults.ts +67 -0
  14. package/client/modeller/proposal.ts +9 -3
  15. package/client/modeller/scene-budget.ts +31 -40
  16. package/client/pages/figure-list-page.ts +4 -9
  17. package/client/pages/figure-modeller-page.ts +124 -41
  18. package/dist-client/graphql/index.d.ts +7 -0
  19. package/dist-client/graphql/index.js +21 -0
  20. package/dist-client/graphql/index.js.map +1 -1
  21. package/dist-client/modeller/base-box.d.ts +47 -0
  22. package/dist-client/modeller/base-box.js +52 -0
  23. package/dist-client/modeller/base-box.js.map +1 -0
  24. package/dist-client/modeller/figure-animations.d.ts +29 -0
  25. package/dist-client/modeller/figure-animations.js +228 -25
  26. package/dist-client/modeller/figure-animations.js.map +1 -1
  27. package/dist-client/modeller/figure-canvas.d.ts +9 -0
  28. package/dist-client/modeller/figure-canvas.js +14 -3
  29. package/dist-client/modeller/figure-canvas.js.map +1 -1
  30. package/dist-client/modeller/figure-inspector.d.ts +37 -0
  31. package/dist-client/modeller/figure-inspector.js +253 -2
  32. package/dist-client/modeller/figure-inspector.js.map +1 -1
  33. package/dist-client/modeller/figure-preview.d.ts +15 -0
  34. package/dist-client/modeller/figure-preview.js +48 -2
  35. package/dist-client/modeller/figure-preview.js.map +1 -1
  36. package/dist-client/modeller/figure-report.d.ts +3 -2
  37. package/dist-client/modeller/figure-report.js +9 -4
  38. package/dist-client/modeller/figure-report.js.map +1 -1
  39. package/dist-client/modeller/figure-side.d.ts +5 -1
  40. package/dist-client/modeller/figure-side.js +12 -0
  41. package/dist-client/modeller/figure-side.js.map +1 -1
  42. package/dist-client/modeller/figure-source.d.ts +15 -0
  43. package/dist-client/modeller/figure-source.js +8 -4
  44. package/dist-client/modeller/figure-source.js.map +1 -1
  45. package/dist-client/modeller/figure-view.d.ts +16 -0
  46. package/dist-client/modeller/figure-view.js +15 -0
  47. package/dist-client/modeller/figure-view.js.map +1 -1
  48. package/dist-client/modeller/joint-edits.d.ts +49 -0
  49. package/dist-client/modeller/joint-edits.js +223 -0
  50. package/dist-client/modeller/joint-edits.js.map +1 -0
  51. package/dist-client/modeller/joint-gizmo.d.ts +31 -0
  52. package/dist-client/modeller/joint-gizmo.js +104 -0
  53. package/dist-client/modeller/joint-gizmo.js.map +1 -0
  54. package/dist-client/modeller/pose-defaults.d.ts +9 -0
  55. package/dist-client/modeller/pose-defaults.js +35 -0
  56. package/dist-client/modeller/pose-defaults.js.map +1 -0
  57. package/dist-client/modeller/proposal.d.ts +1 -1
  58. package/dist-client/modeller/proposal.js +8 -3
  59. package/dist-client/modeller/proposal.js.map +1 -1
  60. package/dist-client/modeller/scene-budget.d.ts +31 -34
  61. package/dist-client/modeller/scene-budget.js +28 -37
  62. package/dist-client/modeller/scene-budget.js.map +1 -1
  63. package/dist-client/pages/figure-list-page.js +4 -9
  64. package/dist-client/pages/figure-list-page.js.map +1 -1
  65. package/dist-client/pages/figure-modeller-page.d.ts +43 -0
  66. package/dist-client/pages/figure-modeller-page.js +121 -40
  67. package/dist-client/pages/figure-modeller-page.js.map +1 -1
  68. package/dist-client/tsconfig.tsbuildinfo +1 -1
  69. package/dist-server/tsconfig.tsbuildinfo +1 -1
  70. package/package.json +3 -3
  71. package/test/ai-proposal-contract.test.ts +16 -11
  72. package/test/base-box.test.ts +154 -0
  73. package/test/figure-source.test.ts +32 -0
  74. package/test/joint-edits.test.ts +165 -0
  75. package/test/joint-gizmo.test.ts +174 -0
  76. package/test/pose-defaults.test.ts +71 -0
  77. package/test/preview-board-depth.test.ts +27 -0
  78. package/test/scene-budget.test.ts +53 -0
  79. package/translations/en.json +37 -2
  80. package/translations/ja.json +37 -2
  81. package/translations/ko.json +37 -2
  82. package/translations/ms.json +37 -2
  83. package/translations/zh.json +37 -2
@@ -4,7 +4,8 @@ import { customElement, property, query, state } from 'lit/decorators.js';
4
4
  import { i18next, localize } from '@operato/i18n';
5
5
  import { compile, validate } from '@hatiolab/figure-model';
6
6
  import { create, registerFigure } from '@hatiolab/things-scene';
7
- import { DEFAULT_VIEW, sceneLook, WORKBENCH } from './figure-view.js';
7
+ import { DEFAULT_VIEW, previewBoardDepth, sceneLook, WORKBENCH } from './figure-view.js';
8
+ import { poseChanges } from './pose-defaults.js';
8
9
  /**
9
10
  * ์ €์ž‘ ์ค‘์ธ ๊ฒƒ์„ **๋„๋ฉด์— ๋†“์•˜์„ ๋•Œ**์˜ ๋ชจ์Šต.
10
11
  *
@@ -126,6 +127,24 @@ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
126
127
  align-items: center;
127
128
  gap: 8px;
128
129
  }
130
+ /*
131
+ ๋ง‰๋Œ€ ์œ„์— ๋†“๋Š” ๋‹จ์ถ”. ์ž์„ธ๋ฅผ ๋งŒ๋“  ์ž๋ฆฌ์— ์žˆ์–ด์•ผ ใ€Œ์ง€๊ธˆ ์ด๊ฒƒ์„ ๊ธฐ๋ณธ์œผ๋กœใ€๊ฐ€ ์ฝํžŒ๋‹ค.
132
+ ์•‰ํž ๊ฒƒ์ด ์žˆ์„ ๋•Œ๋งŒ ๋‚˜์˜ค๋ฏ€๋กœ, ๋Š˜ ์„œ ์žˆ๋Š” ์นธ์ด ์•„๋‹ˆ๋‹ค.
133
+ */
134
+ div[clips] button[pose] {
135
+ align-self: stretch;
136
+ padding: 4px 8px;
137
+ font: inherit;
138
+ font-size: 0.7rem;
139
+ color: rgba(255, 255, 255, 0.92);
140
+ background-color: rgba(255, 255, 255, 0.14);
141
+ border: 1px solid rgba(255, 255, 255, 0.22);
142
+ border-radius: 5px;
143
+ cursor: pointer;
144
+ }
145
+ div[clips] button[pose]:hover {
146
+ background-color: rgba(255, 255, 255, 0.24);
147
+ }
129
148
  div[clips] span[drive] {
130
149
  opacity: 0.6;
131
150
  font-size: 0.66rem;
@@ -176,8 +195,22 @@ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
176
195
  * ๋„ฃ์„ ์ž๋ฆฌ๋ฅผ ๋ชป ์ฐพ๋Š”๋‹ค.
177
196
  */
178
197
  renderDrivers(clips, parameters) {
198
+ /*
199
+ ์ง€๊ธˆ ์„ธ์šด ์ž์„ธ๋ฅผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์•‰ํžˆ๋Š” ์ž๋ฆฌ. **๋ง‰๋Œ€ ์˜†์— ๋‘”๋‹ค** โ€” ์ž์„ธ๋ฅผ ๋งŒ๋“  ๊ณณ์ด ์—ฌ๊ธฐ๋ผ,
200
+ ๊ฐ’์„ ์ฝ์–ด ํŒŒ๋ผ๋ฏธํ„ฐ ์นธ์œผ๋กœ ์˜ฎ๊ฒจ ์ ๋Š” ์™•๋ณต์ด ์—†์–ด์ง„๋‹ค. ์•‰ํž ๊ฒƒ์ด ์—†์œผ๋ฉด ์•„์˜ˆ ์•ˆ ๋‚˜์˜จ๋‹ค.
201
+ */
202
+ const changes = poseChanges(this.draft, this.giving);
179
203
  return html `
180
204
  <div clips>
205
+ ${changes.length > 0
206
+ ? html `<button
207
+ pose
208
+ title=${i18next.t('figure.text.pose-as-default-explained')}
209
+ @click=${() => this.poseAsDefault()}
210
+ >
211
+ ${i18next.t('figure.button.pose-as-default')}
212
+ </button>`
213
+ : ''}
181
214
  ${parameters.map(parameter => {
182
215
  const range = parameter.range;
183
216
  const value = this.giving[parameter.name] ?? parameter.default ?? range?.min ?? 0;
@@ -237,6 +270,15 @@ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
237
270
  this.giving = { ...this.giving, [name]: value };
238
271
  this.tellInstances('parameters', this.giving);
239
272
  }
273
+ /**
274
+ * ์„ธ์šด ์ž์„ธ๋ฅผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ โ€” **์…ˆ์€ ์—ฌ๊ธฐ์„œ ํ•˜์ง€ ์•Š๋Š”๋‹ค.**
275
+ *
276
+ * ์ดˆ์•ˆ์„ ์ฅ๊ณ  ์žˆ๋Š” ๊ฒƒ์€ ํŽ˜์ด์ง€์ด๊ณ , ๋˜๋Œ๋ฆฌ๊ธฐ์™€ ใ€Œ์ €์žฅ ์•ˆ ๋จใ€๋„ ๊ฑฐ๊ธฐ์„œ ๋งค๊ธด๋‹ค. ์—ฌ๊ธฐ์„œ
277
+ * ์ดˆ์•ˆ์„ ๋งŒ๋“ค์–ด ๋ณด๋‚ด๋ฉด ๊ทธ ์…‹์ด ๋‘ ๊ณณ์œผ๋กœ ๊ฐˆ๋ฆฐ๋‹ค. ๋ฏผ ๊ฐ’๋งŒ ์˜ฌ๋ฆฐ๋‹ค.
278
+ */
279
+ poseAsDefault() {
280
+ this.dispatchEvent(new CustomEvent('pose-as-default', { detail: { values: { ...this.giving } }, bubbles: true, composed: true }));
281
+ }
240
282
  tellInstances(key, values) {
241
283
  for (const component of this.scene?.root?.components ?? []) {
242
284
  component.set?.(key, { ...values });
@@ -368,7 +410,7 @@ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
368
410
  ์–ด๋А ๊ฒฝ์šฐ์—๋„ ๋‹ด๊ธฐ๋Š” ๊ฒฝ๊ณ„๋งŒ ์žก๋Š”๋‹ค. ๋ฐ”๋‹ฅ ๊ธฐ๋ฐ˜์€ ๊ฐ€์žฅ ํฐ ๊ฒƒ์˜ ํ‚ค๊นŒ์ง€, ์ฒœ์ • ๊ธฐ๋ฐ˜์€
369
411
  ์ฒœ์žฅ๊นŒ์ง€๋‹ค. ๋ฐฐ์น˜๋ฅผ ๋†’์ด๋กœ ์˜ฎ๊ธฐ๋Š” ๊ณ„์‚ฐ์„ ์—ฌ๊ธฐ์„œ ๋‹ค์‹œ ์“ฐ๋ฉด ๊ทธ๊ฒƒ์ด ๋‘ ๋ฒŒ์งธ๊ฐ€ ๋œ๋‹ค.
370
412
  */
371
- depth: Math.round(Math.max(view.ceilingHeight, base.y * biggest) * 1.1)
413
+ depth: previewBoardDepth(source, view.ceilingHeight, biggest)
372
414
  };
373
415
  this.scene = create({
374
416
  target: this.stage,
@@ -424,6 +466,10 @@ __decorate([
424
466
  property({ type: Object }),
425
467
  __metadata("design:type", Object)
426
468
  ], FigurePreview.prototype, "source", void 0);
469
+ __decorate([
470
+ property({ type: Object }),
471
+ __metadata("design:type", Object)
472
+ ], FigurePreview.prototype, "draft", void 0);
427
473
  __decorate([
428
474
  property({ type: Object }),
429
475
  __metadata("design:type", Object)
@@ -1 +1 @@
1
- {"version":3,"file":"figure-preview.js","sourceRoot":"","sources":["../../client/modeller/figure-preview.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { compile, validate } from '@hatiolab/figure-model'\nimport type { FigureSource } from '@hatiolab/figure-model'\nimport { create, registerFigure } from '@hatiolab/things-scene'\n\nimport { DEFAULT_VIEW, sceneLook, WORKBENCH } from './figure-view.js'\nimport type { ViewSettings } from './figure-view.js'\n\n/**\n * ์ €์ž‘ ์ค‘์ธ ๊ฒƒ์„ **๋„๋ฉด์— ๋†“์•˜์„ ๋•Œ**์˜ ๋ชจ์Šต.\n *\n * ## ํŽธ์ง‘ ์บ”๋ฒ„์Šค๋กœ๋Š” ๋ณผ ์ˆ˜ ์—†๋‹ค\n *\n * ํŽธ์ง‘ ์บ”๋ฒ„์Šค๋Š” ๋ถ€ํ’ˆ์„ ์ปดํฌ๋„ŒํŠธ๋กœ ๋Š˜์–ด๋†“๋Š”๋‹ค. ๊ทธ๋ž˜์„œ ๋Š˜ ๊ธฐ์ค€ ํฌ๊ธฐ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด ํ˜•์‹์˜\n * ๊ฐ’ ์ ˆ๋ฐ˜์€ **ํฌ๊ธฐ๊ฐ€ ๋‹ฌ๋ผ์กŒ์„ ๋•Œ ์–ด๋–ป๊ฒŒ ๋ฐ˜์‘ํ•˜๋Š”๊ฐ€**์— ์žˆ๋‹ค. ๊ธฐ๋‘ฅ๋งŒ ๋Š˜์–ด๋‚˜๋Š” ์‹œ๊ทธ๋„ํƒ€์›Œ,\n * ๋กค๋Ÿฌ ๊ฐœ์ˆ˜๊ฐ€ ๋А๋Š” ์ปจ๋ฒ ์ด์–ด๋Š” ๊ธฐ์ค€ ํฌ๊ธฐ์—์„œ๋Š” ์•„๋ฌด๊ฒƒ๋„ ๋ณด์—ฌ ์ฃผ์ง€ ๋ชปํ•œ๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ ์—ฌ๊ธฐ์„œ๋Š” ์ €์ž‘ํ•œ ๊ฒƒ์„ ์‹ค์ œ๋กœ ์ปดํŒŒ์ผํ•ด `FigureInstance` ๋กœ ์„ธ์šด๋‹ค. ๋„๋ฉด์ด ํ•˜๋Š”\n * ์ผ์„ ๊ทธ๋Œ€๋กœ ํ•œ๋‹ค โ€” ์ฒญ์‚ฌ์ง„์„ ๋“ฑ๋กํ•˜๊ณ , ํƒ€์ž… ์ด๋ฆ„๋งŒ ์ ์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋†“๋Š”๋‹ค.\n *\n * ## ์—ฌ๋Ÿฌ ํฌ๊ธฐ๋ฅผ ํ•œ ๋ฒˆ์— ๋†“๋Š”๋‹ค\n *\n * ํ•˜๋‚˜๋งŒ ๋†“์œผ๋ฉด \"์ด ํฌ๊ธฐ์—์„œ๋Š” ์ด๋ ‡๋‹ค\" ๋ฐ–์— ์•Œ ์ˆ˜ ์—†๋‹ค. ๊ธฐ์ค€ ํฌ๊ธฐ์™€ ๋Š˜๋ฆฐ ๊ฒƒ์„ ๋‚˜๋ž€ํžˆ\n * ๋†“์•„์•ผ ๋ฌด์—‡์ด ๋”ฐ๋ผ ๋Š˜๊ณ  ๋ฌด์—‡์ด ๊ทธ๋Œ€๋กœ์ธ์ง€ ๋ณด์ธ๋‹ค.\n *\n * ## ํŽธ์ง‘ํ•˜์ง€ ์•Š๋Š”๋‹ค\n *\n * ์—ฌ๊ธฐ์„œ ์ง‘๊ฑฐ๋‚˜ ๋Œ ์ˆ˜ ์—†๋‹ค. ํŽธ์ง‘์€ ์บ”๋ฒ„์Šค์—์„œ ํ•œ๋‹ค. ๋ณด์—ฌ ์ฃผ๊ธฐ๋งŒ ํ•˜๋Š” ์ž๋ฆฌ๋ผ ์”ฌ์„\n * ๋ทฐ ๋ชจ๋“œ๋กœ ์„ธ์šด๋‹ค.\n */\n\n/** ์–ผ๋งˆ๋‚˜ ํ‚ค์›Œ ๋ณด๋‚˜. */\nexport const PREVIEW_FACTOR = 2\n\n/**\n * ์–ด๋А ์ถ•์„ ํ‚ค์›Œ ๋†“์•„ ๋ณด๋‚˜ โ€” **์ผ๊ณฑ ์กฐํ•ฉ ์ „๋ถ€.**\n *\n * 1 ๋ฐฐ ยท 2 ๋ฐฐ ยท 3 ๋ฐฐ๋ฅผ ๋‚˜๋ž€ํžˆ ๋†“๋˜ ์ž๋ฆฌ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์„ธ ์ถ•์ด ๋Š˜ ๊ฐ™์ด ๋Š˜์–ด๋‚˜๋ฏ€๋กœ, ์ถ•๋งˆ๋‹ค\n * ๋”ฐ๋กœ ๊ฑธ๋ฆฌ๋Š” ๊ทœ์น™์„ ๋ˆˆ์œผ๋กœ ๋ณผ ์ˆ˜๊ฐ€ ์—†์—ˆ๋‹ค. ์‹ค์ œ๋กœ ๋ชป ๋ณด๊ณ  ๋„˜์–ด๊ฐ„ ๊ฒƒ๋“ค์ด ์žˆ๋‹ค โ€” ์ปจ๋ฒ ์ด์–ด์˜\n * ๋กค๋Ÿฌ๊ฐ€ ํญ์„ ์•ˆ ๋”ฐ๋ผ๊ฐ€๋˜ ๊ฒƒ, ๋ฌธ์˜ ํญ์ด ๋†’์ด๋ฅผ ์•ˆ ๋”ฐ๋ผ๊ฐ€๋˜ ๊ฒƒ์ด ๋‹ค ํ•œ ์ถ•๋งŒ ๋Š˜๋ ธ์„ ๋•Œ\n * ๋“œ๋Ÿฌ๋‚˜๋Š” ๊ฒƒ์ด์—ˆ๋‹ค.\n *\n * ์—ฌ๋Ÿ์ด๋‹ค. ์ฒซ์งธ๊ฐ€ ์ €์ž‘ํ•œ ํฌ๊ธฐ์ด๊ณ  ๋‚˜๋จธ์ง€ ์ผ๊ณฑ์ด ์กฐํ•ฉ์ด๋‹ค. ํ•œ ์ค„๋กœ ๋Š˜์–ด๋†“์œผ๋ฉด ํ™”๋ฉด์—\n * ์•ˆ ๋‹ด๊ฒจ์„œ **๋„ค ์นธ์”ฉ ๋‘ ์ค„**๋กœ ๋†“๋Š”๋‹ค.\n */\nexport const PREVIEW_WAYS: readonly { name: string; axes: readonly ('x' | 'y' | 'z')[] }[] = [\n { name: 'base', axes: [] },\n { name: 'x', axes: ['x'] },\n { name: 'y', axes: ['y'] },\n { name: 'z', axes: ['z'] },\n { name: 'xยทy', axes: ['x', 'y'] },\n { name: 'xยทz', axes: ['x', 'z'] },\n { name: 'yยทz', axes: ['y', 'z'] },\n { name: 'xยทyยทz', axes: ['x', 'y', 'z'] }\n]\n\n/*\n * ๋†’์ด๋Š” ์—ฌ๊ธฐ์„œ ์•ˆ ์ •ํ•œ๋‹ค.\n *\n * ํ•œ๋™์•ˆ ๋ฐฐ์น˜ ๊ธฐ์ค€์„ ๋†’์ด๋กœ ์˜ฎ๊ธฐ๋Š” ๊ณ„์‚ฐ์„ ์ด ํŒŒ์ผ์ด ๋“ค๊ณ  ์žˆ์—ˆ๋‹ค. ์ด์ œ ์”ฌ์ด ํ•œ๋‹ค โ€”\n * `FigureRealObject.effectiveZPos` ๊ฐ€ ์ฒญ์‚ฌ์ง„์˜ `placement` ์™€ ๋ ˆ์ด์–ด์˜ `heights` ๋กœ ์ •ํ•œ๋‹ค\n * (ADR-0045, `operato-twin/design/04-decisions.md`). ๋„๋ฉด์ด ๊ทธ๋ ‡๊ฒŒ ์„ธ์šฐ๋ฏ€๋กœ ใ€Œ๋„๋ฉด์— ๋†“์•˜์„\n * ๋•Œ์˜ ๋ชจ์Šตใ€์„ ๋งํ•˜๋Š” ์ด ํ™”๋ฉด๋„ ๊ทธ๋ ‡๊ฒŒ ์„ธ์›Œ์•ผ ํ•œ๋‹ค โ€” ์—ฌ๊ธฐ์„œ `zPos` ๋ฅผ ์ ์œผ๋ฉด **์ ์€ ๊ฐ’์ด\n * ์ด๊ฒจ์„œ**, ์”ฌ์ด ๋ฌด์—‡์„ ํ• ์ง€๊ฐ€ ์ด ํ™”๋ฉด์—์„œ๋งŒ ์•ˆ ๋ณด์ธ๋‹ค.\n *\n * ๊ทœ์น™์ด ๋‘ ๋ฒŒ์ด๋ฉด ๊ฐˆ๋ฆฐ๋‹ค. ์˜ค๋Š˜ ํ•˜๋ฃจ๊ฐ€ ๊ทธ ์ด์•ผ๊ธฐ์˜€๋‹ค.\n */\n\ninterface SceneHandle {\n dispose?: () => void\n resize?: () => void\n fit?: (type?: string) => void\n root?: {\n invalidate?: () => void\n fitCameraToModel?: (margin?: number) => void\n /** ๋ณด๊ธฐ ์„ค์ •์„ ๋„ฃ๋Š” ์ž๋ฆฌ. ์”ฌ์ด ์Šค์Šค๋กœ ๋ฐ˜์‘ํ•œ๋‹ค. */\n set?: (patch: Record<string, unknown>) => void\n /** ์„ธ์›Œ ๋‘” ์ธ์Šคํ„ด์Šค๋“ค. clip ์„ ๋ชฐ ๋•Œ ์ „๋ถ€์— ๊ฐ™์€ ๊ฐ’์„ ์ค€๋‹ค. */\n components?: { set?: (property: string, value: unknown) => void }[]\n }\n}\n\n@customElement('figure-preview')\nexport class FigurePreview extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n position: relative;\n display: flex;\n overflow: hidden;\n background-color: ${unsafeCSS(WORKBENCH)};\n font: var(--label-font, inherit);\n font-size: 0.76rem;\n }\n\n div[stage] {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n }\n\n /* ์–ด๋А ๊ฒƒ์ด ๋ช‡ ๋ฐฐ์ธ์ง€ โ€” ๋‚˜๋ž€ํžˆ ๋†“์•„๋„ ํ‘œ๊ฐ€ ์—†์œผ๋ฉด ์ฝ์„ ์ˆ˜ ์—†๋‹ค */\n div[legend] {\n position: absolute;\n top: 8px;\n left: 8px;\n display: flex;\n gap: 6px;\n padding: 4px 8px;\n color: rgba(255, 255, 255, 0.9);\n background-color: rgba(28, 28, 30, 0.6);\n border-radius: 6px;\n font-size: 0.72rem;\n }\n\n /*\n ์›€์ง์ž„ ์กฐ์ž‘. **์ €์ž‘์ž๊ฐ€ ์ œ ์• ๋‹ˆ๋ฉ”์ด์…˜๊ณผ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋งŒ์ ธ ๋ณผ ์œ ์ผํ•œ ์ž๋ฆฌ๋‹ค.**\n\n ๋„๋ฉด์—์„œ๋Š” ํŠธ์œˆ์ด ์ด ๊ฐ’์„ ์ค€๋‹ค โ€” ใ€Œ๋‹™์ด 40% ๋‹ซํ˜”๋‹คใ€๋Š” ์‚ฌ์‹ค์ด ์–ด๋””์„ ๊ฐ€ ์˜จ๋‹ค. ์ €์ž‘\n ์ค‘์—๋Š” ๊ทธ ์‚ฌ์‹ค์„ ์ฃผ๋Š” ๊ฒƒ์ด ์—†์–ด์„œ, ์†๋Œ€์ง€ ์•Š์œผ๋ฉด ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ๊ธฐ๋ณธ๊ฐ’์— ๋จธ๋ฌธ ์ฑ„ ์˜์˜\n ์•ˆ ์›€์ง์ธ๋‹ค. ํฌํฌ๊ฐ€ ์•ˆ ์˜ฌ๋ผ๊ฐ€๋Š” ๊ฒƒ์„ ์ €์ž‘์ž๊ฐ€ ใ€Œ์•ˆ ๋˜๋Š”๊ตฌ๋‚˜ใ€๋กœ ์ฝ๊ฒŒ ๋œ๋‹ค.\n\n **๋ฏธ๋ฆฌ๋ณด๊ธฐ ๊ฒƒ์ด์ง€ ์ž์‚ฐ์˜ ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค.** ์—ฌ๊ธฐ์„œ ๋ฏผ ๊ฐ’์€ ์ €์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค.\n */\n div[clips] {\n position: absolute;\n right: 8px;\n bottom: 8px;\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 8px 10px;\n color: rgba(255, 255, 255, 0.92);\n background-color: rgba(28, 28, 30, 0.72);\n border-radius: 8px;\n font-size: 0.72rem;\n }\n div[clips] label {\n display: grid;\n grid-template-columns: auto 96px 34px;\n align-items: center;\n gap: 8px;\n }\n div[clips] span[drive] {\n opacity: 0.6;\n font-size: 0.66rem;\n }\n div[clips] input {\n width: 96px;\n accent-color: var(--md-sys-color-primary);\n }\n div[clips] output {\n font-variant-numeric: tabular-nums;\n text-align: right;\n opacity: 0.85;\n }\n\n /* ์„ธ์šธ ์ˆ˜ ์—†๋Š” ์ƒํƒœ๋ฅผ ๋นˆ ํ™”๋ฉด์œผ๋กœ ๋‘์ง€ ์•Š๋Š”๋‹ค โ€” ์™œ ์•ˆ ๋ณด์ด๋Š”์ง€ ๋งํ•œ๋‹ค */\n div[cannot] {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--spacing-large, 12px);\n text-align: center;\n line-height: 1.6;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n background-color: ${unsafeCSS(WORKBENCH)};\n }\n `\n\n /** ์ €์ž‘ ์ค‘์ธ ๊ฒƒ. ์ €์žฅ ํ˜•์‹์œผ๋กœ ๋ฐ›๋Š”๋‹ค โ€” ๋„๋ฉด์ด ์†Œ๋น„ํ•˜๋Š” ๊ฒƒ์ด ์ด ํ˜•์‹์ด๋‹ค. */\n @property({ type: Object }) source?: FigureSource\n\n /**\n * ๋ณด๊ธฐ ์„ค์ •. ์ €์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค(`figure-view.ts`).\n *\n * ํ•œ๋™์•ˆ ์ด ํ™”๋ฉด๋งŒ ์กฐ๋ช…๊ณผ ํ™˜๊ฒฝ์„ **ํ•˜๋“œ์ฝ”๋”ฉ**ํ–ˆ๋‹ค. ์ €์ž‘์ž๊ฐ€ ํ™˜๊ฒฝ ํƒญ์—์„œ ๋ฌด์—‡์„ ๋ฐ”๊ฟ”๋„\n * ํŽธ์ง‘ ์บ”๋ฒ„์Šค๋งŒ ๋‹ฌ๋ผ์ง€๊ณ  ์—ฌ๊ธฐ๋Š” ๊ทธ๋Œ€๋กœ์˜€๋‹ค โ€” ๋‘ ํ™”๋ฉด์ด ๊ฐ™์€ ๊ฒƒ์„ ๋‹ค๋ฅด๊ฒŒ ๋ณด์—ฌ ์ฃผ์—ˆ๋‹ค.\n */\n @property({ type: Object }) view: ViewSettings = DEFAULT_VIEW\n\n @query('div[stage]') private stage!: HTMLDivElement\n\n /** ์„ธ์šธ ์ˆ˜ ์—†๋Š” ์‚ฌ์œ . ์—†์œผ๋ฉด ์„ธ์šด ๊ฒƒ์ด๋‹ค. */\n @state() private cannot = ''\n\n private scene?: SceneHandle\n /** ์ง€๊ธˆ ์„ธ์›Œ ๋‘” ๊ฒƒ์˜ ๊ฐ’. ๊ฐ™์œผ๋ฉด ๋‹ค์‹œ ์„ธ์šฐ์ง€ ์•Š๋Š”๋‹ค. */\n private standing?: string\n private watcher?: ResizeObserver\n\n /** ์ง€๊ธˆ ๋ฏผ clip ๋ฐฐ์†. clip ์ด๋ฆ„ โ†’ ์ˆ˜. **์ €์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค.** */\n @state() private driving: Record<string, number> = {}\n /** ์ง€๊ธˆ ๋ฏผ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’. ์ด๋ฆ„ โ†’ `range` ์˜ ๋‹จ์œ„๋กœ ์žฐ ์ˆ˜. **์ €์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค.** */\n @state() private giving: Record<string, number> = {}\n\n render() {\n const clips = this.source?.animations ?? []\n const parameters = this.source?.parameters ?? []\n\n return html`\n <div stage></div>\n ${this.cannot\n ? html`<div cannot>${this.cannot}</div>`\n : html`<div legend>\n ${PREVIEW_WAYS.map(way => html`<span>${way.axes.length === 0 ? i18next.t('figure.label.preview-base') : way.name}</span>`)}\n </div>\n ${clips.length + parameters.length > 0 ? this.renderDrivers(clips, parameters) : ''}`}\n `\n }\n\n /**\n * ์›€์ง์ž„ ํ•˜๋‚˜์— ์†์žก์ด ํ•˜๋‚˜.\n *\n * ๋‘ ๊ฐˆ๋ž˜๋ฅผ **๋ˆˆ๊ธˆ์ด ๋‹ค๋ฅธ ์ฑ„๋กœ** ๋‚ธ๋‹ค. clip ์€ ๋ฐฐ์†์ด๋ผ 0 ์ด ๋ฉˆ์ถค์ด๊ณ  0~3 ์ด ๋œป์ด\n * ์žˆ์œผ๋ฉฐ, ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ๋ฌผ๋ฆฌ๋Ÿ‰์ด๋ผ ๊ทธ `range` ๊ฐ€ ๊ณง ๋ˆˆ๊ธˆ์ด๊ณ  ๋‹จ์œ„๊ฐ€ ๋”ฐ๋ผ ๋ถ™๋Š”๋‹ค. ํ•˜๋‚˜์˜\n * 0~1 ๋กœ ๋ญ‰๋šฑ๊ทธ๋ฆฌ๋ฉด ใ€Œ1ใ€์ด ๋ฌด์Šจ ๋œป์ธ์ง€ ๋งค๋ฒˆ ํ—ท๊ฐˆ๋ฆฌ๊ณ , 1200mm ๋ฅผ ๋„ฃ์–ด ๋ณด๋ ค๋˜ ์ €์ž‘์ž๊ฐ€\n * ๋„ฃ์„ ์ž๋ฆฌ๋ฅผ ๋ชป ์ฐพ๋Š”๋‹ค.\n */\n private renderDrivers(\n clips: NonNullable<FigureSource['animations']>,\n parameters: NonNullable<FigureSource['parameters']>\n ) {\n return html`\n <div clips>\n ${parameters.map(parameter => {\n const range = parameter.range\n const value = this.giving[parameter.name] ?? parameter.default ?? range?.min ?? 0\n const step = range ? Math.max((range.max - range.min) / 100, 0.01) : 1\n\n return html`\n <label>\n <span>${parameter.label ?? parameter.name} <span drive>${range?.unit ?? ''}</span></span>\n <input\n type=\"range\"\n min=${range?.min ?? 0}\n max=${range?.max ?? 1}\n step=${step}\n .value=${String(value)}\n @input=${(e: Event) => this.give(parameter.name, Number((e.target as HTMLInputElement).value))}\n />\n <output>${Math.round(value)}</output>\n </label>\n `\n })}\n ${clips.map(clip => {\n const value = this.driving[clip.name] ?? 1\n\n return html`\n <label>\n <span>${clip.name} <span drive>${i18next.t('figure.label.playback-speed')}</span></span>\n <input\n type=\"range\"\n min=\"0\"\n max=\"3\"\n step=\"0.05\"\n .value=${String(value)}\n @input=${(e: Event) => this.drive(clip.name, Number((e.target as HTMLInputElement).value))}\n />\n <output>${value.toFixed(2)}</output>\n </label>\n `\n })}\n </div>\n `\n }\n\n /**\n * ์„ธ์›Œ ๋‘” ์ธ์Šคํ„ด์Šค ์ „๋ถ€์— ๊ฐ™์€ ๊ฐ’์„ ์ค€๋‹ค.\n *\n * ํ•˜๋‚˜๋งŒ ๋ชฐ๋ฉด ์„ธ ๋ฐฐ์œจ์ด ์„œ๋กœ ๋‹ค๋ฅธ ์ž์„ธ๋กœ ์„œ์„œ, ํฌ๊ธฐ ๋ฐ˜์‘์„ ๋ณด๋ ค๊ณ  ๋‚˜๋ž€ํžˆ ๋†“์€ ๋œป์ด\n * ์‚ฌ๋ผ์ง„๋‹ค.\n */\n private drive(name: string, value: number): void {\n this.driving = { ...this.driving, [name]: value }\n this.tellInstances('clips', this.driving)\n }\n\n /**\n * ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’์„ ์ค€๋‹ค โ€” **`range` ์˜ ๋‹จ์œ„ ๊ทธ๋Œ€๋กœ๋‹ค.**\n *\n * 0~1 ๋กœ ๋ฐ”๊ฟ”์„œ ์ฃผ์ง€ ์•Š๋Š”๋‹ค. ๊ทธ ํ™˜์‚ฐ์€ ๋Ÿฐํƒ€์ž„์˜ ์ผ์ด๊ณ , ์—ฌ๊ธฐ์„œ ํ•œ ๋ฒˆ ๋” ํ•˜๋ฉด ๋‘ ๊ณณ์ด\n * ๊ฐˆ๋ฆด ์ˆ˜ ์žˆ๋‹ค. ์ €์ž‘์ž๊ฐ€ ํ™”๋ฉด์—์„œ ๋ณด๋Š” 1200 ์ด ์”ฌ์— ๊ทธ๋Œ€๋กœ ๊ฐ„๋‹ค.\n */\n private give(name: string, value: number): void {\n this.giving = { ...this.giving, [name]: value }\n this.tellInstances('parameters', this.giving)\n }\n\n private tellInstances(key: 'clips' | 'parameters', values: Record<string, number>): void {\n for (const component of this.scene?.root?.components ?? []) {\n component.set?.(key, { ...values })\n }\n }\n\n /**\n * ๋ณด๊ธฐ ์„ค์ •์ด ๋ฐ”๋€Œ๋ฉด **๋‹ค์‹œ ์„ธ์šฐ์ง€ ์•Š๊ณ  ์”ฌ์— ๋„ฃ๋Š”๋‹ค** โ€” ๋‘ ๊ฐœ๋งŒ ๋นผ๊ณ .\n *\n * ์กฐ๋ช…ยทํ™˜๊ฒฝยท๋ฐ”ํƒ•์€ ์”ฌ์ด ์Šค์Šค๋กœ ๋ฐ˜์‘ํ•œ๋‹ค(`three-capability` ์˜ `onchange`). ์Šฌ๋ผ์ด๋”๋ฅผ\n * ๋„๋Š” ๋™์•ˆ ๋‹ค์‹œ ์„ธ์šฐ๋ฉด ์นด๋ฉ”๋ผ๊ฐ€ ๋งค ํ”„๋ ˆ์ž„ ์ฒ˜์Œ์œผ๋กœ ๋Œ์•„๊ฐ„๋‹ค.\n *\n * ์ขŒํ‘œ ๊ธฐ์ค€๊ณผ ์ฒœ์žฅ ๋†’์ด๋Š” ๋‹ค๋ฅด๋‹ค. ์”ฌ์ด ๊ทธ ๋‘˜๋กœ ์ธ์Šคํ„ด์Šค ๋†’์ด๋ฅผ ์ •ํ•˜๋Š”๋ฐ, ๊ทธ ๊ณ„์‚ฐ์€ ์„ธ์šธ\n * ๋•Œ ํ•œ ๋ฒˆ ๋ˆ๋‹ค โ€” ์ด๋ฏธ ์„ธ์›Œ ๋‘” ๊ฒƒ์— ๋„ฃ์–ด ๋ด์•ผ ์ž๋ฆฌ๊ฐ€ ์•ˆ ๋ฐ”๋€๋‹ค. ๊ทธ๊ฒƒ๋งŒ ๋‹ค์‹œ ์„ธ์šด๋‹ค.\n */\n willUpdate(changed: Map<string, unknown>) {\n if (!this.hasUpdated) return\n\n if (changed.has('source')) {\n this.standUp()\n return\n }\n\n if (!changed.has('view')) return\n\n const before = changed.get('view') as ViewSettings | undefined\n const now = this.view ?? DEFAULT_VIEW\n if (before?.placement !== now.placement || before?.ceilingHeight !== now.ceilingHeight) {\n this.standUp()\n return\n }\n\n this.scene?.root?.set?.(sceneLook(now))\n }\n\n firstUpdated() {\n this.standUp()\n this.watcher = new ResizeObserver(() => this.scene?.resize?.())\n this.watcher.observe(this)\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n this.watcher?.disconnect()\n this.watcher = undefined\n this.teardown()\n }\n\n /**\n * ์ €์ž‘ํ•œ ๊ฒƒ์„ ์ปดํŒŒ์ผํ•ด ์„ธ์šด๋‹ค.\n *\n * **ํ˜•์‹์„ ์–ด๊ฒผ์œผ๋ฉด ์„ธ์šฐ์ง€ ์•Š๋Š”๋‹ค.** ๋ฐ˜์ฏค ์„ธ์šด ๊ฒƒ์„ ๋ณด์—ฌ ์ฃผ๋ฉด ๋ฌด์—‡์ด ์ž˜๋ชป๋๋Š”์ง€ ์•Œ ์ˆ˜\n * ์—†๋‹ค. ํŒ์ • ํŒจ๋„์ด ์ด๋ฏธ ์‚ฌ์œ ๋ฅผ ๋งํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ์—ฌ๊ธฐ์„œ๋Š” ์„ธ์šธ ์ˆ˜ ์—†๋‹ค๊ณ ๋งŒ ํ•œ๋‹ค.\n */\n private standUp() {\n const source = this.source\n if (!source || source.parts.length === 0) {\n this.cannot = i18next.t('figure.text.preview-needs-a-part')\n this.teardown()\n return\n }\n\n const view = this.view ?? DEFAULT_VIEW\n /* ์”ฌ์ด ์ด ๋‘˜๋กœ ์ธ์Šคํ„ด์Šค ๋†’์ด๋ฅผ ์ •ํ•œ๋‹ค โ€” ์„œ๋ช…์— ์•ˆ ๋„ฃ์œผ๋ฉด ๋‹ค์‹œ ์„ธ์›Œ๋„ ๊ทธ๋Œ€๋กœ ์„ ๋‹ค. */\n const signature = JSON.stringify([source, view.placement, view.ceilingHeight])\n if (this.scene && this.standing === signature) return\n\n const { errors } = validate(source)\n if (errors.length > 0) {\n this.cannot = i18next.t('figure.text.preview-blocked-by-errors')\n this.teardown()\n return\n }\n\n this.teardown()\n // ํ‘œ๋ณธ์ด ๋ฐ”๋€Œ๋ฉด ๋ฏผ ๊ฐ’๋„ ์ฒ˜์Œ์œผ๋กœ ๋Œ๋ฆฐ๋‹ค โ€” ๋‹ค๋ฅธ ์ž์‚ฐ์˜ clip ์ด๋ฆ„์ด ๋‚จ์œผ๋ฉด ์•ˆ ๋œ๋‹ค.\n this.driving = {}\n\n try {\n registerFigure(compile(source) as never)\n\n /*\n ๋„๋ฉด์ด ํ•˜๋Š” ์ผ์„ ๊ทธ๋Œ€๋กœ ํ•œ๋‹ค. ์ปดํฌ๋„ŒํŠธ์—๋Š” ํƒ€์ž… ์ด๋ฆ„๊ณผ ์ž๋ฆฌยทํฌ๊ธฐ๋งŒ ์ ๋Š”๋‹ค โ€”\n ์ฒญ์‚ฌ์ง„๋„ ์›๋ณธ๋„ ๋„๋ฉด์— ๋“ค์–ด๊ฐ€์ง€ ์•Š๋Š”๋‹ค.\n\n ๊ฐ€์žฅ ํฐ ๊ฒƒ์ด ๋“ค์–ด๊ฐˆ ๋งŒํผ ํŒ์„ ์žก๊ณ , ์„ธ๋กœ๋กœ ์ค„์„ ๋‚˜๋ˆ  ๋‚˜๋ž€ํžˆ ๋†“๋Š”๋‹ค.\n */\n const { base } = source\n const biggest = PREVIEW_FACTOR\n /** ์ด ์กฐํ•ฉ์—์„œ ์ถ•๋ณ„ ๋ฐฐ์œจ. ์กฐํ•ฉ์— ๋“  ์ถ•๋งŒ ํ‚ค์šด๋‹ค. */\n const growth = (way: (typeof PREVIEW_WAYS)[number]) => ({\n x: way.axes.includes('x') ? PREVIEW_FACTOR : 1,\n y: way.axes.includes('y') ? PREVIEW_FACTOR : 1,\n z: way.axes.includes('z') ? PREVIEW_FACTOR : 1\n })\n // ์—ฌ๋ฐฑ์„ ๋„‰๋„‰ํžˆ ๋‘๋ฉด ํ™”๋ฉด์—์„œ ํ˜•์ƒ์ด ์ž‘์•„์ง„๋‹ค. ๊ฐ€์žฅ ํฐ ๊ฒƒ์ด ๊ฒจ์šฐ ๋“ค์–ด๊ฐˆ ๋งŒํผ๋งŒ ์žก๋Š”๋‹ค.\n /** ๋„ค ์นธ์”ฉ ๋‘ ์ค„. */\n const COLUMNS = 4\n const cell = { x: base.x * biggest * 1.25, z: base.z * biggest * 1.25 }\n const rows = Math.ceil(PREVIEW_WAYS.length / COLUMNS)\n /*\n ์”ฌ์˜ ๋‚ฑ๋ง์ด ํ˜•์‹๊ณผ ๋‹ค๋ฅด๋‹ค โ€” `width` ๊ฐ€ ํ˜•์‹์˜ x, `height` ๊ฐ€ z, `depth` ๊ฐ€ y ๋‹ค.\n ์˜ฎ๊ธฐ๋Š” ์ผ์„ ์—ฌ๊ธฐ ํ•œ ์ค„์— ๋ชจ์•„ ๋‘”๋‹ค.\n\n `depth` ๋ฅผ ๋Š˜ ์ ๋Š” ์ด์œ ๊ฐ€ ์žˆ๋‹ค. ์•ˆ ์ ์œผ๋ฉด ํ‰๋ฉด ๋‘ ์ถ•์˜ ๊ธฐํ•˜ํ‰๊ท ์œผ๋กœ ์žกํ˜€์„œ,\n ใ€Œy ๋งŒ ํ‚ค์šด๋‹คใ€๊ฐ€ xยทz ๋ฅผ ์•ˆ ๊ฑด๋“œ๋ฆฌ๋Š”๋ฐ๋„ ๋†’์ด๊ฐ€ ์•ˆ ์˜ค๋ฅธ๋‹ค.\n\n ๋†’์ด๋Š” **๋ฐฐ์น˜ ๊ธฐ์ค€์ด ์ •ํ•œ๋‹ค.** ๋ฐ”๋‹ฅ ๊ธฐ๋ฐ˜์€ ๋•…์—์„œ ์˜ฌ๋ผ์˜ค๊ณ , ์ฒœ์ • ๊ธฐ๋ฐ˜์€ ์ฒœ์žฅ์—\n ๋ถ™์–ด ๋‚ด๋ ค์˜จ๋‹ค. ์—ฌ๋Ÿ์„ ๋‚˜๋ž€ํžˆ ์„ธ์šฐ๋Š” ์ž๋ฆฌ๋ผ ์ด๊ฒƒ์ด ๋ˆˆ์— ๋ฐ”๋กœ ๋ณด์ธ๋‹ค โ€” ๋ฐ”๋‹ฅ ๊ธฐ๋ฐ˜์ด๋ฉด\n ๋ฐ‘๋ฉด์ด, ์ฒœ์ • ๊ธฐ๋ฐ˜์ด๋ฉด ์œ—๋ฉด์ด ํ•œ ์ค„์ด ๋œ๋‹ค.\n */\n const components = PREVIEW_WAYS.map((way, at) => {\n const grow = growth(way)\n const column = at % COLUMNS\n const row = Math.floor(at / COLUMNS)\n const width = Math.round(base.x * grow.x)\n const height = Math.round(base.z * grow.z)\n const tall = Math.round(base.y * grow.y)\n\n return {\n type: source.type,\n id: `at-${way.name}`,\n // ์นธ ๊ฐ€์šด๋ฐ์— ๋†“๋Š”๋‹ค โ€” ํฌ๊ธฐ๊ฐ€ ์ €๋งˆ๋‹ค ๋‹ฌ๋ผ ์™ผ์ชฝ์— ๋งž์ถ”๋ฉด ์ค„์ด ์•ˆ ์ฝํžŒ๋‹ค.\n left: Math.round(column * cell.x + (cell.x - width) / 2),\n top: Math.round(row * cell.z + (cell.z - height) / 2),\n width,\n height,\n depth: tall\n }\n })\n\n const draft = {\n width: Math.round(cell.x * COLUMNS),\n height: Math.round(cell.z * rows),\n /*\n ํŒ์˜ ๋†’์ด๋„ ๊ฐ€์žฅ ํฐ ์ธ์Šคํ„ด์Šค๋ฅผ ๋‹ด์•„์•ผ ํ•œ๋‹ค. ์•ˆ ์ฃผ๋ฉด ์นด๋ฉ”๋ผ๊ฐ€ ํ‰๋ฉด๋งŒ ๋ณด๊ณ  ์ž๋ฆฌ๋ฅผ\n ์žก์•„์„œ, ํ‚ค๊ฐ€ ํฐ ๋ชจ๋ธ์€ ๋ฐ‘๋™๋งŒ ๋ณด์ธ๋‹ค โ€” ์‹œ๊ทธ๋„ํƒ€์›Œ๋ฅผ 2 ๋ฐฐ๋กœ ๋†“์œผ๋ฉด 2200 ์ธ๋ฐ ํŒ์ด\n ๊ทธ๊ฒƒ์„ ๋ชจ๋ฅด๋ฉด ๋ฐ›์นจ๋งŒ ํ™”๋ฉด์— ๋“ ๋‹ค.\n\n ์–ด๋””์— ์˜ฌ๋ ค ๋†“์„์ง€๋Š” **์”ฌ์ด ์ •ํ•˜๋ฏ€๋กœ**(`FigureRealObject.effectiveZPos`), ์—ฌ๊ธฐ์„œ๋Š”\n ์–ด๋А ๊ฒฝ์šฐ์—๋„ ๋‹ด๊ธฐ๋Š” ๊ฒฝ๊ณ„๋งŒ ์žก๋Š”๋‹ค. ๋ฐ”๋‹ฅ ๊ธฐ๋ฐ˜์€ ๊ฐ€์žฅ ํฐ ๊ฒƒ์˜ ํ‚ค๊นŒ์ง€, ์ฒœ์ • ๊ธฐ๋ฐ˜์€\n ์ฒœ์žฅ๊นŒ์ง€๋‹ค. ๋ฐฐ์น˜๋ฅผ ๋†’์ด๋กœ ์˜ฎ๊ธฐ๋Š” ๊ณ„์‚ฐ์„ ์—ฌ๊ธฐ์„œ ๋‹ค์‹œ ์“ฐ๋ฉด ๊ทธ๊ฒƒ์ด ๋‘ ๋ฒŒ์งธ๊ฐ€ ๋œ๋‹ค.\n */\n depth: Math.round(Math.max(view.ceilingHeight, base.y * biggest) * 1.1)\n }\n\n this.scene = create({\n target: this.stage,\n model: {\n type: 'model-layer',\n width: draft.width,\n height: draft.height,\n depth: draft.depth,\n threed: true,\n sky: 'color',\n /*\n ๋ณด๊ธฐ ์„ค์ •์„ ๊ทธ๋Œ€๋กœ ์‹ฃ๋Š”๋‹ค.\n\n ์—ฌ๊ธฐ๋งŒ ์กฐ๋ช…ยทํ™˜๊ฒฝยท๋ฐ”ํƒ•์„ ํ•˜๋“œ์ฝ”๋”ฉํ•˜๊ณ  ์žˆ์—ˆ๋‹ค. ์ €์ž‘์ž๊ฐ€ ํ™˜๊ฒฝ ํƒญ์—์„œ ์กฐ๋ช…์„\n ์˜ฌ๋ ค๋„ ํŽธ์ง‘ ์บ”๋ฒ„์Šค๋งŒ ๋ฐ์•„์ง€๊ณ  ์ด ํ™”๋ฉด์€ ๊ทธ๋Œ€๋กœ์—ฌ์„œ, ๊ฐ™์€ ๊ฒƒ์„ ๋‘ ํ™”๋ฉด์ด\n ๋‹ค๋ฅด๊ฒŒ ๋ณด์—ฌ ์ฃผ์—ˆ๋‹ค.\n\n `sceneLook` ์ด ์ขŒํ‘œ ๊ธฐ์ค€๊ณผ ์ฒœ์žฅ ๋†’์ด๋ฅผ ๋นผ๊ณ  ์ค€๋‹ค โ€” ์”ฌ์ด ์•„๋Š” ์ด๋ฆ„์ด ์•„๋‹ˆ๊ฑฐ๋‚˜\n (`ceilingHeight`) ํŽธ์ง‘ ์บ”๋ฒ„์Šค์— ์ƒˆ๋ฉด ์•ˆ ๋˜๋Š” ๊ฒƒ(`placement`)์ด๋ผ์„œ๋‹ค. ๋‘˜ ๋‹ค ์•„๋ž˜์—\n ์”ฌ์˜ ๋‚ฑ๋ง๋กœ ๋”ฐ๋กœ ์‹ฃ๋Š”๋‹ค.\n */\n ...sceneLook(view),\n placement: view.placement,\n /*\n ๋ถ€์ฐฉ๋ฉด์˜ ๋†’์ด. ์”ฌ์ด ์ด ์ž๋ฆฌ๋ฅผ ๊ฐ–๊ณ (`real-object.ts` ์˜ `sceneHeights`), ์ฒœ์ • ๊ธฐ๋ฐ˜\n ๋„ํ˜•์ด ์—ฌ๊ธฐ์„œ ์ œ ๋†’์ด๋ฅผ ์–ป๋Š”๋‹ค. ๋„๋ฉด์—์„œ๋Š” ํ˜„์žฅ์ด ์ด ๊ฐ’์„ ์ค€๋‹ค.\n */\n heights: { floor: 0, ceiling: view.ceilingHeight },\n pixelRatio: Math.min(3, (window.devicePixelRatio || 1) * 2),\n components\n },\n // ๋ณด๊ธฐ๋งŒ ํ•˜๋Š” ์ž๋ฆฌ๋‹ค. ์ง‘๊ฑฐ๋‚˜ ๋Œ ์ˆ˜ ์—†์–ด์•ผ ํ•œ๋‹ค.\n mode: 0\n }) as SceneHandle\n\n this.standing = signature\n this.scene.resize?.()\n this.scene.fit?.('ratio')\n this.scene.root?.fitCameraToModel?.()\n this.cannot = ''\n } catch (e) {\n // ์›์ธ์„ ์ง€์–ด๋‚ด์ง€ ์•Š๋Š”๋‹ค โ€” ๋˜์ง„ ๋ง์„ ๊ทธ๋Œ€๋กœ ๋ณด์—ฌ ์ค€๋‹ค.\n this.cannot = (e as Error).message\n }\n }\n\n private teardown() {\n this.scene?.dispose?.()\n this.scene = undefined\n this.standing = undefined\n }\n}\n"]}
1
+ {"version":3,"file":"figure-preview.js","sourceRoot":"","sources":["../../client/modeller/figure-preview.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, unsafeCSS } from 'lit'\nimport { customElement, property, query, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { compile, validate } from '@hatiolab/figure-model'\nimport type { FigureSource } from '@hatiolab/figure-model'\nimport { create, registerFigure } from '@hatiolab/things-scene'\n\nimport { DEFAULT_VIEW, previewBoardDepth, sceneLook, WORKBENCH } from './figure-view.js'\nimport type { ViewSettings } from './figure-view.js'\nimport { poseChanges } from './pose-defaults.js'\nimport type { FigureDraft } from './figure-source.js'\n\n/**\n * ์ €์ž‘ ์ค‘์ธ ๊ฒƒ์„ **๋„๋ฉด์— ๋†“์•˜์„ ๋•Œ**์˜ ๋ชจ์Šต.\n *\n * ## ํŽธ์ง‘ ์บ”๋ฒ„์Šค๋กœ๋Š” ๋ณผ ์ˆ˜ ์—†๋‹ค\n *\n * ํŽธ์ง‘ ์บ”๋ฒ„์Šค๋Š” ๋ถ€ํ’ˆ์„ ์ปดํฌ๋„ŒํŠธ๋กœ ๋Š˜์–ด๋†“๋Š”๋‹ค. ๊ทธ๋ž˜์„œ ๋Š˜ ๊ธฐ์ค€ ํฌ๊ธฐ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ด ํ˜•์‹์˜\n * ๊ฐ’ ์ ˆ๋ฐ˜์€ **ํฌ๊ธฐ๊ฐ€ ๋‹ฌ๋ผ์กŒ์„ ๋•Œ ์–ด๋–ป๊ฒŒ ๋ฐ˜์‘ํ•˜๋Š”๊ฐ€**์— ์žˆ๋‹ค. ๊ธฐ๋‘ฅ๋งŒ ๋Š˜์–ด๋‚˜๋Š” ์‹œ๊ทธ๋„ํƒ€์›Œ,\n * ๋กค๋Ÿฌ ๊ฐœ์ˆ˜๊ฐ€ ๋А๋Š” ์ปจ๋ฒ ์ด์–ด๋Š” ๊ธฐ์ค€ ํฌ๊ธฐ์—์„œ๋Š” ์•„๋ฌด๊ฒƒ๋„ ๋ณด์—ฌ ์ฃผ์ง€ ๋ชปํ•œ๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ ์—ฌ๊ธฐ์„œ๋Š” ์ €์ž‘ํ•œ ๊ฒƒ์„ ์‹ค์ œ๋กœ ์ปดํŒŒ์ผํ•ด `FigureInstance` ๋กœ ์„ธ์šด๋‹ค. ๋„๋ฉด์ด ํ•˜๋Š”\n * ์ผ์„ ๊ทธ๋Œ€๋กœ ํ•œ๋‹ค โ€” ์ฒญ์‚ฌ์ง„์„ ๋“ฑ๋กํ•˜๊ณ , ํƒ€์ž… ์ด๋ฆ„๋งŒ ์ ์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋†“๋Š”๋‹ค.\n *\n * ## ์—ฌ๋Ÿฌ ํฌ๊ธฐ๋ฅผ ํ•œ ๋ฒˆ์— ๋†“๋Š”๋‹ค\n *\n * ํ•˜๋‚˜๋งŒ ๋†“์œผ๋ฉด \"์ด ํฌ๊ธฐ์—์„œ๋Š” ์ด๋ ‡๋‹ค\" ๋ฐ–์— ์•Œ ์ˆ˜ ์—†๋‹ค. ๊ธฐ์ค€ ํฌ๊ธฐ์™€ ๋Š˜๋ฆฐ ๊ฒƒ์„ ๋‚˜๋ž€ํžˆ\n * ๋†“์•„์•ผ ๋ฌด์—‡์ด ๋”ฐ๋ผ ๋Š˜๊ณ  ๋ฌด์—‡์ด ๊ทธ๋Œ€๋กœ์ธ์ง€ ๋ณด์ธ๋‹ค.\n *\n * ## ํŽธ์ง‘ํ•˜์ง€ ์•Š๋Š”๋‹ค\n *\n * ์—ฌ๊ธฐ์„œ ์ง‘๊ฑฐ๋‚˜ ๋Œ ์ˆ˜ ์—†๋‹ค. ํŽธ์ง‘์€ ์บ”๋ฒ„์Šค์—์„œ ํ•œ๋‹ค. ๋ณด์—ฌ ์ฃผ๊ธฐ๋งŒ ํ•˜๋Š” ์ž๋ฆฌ๋ผ ์”ฌ์„\n * ๋ทฐ ๋ชจ๋“œ๋กœ ์„ธ์šด๋‹ค.\n */\n\n/** ์–ผ๋งˆ๋‚˜ ํ‚ค์›Œ ๋ณด๋‚˜. */\nexport const PREVIEW_FACTOR = 2\n\n/**\n * ์–ด๋А ์ถ•์„ ํ‚ค์›Œ ๋†“์•„ ๋ณด๋‚˜ โ€” **์ผ๊ณฑ ์กฐํ•ฉ ์ „๋ถ€.**\n *\n * 1 ๋ฐฐ ยท 2 ๋ฐฐ ยท 3 ๋ฐฐ๋ฅผ ๋‚˜๋ž€ํžˆ ๋†“๋˜ ์ž๋ฆฌ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์„ธ ์ถ•์ด ๋Š˜ ๊ฐ™์ด ๋Š˜์–ด๋‚˜๋ฏ€๋กœ, ์ถ•๋งˆ๋‹ค\n * ๋”ฐ๋กœ ๊ฑธ๋ฆฌ๋Š” ๊ทœ์น™์„ ๋ˆˆ์œผ๋กœ ๋ณผ ์ˆ˜๊ฐ€ ์—†์—ˆ๋‹ค. ์‹ค์ œ๋กœ ๋ชป ๋ณด๊ณ  ๋„˜์–ด๊ฐ„ ๊ฒƒ๋“ค์ด ์žˆ๋‹ค โ€” ์ปจ๋ฒ ์ด์–ด์˜\n * ๋กค๋Ÿฌ๊ฐ€ ํญ์„ ์•ˆ ๋”ฐ๋ผ๊ฐ€๋˜ ๊ฒƒ, ๋ฌธ์˜ ํญ์ด ๋†’์ด๋ฅผ ์•ˆ ๋”ฐ๋ผ๊ฐ€๋˜ ๊ฒƒ์ด ๋‹ค ํ•œ ์ถ•๋งŒ ๋Š˜๋ ธ์„ ๋•Œ\n * ๋“œ๋Ÿฌ๋‚˜๋Š” ๊ฒƒ์ด์—ˆ๋‹ค.\n *\n * ์—ฌ๋Ÿ์ด๋‹ค. ์ฒซ์งธ๊ฐ€ ์ €์ž‘ํ•œ ํฌ๊ธฐ์ด๊ณ  ๋‚˜๋จธ์ง€ ์ผ๊ณฑ์ด ์กฐํ•ฉ์ด๋‹ค. ํ•œ ์ค„๋กœ ๋Š˜์–ด๋†“์œผ๋ฉด ํ™”๋ฉด์—\n * ์•ˆ ๋‹ด๊ฒจ์„œ **๋„ค ์นธ์”ฉ ๋‘ ์ค„**๋กœ ๋†“๋Š”๋‹ค.\n */\nexport const PREVIEW_WAYS: readonly { name: string; axes: readonly ('x' | 'y' | 'z')[] }[] = [\n { name: 'base', axes: [] },\n { name: 'x', axes: ['x'] },\n { name: 'y', axes: ['y'] },\n { name: 'z', axes: ['z'] },\n { name: 'xยทy', axes: ['x', 'y'] },\n { name: 'xยทz', axes: ['x', 'z'] },\n { name: 'yยทz', axes: ['y', 'z'] },\n { name: 'xยทyยทz', axes: ['x', 'y', 'z'] }\n]\n\n/*\n * ๋†’์ด๋Š” ์—ฌ๊ธฐ์„œ ์•ˆ ์ •ํ•œ๋‹ค.\n *\n * ํ•œ๋™์•ˆ ๋ฐฐ์น˜ ๊ธฐ์ค€์„ ๋†’์ด๋กœ ์˜ฎ๊ธฐ๋Š” ๊ณ„์‚ฐ์„ ์ด ํŒŒ์ผ์ด ๋“ค๊ณ  ์žˆ์—ˆ๋‹ค. ์ด์ œ ์”ฌ์ด ํ•œ๋‹ค โ€”\n * `FigureRealObject.effectiveZPos` ๊ฐ€ ์ฒญ์‚ฌ์ง„์˜ `placement` ์™€ ๋ ˆ์ด์–ด์˜ `heights` ๋กœ ์ •ํ•œ๋‹ค\n * (ADR-0045, `operato-twin/design/04-decisions.md`). ๋„๋ฉด์ด ๊ทธ๋ ‡๊ฒŒ ์„ธ์šฐ๋ฏ€๋กœ ใ€Œ๋„๋ฉด์— ๋†“์•˜์„\n * ๋•Œ์˜ ๋ชจ์Šตใ€์„ ๋งํ•˜๋Š” ์ด ํ™”๋ฉด๋„ ๊ทธ๋ ‡๊ฒŒ ์„ธ์›Œ์•ผ ํ•œ๋‹ค โ€” ์—ฌ๊ธฐ์„œ `zPos` ๋ฅผ ์ ์œผ๋ฉด **์ ์€ ๊ฐ’์ด\n * ์ด๊ฒจ์„œ**, ์”ฌ์ด ๋ฌด์—‡์„ ํ• ์ง€๊ฐ€ ์ด ํ™”๋ฉด์—์„œ๋งŒ ์•ˆ ๋ณด์ธ๋‹ค.\n *\n * ๊ทœ์น™์ด ๋‘ ๋ฒŒ์ด๋ฉด ๊ฐˆ๋ฆฐ๋‹ค. ์˜ค๋Š˜ ํ•˜๋ฃจ๊ฐ€ ๊ทธ ์ด์•ผ๊ธฐ์˜€๋‹ค.\n */\n\ninterface SceneHandle {\n dispose?: () => void\n resize?: () => void\n fit?: (type?: string) => void\n root?: {\n invalidate?: () => void\n fitCameraToModel?: (margin?: number) => void\n /** ๋ณด๊ธฐ ์„ค์ •์„ ๋„ฃ๋Š” ์ž๋ฆฌ. ์”ฌ์ด ์Šค์Šค๋กœ ๋ฐ˜์‘ํ•œ๋‹ค. */\n set?: (patch: Record<string, unknown>) => void\n /** ์„ธ์›Œ ๋‘” ์ธ์Šคํ„ด์Šค๋“ค. clip ์„ ๋ชฐ ๋•Œ ์ „๋ถ€์— ๊ฐ™์€ ๊ฐ’์„ ์ค€๋‹ค. */\n components?: { set?: (property: string, value: unknown) => void }[]\n }\n}\n\n@customElement('figure-preview')\nexport class FigurePreview extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n position: relative;\n display: flex;\n overflow: hidden;\n background-color: ${unsafeCSS(WORKBENCH)};\n font: var(--label-font, inherit);\n font-size: 0.76rem;\n }\n\n div[stage] {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n }\n\n /* ์–ด๋А ๊ฒƒ์ด ๋ช‡ ๋ฐฐ์ธ์ง€ โ€” ๋‚˜๋ž€ํžˆ ๋†“์•„๋„ ํ‘œ๊ฐ€ ์—†์œผ๋ฉด ์ฝ์„ ์ˆ˜ ์—†๋‹ค */\n div[legend] {\n position: absolute;\n top: 8px;\n left: 8px;\n display: flex;\n gap: 6px;\n padding: 4px 8px;\n color: rgba(255, 255, 255, 0.9);\n background-color: rgba(28, 28, 30, 0.6);\n border-radius: 6px;\n font-size: 0.72rem;\n }\n\n /*\n ์›€์ง์ž„ ์กฐ์ž‘. **์ €์ž‘์ž๊ฐ€ ์ œ ์• ๋‹ˆ๋ฉ”์ด์…˜๊ณผ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋งŒ์ ธ ๋ณผ ์œ ์ผํ•œ ์ž๋ฆฌ๋‹ค.**\n\n ๋„๋ฉด์—์„œ๋Š” ํŠธ์œˆ์ด ์ด ๊ฐ’์„ ์ค€๋‹ค โ€” ใ€Œ๋‹™์ด 40% ๋‹ซํ˜”๋‹คใ€๋Š” ์‚ฌ์‹ค์ด ์–ด๋””์„ ๊ฐ€ ์˜จ๋‹ค. ์ €์ž‘\n ์ค‘์—๋Š” ๊ทธ ์‚ฌ์‹ค์„ ์ฃผ๋Š” ๊ฒƒ์ด ์—†์–ด์„œ, ์†๋Œ€์ง€ ์•Š์œผ๋ฉด ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ๊ธฐ๋ณธ๊ฐ’์— ๋จธ๋ฌธ ์ฑ„ ์˜์˜\n ์•ˆ ์›€์ง์ธ๋‹ค. ํฌํฌ๊ฐ€ ์•ˆ ์˜ฌ๋ผ๊ฐ€๋Š” ๊ฒƒ์„ ์ €์ž‘์ž๊ฐ€ ใ€Œ์•ˆ ๋˜๋Š”๊ตฌ๋‚˜ใ€๋กœ ์ฝ๊ฒŒ ๋œ๋‹ค.\n\n **๋ฏธ๋ฆฌ๋ณด๊ธฐ ๊ฒƒ์ด์ง€ ์ž์‚ฐ์˜ ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค.** ์—ฌ๊ธฐ์„œ ๋ฏผ ๊ฐ’์€ ์ €์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค.\n */\n div[clips] {\n position: absolute;\n right: 8px;\n bottom: 8px;\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 8px 10px;\n color: rgba(255, 255, 255, 0.92);\n background-color: rgba(28, 28, 30, 0.72);\n border-radius: 8px;\n font-size: 0.72rem;\n }\n div[clips] label {\n display: grid;\n grid-template-columns: auto 96px 34px;\n align-items: center;\n gap: 8px;\n }\n /*\n ๋ง‰๋Œ€ ์œ„์— ๋†“๋Š” ๋‹จ์ถ”. ์ž์„ธ๋ฅผ ๋งŒ๋“  ์ž๋ฆฌ์— ์žˆ์–ด์•ผ ใ€Œ์ง€๊ธˆ ์ด๊ฒƒ์„ ๊ธฐ๋ณธ์œผ๋กœใ€๊ฐ€ ์ฝํžŒ๋‹ค.\n ์•‰ํž ๊ฒƒ์ด ์žˆ์„ ๋•Œ๋งŒ ๋‚˜์˜ค๋ฏ€๋กœ, ๋Š˜ ์„œ ์žˆ๋Š” ์นธ์ด ์•„๋‹ˆ๋‹ค.\n */\n div[clips] button[pose] {\n align-self: stretch;\n padding: 4px 8px;\n font: inherit;\n font-size: 0.7rem;\n color: rgba(255, 255, 255, 0.92);\n background-color: rgba(255, 255, 255, 0.14);\n border: 1px solid rgba(255, 255, 255, 0.22);\n border-radius: 5px;\n cursor: pointer;\n }\n div[clips] button[pose]:hover {\n background-color: rgba(255, 255, 255, 0.24);\n }\n div[clips] span[drive] {\n opacity: 0.6;\n font-size: 0.66rem;\n }\n div[clips] input {\n width: 96px;\n accent-color: var(--md-sys-color-primary);\n }\n div[clips] output {\n font-variant-numeric: tabular-nums;\n text-align: right;\n opacity: 0.85;\n }\n\n /* ์„ธ์šธ ์ˆ˜ ์—†๋Š” ์ƒํƒœ๋ฅผ ๋นˆ ํ™”๋ฉด์œผ๋กœ ๋‘์ง€ ์•Š๋Š”๋‹ค โ€” ์™œ ์•ˆ ๋ณด์ด๋Š”์ง€ ๋งํ•œ๋‹ค */\n div[cannot] {\n position: absolute;\n inset: 0;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--spacing-large, 12px);\n text-align: center;\n line-height: 1.6;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n background-color: ${unsafeCSS(WORKBENCH)};\n }\n `\n\n /** ์ €์ž‘ ์ค‘์ธ ๊ฒƒ. ์ €์žฅ ํ˜•์‹์œผ๋กœ ๋ฐ›๋Š”๋‹ค โ€” ๋„๋ฉด์ด ์†Œ๋น„ํ•˜๋Š” ๊ฒƒ์ด ์ด ํ˜•์‹์ด๋‹ค. */\n @property({ type: Object }) source?: FigureSource\n\n /**\n * ์ €์ž‘ ์ค‘์ธ ์ดˆ์•ˆ. **๊ธฐ๋ณธ๊ฐ’์ด ์ง€๊ธˆ ๋ฌด์—‡์ธ์ง€ ์•Œ๋ ค๊ณ ๋งŒ ์ฅ”๋‹ค** โ€” ๊ณ ์น˜์ง€ ์•Š๋Š”๋‹ค.\n *\n * `source` ๋กœ๋„ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ์ง€๋งŒ, ํ›„๋ณด๋ฅผ ๋ฏธ๋ฆฌ ๋ณผ ๋•Œ๋Š” `source` ๊ฐ€ ํ›„๋ณด์˜ ๊ฒƒ์ด๊ณ \n * ์ดˆ์•ˆ์€ ์—ด๋ ค ์žˆ๋Š” ๋„ํ˜•์˜ ๊ฒƒ์ด๋‹ค. ใ€Œ์ด ์ž์„ธ๋ฅผ ๊ธฐ๋ณธ์œผ๋กœใ€๋Š” ์—ด๋ ค ์žˆ๋Š” ๋„ํ˜•์—๋งŒ ๋œป์ด ์žˆ๋‹ค.\n */\n @property({ type: Object }) draft?: FigureDraft\n\n /**\n * ๋ณด๊ธฐ ์„ค์ •. ์ €์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค(`figure-view.ts`).\n *\n * ํ•œ๋™์•ˆ ์ด ํ™”๋ฉด๋งŒ ์กฐ๋ช…๊ณผ ํ™˜๊ฒฝ์„ **ํ•˜๋“œ์ฝ”๋”ฉ**ํ–ˆ๋‹ค. ์ €์ž‘์ž๊ฐ€ ํ™˜๊ฒฝ ํƒญ์—์„œ ๋ฌด์—‡์„ ๋ฐ”๊ฟ”๋„\n * ํŽธ์ง‘ ์บ”๋ฒ„์Šค๋งŒ ๋‹ฌ๋ผ์ง€๊ณ  ์—ฌ๊ธฐ๋Š” ๊ทธ๋Œ€๋กœ์˜€๋‹ค โ€” ๋‘ ํ™”๋ฉด์ด ๊ฐ™์€ ๊ฒƒ์„ ๋‹ค๋ฅด๊ฒŒ ๋ณด์—ฌ ์ฃผ์—ˆ๋‹ค.\n */\n @property({ type: Object }) view: ViewSettings = DEFAULT_VIEW\n\n @query('div[stage]') private stage!: HTMLDivElement\n\n /** ์„ธ์šธ ์ˆ˜ ์—†๋Š” ์‚ฌ์œ . ์—†์œผ๋ฉด ์„ธ์šด ๊ฒƒ์ด๋‹ค. */\n @state() private cannot = ''\n\n private scene?: SceneHandle\n /** ์ง€๊ธˆ ์„ธ์›Œ ๋‘” ๊ฒƒ์˜ ๊ฐ’. ๊ฐ™์œผ๋ฉด ๋‹ค์‹œ ์„ธ์šฐ์ง€ ์•Š๋Š”๋‹ค. */\n private standing?: string\n private watcher?: ResizeObserver\n\n /** ์ง€๊ธˆ ๋ฏผ clip ๋ฐฐ์†. clip ์ด๋ฆ„ โ†’ ์ˆ˜. **์ €์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค.** */\n @state() private driving: Record<string, number> = {}\n /** ์ง€๊ธˆ ๋ฏผ ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’. ์ด๋ฆ„ โ†’ `range` ์˜ ๋‹จ์œ„๋กœ ์žฐ ์ˆ˜. **์ €์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค.** */\n @state() private giving: Record<string, number> = {}\n\n render() {\n const clips = this.source?.animations ?? []\n const parameters = this.source?.parameters ?? []\n\n return html`\n <div stage></div>\n ${this.cannot\n ? html`<div cannot>${this.cannot}</div>`\n : html`<div legend>\n ${PREVIEW_WAYS.map(way => html`<span>${way.axes.length === 0 ? i18next.t('figure.label.preview-base') : way.name}</span>`)}\n </div>\n ${clips.length + parameters.length > 0 ? this.renderDrivers(clips, parameters) : ''}`}\n `\n }\n\n /**\n * ์›€์ง์ž„ ํ•˜๋‚˜์— ์†์žก์ด ํ•˜๋‚˜.\n *\n * ๋‘ ๊ฐˆ๋ž˜๋ฅผ **๋ˆˆ๊ธˆ์ด ๋‹ค๋ฅธ ์ฑ„๋กœ** ๋‚ธ๋‹ค. clip ์€ ๋ฐฐ์†์ด๋ผ 0 ์ด ๋ฉˆ์ถค์ด๊ณ  0~3 ์ด ๋œป์ด\n * ์žˆ์œผ๋ฉฐ, ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ๋ฌผ๋ฆฌ๋Ÿ‰์ด๋ผ ๊ทธ `range` ๊ฐ€ ๊ณง ๋ˆˆ๊ธˆ์ด๊ณ  ๋‹จ์œ„๊ฐ€ ๋”ฐ๋ผ ๋ถ™๋Š”๋‹ค. ํ•˜๋‚˜์˜\n * 0~1 ๋กœ ๋ญ‰๋šฑ๊ทธ๋ฆฌ๋ฉด ใ€Œ1ใ€์ด ๋ฌด์Šจ ๋œป์ธ์ง€ ๋งค๋ฒˆ ํ—ท๊ฐˆ๋ฆฌ๊ณ , 1200mm ๋ฅผ ๋„ฃ์–ด ๋ณด๋ ค๋˜ ์ €์ž‘์ž๊ฐ€\n * ๋„ฃ์„ ์ž๋ฆฌ๋ฅผ ๋ชป ์ฐพ๋Š”๋‹ค.\n */\n private renderDrivers(\n clips: NonNullable<FigureSource['animations']>,\n parameters: NonNullable<FigureSource['parameters']>\n ) {\n /*\n ์ง€๊ธˆ ์„ธ์šด ์ž์„ธ๋ฅผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์•‰ํžˆ๋Š” ์ž๋ฆฌ. **๋ง‰๋Œ€ ์˜†์— ๋‘”๋‹ค** โ€” ์ž์„ธ๋ฅผ ๋งŒ๋“  ๊ณณ์ด ์—ฌ๊ธฐ๋ผ,\n ๊ฐ’์„ ์ฝ์–ด ํŒŒ๋ผ๋ฏธํ„ฐ ์นธ์œผ๋กœ ์˜ฎ๊ฒจ ์ ๋Š” ์™•๋ณต์ด ์—†์–ด์ง„๋‹ค. ์•‰ํž ๊ฒƒ์ด ์—†์œผ๋ฉด ์•„์˜ˆ ์•ˆ ๋‚˜์˜จ๋‹ค.\n */\n const changes = poseChanges(this.draft, this.giving)\n\n return html`\n <div clips>\n ${changes.length > 0\n ? html`<button\n pose\n title=${i18next.t('figure.text.pose-as-default-explained')}\n @click=${() => this.poseAsDefault()}\n >\n ${i18next.t('figure.button.pose-as-default')}\n </button>`\n : ''}\n ${parameters.map(parameter => {\n const range = parameter.range\n const value = this.giving[parameter.name] ?? parameter.default ?? range?.min ?? 0\n const step = range ? Math.max((range.max - range.min) / 100, 0.01) : 1\n\n return html`\n <label>\n <span>${parameter.label ?? parameter.name} <span drive>${range?.unit ?? ''}</span></span>\n <input\n type=\"range\"\n min=${range?.min ?? 0}\n max=${range?.max ?? 1}\n step=${step}\n .value=${String(value)}\n @input=${(e: Event) => this.give(parameter.name, Number((e.target as HTMLInputElement).value))}\n />\n <output>${Math.round(value)}</output>\n </label>\n `\n })}\n ${clips.map(clip => {\n const value = this.driving[clip.name] ?? 1\n\n return html`\n <label>\n <span>${clip.name} <span drive>${i18next.t('figure.label.playback-speed')}</span></span>\n <input\n type=\"range\"\n min=\"0\"\n max=\"3\"\n step=\"0.05\"\n .value=${String(value)}\n @input=${(e: Event) => this.drive(clip.name, Number((e.target as HTMLInputElement).value))}\n />\n <output>${value.toFixed(2)}</output>\n </label>\n `\n })}\n </div>\n `\n }\n\n /**\n * ์„ธ์›Œ ๋‘” ์ธ์Šคํ„ด์Šค ์ „๋ถ€์— ๊ฐ™์€ ๊ฐ’์„ ์ค€๋‹ค.\n *\n * ํ•˜๋‚˜๋งŒ ๋ชฐ๋ฉด ์„ธ ๋ฐฐ์œจ์ด ์„œ๋กœ ๋‹ค๋ฅธ ์ž์„ธ๋กœ ์„œ์„œ, ํฌ๊ธฐ ๋ฐ˜์‘์„ ๋ณด๋ ค๊ณ  ๋‚˜๋ž€ํžˆ ๋†“์€ ๋œป์ด\n * ์‚ฌ๋ผ์ง„๋‹ค.\n */\n private drive(name: string, value: number): void {\n this.driving = { ...this.driving, [name]: value }\n this.tellInstances('clips', this.driving)\n }\n\n /**\n * ํŒŒ๋ผ๋ฏธํ„ฐ ๊ฐ’์„ ์ค€๋‹ค โ€” **`range` ์˜ ๋‹จ์œ„ ๊ทธ๋Œ€๋กœ๋‹ค.**\n *\n * 0~1 ๋กœ ๋ฐ”๊ฟ”์„œ ์ฃผ์ง€ ์•Š๋Š”๋‹ค. ๊ทธ ํ™˜์‚ฐ์€ ๋Ÿฐํƒ€์ž„์˜ ์ผ์ด๊ณ , ์—ฌ๊ธฐ์„œ ํ•œ ๋ฒˆ ๋” ํ•˜๋ฉด ๋‘ ๊ณณ์ด\n * ๊ฐˆ๋ฆด ์ˆ˜ ์žˆ๋‹ค. ์ €์ž‘์ž๊ฐ€ ํ™”๋ฉด์—์„œ ๋ณด๋Š” 1200 ์ด ์”ฌ์— ๊ทธ๋Œ€๋กœ ๊ฐ„๋‹ค.\n */\n private give(name: string, value: number): void {\n this.giving = { ...this.giving, [name]: value }\n this.tellInstances('parameters', this.giving)\n }\n\n /**\n * ์„ธ์šด ์ž์„ธ๋ฅผ ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ โ€” **์…ˆ์€ ์—ฌ๊ธฐ์„œ ํ•˜์ง€ ์•Š๋Š”๋‹ค.**\n *\n * ์ดˆ์•ˆ์„ ์ฅ๊ณ  ์žˆ๋Š” ๊ฒƒ์€ ํŽ˜์ด์ง€์ด๊ณ , ๋˜๋Œ๋ฆฌ๊ธฐ์™€ ใ€Œ์ €์žฅ ์•ˆ ๋จใ€๋„ ๊ฑฐ๊ธฐ์„œ ๋งค๊ธด๋‹ค. ์—ฌ๊ธฐ์„œ\n * ์ดˆ์•ˆ์„ ๋งŒ๋“ค์–ด ๋ณด๋‚ด๋ฉด ๊ทธ ์…‹์ด ๋‘ ๊ณณ์œผ๋กœ ๊ฐˆ๋ฆฐ๋‹ค. ๋ฏผ ๊ฐ’๋งŒ ์˜ฌ๋ฆฐ๋‹ค.\n */\n private poseAsDefault(): void {\n this.dispatchEvent(\n new CustomEvent('pose-as-default', { detail: { values: { ...this.giving } }, bubbles: true, composed: true })\n )\n }\n\n private tellInstances(key: 'clips' | 'parameters', values: Record<string, number>): void {\n for (const component of this.scene?.root?.components ?? []) {\n component.set?.(key, { ...values })\n }\n }\n\n /**\n * ๋ณด๊ธฐ ์„ค์ •์ด ๋ฐ”๋€Œ๋ฉด **๋‹ค์‹œ ์„ธ์šฐ์ง€ ์•Š๊ณ  ์”ฌ์— ๋„ฃ๋Š”๋‹ค** โ€” ๋‘ ๊ฐœ๋งŒ ๋นผ๊ณ .\n *\n * ์กฐ๋ช…ยทํ™˜๊ฒฝยท๋ฐ”ํƒ•์€ ์”ฌ์ด ์Šค์Šค๋กœ ๋ฐ˜์‘ํ•œ๋‹ค(`three-capability` ์˜ `onchange`). ์Šฌ๋ผ์ด๋”๋ฅผ\n * ๋„๋Š” ๋™์•ˆ ๋‹ค์‹œ ์„ธ์šฐ๋ฉด ์นด๋ฉ”๋ผ๊ฐ€ ๋งค ํ”„๋ ˆ์ž„ ์ฒ˜์Œ์œผ๋กœ ๋Œ์•„๊ฐ„๋‹ค.\n *\n * ์ขŒํ‘œ ๊ธฐ์ค€๊ณผ ์ฒœ์žฅ ๋†’์ด๋Š” ๋‹ค๋ฅด๋‹ค. ์”ฌ์ด ๊ทธ ๋‘˜๋กœ ์ธ์Šคํ„ด์Šค ๋†’์ด๋ฅผ ์ •ํ•˜๋Š”๋ฐ, ๊ทธ ๊ณ„์‚ฐ์€ ์„ธ์šธ\n * ๋•Œ ํ•œ ๋ฒˆ ๋ˆ๋‹ค โ€” ์ด๋ฏธ ์„ธ์›Œ ๋‘” ๊ฒƒ์— ๋„ฃ์–ด ๋ด์•ผ ์ž๋ฆฌ๊ฐ€ ์•ˆ ๋ฐ”๋€๋‹ค. ๊ทธ๊ฒƒ๋งŒ ๋‹ค์‹œ ์„ธ์šด๋‹ค.\n */\n willUpdate(changed: Map<string, unknown>) {\n if (!this.hasUpdated) return\n\n if (changed.has('source')) {\n this.standUp()\n return\n }\n\n if (!changed.has('view')) return\n\n const before = changed.get('view') as ViewSettings | undefined\n const now = this.view ?? DEFAULT_VIEW\n if (before?.placement !== now.placement || before?.ceilingHeight !== now.ceilingHeight) {\n this.standUp()\n return\n }\n\n this.scene?.root?.set?.(sceneLook(now))\n }\n\n firstUpdated() {\n this.standUp()\n this.watcher = new ResizeObserver(() => this.scene?.resize?.())\n this.watcher.observe(this)\n }\n\n disconnectedCallback() {\n super.disconnectedCallback()\n this.watcher?.disconnect()\n this.watcher = undefined\n this.teardown()\n }\n\n /**\n * ์ €์ž‘ํ•œ ๊ฒƒ์„ ์ปดํŒŒ์ผํ•ด ์„ธ์šด๋‹ค.\n *\n * **ํ˜•์‹์„ ์–ด๊ฒผ์œผ๋ฉด ์„ธ์šฐ์ง€ ์•Š๋Š”๋‹ค.** ๋ฐ˜์ฏค ์„ธ์šด ๊ฒƒ์„ ๋ณด์—ฌ ์ฃผ๋ฉด ๋ฌด์—‡์ด ์ž˜๋ชป๋๋Š”์ง€ ์•Œ ์ˆ˜\n * ์—†๋‹ค. ํŒ์ • ํŒจ๋„์ด ์ด๋ฏธ ์‚ฌ์œ ๋ฅผ ๋งํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ์—ฌ๊ธฐ์„œ๋Š” ์„ธ์šธ ์ˆ˜ ์—†๋‹ค๊ณ ๋งŒ ํ•œ๋‹ค.\n */\n private standUp() {\n const source = this.source\n if (!source || source.parts.length === 0) {\n this.cannot = i18next.t('figure.text.preview-needs-a-part')\n this.teardown()\n return\n }\n\n const view = this.view ?? DEFAULT_VIEW\n /* ์”ฌ์ด ์ด ๋‘˜๋กœ ์ธ์Šคํ„ด์Šค ๋†’์ด๋ฅผ ์ •ํ•œ๋‹ค โ€” ์„œ๋ช…์— ์•ˆ ๋„ฃ์œผ๋ฉด ๋‹ค์‹œ ์„ธ์›Œ๋„ ๊ทธ๋Œ€๋กœ ์„ ๋‹ค. */\n const signature = JSON.stringify([source, view.placement, view.ceilingHeight])\n if (this.scene && this.standing === signature) return\n\n const { errors } = validate(source)\n if (errors.length > 0) {\n this.cannot = i18next.t('figure.text.preview-blocked-by-errors')\n this.teardown()\n return\n }\n\n this.teardown()\n // ํ‘œ๋ณธ์ด ๋ฐ”๋€Œ๋ฉด ๋ฏผ ๊ฐ’๋„ ์ฒ˜์Œ์œผ๋กœ ๋Œ๋ฆฐ๋‹ค โ€” ๋‹ค๋ฅธ ์ž์‚ฐ์˜ clip ์ด๋ฆ„์ด ๋‚จ์œผ๋ฉด ์•ˆ ๋œ๋‹ค.\n this.driving = {}\n\n try {\n registerFigure(compile(source) as never)\n\n /*\n ๋„๋ฉด์ด ํ•˜๋Š” ์ผ์„ ๊ทธ๋Œ€๋กœ ํ•œ๋‹ค. ์ปดํฌ๋„ŒํŠธ์—๋Š” ํƒ€์ž… ์ด๋ฆ„๊ณผ ์ž๋ฆฌยทํฌ๊ธฐ๋งŒ ์ ๋Š”๋‹ค โ€”\n ์ฒญ์‚ฌ์ง„๋„ ์›๋ณธ๋„ ๋„๋ฉด์— ๋“ค์–ด๊ฐ€์ง€ ์•Š๋Š”๋‹ค.\n\n ๊ฐ€์žฅ ํฐ ๊ฒƒ์ด ๋“ค์–ด๊ฐˆ ๋งŒํผ ํŒ์„ ์žก๊ณ , ์„ธ๋กœ๋กœ ์ค„์„ ๋‚˜๋ˆ  ๋‚˜๋ž€ํžˆ ๋†“๋Š”๋‹ค.\n */\n const { base } = source\n const biggest = PREVIEW_FACTOR\n /** ์ด ์กฐํ•ฉ์—์„œ ์ถ•๋ณ„ ๋ฐฐ์œจ. ์กฐํ•ฉ์— ๋“  ์ถ•๋งŒ ํ‚ค์šด๋‹ค. */\n const growth = (way: (typeof PREVIEW_WAYS)[number]) => ({\n x: way.axes.includes('x') ? PREVIEW_FACTOR : 1,\n y: way.axes.includes('y') ? PREVIEW_FACTOR : 1,\n z: way.axes.includes('z') ? PREVIEW_FACTOR : 1\n })\n // ์—ฌ๋ฐฑ์„ ๋„‰๋„‰ํžˆ ๋‘๋ฉด ํ™”๋ฉด์—์„œ ํ˜•์ƒ์ด ์ž‘์•„์ง„๋‹ค. ๊ฐ€์žฅ ํฐ ๊ฒƒ์ด ๊ฒจ์šฐ ๋“ค์–ด๊ฐˆ ๋งŒํผ๋งŒ ์žก๋Š”๋‹ค.\n /** ๋„ค ์นธ์”ฉ ๋‘ ์ค„. */\n const COLUMNS = 4\n const cell = { x: base.x * biggest * 1.25, z: base.z * biggest * 1.25 }\n const rows = Math.ceil(PREVIEW_WAYS.length / COLUMNS)\n /*\n ์”ฌ์˜ ๋‚ฑ๋ง์ด ํ˜•์‹๊ณผ ๋‹ค๋ฅด๋‹ค โ€” `width` ๊ฐ€ ํ˜•์‹์˜ x, `height` ๊ฐ€ z, `depth` ๊ฐ€ y ๋‹ค.\n ์˜ฎ๊ธฐ๋Š” ์ผ์„ ์—ฌ๊ธฐ ํ•œ ์ค„์— ๋ชจ์•„ ๋‘”๋‹ค.\n\n `depth` ๋ฅผ ๋Š˜ ์ ๋Š” ์ด์œ ๊ฐ€ ์žˆ๋‹ค. ์•ˆ ์ ์œผ๋ฉด ํ‰๋ฉด ๋‘ ์ถ•์˜ ๊ธฐํ•˜ํ‰๊ท ์œผ๋กœ ์žกํ˜€์„œ,\n ใ€Œy ๋งŒ ํ‚ค์šด๋‹คใ€๊ฐ€ xยทz ๋ฅผ ์•ˆ ๊ฑด๋“œ๋ฆฌ๋Š”๋ฐ๋„ ๋†’์ด๊ฐ€ ์•ˆ ์˜ค๋ฅธ๋‹ค.\n\n ๋†’์ด๋Š” **๋ฐฐ์น˜ ๊ธฐ์ค€์ด ์ •ํ•œ๋‹ค.** ๋ฐ”๋‹ฅ ๊ธฐ๋ฐ˜์€ ๋•…์—์„œ ์˜ฌ๋ผ์˜ค๊ณ , ์ฒœ์ • ๊ธฐ๋ฐ˜์€ ์ฒœ์žฅ์—\n ๋ถ™์–ด ๋‚ด๋ ค์˜จ๋‹ค. ์—ฌ๋Ÿ์„ ๋‚˜๋ž€ํžˆ ์„ธ์šฐ๋Š” ์ž๋ฆฌ๋ผ ์ด๊ฒƒ์ด ๋ˆˆ์— ๋ฐ”๋กœ ๋ณด์ธ๋‹ค โ€” ๋ฐ”๋‹ฅ ๊ธฐ๋ฐ˜์ด๋ฉด\n ๋ฐ‘๋ฉด์ด, ์ฒœ์ • ๊ธฐ๋ฐ˜์ด๋ฉด ์œ—๋ฉด์ด ํ•œ ์ค„์ด ๋œ๋‹ค.\n */\n const components = PREVIEW_WAYS.map((way, at) => {\n const grow = growth(way)\n const column = at % COLUMNS\n const row = Math.floor(at / COLUMNS)\n const width = Math.round(base.x * grow.x)\n const height = Math.round(base.z * grow.z)\n const tall = Math.round(base.y * grow.y)\n\n return {\n type: source.type,\n id: `at-${way.name}`,\n // ์นธ ๊ฐ€์šด๋ฐ์— ๋†“๋Š”๋‹ค โ€” ํฌ๊ธฐ๊ฐ€ ์ €๋งˆ๋‹ค ๋‹ฌ๋ผ ์™ผ์ชฝ์— ๋งž์ถ”๋ฉด ์ค„์ด ์•ˆ ์ฝํžŒ๋‹ค.\n left: Math.round(column * cell.x + (cell.x - width) / 2),\n top: Math.round(row * cell.z + (cell.z - height) / 2),\n width,\n height,\n depth: tall\n }\n })\n\n const draft = {\n width: Math.round(cell.x * COLUMNS),\n height: Math.round(cell.z * rows),\n /*\n ํŒ์˜ ๋†’์ด๋„ ๊ฐ€์žฅ ํฐ ์ธ์Šคํ„ด์Šค๋ฅผ ๋‹ด์•„์•ผ ํ•œ๋‹ค. ์•ˆ ์ฃผ๋ฉด ์นด๋ฉ”๋ผ๊ฐ€ ํ‰๋ฉด๋งŒ ๋ณด๊ณ  ์ž๋ฆฌ๋ฅผ\n ์žก์•„์„œ, ํ‚ค๊ฐ€ ํฐ ๋ชจ๋ธ์€ ๋ฐ‘๋™๋งŒ ๋ณด์ธ๋‹ค โ€” ์‹œ๊ทธ๋„ํƒ€์›Œ๋ฅผ 2 ๋ฐฐ๋กœ ๋†“์œผ๋ฉด 2200 ์ธ๋ฐ ํŒ์ด\n ๊ทธ๊ฒƒ์„ ๋ชจ๋ฅด๋ฉด ๋ฐ›์นจ๋งŒ ํ™”๋ฉด์— ๋“ ๋‹ค.\n\n ์–ด๋””์— ์˜ฌ๋ ค ๋†“์„์ง€๋Š” **์”ฌ์ด ์ •ํ•˜๋ฏ€๋กœ**(`FigureRealObject.effectiveZPos`), ์—ฌ๊ธฐ์„œ๋Š”\n ์–ด๋А ๊ฒฝ์šฐ์—๋„ ๋‹ด๊ธฐ๋Š” ๊ฒฝ๊ณ„๋งŒ ์žก๋Š”๋‹ค. ๋ฐ”๋‹ฅ ๊ธฐ๋ฐ˜์€ ๊ฐ€์žฅ ํฐ ๊ฒƒ์˜ ํ‚ค๊นŒ์ง€, ์ฒœ์ • ๊ธฐ๋ฐ˜์€\n ์ฒœ์žฅ๊นŒ์ง€๋‹ค. ๋ฐฐ์น˜๋ฅผ ๋†’์ด๋กœ ์˜ฎ๊ธฐ๋Š” ๊ณ„์‚ฐ์„ ์—ฌ๊ธฐ์„œ ๋‹ค์‹œ ์“ฐ๋ฉด ๊ทธ๊ฒƒ์ด ๋‘ ๋ฒŒ์งธ๊ฐ€ ๋œ๋‹ค.\n */\n depth: previewBoardDepth(source, view.ceilingHeight, biggest)\n }\n\n this.scene = create({\n target: this.stage,\n model: {\n type: 'model-layer',\n width: draft.width,\n height: draft.height,\n depth: draft.depth,\n threed: true,\n sky: 'color',\n /*\n ๋ณด๊ธฐ ์„ค์ •์„ ๊ทธ๋Œ€๋กœ ์‹ฃ๋Š”๋‹ค.\n\n ์—ฌ๊ธฐ๋งŒ ์กฐ๋ช…ยทํ™˜๊ฒฝยท๋ฐ”ํƒ•์„ ํ•˜๋“œ์ฝ”๋”ฉํ•˜๊ณ  ์žˆ์—ˆ๋‹ค. ์ €์ž‘์ž๊ฐ€ ํ™˜๊ฒฝ ํƒญ์—์„œ ์กฐ๋ช…์„\n ์˜ฌ๋ ค๋„ ํŽธ์ง‘ ์บ”๋ฒ„์Šค๋งŒ ๋ฐ์•„์ง€๊ณ  ์ด ํ™”๋ฉด์€ ๊ทธ๋Œ€๋กœ์—ฌ์„œ, ๊ฐ™์€ ๊ฒƒ์„ ๋‘ ํ™”๋ฉด์ด\n ๋‹ค๋ฅด๊ฒŒ ๋ณด์—ฌ ์ฃผ์—ˆ๋‹ค.\n\n `sceneLook` ์ด ์ขŒํ‘œ ๊ธฐ์ค€๊ณผ ์ฒœ์žฅ ๋†’์ด๋ฅผ ๋นผ๊ณ  ์ค€๋‹ค โ€” ์”ฌ์ด ์•„๋Š” ์ด๋ฆ„์ด ์•„๋‹ˆ๊ฑฐ๋‚˜\n (`ceilingHeight`) ํŽธ์ง‘ ์บ”๋ฒ„์Šค์— ์ƒˆ๋ฉด ์•ˆ ๋˜๋Š” ๊ฒƒ(`placement`)์ด๋ผ์„œ๋‹ค. ๋‘˜ ๋‹ค ์•„๋ž˜์—\n ์”ฌ์˜ ๋‚ฑ๋ง๋กœ ๋”ฐ๋กœ ์‹ฃ๋Š”๋‹ค.\n */\n ...sceneLook(view),\n placement: view.placement,\n /*\n ๋ถ€์ฐฉ๋ฉด์˜ ๋†’์ด. ์”ฌ์ด ์ด ์ž๋ฆฌ๋ฅผ ๊ฐ–๊ณ (`real-object.ts` ์˜ `sceneHeights`), ์ฒœ์ • ๊ธฐ๋ฐ˜\n ๋„ํ˜•์ด ์—ฌ๊ธฐ์„œ ์ œ ๋†’์ด๋ฅผ ์–ป๋Š”๋‹ค. ๋„๋ฉด์—์„œ๋Š” ํ˜„์žฅ์ด ์ด ๊ฐ’์„ ์ค€๋‹ค.\n */\n heights: { floor: 0, ceiling: view.ceilingHeight },\n pixelRatio: Math.min(3, (window.devicePixelRatio || 1) * 2),\n components\n },\n // ๋ณด๊ธฐ๋งŒ ํ•˜๋Š” ์ž๋ฆฌ๋‹ค. ์ง‘๊ฑฐ๋‚˜ ๋Œ ์ˆ˜ ์—†์–ด์•ผ ํ•œ๋‹ค.\n mode: 0\n }) as SceneHandle\n\n this.standing = signature\n this.scene.resize?.()\n this.scene.fit?.('ratio')\n this.scene.root?.fitCameraToModel?.()\n this.cannot = ''\n } catch (e) {\n // ์›์ธ์„ ์ง€์–ด๋‚ด์ง€ ์•Š๋Š”๋‹ค โ€” ๋˜์ง„ ๋ง์„ ๊ทธ๋Œ€๋กœ ๋ณด์—ฌ ์ค€๋‹ค.\n this.cannot = (e as Error).message\n }\n }\n\n private teardown() {\n this.scene?.dispose?.()\n this.scene = undefined\n this.standing = undefined\n }\n}\n"]}
@@ -65,8 +65,9 @@ export declare class FigureReport extends FigureReport_base {
65
65
  * ์ง์ ‘ ๋‹ตํ•˜์ง€ ์•Š๋Š”๋‹ค โ€” ํ˜•์ƒ์ด ์„ ์–ธ๋œ ํ•œ๋„ ์•ˆ์ธ์ง€๋ฅผ ๋งํ•  ๋ฟ์ด๋‹ค. ๊ทธ๋ž˜์„œ ๊ฐœ์ˆ˜๋ฅผ
66
66
  * ๋จธ๋ฆฌ์— ์˜ฌ๋ฆฌ๊ณ  ๋“ฑ๊ธ‰์€ ์˜†์˜ badge ๋กœ ๋‚ด๋ฆฐ๋‹ค.
67
67
  *
68
- * ๊ทผ๊ฑฐ๋ฅผ ํ•จ๊ป˜ ๋‚ธ๋‹ค. ์ด ๊ฐœ์ˆ˜์˜ ๋ถ„๋ชจ๋Š” ์‹ค์ธก์ด ์•„๋‹ˆ๋ผ ์„ค๊ณ„ ๋ฌธ์„œ์˜ ๋ชฉํ‘œ์น˜์ด๊ณ (๋ฏธ๊ฒฐ
69
- * D-20), ๊ทธ ์‚ฌ์‹ค์ด ํ™”๋ฉด์— ์—†์œผ๋ฉด ์žฌ ๋ณธ ๊ฐ’์ฒ˜๋Ÿผ ์ฝํžŒ๋‹ค.
68
+ * ๊ทผ๊ฑฐ๋ฅผ ํ•จ๊ป˜ ๋‚ธ๋‹ค. ๋ฌถ์Œ์œผ๋กœ ๊ฐˆ๋ฆฌ๋Š” ๊ฐœ์ˆ˜์˜ ๋ถ„๋ชจ๋Š” **์‹ค์ธก**์ด๊ณ (2026-09-18, Apple M5), ์žฐ
69
+ * ๊ธฐ๊ณ„์™€ ๋‚ ์งœ๋ฅผ ํ•จ๊ป˜ ์ ๋Š”๋‹ค โ€” ์ ์ง€ ์•Š์œผ๋ฉด ์–ด๋””์„œ๋‚˜ ์ฐธ์ธ ์ˆ˜๋กœ ์ฝํžŒ๋‹ค. ์‚ผ๊ฐํ˜• ์ชฝ์€ ์•„์ง ์„ค๊ณ„
70
+ * ๋ฌธ์„œ์˜ ๋ชฉํ‘œ์น˜๋ผ ๊ทธ๋ ‡๋‹ค๊ณ  ์ ๋Š”๋‹ค.
70
71
  */
71
72
  private renderVerdict;
72
73
  /**
@@ -6,7 +6,7 @@ import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
6
6
  import { i18next, localize } from '@operato/i18n';
7
7
  import { ScrollbarStyles } from '@operato/styles';
8
8
  import { blocksRelease, compile, costCurveSvg, costOf, scoreOf, sizingReport, validate } from '@hatiolab/figure-model';
9
- import { capacityOf } from './scene-budget.js';
9
+ import { capacityOf, MEASURED } from './scene-budget.js';
10
10
  import { maturityOf } from './maturity.js';
11
11
  /**
12
12
  * ํŒ๋‹จ ํŒจ๋„. ๋ชจ๋ธ๋Ÿฌ ํ™”๋ฉด์— **๋Š˜ ๋–  ์žˆ๋‹ค.**
@@ -488,8 +488,9 @@ let FigureReport = class FigureReport extends localize(i18next)(LitElement) {
488
488
  * ์ง์ ‘ ๋‹ตํ•˜์ง€ ์•Š๋Š”๋‹ค โ€” ํ˜•์ƒ์ด ์„ ์–ธ๋œ ํ•œ๋„ ์•ˆ์ธ์ง€๋ฅผ ๋งํ•  ๋ฟ์ด๋‹ค. ๊ทธ๋ž˜์„œ ๊ฐœ์ˆ˜๋ฅผ
489
489
  * ๋จธ๋ฆฌ์— ์˜ฌ๋ฆฌ๊ณ  ๋“ฑ๊ธ‰์€ ์˜†์˜ badge ๋กœ ๋‚ด๋ฆฐ๋‹ค.
490
490
  *
491
- * ๊ทผ๊ฑฐ๋ฅผ ํ•จ๊ป˜ ๋‚ธ๋‹ค. ์ด ๊ฐœ์ˆ˜์˜ ๋ถ„๋ชจ๋Š” ์‹ค์ธก์ด ์•„๋‹ˆ๋ผ ์„ค๊ณ„ ๋ฌธ์„œ์˜ ๋ชฉํ‘œ์น˜์ด๊ณ (๋ฏธ๊ฒฐ
492
- * D-20), ๊ทธ ์‚ฌ์‹ค์ด ํ™”๋ฉด์— ์—†์œผ๋ฉด ์žฌ ๋ณธ ๊ฐ’์ฒ˜๋Ÿผ ์ฝํžŒ๋‹ค.
491
+ * ๊ทผ๊ฑฐ๋ฅผ ํ•จ๊ป˜ ๋‚ธ๋‹ค. ๋ฌถ์Œ์œผ๋กœ ๊ฐˆ๋ฆฌ๋Š” ๊ฐœ์ˆ˜์˜ ๋ถ„๋ชจ๋Š” **์‹ค์ธก**์ด๊ณ (2026-09-18, Apple M5), ์žฐ
492
+ * ๊ธฐ๊ณ„์™€ ๋‚ ์งœ๋ฅผ ํ•จ๊ป˜ ์ ๋Š”๋‹ค โ€” ์ ์ง€ ์•Š์œผ๋ฉด ์–ด๋””์„œ๋‚˜ ์ฐธ์ธ ์ˆ˜๋กœ ์ฝํžŒ๋‹ค. ์‚ผ๊ฐํ˜• ์ชฝ์€ ์•„์ง ์„ค๊ณ„
493
+ * ๋ฌธ์„œ์˜ ๋ชฉํ‘œ์น˜๋ผ ๊ทธ๋ ‡๋‹ค๊ณ  ์ ๋Š”๋‹ค.
493
494
  */
494
495
  renderVerdict() {
495
496
  const score = this.score;
@@ -525,7 +526,11 @@ let FigureReport = class FigureReport extends localize(i18next)(LitElement) {
525
526
  per: capacity.per.toLocaleString(),
526
527
  budget: capacity.budget.toLocaleString()
527
528
  })}
528
- <em>${i18next.t('figure.text.budget-not-measured-yet')}</em>
529
+ <em>
530
+ ${capacity.bound === 'groups'
531
+ ? i18next.t('figure.text.budget-measured-on', { gpu: MEASURED.gpu, on: MEASURED.on })
532
+ : i18next.t('figure.text.budget-not-measured-yet')}
533
+ </em>
529
534
  </p>
530
535
  </section>
531
536
  `;
@@ -1 +1 @@
1
- {"version":3,"file":"figure-report.js","sourceRoot":"","sources":["../../client/modeller/figure-report.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport { css, html, LitElement, nothing, svg } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { unsafeSVG } from 'lit/directives/unsafe-svg.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\nimport { blocksRelease, compile, costCurveSvg, costOf, scoreOf, sizingReport, validate } from '@hatiolab/figure-model'\nimport type { FigureCost, FigureScore, FigureSource } from '@hatiolab/figure-model'\n\nimport { capacityOf } from './scene-budget.js'\nimport { maturityOf } from './maturity.js'\nimport type { MaturityAxis } from './maturity.js'\nimport type { FigureCapacity } from './scene-budget.js'\n\n/**\n * ํŒ๋‹จ ํŒจ๋„. ๋ชจ๋ธ๋Ÿฌ ํ™”๋ฉด์— **๋Š˜ ๋–  ์žˆ๋‹ค.**\n *\n * ์ €์žฅ์„ ์„ ํƒํ•ด์•ผ ์•„๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค. ๋ถ€ํ’ˆ์„ ํ•˜๋‚˜ ๋†“์„ ๋•Œ๋งˆ๋‹ค ๋ฌด๊ฒŒ์™€ ์ ์ˆ˜๊ฐ€ ์›€์ง์ด๊ณ ,\n * ๊ทธ๊ฒƒ์ด ๋ณด์—ฌ์•ผ ์ €์ž‘์ž๊ฐ€ ๊ณ ์น  ์ˆ˜ ์žˆ๋‹ค. ใ€Œ๋ฌด์—‡ ๋•Œ๋ฌธ์— ์ ์ˆ˜๊ฐ€ ๋‚ฎ์€๊ฐ€ใ€๋ฅผ ๋งํ•ด ์ฃผ์ง€\n * ์•Š์œผ๋ฉด ์ ์ˆ˜๋Š” ์ž”์†Œ๋ฆฌ์ผ ๋ฟ์ด๋‹ค.\n *\n * ## ์…ˆ์„ ์—ฌ๊ธฐ์„œ ํ•˜์ง€ ์•Š๋Š”๋‹ค\n *\n * ๊ฒ€์ฆยท์›๊ฐ€ยท์ ์ˆ˜๋Š” ์ „๋ถ€ `@hatiolab/figure-model` ์ด ํ•œ๋‹ค. ํ™”๋ฉด์€ **๋ถ€๋ฅด๊ณ  ๋ณด์—ฌ ์ค„\n * ๋ฟ**์ด๋‹ค. ํ•œ๋„๋‚˜ ๋“ฑ๊ธ‰ ๊ฒฝ๊ณ„๋ฅผ ํ™”๋ฉด์ด ๋‹ค์‹œ ์ •ํ•˜๋ฉด ์„œ๋ฒ„๊ฐ€ ๊ฑฐ์ ˆํ•  ๊ฒƒ์„ ํ™”๋ฉด์ด\n * ํ†ต๊ณผ์‹œํ‚ค๊ฒŒ ๋œ๋‹ค.\n */\n@customElement('figure-report')\nexport class FigureReport extends localize(i18next)(LitElement) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n overflow-y: auto;\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 section {\n padding: var(--spacing-medium, 8px) var(--spacing-large, 12px);\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n section > h3 {\n margin: 0 0 6px 0;\n font-size: var(--ui-t-micro, 11px);\n font-weight: 700;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n\n /* โ”€โ”€ ๋ช‡ ๊ฐœ๊นŒ์ง€ ํŽธํ•œ๊ฐ€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n ๋กœ์šฐํด๋ฆฌ์˜ ๊ฐ’์€ ใ€Œ์–ผ๋งˆ๋‚˜ ๋งŽ์ด ํŽธํ•˜๊ฒŒ ๋†“์„ ์ˆ˜ ์žˆ๋‚˜ใ€๋‹ค. ๊ทธ ๋‹ต์ด ๋จธ๋ฆฌ์— ์˜จ๋‹ค.\n ๋“ฑ๊ธ‰์€ ํ˜•์ƒ ์ž์ฒด๊ฐ€ ํ•œ๋„ ์•ˆ์ธ์ง€๋ฅผ ๋งํ•  ๋ฟ์ด๋ผ ์˜†์˜ ์ž‘์€ badge ๋กœ ๋‘”๋‹ค. */\n div[verdict] {\n display: flex;\n align-items: baseline;\n gap: 6px;\n }\n span[capacity] {\n font-size: 2.1rem;\n font-weight: 800;\n line-height: 1;\n letter-spacing: -0.01em;\n color: var(--md-sys-color-primary);\n }\n span[unit] {\n font-size: 0.9rem;\n font-weight: 600;\n color: var(--md-sys-color-primary);\n }\n /*\n ๋“ฑ๊ธ‰ badge.\n\n ์ „์—๋Š” \"C 0\" ๋งŒ ์žˆ์—ˆ๋‹ค. ๊ธ€์ž ํ•˜๋‚˜์™€ ์ˆซ์ž ํ•˜๋‚˜์ธ๋ฐ ์–ด๋””์—๋„ ๋œป์ด ์—†์–ด์„œ, ํฌ๊ฒŒ ๋œฌ\n ๊ฐœ์ˆ˜ ์˜†์— ๋นจ๊ฐ„ badge ๊ฐ€ ๋ถ™์€ ๊ฒƒ์œผ๋กœ๋งŒ ์ฝํ˜”๋‹ค. 0 ์„ 100์  ๋งŒ์ ์˜ 0 ์ ์œผ๋กœ ์ฝ๋Š” ๊ฒƒ์ด\n ์ž์—ฐ์Šค๋Ÿฝ๋‹ค. ์‹ค์ œ ๋œป์€ \"์„ ์–ธํ•œ ํ•œ๋„์— ๋‚จ์€ ์—ฌ์œ ๊ฐ€ 0\" ์ด๋‹ค.\n\n ๊ทธ๋ž˜์„œ ๋ฌด์—‡์„ ์ธก์ •ํ•˜๋Š”์ง€๋ฅผ badge ์•ˆ์— ์ ๊ณ , ๋ˆˆ๊ธˆ์€ ๋ฐ”๋กœ ์•„๋ž˜ ์ค„์— ๋Š˜ ๋ณด์ด๊ฒŒ ๋‘”๋‹ค.\n */\n span[grade] {\n display: flex;\n align-items: baseline;\n gap: 5px;\n margin-left: auto;\n padding: 3px 10px;\n font-size: 0.76rem;\n font-weight: 700;\n color: var(--md-sys-color-on-primary-container);\n background-color: var(--md-sys-color-primary-container);\n border-radius: 999em;\n }\n span[grade] small {\n font-size: 0.68rem;\n font-weight: 500;\n }\n /*\n C ๋Š” ํ•œ๋„๋ฅผ ์ง€ํ‚จ ๊ฒƒ์ด๋‹ค. ๋นจ๊ฐ•์€ ๋„˜๊ธด ๊ฒƒ(D)์—๋งŒ ์“ด๋‹ค. ์ง€ํ‚จ ๊ฒƒ์— ๋นจ๊ฐ•์„ ์“ฐ๋ฉด\n ๊ณ ์น  ๊ฒƒ์ด ์—†๋Š”๋ฐ๋„ ๊ณ ์ณ์•ผ ํ•  ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค.\n */\n span[grade][tight] {\n color: var(--md-sys-color-on-tertiary-container, #3d2f00);\n background-color: var(--md-sys-color-tertiary-container, #ffdf9a);\n }\n /*\n Pair the container with its on-container.\n\n This used to fill with --md-sys-color-error and write with\n --md-sys-color-on-error-container. Once the palette made containers\n neutral and moved the meaning into the text colour, those two became the\n same red and the badge went blank -- a filled pill with no readable text.\n */\n span[grade][over] {\n color: var(--md-sys-color-on-error-container);\n background-color: var(--md-sys-color-error-container);\n }\n\n /* ๋“ฑ๊ธ‰ ๋ˆˆ๊ธˆ. ์ ‘์–ด ๋‘์ง€ ์•Š๋Š”๋‹ค โ€” ํ•œ ๋ฒˆ ๋ณด๊ณ  ๋งˆ๋Š” ๊ฐ’์ด ์•„๋‹ˆ๋ผ ๋ณผ ๋•Œ๋งˆ๋‹ค ํ•„์š”ํ•˜๋‹ค */\n p[scale] {\n display: flex;\n flex-wrap: wrap;\n gap: 2px 10px;\n margin: 6px 0 0 0;\n font-size: 0.7rem;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n p[scale] b {\n font-weight: 700;\n }\n p[scale] span[now] b {\n color: var(--md-sys-color-primary);\n }\n p[scale] span[now] {\n color: var(--md-sys-color-on-surface);\n }\n /* ์ด ํฐ ์ˆซ์ž๊ฐ€ ์–ด๋А ์ถ•์ธ์ง€ ๋จผ์ € ๋งํ•œ๋‹ค โ€” ์„ฑ์ˆ™๋„์˜ ํ•œ ์ถ•์ด์ง€ ์ „๋ถ€๊ฐ€ ์•„๋‹ˆ๋‹ค */\n p[lead] {\n margin: 0 0 4px 0;\n font-size: 0.74rem;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n\n /* ๊ทผ๊ฑฐ๋ฅผ ํ•จ๊ป˜ ๋‚ธ๋‹ค โ€” ์ˆซ์ž๋งŒ ํฌ๊ฒŒ ๋‚ด๊ฑธ๋ฉด ์žฌ ๋ณธ ๊ฐ’์ฒ˜๋Ÿผ ์ฝํžŒ๋‹ค */\n p[basis] {\n margin: 6px 0 0 0;\n font-size: 0.72rem;\n line-height: 1.55;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n p[basis] em {\n font-style: normal;\n color: var(--md-sys-color-tertiary);\n }\n span[score] {\n font-size: 0.8rem;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n\n /* ๋ฌด์—‡ ๋•Œ๋ฌธ์— ์ด ๋“ฑ๊ธ‰์ธ๊ฐ€ โ€” ํ•œ๋„์— ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ํ•ญ๋ชฉ */\n p[because] {\n margin: 8px 0 0 0;\n /* ๋ณธ๋ฌธ ํฌ๊ธฐ๋ฅผ ๋ฌผ๋ ค๋ฐ›์œผ๋ฉด ์ด ์ค„๋งŒ ์ œ๋ชฉ์ฒ˜๋Ÿผ ์ปค์ง„๋‹ค โ€” ํ™”๋ฉด์„ ๋„์›Œ ๋ณด๊ณ  ์•Œ์•˜๋‹ค */\n font-size: 0.78rem;\n line-height: 1.6;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n p[because] strong {\n color: var(--md-sys-color-on-surface);\n }\n\n /* โ”€โ”€ ์„ฑ์ˆ™๋„ radar โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n ์—ฌ์„ฏ ์ถ•์„ ํ•œ ๊ทธ๋ฆผ์œผ๋กœ. ๋ชฉ๋ก๋งŒ ๋‘๋ฉด ใ€Œ์–ด๋А ์ชฝ์ด ๋ชจ์ž๋ž€๊ฐ€ใ€๊ฐ€ ์•ˆ ๋ณด์ธ๋‹ค.\n ๋ชป ์žฐ ์ถ•์€ ์ ์„ ์ฐ์ง€ ์•Š๊ณ  ์‚ด๋งŒ ํ๋ฆฌ๊ฒŒ ๋‚จ๊ธด๋‹ค โ€” 0 ์œผ๋กœ ์ฐ์œผ๋ฉด ใ€Œ๋‚˜์˜๋‹คใ€๊ฐ€ ๋œ๋‹ค. */\n div[radar] {\n display: flex;\n justify-content: center;\n padding: 2px 0 6px 0;\n color: var(--md-sys-color-primary);\n }\n div[radar] svg {\n width: 100%;\n max-width: 240px;\n height: auto;\n }\n div[radar] polygon[web] {\n fill: none;\n stroke: var(--md-sys-color-outline-variant);\n stroke-width: 0.6;\n }\n div[radar] line[spoke] {\n stroke: var(--md-sys-color-outline-variant);\n stroke-width: 0.6;\n }\n div[radar] polygon[shape] {\n fill: color-mix(in srgb, var(--md-sys-color-primary) 22%, transparent);\n stroke: var(--md-sys-color-primary);\n stroke-width: 1.4;\n stroke-linejoin: round;\n }\n div[radar] circle[dot] {\n fill: var(--md-sys-color-primary);\n }\n div[radar] text {\n font-size: 5.2px;\n fill: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n\n /* ๊ทธ๋ฆผ์— ์ž๋ฆฌ๋ฅผ ์ฃผ์ง€ ์•Š์€ ์ถ•์„ ๊ธ€๋กœ ๋ฐํžŒ๋‹ค */\n p[unmeasured] {\n margin: 0 0 8px 0;\n font-size: 0.7rem;\n line-height: 1.5;\n color: var(--md-sys-color-tertiary);\n }\n\n /* โ”€โ”€ ์„ฑ์ˆ™๋„ ์ถ• โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n ํ•œ ์ˆซ์ž๋กœ ํ•ฉ์น˜์ง€ ์•Š๋Š”๋‹ค. ํ•ฉ์น˜๋ฉด ใ€Œ๋ฌด์—‡์„ ๊ณ ์ณ์•ผ ํ•˜๋‚˜ใ€๊ฐ€ ์‚ฌ๋ผ์ง„๋‹ค. */\n ul[axes] {\n margin: 0;\n padding: 0;\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 7px;\n }\n ul[axes] li {\n display: grid;\n grid-template-columns: 1fr auto;\n gap: 2px 8px;\n font-size: 0.75rem;\n }\n ul[axes] li[blocked] {\n opacity: 0.7;\n }\n ul[axes] em {\n grid-column: 1 / -1;\n font-style: normal;\n font-size: 0.68rem;\n line-height: 1.5;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n /* ๋ชป ์žฐ ์ถ•์€ 0 ์œผ๋กœ ๋‘์ง€ ์•Š๋Š”๋‹ค โ€” 0 ์€ ใ€Œ๋‚˜์˜๋‹คใ€๋Š” ๋œป์ด ๋˜์–ด ๋ฒ„๋ฆฐ๋‹ค */\n ul[axes] li[blocked] em {\n color: var(--md-sys-color-tertiary);\n }\n span[reading] {\n font-family: var(--mono-font, monospace);\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n\n /* โ”€โ”€ ์˜ˆ์‚ฐ ๋ง‰๋Œ€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */\n ul[budgets] {\n margin: 0;\n padding: 0;\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n ul[budgets] li {\n display: grid;\n grid-template-columns: 1fr auto;\n gap: 2px 8px;\n font-size: 0.75rem;\n }\n div[bar] {\n grid-column: 1 / -1;\n height: 4px;\n background-color: var(--md-sys-color-surface-container-highest);\n border-radius: 2px;\n overflow: hidden;\n }\n div[bar] > i {\n display: block;\n height: 100%;\n background-color: var(--md-sys-color-primary);\n }\n div[bar] > i[tight] {\n background-color: var(--md-sys-color-error);\n }\n\n /* โ”€โ”€ ๋ฌด๊ฒŒ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */\n dl[metrics] {\n margin: 0;\n display: grid;\n grid-template-columns: 1fr auto;\n gap: 4px 8px;\n font-size: 0.78rem;\n }\n dl[metrics] dt {\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n dl[metrics] dd {\n margin: 0;\n text-align: right;\n font-family: var(--mono-font, monospace);\n }\n\n /* โ”€โ”€ ์ถ”์ด โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n ๊ทธ๋ฆผ์€ ์ž์—ฐ ํฌ๊ธฐ๊ฐ€ 680px ๋‹ค. 300px ์นธ์— ๋„ฃ์œผ๋ฉด ๊ธ€์ž๊ฐ€ 4px ์ด ๋˜์–ด ์•„๋ฌด๊ฒƒ๋„\n ์ฝ์„ ์ˆ˜ ์—†๋‹ค โ€” ์‚ฌ์ด๋“œ๋ฐ”์—๋Š” ์ˆซ์ž๋ฅผ ๋‘๊ณ , ๊ทธ๋ฆผ์€ ์„ ํƒํ•ด์„œ ํฌ๊ฒŒ ๋ณธ๋‹ค. */\n button[expand] {\n margin-top: 6px;\n padding: 4px 10px;\n font: var(--label-font, inherit);\n font-size: 0.74rem;\n color: var(--md-sys-color-on-surface);\n background: none;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 6px;\n cursor: pointer;\n }\n button[expand]:hover {\n background-color: var(--md-sys-color-surface-container);\n }\n\n div[sheet] {\n position: fixed;\n inset: 0;\n z-index: 10;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--spacing-large, 12px);\n background-color: rgba(0, 0, 0, 0.32);\n }\n div[sheet] > figure {\n max-width: 100%;\n max-height: 100%;\n margin: 0;\n padding: var(--spacing-large, 12px);\n overflow: auto;\n color: var(--md-sys-color-primary);\n background-color: var(--md-sys-color-surface-container-lowest);\n /* ๋‹ด๋Š” ๋ฉด์ด ํŒ์—…์ด๋ฉด ์•ˆ์ชฝ ๋ชจ์„œ๋ฆฌ๋Š” ์•Œ์•ฝ์ด๋‹ค โ€” ์‹œํŠธ ์ž์ฒด๋Š” ํŽ˜์ด์ง€ ๊ฐ’์„ ์“ด๋‹ค */\n border-radius: 6px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.28);\n }\n div[sheet] svg {\n display: block;\n /* ์ž์—ฐ ํฌ๊ธฐ๋ณด๋‹ค ์ž‘๊ฒŒ ์ค„์ด์ง€ ์•Š๋Š”๋‹ค โ€” ์ข์œผ๋ฉด ๋„˜๊ฒจ ๋ณด๊ฒŒ ๋‘”๋‹ค */\n min-width: 680px;\n }\n div[sheet] figcaption {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n }\n div[sheet] button[close] {\n padding: 5px 14px;\n font: var(--label-font, inherit);\n color: var(--md-sys-color-on-surface);\n background: none;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 999em;\n cursor: pointer;\n }\n\n /* โ”€โ”€ ์•Œ๋ฆผ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */\n ul[findings] {\n margin: 0;\n padding: 0;\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n ul[findings] li {\n display: flex;\n gap: 6px;\n line-height: 1.5;\n }\n ul[findings] md-icon {\n --md-icon-size: 16px;\n flex: none;\n color: var(--md-sys-color-error);\n }\n ul[findings] li[violation] md-icon {\n color: var(--md-sys-color-tertiary);\n }\n /* ์–ด๊ธด ์ž๋ฆฌ. ๋ฌธ๊ตฌ์— ๋ถ™์–ด ํ๋ฅด๋ฉด ๋ฌธ์žฅ์˜ ์ผ๋ถ€๋กœ ์ฝํžŒ๋‹ค โ€” badge ๋กœ ๋ณด์ด๊ฒŒ ๋—€๋‹ค */\n code[at] {\n padding: 1px 5px;\n font-family: var(--mono-font, monospace);\n font-size: 0.68rem;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n background-color: var(--md-sys-color-surface-container);\n border-radius: 4px;\n white-space: nowrap;\n }\n\n /*\n ๋ฐœ๊ฒฌ์ด ์—†์„ ๋•Œ์˜ ๋ฌธ๊ตฌ.\n\n ํฌ๊ธฐ๋ฅผ ์•ˆ ์ ์–ด ๋‘์—ˆ๋”๋‹ˆ ๋ณธ๋ฌธ ๊ธฐ๋ณธ ํฌ๊ธฐ๋ฅผ ๋ฌผ๋ ค๋ฐ›์•„ ์ด ์ค„๋งŒ ์ œ๋ชฉ์ฒ˜๋Ÿผ ์ปค์กŒ๋‹ค. ์ด\n ํŒจ๋„์˜ ๊ธ€์ž๋Š” ์ „๋ถ€ 0.7rem ๋Œ€์ธ๋ฐ ์—ฌ๊ธฐ๋งŒ 1rem ์ด๋ผ ์•„๋ž˜์ชฝ์ด ๋ฌด๋„ˆ์ ธ ๋ณด์˜€๋‹ค.\n\n ์ฐพ์€ ๊ฒƒ์ด ์žˆ์„ ๋•Œ์˜ ๋ชฉ๋ก(ul[findings] li)๊ณผ ๊ฐ™์€ ํฌ๊ธฐ๋กœ ๋งž์ถ˜๋‹ค. ์žˆ์„ ๋•Œ์™€ ์—†์„ ๋•Œ\n ์ ˆ์˜ ์ƒ๊น€์ƒˆ๊ฐ€ ๋‹ฌ๋ผ์งˆ ์ด์œ ๊ฐ€ ์—†๋‹ค.\n\n ์ด ํŒŒ์ผ์—์„œ ๊ฐ™์€ ์‹ค์ˆ˜๋ฅผ ๋‘ ๋ฒˆ์งธ๋กœ ํ•œ๋‹ค. p[because] ์—๋„ ๊ฐ™์€ ์ฃผ์„์ด ์žˆ๋‹ค.\n */\n p[quiet] {\n margin: 0;\n font-size: 0.76rem;\n line-height: 1.6;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n `\n ]\n\n /** ์ €์ž‘ ์ค‘์ธ ์›๋ณธ ๋ฐ์ดํ„ฐ. ๋ฐ”๋€Œ๋ฉด ๋‹ค์‹œ ์ธก์ •ํ•œ๋‹ค. */\n @property({ type: Object }) source?: FigureSource\n\n @state() private cost?: FigureCost\n @state() private score?: FigureScore\n @state() private curve = ''\n /** 1๋งŒ ๊ฐœ๋ฅผ ๋†“์•˜์„ ๋•Œ. ์ €์ž‘์ž๊ฐ€ ์‹ค์ œ๋กœ ๊ถ๊ธˆํ•œ ์ˆซ์ž๋‹ค. */\n @state() private many?: FigureCost\n /** ๋ช‡ ๊ฐœ๊นŒ์ง€ ๋†“์„ ์ˆ˜ ์žˆ๋‚˜. ์ด ํŒจ๋„์˜ ๋จธ๋ฆฌ๋‹ค. */\n @state() private capacity?: FigureCapacity\n /** ์ถ”์ด ๊ทธ๋ฆผ์„ ์ œ ํฌ๊ธฐ๋กœ ํŽผ์ณค๋‚˜. */\n @state() private expanded = false\n @state() private errors: { code: string; message: string; at?: string }[] = []\n /**\n * ํ˜•์‹์ด ๊ถŒํ•˜์ง€ ์•Š๋Š” ๊ฒƒ โ€” **๊ทธ์ค‘ ๋‘˜์€ ๋ฐœํ–‰์„ ๋ง‰๋Š”๋‹ค.**\n *\n * ๋“ฑ๊ธ‰์„ ํ˜•์‹์—์„œ ๋ฐ›๋Š”๋‹ค(`blocksRelease`). ํ™”๋ฉด์ด ์ œ ๋ชฉ๋ก์„ ๋“ค๋ฉด ํ˜•์‹์— ์ฝ”๋“œ๊ฐ€ ํ•˜๋‚˜ ๋Š˜ ๋•Œ\n * ์กฐ์šฉํžˆ ใ€Œ์•Œ๋ฆผใ€์œผ๋กœ ๊ทธ๋ ค์ง€๊ณ , ์ €์ž‘์ž๋Š” ๋ฐœํ–‰์ด ๋ง‰ํžŒ ๊ฒƒ์„ **๋ˆŒ๋Ÿฌ ๋ณด๊ณ  ๋‚˜์„œ์•ผ** ์•ˆ๋‹ค.\n *\n * `actual` ์€ ์–ผ๋งˆ๋‚˜ ๋„˜์ณค๋‚˜๋‹ค. ใ€Œ์ƒ์ž๋ฅผ ๋ฒ—์–ด๋‚œ๋‹คใ€๋งŒ์œผ๋กœ๋Š” 2mm ์ธ์ง€ 250mm ์ธ์ง€ ๋ชจ๋ฅด๊ณ ,\n * ๊ทธ ๋‘˜์€ ๊ณ ์น˜๋Š” ํ’ˆ์ด ๋‹ค๋ฅด๋‹ค.\n */\n @state() private violations: { code: string; message: string; blocking: boolean; actual?: number }[] = []\n /**\n * ํฌ๊ธฐ๋ฅผ ๋ฐ”๊ฟ” ๋ดค์„ ๋•Œ ๊ฐˆ๋ผ์ง€๋Š”๊ฐ€ โ€” **๋ฐœํ–‰์„ ๋ง‰๋Š” ๊ฒƒ**์ด๋‹ค.\n *\n * ์ด๋ ฅ ํƒญ์ด ๊ฐ™์€ ํŒ์ •์„ ์„œ๋ฒ„์—์„œ ๋ฐ›์•„ ๋ฐœํ–‰ ๋ฌธ์„ ์ž ๊ทธ์ง€๋งŒ, ๊ทธ๊ฒƒ์€ **์ €์žฅ๋œ ์ •๋ณธ**์— ๋Œ€ํ•œ\n * ๊ฒƒ์ด๋ผ ์ €์žฅํ•˜๊ธฐ ์ „์—๋Š” ๋‹ตํ•˜์ง€ ๋ชปํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ์ €์ž‘ ์ค‘์ธ ์ •๋ณธ์„ ๊ทธ๋Œ€๋กœ ์žฌ๋ฏ€๋กœ, ๋ถ€ํ’ˆ์„\n * ์˜ฎ๊ธฐ๋Š” ๊ทธ ์ž๋ฆฌ์—์„œ ๊ฐˆ๋ผ์ง์ด ์ƒ๊ฒผ๋Š”์ง€ ์‚ฌ๋ผ์กŒ๋Š”์ง€ ๋ณด์ธ๋‹ค โ€” ์ €์žฅํ•˜๊ณ  ํƒญ์„ ์˜ฎ๊ฒจ ํ™•์ธํ•˜๊ฒŒ\n * ๋‘๋ฉด ๊ณ ์น  ๋•Œ๊ฐ€ ์ด๋ฏธ ์ง€๋‚˜ ์žˆ๋‹ค.\n */\n @state() private sizing: { code: string; message: string; at?: string; blocking: boolean }[] = []\n /**\n * ์•„์ง ๋ถ€ํ’ˆ์ด ํ•˜๋‚˜๋„ ์—†๋‚˜ โ€” **์ €์ž‘ ์ „์ด์ง€ ํ˜•์‹์„ ์–ด๊ธด ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค.**\n *\n * ํ˜•์‹์€ ๋ถ€ํ’ˆ 0๊ฐœ๋ฅผ ์˜ค๋ฅ˜๋กœ ๋ณธ๋‹ค(`missing-parts`). ๋ฐœํ–‰ ๊ด€์ ์—์„œ๋Š” ๋งž๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ƒˆ๋กœ ๋งŒ๋“ค๊ธฐ๋ฅผ\n * ๋ˆ„๋ฅธ ์งํ›„๊ฐ€ ๋ฐ”๋กœ ๊ทธ ์ƒํƒœ์ด๋ฏ€๋กœ, ๊ทธ๊ฒƒ์„ ๊ทธ๋Œ€๋กœ ์˜ค๋ฅ˜๋กœ ๊ทธ๋ฆฌ๋ฉด **์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š์•˜๋Š”๋ฐ ๋ถ‰์€\n * ํ™”๋ฉด**์„ ๋ณด๊ฒŒ ๋œ๋‹ค. ๊ทธ๋ž˜์„œ ์ด ์ž๋ฆฌ์—์„œ ๋‘˜์„ ๊ฐ€๋ฅธ๋‹ค.\n */\n @state() private bare = false\n\n willUpdate(changed: Map<string, unknown>) {\n if (changed.has('source')) {\n this.measure()\n }\n }\n\n render() {\n /*\n ๋ถ€ํ’ˆ์ด ์—†์œผ๋ฉด ์ด ์ž๋ฆฌ๋Š” **ํŒ์ •์ด ์•„๋‹ˆ๋ผ ์•ˆ๋‚ด**๋‹ค. ์ด๋ฏธ ์žˆ๋˜ ใ€Œ๋ถ€ํ’ˆ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๋‚˜์˜ต๋‹ˆ๋‹คใ€๊ฐ€\n ์ •ํ™•ํžˆ ๊ทธ ๋ง์ด๋ฏ€๋กœ ๊ทธ๊ฒƒ์„ ์“ด๋‹ค โ€” ๊ฐ™์€ ์ƒํƒœ์— ๋ฌธ์žฅ์„ ๋‘˜ ๋‘์ง€ ์•Š๋Š”๋‹ค.\n\n ์•„๋ž˜ ์…ˆ๋“ค(๋จธ๋ฆฌยท์ถ•ยทํ•œ๋„ยท์ถ”์ด)์€ ๋ถ€ํ’ˆ์ด ์žˆ์–ด์•ผ ๋œป์ด ์žˆ๊ณ , ์žฌ์ง€ ์•Š์€ ๊ฐ’์„ ๋“ค๊ณ  ๊ทธ๋ฆฌ๋ฉด 0 ์œผ๋กœ\n ๋ณด์ธ๋‹ค. 0 ์€ ใ€Œ๋‚˜์˜๋‹คใ€๋กœ ์ฝํžˆ๋ฏ€๋กœ ๊ทธ ์ž๋ฆฌ์— ๋‘์ง€ ์•Š๋Š”๋‹ค.\n */\n if (!this.source || this.bare) {\n return html`\n <section>\n <p quiet>${i18next.t('figure.text.report-appears-when-you-add-a-part')}</p>\n </section>\n `\n }\n\n // ํ˜•์‹์„ ์–ด๊ธด ์ƒํƒœ์—์„œ๋Š” ์…ˆ์ด ๋œป์„ ๊ฐ–์ง€ ๋ชปํ•œ๋‹ค โ€” ๋ฌด์—‡์ด ์ž˜๋ชป๋๋Š”์ง€๋งŒ ๋ณด์—ฌ ์ค€๋‹ค.\n if (this.errors.length > 0) {\n return html`${this.renderFindings()}`\n }\n\n return html`\n ${this.renderVerdict()} ${this.renderAxes()} ${this.renderBudgets()} ${this.renderMetrics()} ${this.renderCurve()}\n ${this.renderFindings()} ${this.renderSheet()}\n `\n }\n\n /**\n * ๋จธ๋ฆฌ โ€” ๋ช‡ ๊ฐœ๊นŒ์ง€ ํŽธํ•œ๊ฐ€.\n *\n * ๋กœ์šฐํด๋ฆฌ์˜ ๊ฐ’์€ ใ€Œ์–ผ๋งˆ๋‚˜ ๋งŽ์ด ํŽธํ•˜๊ฒŒ ๋†“์„ ์ˆ˜ ์žˆ๋‚˜ใ€์— ์žˆ๋‹ค. ๋“ฑ๊ธ‰ B ๋Š” ๊ทธ ๋ฌผ์Œ์—\n * ์ง์ ‘ ๋‹ตํ•˜์ง€ ์•Š๋Š”๋‹ค โ€” ํ˜•์ƒ์ด ์„ ์–ธ๋œ ํ•œ๋„ ์•ˆ์ธ์ง€๋ฅผ ๋งํ•  ๋ฟ์ด๋‹ค. ๊ทธ๋ž˜์„œ ๊ฐœ์ˆ˜๋ฅผ\n * ๋จธ๋ฆฌ์— ์˜ฌ๋ฆฌ๊ณ  ๋“ฑ๊ธ‰์€ ์˜†์˜ badge ๋กœ ๋‚ด๋ฆฐ๋‹ค.\n *\n * ๊ทผ๊ฑฐ๋ฅผ ํ•จ๊ป˜ ๋‚ธ๋‹ค. ์ด ๊ฐœ์ˆ˜์˜ ๋ถ„๋ชจ๋Š” ์‹ค์ธก์ด ์•„๋‹ˆ๋ผ ์„ค๊ณ„ ๋ฌธ์„œ์˜ ๋ชฉํ‘œ์น˜์ด๊ณ (๋ฏธ๊ฒฐ\n * D-20), ๊ทธ ์‚ฌ์‹ค์ด ํ™”๋ฉด์— ์—†์œผ๋ฉด ์žฌ ๋ณธ ๊ฐ’์ฒ˜๋Ÿผ ์ฝํžŒ๋‹ค.\n */\n private renderVerdict() {\n const score = this.score\n const capacity = this.capacity\n if (!score || !capacity) return nothing\n\n return html`\n <section>\n <h3>${i18next.t('figure.label.maturity')}</h3>\n <p lead>${i18next.t('figure.label.axis-scale')} โ€” ${i18next.t('figure.text.how-many-fit')}</p>\n <div verdict>\n <span capacity>${capacity.instances.toLocaleString()}</span>\n <span unit>${i18next.t('figure.text.instances-unit')}</span>\n <span\n grade\n ?tight=${score.grade === 'C'}\n ?over=${score.grade === 'D'}\n title=${i18next.t('figure.text.grade-explained')}\n >\n ${score.grade}\n <small>${i18next.t('figure.text.headroom-percent', { percent: Math.round(score.score) })}</small>\n </span>\n </div>\n <p because>\n ${i18next.t('figure.text.grade-decided-by')}\n <strong>${i18next.t('figure.label.budget-' + score.tightest.key)}</strong>\n โ€” ${score.tightest.used} / ${score.tightest.limit}\n (${Math.round((score.tightest.used / score.tightest.limit) * 100)}%)\n </p>\n ${this.renderGradeScale(score.grade)}\n <p basis>\n ${i18next.t('figure.text.bound-by-' + capacity.bound, {\n per: capacity.per.toLocaleString(),\n budget: capacity.budget.toLocaleString()\n })}\n <em>${i18next.t('figure.text.budget-not-measured-yet')}</em>\n </p>\n </section>\n `\n }\n\n /**\n * ๋“ฑ๊ธ‰ ๋ˆˆ๊ธˆ.\n *\n * AยทBยทCยทD ๊ฐ€ ๋ฌด์—‡์„ ๋œปํ•˜๋Š”์ง€ ํ™”๋ฉด ์–ด๋””์—๋„ ์—†์—ˆ๋‹ค. badge ๋งŒ ๋ณด๊ณ ๋Š” ์ข‹์€์ง€ ๋‚˜์œ์ง€๋„,\n * ๋ฌด์—‡์„ ๊ณ ์ณ์•ผ ์˜ค๋ฅด๋Š”์ง€๋„ ์•Œ ์ˆ˜ ์—†๋‹ค. ๋ˆˆ๊ธˆ์„ ๋Š˜ ๊ณ์— ๋‘๊ณ  ์ง€๊ธˆ ์–ด๋””์— ์žˆ๋Š”์ง€๋ฅผ\n * ํ‘œ์‹œํ•œ๋‹ค.\n *\n * ์ ‘์–ด ๋‘์ง€ ์•Š๋Š”๋‹ค. ํ•œ ๋ฒˆ ๋ฐฐ์šฐ๊ณ  ๋งˆ๋Š” ๊ฐ’์ด ์•„๋‹ˆ๋ผ ๋ณผ ๋•Œ๋งˆ๋‹ค ๋Œ€์กฐํ•˜๋Š” ๊ฐ’์ด๋‹ค.\n */\n private renderGradeScale(now: string) {\n const bounds: [string, string][] = [\n ['A', 'โ‰ค 50%'],\n ['B', 'โ‰ค 75%'],\n ['C', 'โ‰ค 100%'],\n ['D', '> 100%']\n ]\n\n return html`\n <p scale>\n <span>${i18next.t('figure.text.grade-scale-lead')}</span>\n ${bounds.map(\n ([grade, bound]) => html`<span ?now=${grade === now}><b>${grade}</b> ${bound}</span>`\n )}\n </p>\n `\n }\n\n /**\n * ์„ฑ์ˆ™๋„ โ€” ์—ฌ๋Ÿฌ ์ถ•์œผ๋กœ ๋ณธ๋‹ค.\n *\n * ใ€Œ๋ช‡ ๊ฐœ๊นŒ์ง€ ํŽธํ•œ๊ฐ€ใ€ ํ•˜๋‚˜๋กœ๋Š” ์ข‹์€ ํ˜•์ƒ๊ณผ ๋‚˜์œ ํ˜•์ƒ์ด ๊ตฌ๋ถ„๋˜์ง€ ์•Š๋Š”๋‹ค. ๋ถ€ํ’ˆ ํ•˜๋‚˜์งœ๋ฆฌ\n * ์ƒ์ž๋„ ๊ทธ ์ถ•์—์„œ๋Š” ๋งŒ์ ์ด๋‹ค.\n *\n * **๋ชป ์žฌ๋Š” ์ถ•์„ 0 ์œผ๋กœ ๋‘์ง€ ์•Š๋Š”๋‹ค.** 0 ์€ ใ€Œ๋‚˜์˜๋‹คใ€๋Š” ๋œป์ด ๋˜๋Š”๋ฐ, ์‚ฌ์‹ค์€ ์•„์ง\n * ์ธก์ •ํ•  ๋ฐฉ๋ฒ•์ด ์—†๋Š” ๊ฒƒ์ด๋‹ค. ์ธก์ •ํ•˜์ง€ ๋ชปํ•œ๋‹ค๊ณ  ์•Œ๋ฆฌ๊ณ  ์ด์œ ๋ฅผ ๋ถ™์ธ๋‹ค. ์ง€์–ด๋‚ธ ์ ์ˆ˜๋ณด๋‹ค ๊ทธ๊ฒƒ์ด\n * ์ด ๋ฆฌํฌํŠธ๋ฅผ ๋ฏฟ์„ ๋งŒํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค.\n */\n private renderAxes() {\n if (!this.cost || !this.score || !this.source) return nothing\n\n /*\n ๊ทœ๋ชจ๋Š” ๋ชฉ๋ก์—์„œ ๋บ€๋‹ค โ€” ๋จธ๋ฆฌ๋กœ ์˜ฌ๋ผ๊ฐ”๋‹ค. ๊ฐ™์€ ์ˆซ์ž๋ฅผ ๋‘ ๋ฒˆ ๋‚ด๋ฉด ์ฝ๋Š” ์‚ฌ๋žŒ์ด\n ๋‘˜์ด ๋‹ค๋ฅธ ๊ฒƒ์ธ ์ค„ ์•ˆ๋‹ค.\n */\n const axes = maturityOf(this.source, this.cost, this.score).filter(axis => axis.key !== 'scale')\n\n // radar ์—๋Š” ์—ฌ์„ฏ์„ ๋‹ค ๊ทธ๋ฆฐ๋‹ค. ๊ทœ๋ชจ๊ฐ€ ์–ด๋””์ฏค์ธ์ง€ ํ•จ๊ป˜ ๋ณด์—ฌ์•ผ ๋œป์ด ์žˆ๋‹ค\n const all = maturityOf(this.source, this.cost, this.score)\n\n return html`\n <section>\n <h3>${i18next.t('figure.label.by-axis')}</h3>\n <div radar>${this.renderRadar(all.filter(axis => axis.ratio !== undefined))}</div>\n ${this.renderUnmeasured(all.filter(axis => axis.ratio === undefined))}\n <ul axes>\n ${axes.map(axis => this.renderAxis(axis))}\n </ul>\n </section>\n `\n }\n\n /**\n * ์„ฑ์ˆ™๋„ radar. **์ธก์ •ํ•œ ์ถ•๋งŒ ๊ทธ๋ฆฐ๋‹ค.**\n *\n * ์ธก์ •ํ•˜์ง€ ๋ชปํ•˜๋Š” ์ถ•๋„ spoke ๋ฅผ ๊ทธ๋ ค ๋‘๊ณ  ๋„ํ˜•๋งŒ ๊ฑด๋„ˆ๋›ฐ๋˜ ๋•Œ๊ฐ€ ์žˆ์—ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๊ทธ ๋ฐฉํ–ฅ์„ ๊ฐ€๋กœ์ง€๋ฅด๋Š”\n * ์ง์„ ์ด ์ƒ๊ฒจ์„œ ๋„ํ˜•์ด ๊ทธ์ชฝ์œผ๋กœ ์›€ํ‘น ๋“ค์–ด๊ฐ„ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค. 0 ์œผ๋กœ ์ฐ์ง€ ์•Š์œผ๋ ค๊ณ  ํ•œ\n * ์ผ์ธ๋ฐ ๊ฒฐ๊ณผ๋Š” 0 ์œผ๋กœ ์ฐ์€ ๊ฒƒ๊ณผ ๋˜‘๊ฐ™์ด ์ฝํ˜”๋‹ค. ์ ์„  ์‚ด๊ณผ ๋ฌผ์Œํ‘œ๋กœ๋Š” ๊ทธ ์ธ์ƒ์ด\n * ์ง€์›Œ์ง€์ง€ ์•Š์•˜๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ ์•„์˜ˆ ๋นผ๊ณ , ๋ชป ์žฌ๋Š” ์ถ•์€ ๊ทธ๋ฆผ ์•„๋ž˜์— ๊ธ€๋กœ ์ ๋Š”๋‹ค. ์žด ์ˆ˜ ์—†๋Š” ๊ฒƒ์€ ๊ทธ๋ฆผ์—\n * ์ž๋ฆฌ๋ฅผ ์ฃผ์ง€ ์•Š๋Š” ํŽธ์ด ์ •์งํ•˜๋‹ค.\n */\n private renderRadar(axes: MaturityAxis[]) {\n // ๊ทธ๋ฆผ ์•ˆ์—์„œ๋Š” **์งง์€ ์ด๋ฆ„**์„ ์“ด๋‹ค. ๊ธด ์ด๋ฆ„์„ ๊ทธ๋Œ€๋กœ ์“ฐ๋ฉด ์™ผ์ชฝ์ด ์ž˜๋ฆฐ๋‹ค โ€”\n // ํ™”๋ฉด์„ ๋„์›Œ ๋ณด๊ณ  ์•Œ์•˜๋‹ค.\n const cx = 60\n const cy = 46\n const r = 28\n\n const at = (index: number, ratio: number) => {\n const angle = -Math.PI / 2 + (index * 2 * Math.PI) / axes.length\n return [cx + r * ratio * Math.cos(angle), cy + r * ratio * Math.sin(angle)]\n }\n\n const points = axes\n .map((axis, index) => at(index, Math.max(0.04, Math.min(1, axis.ratio ?? 0))).map(n => n.toFixed(1)).join(','))\n .join(' ')\n\n return svg`\n <svg viewBox=\"0 0 120 96\" aria-hidden=\"true\">\n ${[0.33, 0.66, 1].map(\n ring => svg`<polygon web points=${axes.map((_, i) => at(i, ring).map(n => n.toFixed(1)).join(',')).join(' ')}></polygon>`\n )}\n ${axes.map((_, index) => {\n const [x, y] = at(index, 1)\n return svg`<line spoke x1=${cx} y1=${cy} x2=${x.toFixed(1)} y2=${y.toFixed(1)}></line>`\n })}\n <polygon shape points=${points}></polygon>\n ${axes.map((axis, index) => {\n const [x, y] = at(index, Math.max(0.04, Math.min(1, axis.ratio ?? 0)))\n return svg`<circle dot cx=${x.toFixed(1)} cy=${y.toFixed(1)} r=\"1.4\"></circle>`\n })}\n ${axes.map((axis, index) => {\n const [x, y] = at(index, 1.28)\n const anchor = x < cx - 3 ? 'end' : x > cx + 3 ? 'start' : 'middle'\n return svg`\n <text x=${x.toFixed(1)} y=${(y + 1.8).toFixed(1)} text-anchor=${anchor}>\n ${i18next.t('figure.label.axis-' + axis.key + '-short')}\n </text>\n `\n })}\n </svg>\n `\n }\n\n /**\n * ๊ทธ๋ฆผ์— ์—†๋Š” ์ถ•์„ ๊ธ€๋กœ ๋ฐํžŒ๋‹ค.\n *\n * ๋นผ๊ธฐ๋งŒ ํ•˜๋ฉด ์ถ•์ด ์—ฌ์„ฏ์ธ์ง€ ๋‹ค์„ฏ์ธ์ง€ ์•Œ ์ˆ˜ ์—†๊ณ , ์—†๋Š” ๊ฒƒ์„ ์—†๋‹ค๊ณ  ๋งํ•˜์ง€ ์•Š์€ ์…ˆ์ด\n * ๋œ๋‹ค. ๋ฌด์—‡์„ ์•„์ง ๋ชป ์žฌ๋Š”์ง€ ํ•œ ์ค„๋กœ ์ ๋Š”๋‹ค. ์™œ ๋ชป ์žฌ๋Š”์ง€๋Š” ์•„๋ž˜ ๋ชฉ๋ก์˜ ๊ทธ ํ•ญ๋ชฉ์—\n * ๊ทธ๋Œ€๋กœ ์žˆ๋‹ค.\n */\n private renderUnmeasured(axes: MaturityAxis[]) {\n if (axes.length === 0) return nothing\n\n return html`\n <p unmeasured>\n ${i18next.t('figure.text.axes-not-measurable-yet', {\n axes: axes.map(axis => i18next.t('figure.label.axis-' + axis.key)).join(' ยท ')\n })}\n </p>\n `\n }\n\n private renderAxis(axis: MaturityAxis) {\n const name = i18next.t('figure.label.axis-' + axis.key)\n\n if (axis.blocked) {\n return html`\n <li blocked>\n <span>${name}</span>\n <span reading>${i18next.t('figure.text.not-measurable-yet')}</span>\n <em>${i18next.t(axis.blocked)}</em>\n </li>\n `\n }\n\n const ratio = Math.max(0, Math.min(1, axis.ratio ?? 0))\n return html`\n <li>\n <span>${name}</span>\n <span reading>${axis.readingKey ? i18next.t(axis.readingKey) : (axis.reading ?? '')}</span>\n <div bar><i style=\"width:${Math.round(ratio * 100)}%\"></i></div>\n ${axis.because ? html`<em>${i18next.t(axis.because)}</em>` : ''}\n </li>\n `\n }\n\n /**\n * ์˜ˆ์‚ฐ ๋ง‰๋Œ€.\n *\n * ์ˆซ์ž๋งŒ ๋Š˜์–ด๋†“์œผ๋ฉด ์–ด๋А ๊ฒƒ์ด ๊ฝ‰ ์ฐผ๋Š”์ง€ ๋ˆˆ์— ์•ˆ ๋“ค์–ด์˜จ๋‹ค. ํ•œ๋„์— ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ํ•˜๋‚˜๋ฅผ ์ƒ‰์œผ๋กœ\n * ๊ตฌ๋ถ„ํ•œ๋‹ค. ๊ทธ๊ฒƒ์ด ์ ์ˆ˜๋ฅผ ์ •ํ•œ ํ•ญ๋ชฉ์ด๋‹ค.\n *\n * ## `use.label` ์„ ์“ฐ์ง€ ์•Š๋Š” ์ด์œ \n *\n * `FigureBudgetUse` ์— `label` ๊ณผ `why` ๊ฐ€ ์žˆ๊ณ  ใ€Œ์ €์ž‘์ž์—๊ฒŒ ๊ทธ๋Œ€๋กœ ๋ณด์—ฌ ์ค€๋‹คใ€๊ณ \n * ์ ํ˜€ ์žˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ทธ ๋ฌธ๊ตฌ๊ฐ€ **ํ•œ๊ตญ์–ด๋กœ ๊ตฌ์›Œ์ ธ** ์žˆ๋‹ค. ์ด ์ œํ’ˆ์€ 5์–ธ์–ด๋ฅผ ์“ฐ๋ฏ€๋กœ\n * ๊ทธ๊ฒƒ์„ ๊ทธ๋Œ€๋กœ ์‹ค์œผ๋ฉด ๋‹ค๋ฅธ ์–ธ์–ด ์‚ฌ์šฉ์ž์—๊ฒŒ ํ•œ๊ตญ์–ด๊ฐ€ ๋‚˜์˜จ๋‹ค.\n *\n * `budgets` ๋Š” **๋ฐฐ์—ด**์ด๋‹ค. `Object.entries` ๋กœ ๋Œ๋ฉด ํ‚ค๊ฐ€ ์ธ๋ฑ์Šค(0ยท1ยท2โ€ฆ)๊ฐ€ ๋˜์–ด\n * `figure.label.budget-0` ๊ฐ™์€ ์—†๋Š” ํ‚ค๋ฅผ ์ฐพ๋Š”๋‹ค โ€” ํ™”๋ฉด์„ ๋„์›Œ ๋ณด๊ณ ์„œ์•ผ ๋“œ๋Ÿฌ๋‚ฌ๋‹ค.\n * ๋ฐฐ์—ด์„ ๊ทธ๋Œ€๋กœ ๋Œ๊ณ  `use.key` ๋ฅผ ์“ด๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ **์•ˆ์ •๋œ `key`** ๋กœ ์ด ํ™”๋ฉด์˜ i18n ์„ ์ฐพ๋Š”๋‹ค. `key` ๋Š” ์—ด๊ฑฐํ˜•์ด๋ผ ํ˜•์‹์˜\n * ์ผ๋ถ€์ด๊ณ , ๋ฌธ๊ตฌ๋Š” ํ™”๋ฉด์˜ ๋ชซ์ด๋‹ค. figure-model ์ด ๋ฌธ๊ตฌ๋ฅผ ์–ธ์–ด ์ค‘๋ฆฝ์œผ๋กœ ๋ฐ”๊พธ๋ฉด\n * ๊ทธ๋•Œ `label` ์„ ์“ธ ์ˆ˜ ์žˆ๋‹ค.\n */\n private renderBudgets() {\n const score = this.score\n if (!score) return nothing\n\n return html`\n <section>\n <h3>${i18next.t('figure.label.budgets')}</h3>\n <ul budgets>\n ${score.budgets.map(use => {\n const ratio = Math.min(1, use.ratio)\n const tight = use.key === score.tightest.key\n return html`\n <li>\n <span>${i18next.t('figure.label.budget-' + use.key)}</span>\n <span>${use.used} / ${use.limit}</span>\n <div bar><i ?tight=${tight} style=\"width:${Math.round(ratio * 100)}%\"></i></div>\n </li>\n `\n })}\n </ul>\n </section>\n `\n }\n\n private renderMetrics() {\n const cost = this.cost\n if (!cost) return nothing\n\n return html`\n <section>\n <h3>${i18next.t('figure.label.weight')}</h3>\n <dl metrics>\n <dt>${i18next.t('figure.label.triangles')}</dt>\n <dd>${cost.triangles.toLocaleString()}</dd>\n\n <dt>${i18next.t('figure.label.triangles-at-100')}</dt>\n <dd>${cost.at.triangles.toLocaleString()}</dd>\n\n <dt>${i18next.t('figure.label.draw-calls-at-100')}</dt>\n <dd>${cost.at.drawCalls.toLocaleString()}</dd>\n\n <dt>${i18next.t('figure.label.distinct-shapes')}</dt>\n <dd>${cost.distinctShapes}</dd>\n\n <dt>${i18next.t('figure.label.distinct-materials')}</dt>\n <dd>${cost.distinctMaterials}</dd>\n </dl>\n </section>\n `\n }\n\n /**\n * ์žฌํ™œ์šฉ ์ถ”์ด โ€” ใ€Œ๋งŽ์ด ๋†“์œผ๋ฉด ์–ด๋–ป๊ฒŒ ๋˜๋‚˜ใ€์— ๋‹ตํ•œ๋‹ค.\n *\n * ## ๊ทธ๋ฆผ์„ ์‚ฌ์ด๋“œ๋ฐ”์— ๋ฐ€์–ด ๋„ฃ์ง€ ์•Š๋Š”๋‹ค\n *\n * `costCurveSvg` ์˜ ์ž์—ฐ ํฌ๊ธฐ๋Š” 680x380 ์ด๊ณ  ๊ธ€์ž๊ฐ€ 11px ๋‹ค. 300px ์นธ์—์„œ\n * width:100% ๋กœ ์ค„์ด๋ฉด ๊ธ€์ž๊ฐ€ 4px ์ด ๋˜์–ด **์•„๋ฌด๊ฒƒ๋„ ์ฝ์„ ์ˆ˜ ์—†๋‹ค** โ€” ํ™”๋ฉด์„ ๋„์›Œ\n * ๋ณด๊ณ ์„œ์•ผ ๋“œ๋Ÿฌ๋‚ฌ๋‹ค. ์ฝ์„ ์ˆ˜ ์—†๋Š” ๊ทธ๋ฆผ์€ ์—†๋Š” ๊ฒƒ๊ณผ ๊ฐ™์œผ๋ฏ€๋กœ, ์‚ฌ์ด๋“œ๋ฐ”์—๋Š” ์ €์ž‘์ž๊ฐ€\n * ์‹ค์ œ๋กœ ๊ถ๊ธˆํ•œ ์ˆซ์ž(1๋งŒ ๊ฐœ์ผ ๋•Œ)๋ฅผ ๋‘๊ณ  ๊ทธ๋ฆผ์€ ์„ ํƒํ•ด์„œ ์ œ ํฌ๊ธฐ๋กœ ๋ณธ๋‹ค.\n */\n private renderCurve() {\n const many = this.many\n if (!many && !this.curve) return nothing\n\n return html`\n <section>\n <h3>${i18next.t('figure.label.reuse-trend')}</h3>\n ${many\n ? html`\n <dl metrics>\n <dt>${i18next.t('figure.label.triangles-at-10k')}</dt>\n <dd>${many.at.triangles.toLocaleString()}</dd>\n\n <dt>${i18next.t('figure.label.draw-calls-at-10k')}</dt>\n <dd>${many.at.drawCalls.toLocaleString()}</dd>\n </dl>\n `\n : nothing}\n ${this.curve\n ? html`\n <button expand @click=${() => (this.expanded = true)}>\n ${i18next.t('figure.button.see-the-trend-chart')}\n </button>\n `\n : nothing}\n </section>\n `\n }\n\n /** ๊ทธ๋ฆผ์„ ์ œ ํฌ๊ธฐ๋กœ ๋ณด์—ฌ ์ค€๋‹ค. ์ข์œผ๋ฉด ์ค„์ด์ง€ ์•Š๊ณ  ๋„˜๊ฒจ ๋ณด๊ฒŒ ๋‘”๋‹ค. */\n private renderSheet() {\n if (!this.expanded || !this.curve) return nothing\n\n return html`\n <div sheet @click=${() => (this.expanded = false)}>\n <figure @click=${(e: Event) => e.stopPropagation()}>\n ${unsafeSVG(this.curve)}\n <figcaption>\n <button close @click=${() => (this.expanded = false)}>${i18next.t('figure.button.close')}</button>\n </figcaption>\n </figure>\n </div>\n `\n }\n\n /**\n * ๋ฐœ๊ฒฌ.\n *\n * ์˜ค๋ฅ˜(๋ง‰๋Š” ๊ฒƒ)์™€ ์œ„๋ฐ˜(์•Œ๋ฆฌ๋Š” ๊ฒƒ)์„ **๊ฐ€๋ ค์„œ** ๋ณด์—ฌ ์ค€๋‹ค. ์„ž์œผ๋ฉด ์ €์ž‘์ž๊ฐ€ ๋ฌด์—‡์„\n * ๋ฐ˜๋“œ์‹œ ๊ณ ์ณ์•ผ ํ•˜๋Š”์ง€ ๋ชจ๋ฅธ๋‹ค. ์•„๋ฌด๊ฒƒ๋„ ์—†์œผ๋ฉด ใ€Œ์—†๋‹คใ€๊ณ  ๋งํ•œ๋‹ค โ€” ๋นˆ ์ž๋ฆฌ๋กœ ๋‘๋ฉด\n * ๊ฒ€์‚ฌ๊ฐ€ ๋Œ์•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค.\n */\n private renderFindings() {\n if (this.errors.length === 0 && this.violations.length === 0 && this.sizing.length === 0) {\n return html`\n <section>\n <h3>${i18next.t('figure.label.findings')}</h3>\n <p quiet>${i18next.t('figure.text.no-findings')}</p>\n </section>\n `\n }\n\n return html`\n <section>\n <h3>${i18next.t('figure.label.findings')}</h3>\n <ul findings>\n ${this.sizing.map(\n finding => html`\n <li ?violation=${!finding.blocking}>\n <md-icon>call_split</md-icon>\n <span>${finding.message} ${finding.at ? html`<code at>${finding.at}</code>` : ''}</span>\n </li>\n `\n )}\n ${this.errors.map(\n e => html`\n <li>\n <md-icon>error</md-icon>\n <span>${e.message} ${e.at ? html`<code at>${e.at}</code>` : ''}</span>\n </li>\n `\n )}\n ${this.violations.map(\n v => html`\n <li ?violation=${!v.blocking}>\n <md-icon>${v.blocking ? 'block' : 'info'}</md-icon>\n <span>\n ${v.message}${v.blocking && v.actual !== undefined\n ? html` <code at>${v.actual}</code>`\n : ''}\n </span>\n </li>\n `\n )}\n </ul>\n </section>\n `\n }\n\n /** ์›๋ณธ ๋ฐ์ดํ„ฐ๋ฅผ ์ธก์ •ํ•ด ๊ฒฐ๊ณผ๋ฅผ ์ƒํƒœ์— ๋‹ด๋Š”๋‹ค. ์…ˆ์€ ์ „๋ถ€ figure-model ์ด ํ•œ๋‹ค. */\n private measure() {\n const source = this.source\n if (!source) {\n this.cost = undefined\n this.score = undefined\n this.many = undefined\n this.capacity = undefined\n this.curve = ''\n this.errors = []\n this.violations = []\n this.sizing = []\n return\n }\n\n /*\n ๋ถ€ํ’ˆ์ด ์—†์œผ๋ฉด ํŒ์ •์„ ์•„์˜ˆ ํ•˜์ง€ ์•Š๋Š”๋‹ค โ€” ์žด ๊ฒƒ์ด ์—†๋‹ค. ใ€Œ๋ฌด์—‡์„ ๊ณ ์ณ์•ผ ํ•˜๋‚˜ใ€๊ฐ€ ์•„๋‹ˆ๋ผ\n ใ€Œ๋ฌด์—‡๋ถ€ํ„ฐ ๋†“๋‚˜ใ€์ธ ์ƒํƒœ์ด๊ณ , ๊ทธ ์•ˆ๋‚ด๋Š” ๋ถ€ํ’ˆ ๋ชฉ๋ก์ด ์ด๋ฏธ ํ•˜๊ณ  ์žˆ๋‹ค.\n */\n this.bare = !source.parts?.length\n if (this.bare) {\n this.cost = undefined\n this.score = undefined\n this.many = undefined\n this.capacity = undefined\n this.curve = ''\n this.errors = []\n this.violations = []\n this.sizing = []\n return\n }\n\n const result = validate(source)\n this.errors = result.errors.map(e => ({ code: e.code, message: e.message, at: e.path }))\n this.violations = result.violations.map(v => ({\n code: v.code,\n message: v.message,\n blocking: blocksRelease(v.code),\n actual: v.actual\n }))\n\n if (this.errors.length > 0) {\n // ํ˜•์‹์„ ์–ด๊ฒผ์œผ๋ฉด ์ปดํŒŒ์ผ์ด ๋˜์ง„๋‹ค. ์…ˆ์„ ๋น„์šฐ๊ณ  ์˜ค๋ฅ˜๋งŒ ๋ณด์—ฌ ์ค€๋‹ค.\n this.cost = undefined\n this.score = undefined\n this.many = undefined\n this.capacity = undefined\n this.curve = ''\n this.sizing = []\n this.dispatchEvent(\n new CustomEvent('verdict-changed', { detail: {}, bubbles: true, composed: true })\n )\n return\n }\n\n const blueprint = compile(source)\n\n /*\n ํฌ๊ธฐ๋ฅผ ๋ฐ”๊ฟ” ๋ณด๋Š” ์ผ๊ณฑ ์กฐํ•ฉ. ํŒ์ • ๊ทœ์น™์€ `figure-model` ์˜ `gate.ts` ๊ฐ€ ์ •ํ•œ ๊ฒƒ์„ ๊ทธ๋Œ€๋กœ\n ์“ด๋‹ค โ€” ๋ฌด์—‡์ด ๋ง‰๋Š” ๊ฒƒ์ธ์ง€ ํ™”๋ฉด์ด ๋‹ค์‹œ ์ •ํ•˜๋ฉด ์„œ๋ฒ„์™€ ๋‹ค๋ฅธ ๋ง์„ ํ•˜๊ฒŒ ๋œ๋‹ค.\n */\n const report = sizingReport(blueprint)\n this.sizing = report.findings.map(finding => ({\n code: finding.code,\n message: finding.message,\n /* ์ˆซ์ž๊ฐ€ ์•„๋‹ˆ๋ผ ์ž๋ฆฌ๋ฅผ ๋งํ•œ๋‹ค โ€” ๊ฐˆ๋ผ์ ธ ๋‚˜์˜จ ๋ถ€ํ’ˆ ์ด๋ฆ„์ด ๊ณ ์น  ์ž๋ฆฌ๋‹ค. */\n at: finding.clumps.map(clump => [...clump].sort().join('+')).join(' | ') || undefined,\n blocking: finding.code === 'sizing-splits'\n }))\n\n this.cost = costOf(blueprint, 100)\n // 1๋งŒ ๊ฐœ๋Š” figure-model ์— ๋‹ค์‹œ ๋ฌป๋Š”๋‹ค โ€” ํ™”๋ฉด์ด ๊ณฑ์…ˆ์œผ๋กœ ์ง์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค.\n this.many = costOf(blueprint, 10000)\n this.score = scoreOf(blueprint)\n this.capacity = capacityOf(this.cost)\n\n // ๊ฐœ์ˆ˜๋ฅผ ๋ฐ–์œผ๋กœ ์•Œ๋ฆฐ๋‹ค. ํƒญ ์ด๋ฆ„ํ‘œ๊ฐ€ ์ด ๊ฐ’์„ ๋ณด์—ฌ ์ฃผ๋Š”๋ฐ, ๊ฑฐ๊ธฐ์„œ ๋‹ค์‹œ ์…ˆํ•˜๋ฉด\n // ๊ฐ™์€ ํ˜•์ƒ์ด ๋‘ ์ž๋ฆฌ์—์„œ ๋‹ค๋ฅด๊ฒŒ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋‹ค.\n this.dispatchEvent(\n new CustomEvent('verdict-changed', {\n detail: { instances: this.capacity?.instances, grade: this.score?.grade },\n bubbles: true,\n composed: true\n })\n )\n this.curve = costCurveSvg(blueprint)\n }\n}\n"]}
1
+ {"version":3,"file":"figure-report.js","sourceRoot":"","sources":["../../client/modeller/figure-report.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport { css, html, LitElement, nothing, svg } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { unsafeSVG } from 'lit/directives/unsafe-svg.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\nimport { blocksRelease, compile, costCurveSvg, costOf, scoreOf, sizingReport, validate } from '@hatiolab/figure-model'\nimport type { FigureCost, FigureScore, FigureSource } from '@hatiolab/figure-model'\n\nimport { capacityOf, MEASURED } from './scene-budget.js'\nimport { maturityOf } from './maturity.js'\nimport type { MaturityAxis } from './maturity.js'\nimport type { FigureCapacity } from './scene-budget.js'\n\n/**\n * ํŒ๋‹จ ํŒจ๋„. ๋ชจ๋ธ๋Ÿฌ ํ™”๋ฉด์— **๋Š˜ ๋–  ์žˆ๋‹ค.**\n *\n * ์ €์žฅ์„ ์„ ํƒํ•ด์•ผ ์•„๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค. ๋ถ€ํ’ˆ์„ ํ•˜๋‚˜ ๋†“์„ ๋•Œ๋งˆ๋‹ค ๋ฌด๊ฒŒ์™€ ์ ์ˆ˜๊ฐ€ ์›€์ง์ด๊ณ ,\n * ๊ทธ๊ฒƒ์ด ๋ณด์—ฌ์•ผ ์ €์ž‘์ž๊ฐ€ ๊ณ ์น  ์ˆ˜ ์žˆ๋‹ค. ใ€Œ๋ฌด์—‡ ๋•Œ๋ฌธ์— ์ ์ˆ˜๊ฐ€ ๋‚ฎ์€๊ฐ€ใ€๋ฅผ ๋งํ•ด ์ฃผ์ง€\n * ์•Š์œผ๋ฉด ์ ์ˆ˜๋Š” ์ž”์†Œ๋ฆฌ์ผ ๋ฟ์ด๋‹ค.\n *\n * ## ์…ˆ์„ ์—ฌ๊ธฐ์„œ ํ•˜์ง€ ์•Š๋Š”๋‹ค\n *\n * ๊ฒ€์ฆยท์›๊ฐ€ยท์ ์ˆ˜๋Š” ์ „๋ถ€ `@hatiolab/figure-model` ์ด ํ•œ๋‹ค. ํ™”๋ฉด์€ **๋ถ€๋ฅด๊ณ  ๋ณด์—ฌ ์ค„\n * ๋ฟ**์ด๋‹ค. ํ•œ๋„๋‚˜ ๋“ฑ๊ธ‰ ๊ฒฝ๊ณ„๋ฅผ ํ™”๋ฉด์ด ๋‹ค์‹œ ์ •ํ•˜๋ฉด ์„œ๋ฒ„๊ฐ€ ๊ฑฐ์ ˆํ•  ๊ฒƒ์„ ํ™”๋ฉด์ด\n * ํ†ต๊ณผ์‹œํ‚ค๊ฒŒ ๋œ๋‹ค.\n */\n@customElement('figure-report')\nexport class FigureReport extends localize(i18next)(LitElement) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n overflow-y: auto;\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 section {\n padding: var(--spacing-medium, 8px) var(--spacing-large, 12px);\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n section > h3 {\n margin: 0 0 6px 0;\n font-size: var(--ui-t-micro, 11px);\n font-weight: 700;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n\n /* โ”€โ”€ ๋ช‡ ๊ฐœ๊นŒ์ง€ ํŽธํ•œ๊ฐ€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n ๋กœ์šฐํด๋ฆฌ์˜ ๊ฐ’์€ ใ€Œ์–ผ๋งˆ๋‚˜ ๋งŽ์ด ํŽธํ•˜๊ฒŒ ๋†“์„ ์ˆ˜ ์žˆ๋‚˜ใ€๋‹ค. ๊ทธ ๋‹ต์ด ๋จธ๋ฆฌ์— ์˜จ๋‹ค.\n ๋“ฑ๊ธ‰์€ ํ˜•์ƒ ์ž์ฒด๊ฐ€ ํ•œ๋„ ์•ˆ์ธ์ง€๋ฅผ ๋งํ•  ๋ฟ์ด๋ผ ์˜†์˜ ์ž‘์€ badge ๋กœ ๋‘”๋‹ค. */\n div[verdict] {\n display: flex;\n align-items: baseline;\n gap: 6px;\n }\n span[capacity] {\n font-size: 2.1rem;\n font-weight: 800;\n line-height: 1;\n letter-spacing: -0.01em;\n color: var(--md-sys-color-primary);\n }\n span[unit] {\n font-size: 0.9rem;\n font-weight: 600;\n color: var(--md-sys-color-primary);\n }\n /*\n ๋“ฑ๊ธ‰ badge.\n\n ์ „์—๋Š” \"C 0\" ๋งŒ ์žˆ์—ˆ๋‹ค. ๊ธ€์ž ํ•˜๋‚˜์™€ ์ˆซ์ž ํ•˜๋‚˜์ธ๋ฐ ์–ด๋””์—๋„ ๋œป์ด ์—†์–ด์„œ, ํฌ๊ฒŒ ๋œฌ\n ๊ฐœ์ˆ˜ ์˜†์— ๋นจ๊ฐ„ badge ๊ฐ€ ๋ถ™์€ ๊ฒƒ์œผ๋กœ๋งŒ ์ฝํ˜”๋‹ค. 0 ์„ 100์  ๋งŒ์ ์˜ 0 ์ ์œผ๋กœ ์ฝ๋Š” ๊ฒƒ์ด\n ์ž์—ฐ์Šค๋Ÿฝ๋‹ค. ์‹ค์ œ ๋œป์€ \"์„ ์–ธํ•œ ํ•œ๋„์— ๋‚จ์€ ์—ฌ์œ ๊ฐ€ 0\" ์ด๋‹ค.\n\n ๊ทธ๋ž˜์„œ ๋ฌด์—‡์„ ์ธก์ •ํ•˜๋Š”์ง€๋ฅผ badge ์•ˆ์— ์ ๊ณ , ๋ˆˆ๊ธˆ์€ ๋ฐ”๋กœ ์•„๋ž˜ ์ค„์— ๋Š˜ ๋ณด์ด๊ฒŒ ๋‘”๋‹ค.\n */\n span[grade] {\n display: flex;\n align-items: baseline;\n gap: 5px;\n margin-left: auto;\n padding: 3px 10px;\n font-size: 0.76rem;\n font-weight: 700;\n color: var(--md-sys-color-on-primary-container);\n background-color: var(--md-sys-color-primary-container);\n border-radius: 999em;\n }\n span[grade] small {\n font-size: 0.68rem;\n font-weight: 500;\n }\n /*\n C ๋Š” ํ•œ๋„๋ฅผ ์ง€ํ‚จ ๊ฒƒ์ด๋‹ค. ๋นจ๊ฐ•์€ ๋„˜๊ธด ๊ฒƒ(D)์—๋งŒ ์“ด๋‹ค. ์ง€ํ‚จ ๊ฒƒ์— ๋นจ๊ฐ•์„ ์“ฐ๋ฉด\n ๊ณ ์น  ๊ฒƒ์ด ์—†๋Š”๋ฐ๋„ ๊ณ ์ณ์•ผ ํ•  ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค.\n */\n span[grade][tight] {\n color: var(--md-sys-color-on-tertiary-container, #3d2f00);\n background-color: var(--md-sys-color-tertiary-container, #ffdf9a);\n }\n /*\n Pair the container with its on-container.\n\n This used to fill with --md-sys-color-error and write with\n --md-sys-color-on-error-container. Once the palette made containers\n neutral and moved the meaning into the text colour, those two became the\n same red and the badge went blank -- a filled pill with no readable text.\n */\n span[grade][over] {\n color: var(--md-sys-color-on-error-container);\n background-color: var(--md-sys-color-error-container);\n }\n\n /* ๋“ฑ๊ธ‰ ๋ˆˆ๊ธˆ. ์ ‘์–ด ๋‘์ง€ ์•Š๋Š”๋‹ค โ€” ํ•œ ๋ฒˆ ๋ณด๊ณ  ๋งˆ๋Š” ๊ฐ’์ด ์•„๋‹ˆ๋ผ ๋ณผ ๋•Œ๋งˆ๋‹ค ํ•„์š”ํ•˜๋‹ค */\n p[scale] {\n display: flex;\n flex-wrap: wrap;\n gap: 2px 10px;\n margin: 6px 0 0 0;\n font-size: 0.7rem;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n p[scale] b {\n font-weight: 700;\n }\n p[scale] span[now] b {\n color: var(--md-sys-color-primary);\n }\n p[scale] span[now] {\n color: var(--md-sys-color-on-surface);\n }\n /* ์ด ํฐ ์ˆซ์ž๊ฐ€ ์–ด๋А ์ถ•์ธ์ง€ ๋จผ์ € ๋งํ•œ๋‹ค โ€” ์„ฑ์ˆ™๋„์˜ ํ•œ ์ถ•์ด์ง€ ์ „๋ถ€๊ฐ€ ์•„๋‹ˆ๋‹ค */\n p[lead] {\n margin: 0 0 4px 0;\n font-size: 0.74rem;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n\n /* ๊ทผ๊ฑฐ๋ฅผ ํ•จ๊ป˜ ๋‚ธ๋‹ค โ€” ์ˆซ์ž๋งŒ ํฌ๊ฒŒ ๋‚ด๊ฑธ๋ฉด ์žฌ ๋ณธ ๊ฐ’์ฒ˜๋Ÿผ ์ฝํžŒ๋‹ค */\n p[basis] {\n margin: 6px 0 0 0;\n font-size: 0.72rem;\n line-height: 1.55;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n p[basis] em {\n font-style: normal;\n color: var(--md-sys-color-tertiary);\n }\n span[score] {\n font-size: 0.8rem;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n\n /* ๋ฌด์—‡ ๋•Œ๋ฌธ์— ์ด ๋“ฑ๊ธ‰์ธ๊ฐ€ โ€” ํ•œ๋„์— ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ํ•ญ๋ชฉ */\n p[because] {\n margin: 8px 0 0 0;\n /* ๋ณธ๋ฌธ ํฌ๊ธฐ๋ฅผ ๋ฌผ๋ ค๋ฐ›์œผ๋ฉด ์ด ์ค„๋งŒ ์ œ๋ชฉ์ฒ˜๋Ÿผ ์ปค์ง„๋‹ค โ€” ํ™”๋ฉด์„ ๋„์›Œ ๋ณด๊ณ  ์•Œ์•˜๋‹ค */\n font-size: 0.78rem;\n line-height: 1.6;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n p[because] strong {\n color: var(--md-sys-color-on-surface);\n }\n\n /* โ”€โ”€ ์„ฑ์ˆ™๋„ radar โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n ์—ฌ์„ฏ ์ถ•์„ ํ•œ ๊ทธ๋ฆผ์œผ๋กœ. ๋ชฉ๋ก๋งŒ ๋‘๋ฉด ใ€Œ์–ด๋А ์ชฝ์ด ๋ชจ์ž๋ž€๊ฐ€ใ€๊ฐ€ ์•ˆ ๋ณด์ธ๋‹ค.\n ๋ชป ์žฐ ์ถ•์€ ์ ์„ ์ฐ์ง€ ์•Š๊ณ  ์‚ด๋งŒ ํ๋ฆฌ๊ฒŒ ๋‚จ๊ธด๋‹ค โ€” 0 ์œผ๋กœ ์ฐ์œผ๋ฉด ใ€Œ๋‚˜์˜๋‹คใ€๊ฐ€ ๋œ๋‹ค. */\n div[radar] {\n display: flex;\n justify-content: center;\n padding: 2px 0 6px 0;\n color: var(--md-sys-color-primary);\n }\n div[radar] svg {\n width: 100%;\n max-width: 240px;\n height: auto;\n }\n div[radar] polygon[web] {\n fill: none;\n stroke: var(--md-sys-color-outline-variant);\n stroke-width: 0.6;\n }\n div[radar] line[spoke] {\n stroke: var(--md-sys-color-outline-variant);\n stroke-width: 0.6;\n }\n div[radar] polygon[shape] {\n fill: color-mix(in srgb, var(--md-sys-color-primary) 22%, transparent);\n stroke: var(--md-sys-color-primary);\n stroke-width: 1.4;\n stroke-linejoin: round;\n }\n div[radar] circle[dot] {\n fill: var(--md-sys-color-primary);\n }\n div[radar] text {\n font-size: 5.2px;\n fill: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n\n /* ๊ทธ๋ฆผ์— ์ž๋ฆฌ๋ฅผ ์ฃผ์ง€ ์•Š์€ ์ถ•์„ ๊ธ€๋กœ ๋ฐํžŒ๋‹ค */\n p[unmeasured] {\n margin: 0 0 8px 0;\n font-size: 0.7rem;\n line-height: 1.5;\n color: var(--md-sys-color-tertiary);\n }\n\n /* โ”€โ”€ ์„ฑ์ˆ™๋„ ์ถ• โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n ํ•œ ์ˆซ์ž๋กœ ํ•ฉ์น˜์ง€ ์•Š๋Š”๋‹ค. ํ•ฉ์น˜๋ฉด ใ€Œ๋ฌด์—‡์„ ๊ณ ์ณ์•ผ ํ•˜๋‚˜ใ€๊ฐ€ ์‚ฌ๋ผ์ง„๋‹ค. */\n ul[axes] {\n margin: 0;\n padding: 0;\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 7px;\n }\n ul[axes] li {\n display: grid;\n grid-template-columns: 1fr auto;\n gap: 2px 8px;\n font-size: 0.75rem;\n }\n ul[axes] li[blocked] {\n opacity: 0.7;\n }\n ul[axes] em {\n grid-column: 1 / -1;\n font-style: normal;\n font-size: 0.68rem;\n line-height: 1.5;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n /* ๋ชป ์žฐ ์ถ•์€ 0 ์œผ๋กœ ๋‘์ง€ ์•Š๋Š”๋‹ค โ€” 0 ์€ ใ€Œ๋‚˜์˜๋‹คใ€๋Š” ๋œป์ด ๋˜์–ด ๋ฒ„๋ฆฐ๋‹ค */\n ul[axes] li[blocked] em {\n color: var(--md-sys-color-tertiary);\n }\n span[reading] {\n font-family: var(--mono-font, monospace);\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n\n /* โ”€โ”€ ์˜ˆ์‚ฐ ๋ง‰๋Œ€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */\n ul[budgets] {\n margin: 0;\n padding: 0;\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n ul[budgets] li {\n display: grid;\n grid-template-columns: 1fr auto;\n gap: 2px 8px;\n font-size: 0.75rem;\n }\n div[bar] {\n grid-column: 1 / -1;\n height: 4px;\n background-color: var(--md-sys-color-surface-container-highest);\n border-radius: 2px;\n overflow: hidden;\n }\n div[bar] > i {\n display: block;\n height: 100%;\n background-color: var(--md-sys-color-primary);\n }\n div[bar] > i[tight] {\n background-color: var(--md-sys-color-error);\n }\n\n /* โ”€โ”€ ๋ฌด๊ฒŒ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */\n dl[metrics] {\n margin: 0;\n display: grid;\n grid-template-columns: 1fr auto;\n gap: 4px 8px;\n font-size: 0.78rem;\n }\n dl[metrics] dt {\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n dl[metrics] dd {\n margin: 0;\n text-align: right;\n font-family: var(--mono-font, monospace);\n }\n\n /* โ”€โ”€ ์ถ”์ด โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€\n ๊ทธ๋ฆผ์€ ์ž์—ฐ ํฌ๊ธฐ๊ฐ€ 680px ๋‹ค. 300px ์นธ์— ๋„ฃ์œผ๋ฉด ๊ธ€์ž๊ฐ€ 4px ์ด ๋˜์–ด ์•„๋ฌด๊ฒƒ๋„\n ์ฝ์„ ์ˆ˜ ์—†๋‹ค โ€” ์‚ฌ์ด๋“œ๋ฐ”์—๋Š” ์ˆซ์ž๋ฅผ ๋‘๊ณ , ๊ทธ๋ฆผ์€ ์„ ํƒํ•ด์„œ ํฌ๊ฒŒ ๋ณธ๋‹ค. */\n button[expand] {\n margin-top: 6px;\n padding: 4px 10px;\n font: var(--label-font, inherit);\n font-size: 0.74rem;\n color: var(--md-sys-color-on-surface);\n background: none;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 6px;\n cursor: pointer;\n }\n button[expand]:hover {\n background-color: var(--md-sys-color-surface-container);\n }\n\n div[sheet] {\n position: fixed;\n inset: 0;\n z-index: 10;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: var(--spacing-large, 12px);\n background-color: rgba(0, 0, 0, 0.32);\n }\n div[sheet] > figure {\n max-width: 100%;\n max-height: 100%;\n margin: 0;\n padding: var(--spacing-large, 12px);\n overflow: auto;\n color: var(--md-sys-color-primary);\n background-color: var(--md-sys-color-surface-container-lowest);\n /* ๋‹ด๋Š” ๋ฉด์ด ํŒ์—…์ด๋ฉด ์•ˆ์ชฝ ๋ชจ์„œ๋ฆฌ๋Š” ์•Œ์•ฝ์ด๋‹ค โ€” ์‹œํŠธ ์ž์ฒด๋Š” ํŽ˜์ด์ง€ ๊ฐ’์„ ์“ด๋‹ค */\n border-radius: 6px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.28);\n }\n div[sheet] svg {\n display: block;\n /* ์ž์—ฐ ํฌ๊ธฐ๋ณด๋‹ค ์ž‘๊ฒŒ ์ค„์ด์ง€ ์•Š๋Š”๋‹ค โ€” ์ข์œผ๋ฉด ๋„˜๊ฒจ ๋ณด๊ฒŒ ๋‘”๋‹ค */\n min-width: 680px;\n }\n div[sheet] figcaption {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n }\n div[sheet] button[close] {\n padding: 5px 14px;\n font: var(--label-font, inherit);\n color: var(--md-sys-color-on-surface);\n background: none;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 999em;\n cursor: pointer;\n }\n\n /* โ”€โ”€ ์•Œ๋ฆผ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ */\n ul[findings] {\n margin: 0;\n padding: 0;\n list-style: none;\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n ul[findings] li {\n display: flex;\n gap: 6px;\n line-height: 1.5;\n }\n ul[findings] md-icon {\n --md-icon-size: 16px;\n flex: none;\n color: var(--md-sys-color-error);\n }\n ul[findings] li[violation] md-icon {\n color: var(--md-sys-color-tertiary);\n }\n /* ์–ด๊ธด ์ž๋ฆฌ. ๋ฌธ๊ตฌ์— ๋ถ™์–ด ํ๋ฅด๋ฉด ๋ฌธ์žฅ์˜ ์ผ๋ถ€๋กœ ์ฝํžŒ๋‹ค โ€” badge ๋กœ ๋ณด์ด๊ฒŒ ๋—€๋‹ค */\n code[at] {\n padding: 1px 5px;\n font-family: var(--mono-font, monospace);\n font-size: 0.68rem;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n background-color: var(--md-sys-color-surface-container);\n border-radius: 4px;\n white-space: nowrap;\n }\n\n /*\n ๋ฐœ๊ฒฌ์ด ์—†์„ ๋•Œ์˜ ๋ฌธ๊ตฌ.\n\n ํฌ๊ธฐ๋ฅผ ์•ˆ ์ ์–ด ๋‘์—ˆ๋”๋‹ˆ ๋ณธ๋ฌธ ๊ธฐ๋ณธ ํฌ๊ธฐ๋ฅผ ๋ฌผ๋ ค๋ฐ›์•„ ์ด ์ค„๋งŒ ์ œ๋ชฉ์ฒ˜๋Ÿผ ์ปค์กŒ๋‹ค. ์ด\n ํŒจ๋„์˜ ๊ธ€์ž๋Š” ์ „๋ถ€ 0.7rem ๋Œ€์ธ๋ฐ ์—ฌ๊ธฐ๋งŒ 1rem ์ด๋ผ ์•„๋ž˜์ชฝ์ด ๋ฌด๋„ˆ์ ธ ๋ณด์˜€๋‹ค.\n\n ์ฐพ์€ ๊ฒƒ์ด ์žˆ์„ ๋•Œ์˜ ๋ชฉ๋ก(ul[findings] li)๊ณผ ๊ฐ™์€ ํฌ๊ธฐ๋กœ ๋งž์ถ˜๋‹ค. ์žˆ์„ ๋•Œ์™€ ์—†์„ ๋•Œ\n ์ ˆ์˜ ์ƒ๊น€์ƒˆ๊ฐ€ ๋‹ฌ๋ผ์งˆ ์ด์œ ๊ฐ€ ์—†๋‹ค.\n\n ์ด ํŒŒ์ผ์—์„œ ๊ฐ™์€ ์‹ค์ˆ˜๋ฅผ ๋‘ ๋ฒˆ์งธ๋กœ ํ•œ๋‹ค. p[because] ์—๋„ ๊ฐ™์€ ์ฃผ์„์ด ์žˆ๋‹ค.\n */\n p[quiet] {\n margin: 0;\n font-size: 0.76rem;\n line-height: 1.6;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n `\n ]\n\n /** ์ €์ž‘ ์ค‘์ธ ์›๋ณธ ๋ฐ์ดํ„ฐ. ๋ฐ”๋€Œ๋ฉด ๋‹ค์‹œ ์ธก์ •ํ•œ๋‹ค. */\n @property({ type: Object }) source?: FigureSource\n\n @state() private cost?: FigureCost\n @state() private score?: FigureScore\n @state() private curve = ''\n /** 1๋งŒ ๊ฐœ๋ฅผ ๋†“์•˜์„ ๋•Œ. ์ €์ž‘์ž๊ฐ€ ์‹ค์ œ๋กœ ๊ถ๊ธˆํ•œ ์ˆซ์ž๋‹ค. */\n @state() private many?: FigureCost\n /** ๋ช‡ ๊ฐœ๊นŒ์ง€ ๋†“์„ ์ˆ˜ ์žˆ๋‚˜. ์ด ํŒจ๋„์˜ ๋จธ๋ฆฌ๋‹ค. */\n @state() private capacity?: FigureCapacity\n /** ์ถ”์ด ๊ทธ๋ฆผ์„ ์ œ ํฌ๊ธฐ๋กœ ํŽผ์ณค๋‚˜. */\n @state() private expanded = false\n @state() private errors: { code: string; message: string; at?: string }[] = []\n /**\n * ํ˜•์‹์ด ๊ถŒํ•˜์ง€ ์•Š๋Š” ๊ฒƒ โ€” **๊ทธ์ค‘ ๋‘˜์€ ๋ฐœํ–‰์„ ๋ง‰๋Š”๋‹ค.**\n *\n * ๋“ฑ๊ธ‰์„ ํ˜•์‹์—์„œ ๋ฐ›๋Š”๋‹ค(`blocksRelease`). ํ™”๋ฉด์ด ์ œ ๋ชฉ๋ก์„ ๋“ค๋ฉด ํ˜•์‹์— ์ฝ”๋“œ๊ฐ€ ํ•˜๋‚˜ ๋Š˜ ๋•Œ\n * ์กฐ์šฉํžˆ ใ€Œ์•Œ๋ฆผใ€์œผ๋กœ ๊ทธ๋ ค์ง€๊ณ , ์ €์ž‘์ž๋Š” ๋ฐœํ–‰์ด ๋ง‰ํžŒ ๊ฒƒ์„ **๋ˆŒ๋Ÿฌ ๋ณด๊ณ  ๋‚˜์„œ์•ผ** ์•ˆ๋‹ค.\n *\n * `actual` ์€ ์–ผ๋งˆ๋‚˜ ๋„˜์ณค๋‚˜๋‹ค. ใ€Œ์ƒ์ž๋ฅผ ๋ฒ—์–ด๋‚œ๋‹คใ€๋งŒ์œผ๋กœ๋Š” 2mm ์ธ์ง€ 250mm ์ธ์ง€ ๋ชจ๋ฅด๊ณ ,\n * ๊ทธ ๋‘˜์€ ๊ณ ์น˜๋Š” ํ’ˆ์ด ๋‹ค๋ฅด๋‹ค.\n */\n @state() private violations: { code: string; message: string; blocking: boolean; actual?: number }[] = []\n /**\n * ํฌ๊ธฐ๋ฅผ ๋ฐ”๊ฟ” ๋ดค์„ ๋•Œ ๊ฐˆ๋ผ์ง€๋Š”๊ฐ€ โ€” **๋ฐœํ–‰์„ ๋ง‰๋Š” ๊ฒƒ**์ด๋‹ค.\n *\n * ์ด๋ ฅ ํƒญ์ด ๊ฐ™์€ ํŒ์ •์„ ์„œ๋ฒ„์—์„œ ๋ฐ›์•„ ๋ฐœํ–‰ ๋ฌธ์„ ์ž ๊ทธ์ง€๋งŒ, ๊ทธ๊ฒƒ์€ **์ €์žฅ๋œ ์ •๋ณธ**์— ๋Œ€ํ•œ\n * ๊ฒƒ์ด๋ผ ์ €์žฅํ•˜๊ธฐ ์ „์—๋Š” ๋‹ตํ•˜์ง€ ๋ชปํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ์ €์ž‘ ์ค‘์ธ ์ •๋ณธ์„ ๊ทธ๋Œ€๋กœ ์žฌ๋ฏ€๋กœ, ๋ถ€ํ’ˆ์„\n * ์˜ฎ๊ธฐ๋Š” ๊ทธ ์ž๋ฆฌ์—์„œ ๊ฐˆ๋ผ์ง์ด ์ƒ๊ฒผ๋Š”์ง€ ์‚ฌ๋ผ์กŒ๋Š”์ง€ ๋ณด์ธ๋‹ค โ€” ์ €์žฅํ•˜๊ณ  ํƒญ์„ ์˜ฎ๊ฒจ ํ™•์ธํ•˜๊ฒŒ\n * ๋‘๋ฉด ๊ณ ์น  ๋•Œ๊ฐ€ ์ด๋ฏธ ์ง€๋‚˜ ์žˆ๋‹ค.\n */\n @state() private sizing: { code: string; message: string; at?: string; blocking: boolean }[] = []\n /**\n * ์•„์ง ๋ถ€ํ’ˆ์ด ํ•˜๋‚˜๋„ ์—†๋‚˜ โ€” **์ €์ž‘ ์ „์ด์ง€ ํ˜•์‹์„ ์–ด๊ธด ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค.**\n *\n * ํ˜•์‹์€ ๋ถ€ํ’ˆ 0๊ฐœ๋ฅผ ์˜ค๋ฅ˜๋กœ ๋ณธ๋‹ค(`missing-parts`). ๋ฐœํ–‰ ๊ด€์ ์—์„œ๋Š” ๋งž๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์ƒˆ๋กœ ๋งŒ๋“ค๊ธฐ๋ฅผ\n * ๋ˆ„๋ฅธ ์งํ›„๊ฐ€ ๋ฐ”๋กœ ๊ทธ ์ƒํƒœ์ด๋ฏ€๋กœ, ๊ทธ๊ฒƒ์„ ๊ทธ๋Œ€๋กœ ์˜ค๋ฅ˜๋กœ ๊ทธ๋ฆฌ๋ฉด **์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š์•˜๋Š”๋ฐ ๋ถ‰์€\n * ํ™”๋ฉด**์„ ๋ณด๊ฒŒ ๋œ๋‹ค. ๊ทธ๋ž˜์„œ ์ด ์ž๋ฆฌ์—์„œ ๋‘˜์„ ๊ฐ€๋ฅธ๋‹ค.\n */\n @state() private bare = false\n\n willUpdate(changed: Map<string, unknown>) {\n if (changed.has('source')) {\n this.measure()\n }\n }\n\n render() {\n /*\n ๋ถ€ํ’ˆ์ด ์—†์œผ๋ฉด ์ด ์ž๋ฆฌ๋Š” **ํŒ์ •์ด ์•„๋‹ˆ๋ผ ์•ˆ๋‚ด**๋‹ค. ์ด๋ฏธ ์žˆ๋˜ ใ€Œ๋ถ€ํ’ˆ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๋‚˜์˜ต๋‹ˆ๋‹คใ€๊ฐ€\n ์ •ํ™•ํžˆ ๊ทธ ๋ง์ด๋ฏ€๋กœ ๊ทธ๊ฒƒ์„ ์“ด๋‹ค โ€” ๊ฐ™์€ ์ƒํƒœ์— ๋ฌธ์žฅ์„ ๋‘˜ ๋‘์ง€ ์•Š๋Š”๋‹ค.\n\n ์•„๋ž˜ ์…ˆ๋“ค(๋จธ๋ฆฌยท์ถ•ยทํ•œ๋„ยท์ถ”์ด)์€ ๋ถ€ํ’ˆ์ด ์žˆ์–ด์•ผ ๋œป์ด ์žˆ๊ณ , ์žฌ์ง€ ์•Š์€ ๊ฐ’์„ ๋“ค๊ณ  ๊ทธ๋ฆฌ๋ฉด 0 ์œผ๋กœ\n ๋ณด์ธ๋‹ค. 0 ์€ ใ€Œ๋‚˜์˜๋‹คใ€๋กœ ์ฝํžˆ๋ฏ€๋กœ ๊ทธ ์ž๋ฆฌ์— ๋‘์ง€ ์•Š๋Š”๋‹ค.\n */\n if (!this.source || this.bare) {\n return html`\n <section>\n <p quiet>${i18next.t('figure.text.report-appears-when-you-add-a-part')}</p>\n </section>\n `\n }\n\n // ํ˜•์‹์„ ์–ด๊ธด ์ƒํƒœ์—์„œ๋Š” ์…ˆ์ด ๋œป์„ ๊ฐ–์ง€ ๋ชปํ•œ๋‹ค โ€” ๋ฌด์—‡์ด ์ž˜๋ชป๋๋Š”์ง€๋งŒ ๋ณด์—ฌ ์ค€๋‹ค.\n if (this.errors.length > 0) {\n return html`${this.renderFindings()}`\n }\n\n return html`\n ${this.renderVerdict()} ${this.renderAxes()} ${this.renderBudgets()} ${this.renderMetrics()} ${this.renderCurve()}\n ${this.renderFindings()} ${this.renderSheet()}\n `\n }\n\n /**\n * ๋จธ๋ฆฌ โ€” ๋ช‡ ๊ฐœ๊นŒ์ง€ ํŽธํ•œ๊ฐ€.\n *\n * ๋กœ์šฐํด๋ฆฌ์˜ ๊ฐ’์€ ใ€Œ์–ผ๋งˆ๋‚˜ ๋งŽ์ด ํŽธํ•˜๊ฒŒ ๋†“์„ ์ˆ˜ ์žˆ๋‚˜ใ€์— ์žˆ๋‹ค. ๋“ฑ๊ธ‰ B ๋Š” ๊ทธ ๋ฌผ์Œ์—\n * ์ง์ ‘ ๋‹ตํ•˜์ง€ ์•Š๋Š”๋‹ค โ€” ํ˜•์ƒ์ด ์„ ์–ธ๋œ ํ•œ๋„ ์•ˆ์ธ์ง€๋ฅผ ๋งํ•  ๋ฟ์ด๋‹ค. ๊ทธ๋ž˜์„œ ๊ฐœ์ˆ˜๋ฅผ\n * ๋จธ๋ฆฌ์— ์˜ฌ๋ฆฌ๊ณ  ๋“ฑ๊ธ‰์€ ์˜†์˜ badge ๋กœ ๋‚ด๋ฆฐ๋‹ค.\n *\n * ๊ทผ๊ฑฐ๋ฅผ ํ•จ๊ป˜ ๋‚ธ๋‹ค. ๋ฌถ์Œ์œผ๋กœ ๊ฐˆ๋ฆฌ๋Š” ๊ฐœ์ˆ˜์˜ ๋ถ„๋ชจ๋Š” **์‹ค์ธก**์ด๊ณ (2026-09-18, Apple M5), ์žฐ\n * ๊ธฐ๊ณ„์™€ ๋‚ ์งœ๋ฅผ ํ•จ๊ป˜ ์ ๋Š”๋‹ค โ€” ์ ์ง€ ์•Š์œผ๋ฉด ์–ด๋””์„œ๋‚˜ ์ฐธ์ธ ์ˆ˜๋กœ ์ฝํžŒ๋‹ค. ์‚ผ๊ฐํ˜• ์ชฝ์€ ์•„์ง ์„ค๊ณ„\n * ๋ฌธ์„œ์˜ ๋ชฉํ‘œ์น˜๋ผ ๊ทธ๋ ‡๋‹ค๊ณ  ์ ๋Š”๋‹ค.\n */\n private renderVerdict() {\n const score = this.score\n const capacity = this.capacity\n if (!score || !capacity) return nothing\n\n return html`\n <section>\n <h3>${i18next.t('figure.label.maturity')}</h3>\n <p lead>${i18next.t('figure.label.axis-scale')} โ€” ${i18next.t('figure.text.how-many-fit')}</p>\n <div verdict>\n <span capacity>${capacity.instances.toLocaleString()}</span>\n <span unit>${i18next.t('figure.text.instances-unit')}</span>\n <span\n grade\n ?tight=${score.grade === 'C'}\n ?over=${score.grade === 'D'}\n title=${i18next.t('figure.text.grade-explained')}\n >\n ${score.grade}\n <small>${i18next.t('figure.text.headroom-percent', { percent: Math.round(score.score) })}</small>\n </span>\n </div>\n <p because>\n ${i18next.t('figure.text.grade-decided-by')}\n <strong>${i18next.t('figure.label.budget-' + score.tightest.key)}</strong>\n โ€” ${score.tightest.used} / ${score.tightest.limit}\n (${Math.round((score.tightest.used / score.tightest.limit) * 100)}%)\n </p>\n ${this.renderGradeScale(score.grade)}\n <p basis>\n ${i18next.t('figure.text.bound-by-' + capacity.bound, {\n per: capacity.per.toLocaleString(),\n budget: capacity.budget.toLocaleString()\n })}\n <em>\n ${capacity.bound === 'groups'\n ? i18next.t('figure.text.budget-measured-on', { gpu: MEASURED.gpu, on: MEASURED.on })\n : i18next.t('figure.text.budget-not-measured-yet')}\n </em>\n </p>\n </section>\n `\n }\n\n /**\n * ๋“ฑ๊ธ‰ ๋ˆˆ๊ธˆ.\n *\n * AยทBยทCยทD ๊ฐ€ ๋ฌด์—‡์„ ๋œปํ•˜๋Š”์ง€ ํ™”๋ฉด ์–ด๋””์—๋„ ์—†์—ˆ๋‹ค. badge ๋งŒ ๋ณด๊ณ ๋Š” ์ข‹์€์ง€ ๋‚˜์œ์ง€๋„,\n * ๋ฌด์—‡์„ ๊ณ ์ณ์•ผ ์˜ค๋ฅด๋Š”์ง€๋„ ์•Œ ์ˆ˜ ์—†๋‹ค. ๋ˆˆ๊ธˆ์„ ๋Š˜ ๊ณ์— ๋‘๊ณ  ์ง€๊ธˆ ์–ด๋””์— ์žˆ๋Š”์ง€๋ฅผ\n * ํ‘œ์‹œํ•œ๋‹ค.\n *\n * ์ ‘์–ด ๋‘์ง€ ์•Š๋Š”๋‹ค. ํ•œ ๋ฒˆ ๋ฐฐ์šฐ๊ณ  ๋งˆ๋Š” ๊ฐ’์ด ์•„๋‹ˆ๋ผ ๋ณผ ๋•Œ๋งˆ๋‹ค ๋Œ€์กฐํ•˜๋Š” ๊ฐ’์ด๋‹ค.\n */\n private renderGradeScale(now: string) {\n const bounds: [string, string][] = [\n ['A', 'โ‰ค 50%'],\n ['B', 'โ‰ค 75%'],\n ['C', 'โ‰ค 100%'],\n ['D', '> 100%']\n ]\n\n return html`\n <p scale>\n <span>${i18next.t('figure.text.grade-scale-lead')}</span>\n ${bounds.map(\n ([grade, bound]) => html`<span ?now=${grade === now}><b>${grade}</b> ${bound}</span>`\n )}\n </p>\n `\n }\n\n /**\n * ์„ฑ์ˆ™๋„ โ€” ์—ฌ๋Ÿฌ ์ถ•์œผ๋กœ ๋ณธ๋‹ค.\n *\n * ใ€Œ๋ช‡ ๊ฐœ๊นŒ์ง€ ํŽธํ•œ๊ฐ€ใ€ ํ•˜๋‚˜๋กœ๋Š” ์ข‹์€ ํ˜•์ƒ๊ณผ ๋‚˜์œ ํ˜•์ƒ์ด ๊ตฌ๋ถ„๋˜์ง€ ์•Š๋Š”๋‹ค. ๋ถ€ํ’ˆ ํ•˜๋‚˜์งœ๋ฆฌ\n * ์ƒ์ž๋„ ๊ทธ ์ถ•์—์„œ๋Š” ๋งŒ์ ์ด๋‹ค.\n *\n * **๋ชป ์žฌ๋Š” ์ถ•์„ 0 ์œผ๋กœ ๋‘์ง€ ์•Š๋Š”๋‹ค.** 0 ์€ ใ€Œ๋‚˜์˜๋‹คใ€๋Š” ๋œป์ด ๋˜๋Š”๋ฐ, ์‚ฌ์‹ค์€ ์•„์ง\n * ์ธก์ •ํ•  ๋ฐฉ๋ฒ•์ด ์—†๋Š” ๊ฒƒ์ด๋‹ค. ์ธก์ •ํ•˜์ง€ ๋ชปํ•œ๋‹ค๊ณ  ์•Œ๋ฆฌ๊ณ  ์ด์œ ๋ฅผ ๋ถ™์ธ๋‹ค. ์ง€์–ด๋‚ธ ์ ์ˆ˜๋ณด๋‹ค ๊ทธ๊ฒƒ์ด\n * ์ด ๋ฆฌํฌํŠธ๋ฅผ ๋ฏฟ์„ ๋งŒํ•˜๊ฒŒ ๋งŒ๋“ ๋‹ค.\n */\n private renderAxes() {\n if (!this.cost || !this.score || !this.source) return nothing\n\n /*\n ๊ทœ๋ชจ๋Š” ๋ชฉ๋ก์—์„œ ๋บ€๋‹ค โ€” ๋จธ๋ฆฌ๋กœ ์˜ฌ๋ผ๊ฐ”๋‹ค. ๊ฐ™์€ ์ˆซ์ž๋ฅผ ๋‘ ๋ฒˆ ๋‚ด๋ฉด ์ฝ๋Š” ์‚ฌ๋žŒ์ด\n ๋‘˜์ด ๋‹ค๋ฅธ ๊ฒƒ์ธ ์ค„ ์•ˆ๋‹ค.\n */\n const axes = maturityOf(this.source, this.cost, this.score).filter(axis => axis.key !== 'scale')\n\n // radar ์—๋Š” ์—ฌ์„ฏ์„ ๋‹ค ๊ทธ๋ฆฐ๋‹ค. ๊ทœ๋ชจ๊ฐ€ ์–ด๋””์ฏค์ธ์ง€ ํ•จ๊ป˜ ๋ณด์—ฌ์•ผ ๋œป์ด ์žˆ๋‹ค\n const all = maturityOf(this.source, this.cost, this.score)\n\n return html`\n <section>\n <h3>${i18next.t('figure.label.by-axis')}</h3>\n <div radar>${this.renderRadar(all.filter(axis => axis.ratio !== undefined))}</div>\n ${this.renderUnmeasured(all.filter(axis => axis.ratio === undefined))}\n <ul axes>\n ${axes.map(axis => this.renderAxis(axis))}\n </ul>\n </section>\n `\n }\n\n /**\n * ์„ฑ์ˆ™๋„ radar. **์ธก์ •ํ•œ ์ถ•๋งŒ ๊ทธ๋ฆฐ๋‹ค.**\n *\n * ์ธก์ •ํ•˜์ง€ ๋ชปํ•˜๋Š” ์ถ•๋„ spoke ๋ฅผ ๊ทธ๋ ค ๋‘๊ณ  ๋„ํ˜•๋งŒ ๊ฑด๋„ˆ๋›ฐ๋˜ ๋•Œ๊ฐ€ ์žˆ์—ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๊ทธ ๋ฐฉํ–ฅ์„ ๊ฐ€๋กœ์ง€๋ฅด๋Š”\n * ์ง์„ ์ด ์ƒ๊ฒจ์„œ ๋„ํ˜•์ด ๊ทธ์ชฝ์œผ๋กœ ์›€ํ‘น ๋“ค์–ด๊ฐ„ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ธ๋‹ค. 0 ์œผ๋กœ ์ฐ์ง€ ์•Š์œผ๋ ค๊ณ  ํ•œ\n * ์ผ์ธ๋ฐ ๊ฒฐ๊ณผ๋Š” 0 ์œผ๋กœ ์ฐ์€ ๊ฒƒ๊ณผ ๋˜‘๊ฐ™์ด ์ฝํ˜”๋‹ค. ์ ์„  ์‚ด๊ณผ ๋ฌผ์Œํ‘œ๋กœ๋Š” ๊ทธ ์ธ์ƒ์ด\n * ์ง€์›Œ์ง€์ง€ ์•Š์•˜๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ ์•„์˜ˆ ๋นผ๊ณ , ๋ชป ์žฌ๋Š” ์ถ•์€ ๊ทธ๋ฆผ ์•„๋ž˜์— ๊ธ€๋กœ ์ ๋Š”๋‹ค. ์žด ์ˆ˜ ์—†๋Š” ๊ฒƒ์€ ๊ทธ๋ฆผ์—\n * ์ž๋ฆฌ๋ฅผ ์ฃผ์ง€ ์•Š๋Š” ํŽธ์ด ์ •์งํ•˜๋‹ค.\n */\n private renderRadar(axes: MaturityAxis[]) {\n // ๊ทธ๋ฆผ ์•ˆ์—์„œ๋Š” **์งง์€ ์ด๋ฆ„**์„ ์“ด๋‹ค. ๊ธด ์ด๋ฆ„์„ ๊ทธ๋Œ€๋กœ ์“ฐ๋ฉด ์™ผ์ชฝ์ด ์ž˜๋ฆฐ๋‹ค โ€”\n // ํ™”๋ฉด์„ ๋„์›Œ ๋ณด๊ณ  ์•Œ์•˜๋‹ค.\n const cx = 60\n const cy = 46\n const r = 28\n\n const at = (index: number, ratio: number) => {\n const angle = -Math.PI / 2 + (index * 2 * Math.PI) / axes.length\n return [cx + r * ratio * Math.cos(angle), cy + r * ratio * Math.sin(angle)]\n }\n\n const points = axes\n .map((axis, index) => at(index, Math.max(0.04, Math.min(1, axis.ratio ?? 0))).map(n => n.toFixed(1)).join(','))\n .join(' ')\n\n return svg`\n <svg viewBox=\"0 0 120 96\" aria-hidden=\"true\">\n ${[0.33, 0.66, 1].map(\n ring => svg`<polygon web points=${axes.map((_, i) => at(i, ring).map(n => n.toFixed(1)).join(',')).join(' ')}></polygon>`\n )}\n ${axes.map((_, index) => {\n const [x, y] = at(index, 1)\n return svg`<line spoke x1=${cx} y1=${cy} x2=${x.toFixed(1)} y2=${y.toFixed(1)}></line>`\n })}\n <polygon shape points=${points}></polygon>\n ${axes.map((axis, index) => {\n const [x, y] = at(index, Math.max(0.04, Math.min(1, axis.ratio ?? 0)))\n return svg`<circle dot cx=${x.toFixed(1)} cy=${y.toFixed(1)} r=\"1.4\"></circle>`\n })}\n ${axes.map((axis, index) => {\n const [x, y] = at(index, 1.28)\n const anchor = x < cx - 3 ? 'end' : x > cx + 3 ? 'start' : 'middle'\n return svg`\n <text x=${x.toFixed(1)} y=${(y + 1.8).toFixed(1)} text-anchor=${anchor}>\n ${i18next.t('figure.label.axis-' + axis.key + '-short')}\n </text>\n `\n })}\n </svg>\n `\n }\n\n /**\n * ๊ทธ๋ฆผ์— ์—†๋Š” ์ถ•์„ ๊ธ€๋กœ ๋ฐํžŒ๋‹ค.\n *\n * ๋นผ๊ธฐ๋งŒ ํ•˜๋ฉด ์ถ•์ด ์—ฌ์„ฏ์ธ์ง€ ๋‹ค์„ฏ์ธ์ง€ ์•Œ ์ˆ˜ ์—†๊ณ , ์—†๋Š” ๊ฒƒ์„ ์—†๋‹ค๊ณ  ๋งํ•˜์ง€ ์•Š์€ ์…ˆ์ด\n * ๋œ๋‹ค. ๋ฌด์—‡์„ ์•„์ง ๋ชป ์žฌ๋Š”์ง€ ํ•œ ์ค„๋กœ ์ ๋Š”๋‹ค. ์™œ ๋ชป ์žฌ๋Š”์ง€๋Š” ์•„๋ž˜ ๋ชฉ๋ก์˜ ๊ทธ ํ•ญ๋ชฉ์—\n * ๊ทธ๋Œ€๋กœ ์žˆ๋‹ค.\n */\n private renderUnmeasured(axes: MaturityAxis[]) {\n if (axes.length === 0) return nothing\n\n return html`\n <p unmeasured>\n ${i18next.t('figure.text.axes-not-measurable-yet', {\n axes: axes.map(axis => i18next.t('figure.label.axis-' + axis.key)).join(' ยท ')\n })}\n </p>\n `\n }\n\n private renderAxis(axis: MaturityAxis) {\n const name = i18next.t('figure.label.axis-' + axis.key)\n\n if (axis.blocked) {\n return html`\n <li blocked>\n <span>${name}</span>\n <span reading>${i18next.t('figure.text.not-measurable-yet')}</span>\n <em>${i18next.t(axis.blocked)}</em>\n </li>\n `\n }\n\n const ratio = Math.max(0, Math.min(1, axis.ratio ?? 0))\n return html`\n <li>\n <span>${name}</span>\n <span reading>${axis.readingKey ? i18next.t(axis.readingKey) : (axis.reading ?? '')}</span>\n <div bar><i style=\"width:${Math.round(ratio * 100)}%\"></i></div>\n ${axis.because ? html`<em>${i18next.t(axis.because)}</em>` : ''}\n </li>\n `\n }\n\n /**\n * ์˜ˆ์‚ฐ ๋ง‰๋Œ€.\n *\n * ์ˆซ์ž๋งŒ ๋Š˜์–ด๋†“์œผ๋ฉด ์–ด๋А ๊ฒƒ์ด ๊ฝ‰ ์ฐผ๋Š”์ง€ ๋ˆˆ์— ์•ˆ ๋“ค์–ด์˜จ๋‹ค. ํ•œ๋„์— ๊ฐ€์žฅ ๊ฐ€๊นŒ์šด ํ•˜๋‚˜๋ฅผ ์ƒ‰์œผ๋กœ\n * ๊ตฌ๋ถ„ํ•œ๋‹ค. ๊ทธ๊ฒƒ์ด ์ ์ˆ˜๋ฅผ ์ •ํ•œ ํ•ญ๋ชฉ์ด๋‹ค.\n *\n * ## `use.label` ์„ ์“ฐ์ง€ ์•Š๋Š” ์ด์œ \n *\n * `FigureBudgetUse` ์— `label` ๊ณผ `why` ๊ฐ€ ์žˆ๊ณ  ใ€Œ์ €์ž‘์ž์—๊ฒŒ ๊ทธ๋Œ€๋กœ ๋ณด์—ฌ ์ค€๋‹คใ€๊ณ \n * ์ ํ˜€ ์žˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ทธ ๋ฌธ๊ตฌ๊ฐ€ **ํ•œ๊ตญ์–ด๋กœ ๊ตฌ์›Œ์ ธ** ์žˆ๋‹ค. ์ด ์ œํ’ˆ์€ 5์–ธ์–ด๋ฅผ ์“ฐ๋ฏ€๋กœ\n * ๊ทธ๊ฒƒ์„ ๊ทธ๋Œ€๋กœ ์‹ค์œผ๋ฉด ๋‹ค๋ฅธ ์–ธ์–ด ์‚ฌ์šฉ์ž์—๊ฒŒ ํ•œ๊ตญ์–ด๊ฐ€ ๋‚˜์˜จ๋‹ค.\n *\n * `budgets` ๋Š” **๋ฐฐ์—ด**์ด๋‹ค. `Object.entries` ๋กœ ๋Œ๋ฉด ํ‚ค๊ฐ€ ์ธ๋ฑ์Šค(0ยท1ยท2โ€ฆ)๊ฐ€ ๋˜์–ด\n * `figure.label.budget-0` ๊ฐ™์€ ์—†๋Š” ํ‚ค๋ฅผ ์ฐพ๋Š”๋‹ค โ€” ํ™”๋ฉด์„ ๋„์›Œ ๋ณด๊ณ ์„œ์•ผ ๋“œ๋Ÿฌ๋‚ฌ๋‹ค.\n * ๋ฐฐ์—ด์„ ๊ทธ๋Œ€๋กœ ๋Œ๊ณ  `use.key` ๋ฅผ ์“ด๋‹ค.\n *\n * ๊ทธ๋ž˜์„œ **์•ˆ์ •๋œ `key`** ๋กœ ์ด ํ™”๋ฉด์˜ i18n ์„ ์ฐพ๋Š”๋‹ค. `key` ๋Š” ์—ด๊ฑฐํ˜•์ด๋ผ ํ˜•์‹์˜\n * ์ผ๋ถ€์ด๊ณ , ๋ฌธ๊ตฌ๋Š” ํ™”๋ฉด์˜ ๋ชซ์ด๋‹ค. figure-model ์ด ๋ฌธ๊ตฌ๋ฅผ ์–ธ์–ด ์ค‘๋ฆฝ์œผ๋กœ ๋ฐ”๊พธ๋ฉด\n * ๊ทธ๋•Œ `label` ์„ ์“ธ ์ˆ˜ ์žˆ๋‹ค.\n */\n private renderBudgets() {\n const score = this.score\n if (!score) return nothing\n\n return html`\n <section>\n <h3>${i18next.t('figure.label.budgets')}</h3>\n <ul budgets>\n ${score.budgets.map(use => {\n const ratio = Math.min(1, use.ratio)\n const tight = use.key === score.tightest.key\n return html`\n <li>\n <span>${i18next.t('figure.label.budget-' + use.key)}</span>\n <span>${use.used} / ${use.limit}</span>\n <div bar><i ?tight=${tight} style=\"width:${Math.round(ratio * 100)}%\"></i></div>\n </li>\n `\n })}\n </ul>\n </section>\n `\n }\n\n private renderMetrics() {\n const cost = this.cost\n if (!cost) return nothing\n\n return html`\n <section>\n <h3>${i18next.t('figure.label.weight')}</h3>\n <dl metrics>\n <dt>${i18next.t('figure.label.triangles')}</dt>\n <dd>${cost.triangles.toLocaleString()}</dd>\n\n <dt>${i18next.t('figure.label.triangles-at-100')}</dt>\n <dd>${cost.at.triangles.toLocaleString()}</dd>\n\n <dt>${i18next.t('figure.label.draw-calls-at-100')}</dt>\n <dd>${cost.at.drawCalls.toLocaleString()}</dd>\n\n <dt>${i18next.t('figure.label.distinct-shapes')}</dt>\n <dd>${cost.distinctShapes}</dd>\n\n <dt>${i18next.t('figure.label.distinct-materials')}</dt>\n <dd>${cost.distinctMaterials}</dd>\n </dl>\n </section>\n `\n }\n\n /**\n * ์žฌํ™œ์šฉ ์ถ”์ด โ€” ใ€Œ๋งŽ์ด ๋†“์œผ๋ฉด ์–ด๋–ป๊ฒŒ ๋˜๋‚˜ใ€์— ๋‹ตํ•œ๋‹ค.\n *\n * ## ๊ทธ๋ฆผ์„ ์‚ฌ์ด๋“œ๋ฐ”์— ๋ฐ€์–ด ๋„ฃ์ง€ ์•Š๋Š”๋‹ค\n *\n * `costCurveSvg` ์˜ ์ž์—ฐ ํฌ๊ธฐ๋Š” 680x380 ์ด๊ณ  ๊ธ€์ž๊ฐ€ 11px ๋‹ค. 300px ์นธ์—์„œ\n * width:100% ๋กœ ์ค„์ด๋ฉด ๊ธ€์ž๊ฐ€ 4px ์ด ๋˜์–ด **์•„๋ฌด๊ฒƒ๋„ ์ฝ์„ ์ˆ˜ ์—†๋‹ค** โ€” ํ™”๋ฉด์„ ๋„์›Œ\n * ๋ณด๊ณ ์„œ์•ผ ๋“œ๋Ÿฌ๋‚ฌ๋‹ค. ์ฝ์„ ์ˆ˜ ์—†๋Š” ๊ทธ๋ฆผ์€ ์—†๋Š” ๊ฒƒ๊ณผ ๊ฐ™์œผ๋ฏ€๋กœ, ์‚ฌ์ด๋“œ๋ฐ”์—๋Š” ์ €์ž‘์ž๊ฐ€\n * ์‹ค์ œ๋กœ ๊ถ๊ธˆํ•œ ์ˆซ์ž(1๋งŒ ๊ฐœ์ผ ๋•Œ)๋ฅผ ๋‘๊ณ  ๊ทธ๋ฆผ์€ ์„ ํƒํ•ด์„œ ์ œ ํฌ๊ธฐ๋กœ ๋ณธ๋‹ค.\n */\n private renderCurve() {\n const many = this.many\n if (!many && !this.curve) return nothing\n\n return html`\n <section>\n <h3>${i18next.t('figure.label.reuse-trend')}</h3>\n ${many\n ? html`\n <dl metrics>\n <dt>${i18next.t('figure.label.triangles-at-10k')}</dt>\n <dd>${many.at.triangles.toLocaleString()}</dd>\n\n <dt>${i18next.t('figure.label.draw-calls-at-10k')}</dt>\n <dd>${many.at.drawCalls.toLocaleString()}</dd>\n </dl>\n `\n : nothing}\n ${this.curve\n ? html`\n <button expand @click=${() => (this.expanded = true)}>\n ${i18next.t('figure.button.see-the-trend-chart')}\n </button>\n `\n : nothing}\n </section>\n `\n }\n\n /** ๊ทธ๋ฆผ์„ ์ œ ํฌ๊ธฐ๋กœ ๋ณด์—ฌ ์ค€๋‹ค. ์ข์œผ๋ฉด ์ค„์ด์ง€ ์•Š๊ณ  ๋„˜๊ฒจ ๋ณด๊ฒŒ ๋‘”๋‹ค. */\n private renderSheet() {\n if (!this.expanded || !this.curve) return nothing\n\n return html`\n <div sheet @click=${() => (this.expanded = false)}>\n <figure @click=${(e: Event) => e.stopPropagation()}>\n ${unsafeSVG(this.curve)}\n <figcaption>\n <button close @click=${() => (this.expanded = false)}>${i18next.t('figure.button.close')}</button>\n </figcaption>\n </figure>\n </div>\n `\n }\n\n /**\n * ๋ฐœ๊ฒฌ.\n *\n * ์˜ค๋ฅ˜(๋ง‰๋Š” ๊ฒƒ)์™€ ์œ„๋ฐ˜(์•Œ๋ฆฌ๋Š” ๊ฒƒ)์„ **๊ฐ€๋ ค์„œ** ๋ณด์—ฌ ์ค€๋‹ค. ์„ž์œผ๋ฉด ์ €์ž‘์ž๊ฐ€ ๋ฌด์—‡์„\n * ๋ฐ˜๋“œ์‹œ ๊ณ ์ณ์•ผ ํ•˜๋Š”์ง€ ๋ชจ๋ฅธ๋‹ค. ์•„๋ฌด๊ฒƒ๋„ ์—†์œผ๋ฉด ใ€Œ์—†๋‹คใ€๊ณ  ๋งํ•œ๋‹ค โ€” ๋นˆ ์ž๋ฆฌ๋กœ ๋‘๋ฉด\n * ๊ฒ€์‚ฌ๊ฐ€ ๋Œ์•˜๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๋‹ค.\n */\n private renderFindings() {\n if (this.errors.length === 0 && this.violations.length === 0 && this.sizing.length === 0) {\n return html`\n <section>\n <h3>${i18next.t('figure.label.findings')}</h3>\n <p quiet>${i18next.t('figure.text.no-findings')}</p>\n </section>\n `\n }\n\n return html`\n <section>\n <h3>${i18next.t('figure.label.findings')}</h3>\n <ul findings>\n ${this.sizing.map(\n finding => html`\n <li ?violation=${!finding.blocking}>\n <md-icon>call_split</md-icon>\n <span>${finding.message} ${finding.at ? html`<code at>${finding.at}</code>` : ''}</span>\n </li>\n `\n )}\n ${this.errors.map(\n e => html`\n <li>\n <md-icon>error</md-icon>\n <span>${e.message} ${e.at ? html`<code at>${e.at}</code>` : ''}</span>\n </li>\n `\n )}\n ${this.violations.map(\n v => html`\n <li ?violation=${!v.blocking}>\n <md-icon>${v.blocking ? 'block' : 'info'}</md-icon>\n <span>\n ${v.message}${v.blocking && v.actual !== undefined\n ? html` <code at>${v.actual}</code>`\n : ''}\n </span>\n </li>\n `\n )}\n </ul>\n </section>\n `\n }\n\n /** ์›๋ณธ ๋ฐ์ดํ„ฐ๋ฅผ ์ธก์ •ํ•ด ๊ฒฐ๊ณผ๋ฅผ ์ƒํƒœ์— ๋‹ด๋Š”๋‹ค. ์…ˆ์€ ์ „๋ถ€ figure-model ์ด ํ•œ๋‹ค. */\n private measure() {\n const source = this.source\n if (!source) {\n this.cost = undefined\n this.score = undefined\n this.many = undefined\n this.capacity = undefined\n this.curve = ''\n this.errors = []\n this.violations = []\n this.sizing = []\n return\n }\n\n /*\n ๋ถ€ํ’ˆ์ด ์—†์œผ๋ฉด ํŒ์ •์„ ์•„์˜ˆ ํ•˜์ง€ ์•Š๋Š”๋‹ค โ€” ์žด ๊ฒƒ์ด ์—†๋‹ค. ใ€Œ๋ฌด์—‡์„ ๊ณ ์ณ์•ผ ํ•˜๋‚˜ใ€๊ฐ€ ์•„๋‹ˆ๋ผ\n ใ€Œ๋ฌด์—‡๋ถ€ํ„ฐ ๋†“๋‚˜ใ€์ธ ์ƒํƒœ์ด๊ณ , ๊ทธ ์•ˆ๋‚ด๋Š” ๋ถ€ํ’ˆ ๋ชฉ๋ก์ด ์ด๋ฏธ ํ•˜๊ณ  ์žˆ๋‹ค.\n */\n this.bare = !source.parts?.length\n if (this.bare) {\n this.cost = undefined\n this.score = undefined\n this.many = undefined\n this.capacity = undefined\n this.curve = ''\n this.errors = []\n this.violations = []\n this.sizing = []\n return\n }\n\n const result = validate(source)\n this.errors = result.errors.map(e => ({ code: e.code, message: e.message, at: e.path }))\n this.violations = result.violations.map(v => ({\n code: v.code,\n message: v.message,\n blocking: blocksRelease(v.code),\n actual: v.actual\n }))\n\n if (this.errors.length > 0) {\n // ํ˜•์‹์„ ์–ด๊ฒผ์œผ๋ฉด ์ปดํŒŒ์ผ์ด ๋˜์ง„๋‹ค. ์…ˆ์„ ๋น„์šฐ๊ณ  ์˜ค๋ฅ˜๋งŒ ๋ณด์—ฌ ์ค€๋‹ค.\n this.cost = undefined\n this.score = undefined\n this.many = undefined\n this.capacity = undefined\n this.curve = ''\n this.sizing = []\n this.dispatchEvent(\n new CustomEvent('verdict-changed', { detail: {}, bubbles: true, composed: true })\n )\n return\n }\n\n const blueprint = compile(source)\n\n /*\n ํฌ๊ธฐ๋ฅผ ๋ฐ”๊ฟ” ๋ณด๋Š” ์ผ๊ณฑ ์กฐํ•ฉ. ํŒ์ • ๊ทœ์น™์€ `figure-model` ์˜ `gate.ts` ๊ฐ€ ์ •ํ•œ ๊ฒƒ์„ ๊ทธ๋Œ€๋กœ\n ์“ด๋‹ค โ€” ๋ฌด์—‡์ด ๋ง‰๋Š” ๊ฒƒ์ธ์ง€ ํ™”๋ฉด์ด ๋‹ค์‹œ ์ •ํ•˜๋ฉด ์„œ๋ฒ„์™€ ๋‹ค๋ฅธ ๋ง์„ ํ•˜๊ฒŒ ๋œ๋‹ค.\n */\n const report = sizingReport(blueprint)\n this.sizing = report.findings.map(finding => ({\n code: finding.code,\n message: finding.message,\n /* ์ˆซ์ž๊ฐ€ ์•„๋‹ˆ๋ผ ์ž๋ฆฌ๋ฅผ ๋งํ•œ๋‹ค โ€” ๊ฐˆ๋ผ์ ธ ๋‚˜์˜จ ๋ถ€ํ’ˆ ์ด๋ฆ„์ด ๊ณ ์น  ์ž๋ฆฌ๋‹ค. */\n at: finding.clumps.map(clump => [...clump].sort().join('+')).join(' | ') || undefined,\n blocking: finding.code === 'sizing-splits'\n }))\n\n this.cost = costOf(blueprint, 100)\n // 1๋งŒ ๊ฐœ๋Š” figure-model ์— ๋‹ค์‹œ ๋ฌป๋Š”๋‹ค โ€” ํ™”๋ฉด์ด ๊ณฑ์…ˆ์œผ๋กœ ์ง์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค.\n this.many = costOf(blueprint, 10000)\n this.score = scoreOf(blueprint)\n this.capacity = capacityOf(this.cost)\n\n // ๊ฐœ์ˆ˜๋ฅผ ๋ฐ–์œผ๋กœ ์•Œ๋ฆฐ๋‹ค. ํƒญ ์ด๋ฆ„ํ‘œ๊ฐ€ ์ด ๊ฐ’์„ ๋ณด์—ฌ ์ฃผ๋Š”๋ฐ, ๊ฑฐ๊ธฐ์„œ ๋‹ค์‹œ ์…ˆํ•˜๋ฉด\n // ๊ฐ™์€ ํ˜•์ƒ์ด ๋‘ ์ž๋ฆฌ์—์„œ ๋‹ค๋ฅด๊ฒŒ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋‹ค.\n this.dispatchEvent(\n new CustomEvent('verdict-changed', {\n detail: { instances: this.capacity?.instances, grade: this.score?.grade },\n bubbles: true,\n composed: true\n })\n )\n this.curve = costCurveSvg(blueprint)\n }\n}\n"]}
@@ -6,7 +6,7 @@ import './figure-report.js';
6
6
  import './figure-settings.js';
7
7
  import './figure-history-panel.js';
8
8
  import { LitElement } from 'lit';
9
- import type { FigureSource } from '@hatiolab/figure-model';
9
+ import type { ContractChange, FigureSource } from '@hatiolab/figure-model';
10
10
  import type { FigureDraft, PartModel } from './figure-source.js';
11
11
  import type { ViewSettings } from './figure-view.js';
12
12
  declare const FigureSide_base: (new (...args: any[]) => LitElement) & typeof LitElement;
@@ -42,6 +42,10 @@ export declare class FigureSide extends FigureSide_base {
42
42
  draft?: FigureDraft;
43
43
  parts: PartModel[];
44
44
  source?: FigureSource;
45
+ /** ์ด ๊ณ ์นจ์ด ์ด๋ฏธ ๋†“์ธ ์ธ์Šคํ„ด์Šค์— ๋ฌด์—‡์„ ํ•˜๋‚˜(ADR-0063 ๊ฒฐ์ • 3). ๋ฐœํ–‰ ์ „ ๋„ํ˜•์—๋Š” ๋น„์–ด ์žˆ๋‹ค. */
46
+ contract: ContractChange[];
47
+ /** ๊ฒฌ์ฃผ์ง€ ๋ชปํ•œ ๊นŒ๋‹ญ. ์žˆ์œผ๋ฉด ํ™”๋ฉด์ด ใ€Œํ™•์ธํ•˜์ง€ ๋ชปํ–ˆ๋‹คใ€๋กœ ๋งํ•œ๋‹ค. */
48
+ contractFailure?: string;
45
49
  selected: number;
46
50
  /** ์ €์ž‘ ํ™”๋ฉด์˜ ๋ณด๊ธฐ ์„ค์ •. ์ž์‚ฐ์ด ์•„๋‹ˆ๋ผ ์ž‘์—…๋Œ€๋‹ค โ€” ์ €์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค. */
47
51
  view: ViewSettings;
@@ -41,6 +41,8 @@ let FigureSide = class FigureSide extends localize(i18next)(LitElement) {
41
41
  this.figureVersion = 0;
42
42
  this.dirty = false;
43
43
  this.parts = [];
44
+ /** ์ด ๊ณ ์นจ์ด ์ด๋ฏธ ๋†“์ธ ์ธ์Šคํ„ด์Šค์— ๋ฌด์—‡์„ ํ•˜๋‚˜(ADR-0063 ๊ฒฐ์ • 3). ๋ฐœํ–‰ ์ „ ๋„ํ˜•์—๋Š” ๋น„์–ด ์žˆ๋‹ค. */
45
+ this.contract = [];
44
46
  this.selected = -1;
45
47
  /** ์ €์ž‘ ํ™”๋ฉด์˜ ๋ณด๊ธฐ ์„ค์ •. ์ž์‚ฐ์ด ์•„๋‹ˆ๋ผ ์ž‘์—…๋Œ€๋‹ค โ€” ์ €์žฅ๋˜์ง€ ์•Š๋Š”๋‹ค. */
46
48
  this.view = DEFAULT_VIEW;
@@ -177,6 +179,8 @@ let FigureSide = class FigureSide extends localize(i18next)(LitElement) {
177
179
  .figureTags=${this.figureTags}
178
180
  .draft=${this.draft}
179
181
  .parts=${this.parts}
182
+ .contract=${this.contract}
183
+ .contractFailure=${this.contractFailure}
180
184
  .selected=${this.selected}
181
185
  ></figure-inspector>
182
186
 
@@ -276,6 +280,14 @@ __decorate([
276
280
  property({ type: Object }),
277
281
  __metadata("design:type", Object)
278
282
  ], FigureSide.prototype, "source", void 0);
283
+ __decorate([
284
+ property({ type: Array }),
285
+ __metadata("design:type", Array)
286
+ ], FigureSide.prototype, "contract", void 0);
287
+ __decorate([
288
+ property({ type: String }),
289
+ __metadata("design:type", String)
290
+ ], FigureSide.prototype, "contractFailure", void 0);
279
291
  __decorate([
280
292
  property({ type: Number }),
281
293
  __metadata("design:type", Object)