@things-factory/figure-ui 10.1.225 → 10.1.227

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 (94) hide show
  1. package/client/graphql/index.ts +6 -6
  2. package/client/modeller/consumer-capabilities.ts +15 -0
  3. package/client/modeller/editor-styles.ts +18 -1
  4. package/client/modeller/editor.ts +38 -26
  5. package/client/modeller/figure-capability-panel.ts +31 -10
  6. package/client/modeller/figure-clips.ts +2 -1
  7. package/client/modeller/figure-controls.ts +4 -3
  8. package/client/modeller/figure-data-panel.ts +24 -7
  9. package/client/modeller/figure-history-panel.ts +7 -7
  10. package/client/modeller/figure-links.ts +5 -5
  11. package/client/modeller/figure-material-panel.ts +2 -0
  12. package/client/modeller/figure-preview.ts +69 -2
  13. package/client/modeller/figure-recipe-catalog.ts +4 -0
  14. package/client/modeller/figure-slot-layout-panel.ts +25 -8
  15. package/client/modeller/figure-verdict.ts +4 -1
  16. package/client/modeller/unit-words.ts +11 -0
  17. package/client/pages/figure-list-page.ts +2 -2
  18. package/client/pages/figure-modeller-page.ts +7 -6
  19. package/client/types.ts +2 -2
  20. package/client/viewparts/figure-thumb.ts +1 -1
  21. package/dist-client/graphql/index.d.ts +5 -5
  22. package/dist-client/graphql/index.js +6 -6
  23. package/dist-client/graphql/index.js.map +1 -1
  24. package/dist-client/modeller/consumer-capabilities.d.ts +11 -0
  25. package/dist-client/modeller/consumer-capabilities.js +14 -0
  26. package/dist-client/modeller/consumer-capabilities.js.map +1 -1
  27. package/dist-client/modeller/editor-styles.js +18 -1
  28. package/dist-client/modeller/editor-styles.js.map +1 -1
  29. package/dist-client/modeller/editor.js +38 -26
  30. package/dist-client/modeller/editor.js.map +1 -1
  31. package/dist-client/modeller/figure-capability-panel.d.ts +3 -0
  32. package/dist-client/modeller/figure-capability-panel.js +29 -11
  33. package/dist-client/modeller/figure-capability-panel.js.map +1 -1
  34. package/dist-client/modeller/figure-clips.js +2 -1
  35. package/dist-client/modeller/figure-clips.js.map +1 -1
  36. package/dist-client/modeller/figure-controls.js +4 -3
  37. package/dist-client/modeller/figure-controls.js.map +1 -1
  38. package/dist-client/modeller/figure-data-panel.js +24 -7
  39. package/dist-client/modeller/figure-data-panel.js.map +1 -1
  40. package/dist-client/modeller/figure-history-panel.d.ts +5 -5
  41. package/dist-client/modeller/figure-history-panel.js +7 -7
  42. package/dist-client/modeller/figure-history-panel.js.map +1 -1
  43. package/dist-client/modeller/figure-links.js +5 -5
  44. package/dist-client/modeller/figure-links.js.map +1 -1
  45. package/dist-client/modeller/figure-material-panel.js +2 -0
  46. package/dist-client/modeller/figure-material-panel.js.map +1 -1
  47. package/dist-client/modeller/figure-preview.d.ts +3 -0
  48. package/dist-client/modeller/figure-preview.js +78 -2
  49. package/dist-client/modeller/figure-preview.js.map +1 -1
  50. package/dist-client/modeller/figure-recipe-catalog.js +4 -0
  51. package/dist-client/modeller/figure-recipe-catalog.js.map +1 -1
  52. package/dist-client/modeller/figure-slot-layout-panel.d.ts +1 -1
  53. package/dist-client/modeller/figure-slot-layout-panel.js +25 -8
  54. package/dist-client/modeller/figure-slot-layout-panel.js.map +1 -1
  55. package/dist-client/modeller/figure-verdict.js +4 -1
  56. package/dist-client/modeller/figure-verdict.js.map +1 -1
  57. package/dist-client/modeller/unit-words.d.ts +5 -0
  58. package/dist-client/modeller/unit-words.js +12 -0
  59. package/dist-client/modeller/unit-words.js.map +1 -0
  60. package/dist-client/pages/figure-list-page.d.ts +1 -1
  61. package/dist-client/pages/figure-list-page.js +2 -2
  62. package/dist-client/pages/figure-list-page.js.map +1 -1
  63. package/dist-client/pages/figure-modeller-page.d.ts +3 -3
  64. package/dist-client/pages/figure-modeller-page.js +7 -6
  65. package/dist-client/pages/figure-modeller-page.js.map +1 -1
  66. package/dist-client/tsconfig.tsbuildinfo +1 -1
  67. package/dist-client/types.d.ts +2 -2
  68. package/dist-client/types.js.map +1 -1
  69. package/dist-client/viewparts/figure-thumb.js +1 -1
  70. package/dist-client/viewparts/figure-thumb.js.map +1 -1
  71. package/package.json +9 -9
  72. package/test/browser/detail-page.js +1 -1
  73. package/test/browser/editing-page.js +3 -3
  74. package/test/browser/editing.check.mjs +5 -5
  75. package/test/browser/links-page.js +1 -1
  76. package/test/browser/links.check.mjs +2 -3
  77. package/test/browser/modeller-page.js +4 -4
  78. package/test/browser/modeller-revision.check.mjs +5 -5
  79. package/test/browser/modeller.check.mjs +5 -5
  80. package/test/browser/parts.check.mjs +2 -2
  81. package/test/browser/product-page.check.mjs +6 -0
  82. package/test/browser/props.check.mjs +3 -4
  83. package/test/browser/row-preview.check.mjs +3 -3
  84. package/test/browser/screen.check.mjs +13 -11
  85. package/test/consumer-capabilities.test.ts +7 -0
  86. package/test/links.test.ts +1 -1
  87. package/test/refusals.test.ts +1 -1
  88. package/test/resolve-ts-siblings.mjs +3 -3
  89. package/translations/en.json +23 -12
  90. package/translations/es.json +23 -12
  91. package/translations/ja.json +24 -13
  92. package/translations/ko.json +83 -72
  93. package/translations/ms.json +23 -12
  94. package/translations/zh.json +23 -12
@@ -4,6 +4,7 @@ import { customElement, property, state } from 'lit/decorators.js';
4
4
  import { i18next, localize } from '@operato/i18n';
5
5
  import '@material/web/icon/icon.js';
6
6
  import '@operato/slot-layout-editor';
7
+ import { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js';
7
8
  import { compileFigureAsset } from '@hatiolab/figure-model';
8
9
  import { anchorFacesOf, anchorRoomOf, anchorIdFor, figureSlotIssues, slotLayoutCommandOf, slotLayoutFormOf, slotPresetsOf, startSizeOf } from './slot-layout-host.js';
9
10
  /**
@@ -21,15 +22,30 @@ let FigureSlotLayoutPanel = class FigureSlotLayoutPanel extends localize(i18next
21
22
  this.partId = '';
22
23
  this.locked = false;
23
24
  }
24
- static { this.styles = css `
25
+ /*
26
+ The panel's controls, and the shared editor given the same (sweep 2026-10-27 M2): its own 12px, boxed 24px fields and
27
+ right-aligned labels at 34% stood under the panel's 11.5px, 26px underlined fields and 72px labels.
28
+ */
29
+ static { this.styles = [SidePanelStyles, css `
25
30
  :host {
26
31
  display: flex;
27
32
  flex-direction: column;
28
33
  gap: 6px;
29
34
  }
35
+ ox-slot-layout-editor {
36
+ --slot-layout-font-size: var(--ui-t-small, 11.5px);
37
+ --slot-layout-label-column: var(--figure-label-width);
38
+ --slot-layout-label-align: left;
39
+ --property-editor-field-height: var(--figure-control-height);
40
+ --slot-layout-field-border: 0 solid transparent;
41
+ --slot-layout-field-border-bottom: 1px solid var(--md-sys-color-outline-variant, #c4c7c5);
42
+ --slot-layout-field-radius: 0;
43
+ --slot-layout-field-background: transparent;
44
+ --property-editor-label-color: var(--md-sys-color-on-surface-variant);
45
+ }
30
46
  div[form] {
31
47
  display: grid;
32
- grid-template-columns: auto 1fr;
48
+ grid-template-columns: var(--figure-label-width) minmax(0, 1fr);
33
49
  gap: 4px 8px;
34
50
  align-items: center;
35
51
  }
@@ -69,7 +85,7 @@ let FigureSlotLayoutPanel = class FigureSlotLayoutPanel extends localize(i18next
69
85
  small[hint] {
70
86
  color: var(--md-sys-color-on-surface-variant);
71
87
  }
72
- `; }
88
+ `]; }
73
89
  willUpdate() {
74
90
  /* A figure changed under the panel (an undo, another edit): what is shown is the figure's, not an old draft. */
75
91
  if (this.asset !== this.formFor) {
@@ -108,12 +124,12 @@ let FigureSlotLayoutPanel = class FigureSlotLayoutPanel extends localize(i18next
108
124
  ${['top', 'bottom'].map(f => html `<option value=${f} ?selected=${f === a.face}>${i18next.t('figure.label.face-' + f)}</option>`)}
109
125
  </select>
110
126
  <button ?disabled=${this.locked || form.anchors.length <= 1} title=${i18next.t('figure.button.remove-slot-anchor')} @click=${() => this.edit({ anchors: form.anchors.filter((_, k) => k !== i) })}>
111
- <md-icon>close</md-icon>
127
+ <md-icon>delete</md-icon>
112
128
  </button>
113
129
  </li>`)}
114
130
  </ul>
115
131
  <div actions>
116
- ${['top', 'bottom'].map(face => html `<button ?disabled=${this.locked || !this.partId} @click=${() => this.addAnchor(face)}>
132
+ ${['top', 'bottom'].map(face => html `<button act ?disabled=${this.locked || !this.partId} @click=${() => this.addAnchor(face)}>
117
133
  <md-icon>add</md-icon>${i18next.t(face === 'top' ? 'figure.button.add-slot-anchor-top' : 'figure.button.add-slot-anchor-bottom', { part: this.partId })}
118
134
  </button>`)}
119
135
  </div>
@@ -123,10 +139,10 @@ let FigureSlotLayoutPanel = class FigureSlotLayoutPanel extends localize(i18next
123
139
 
124
140
  <div actions>
125
141
  ${stored.layout && changed
126
- ? html `<button ?disabled=${this.locked} @click=${() => this.apply(stored.layout)}><md-icon>check</md-icon>${i18next.t('figure.button.apply-slot-anchors')}</button>`
142
+ ? html `<button act ?disabled=${this.locked} @click=${() => this.apply(stored.layout)}><md-icon>check</md-icon>${i18next.t('figure.button.apply-slot-anchors')}</button>`
127
143
  : nothing}
128
144
  ${stored.layout
129
- ? html `<button ?disabled=${this.locked} @click=${() => this.command({ kind: 'remove-slot-layout' })}><md-icon>delete</md-icon>${i18next.t('figure.button.remove-slot-layout')}</button>`
145
+ ? html `<button act ?disabled=${this.locked} @click=${() => this.command({ kind: 'remove-slot-layout' })}><md-icon>delete</md-icon>${i18next.t('figure.button.remove-slot-layout')}</button>`
130
146
  : nothing}
131
147
  </div>
132
148
  `;
@@ -148,7 +164,8 @@ let FigureSlotLayoutPanel = class FigureSlotLayoutPanel extends localize(i18next
148
164
  presetSize: startSizeOf(form.anchors, anchorFaces, anchorRoomOf(form.anchors, geometry)),
149
165
  /* No layout yet: the whole face is one slot, shown at once and put in on Apply. */
150
166
  startFrom: 'single',
151
- anchors: form.anchors.map(a => ({ id: a.id, label: `${a.id} · ${a.part} ${i18next.t('figure.label.face-' + a.face)}` })),
167
+ /* The face names its part: an anchor named as its part is not named twice (「tub · tub 윗면」, sweep 2026-10-27 M5). */
168
+ anchors: form.anchors.map(a => ({ id: a.id, label: `${a.id === a.part ? '' : `${a.id} · `}${a.part} ${i18next.t('figure.label.face-' + a.face)}` })),
152
169
  anchorFaces,
153
170
  validate: (layout) => figureSlotIssues(layout, form.anchors.map(a => a.id)),
154
171
  issueText: (issue) => issue.code === 'ACCEPTS_EMPTY' ? `${issue.path}: ${i18next.t('figure.text.slot-accepts-empty-list')}` : undefined
@@ -1 +1 @@
1
- {"version":3,"file":"figure-slot-layout-panel.js","sourceRoot":"","sources":["../../client/modeller/figure-slot-layout-panel.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { i18next, localize } from '@operato/i18n'\nimport '@material/web/icon/icon.js'\nimport '@operato/slot-layout-editor'\nimport { compileFigureAsset, type FigureAsset, type SlotLayout } from '@hatiolab/figure-model'\n\nimport {\n anchorFacesOf,\n anchorRoomOf,\n anchorIdFor,\n figureSlotIssues,\n slotLayoutCommandOf,\n slotLayoutFormOf,\n slotPresetsOf,\n startSizeOf,\n type SlotAnchor,\n type SlotAnchorFace,\n type SlotLayoutForm\n} from './slot-layout-host.js'\n\n/**\n * A figure's slot layout (ADR-0118): places made by a rule -- anchors on parts' tops or bottoms, tiers on them, slots in\n * the tiers. The tiers and slots are edited in the shared editor (`ox-slot-layout-editor`, the one fmsim hosts); this\n * panel owns what only the modeller knows: which part's face each anchor is, the layout's name and what its slots are.\n * Every change goes out as one `set-slot-layout` command -- one step of the history, refused by figure-model in its words.\n *\n * The layout here is the only one: a scene or a run never overrides it (ADR-0118 decision 8), so there is no \"default\".\n */\n@customElement('figure-slot-layout-panel')\nexport class FigureSlotLayoutPanel extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n div[form] {\n display: grid;\n grid-template-columns: auto 1fr;\n gap: 4px 8px;\n align-items: center;\n }\n ul {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n li {\n display: grid;\n grid-template-columns: 1fr 1fr auto auto;\n gap: 4px;\n align-items: center;\n }\n input,\n select {\n min-width: 0;\n font: inherit;\n }\n div[actions] {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n }\n button {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font: inherit;\n }\n md-icon {\n --md-icon-size: 16px;\n }\n small[hint] {\n color: var(--md-sys-color-on-surface-variant);\n }\n `\n\n @property({ attribute: false }) asset?: FigureAsset\n /** The part selected on the canvas: what a new anchor stands on. */\n @property() partId = ''\n @property({ type: Boolean }) locked = false\n\n /** The name, role and anchors being edited; started again from the figure whenever the figure changes. */\n @state() private form?: SlotLayoutForm\n private formFor?: FigureAsset\n private options?: { key: string; asset: FigureAsset; value: object }\n /*\n The figure's layout, read once per figure: the editor starts its draft again whenever its value changes, so a value\n read again every render would throw the author's edits away.\n */\n private stored?: ReturnType<typeof slotLayoutFormOf>\n\n willUpdate() {\n /* A figure changed under the panel (an undo, another edit): what is shown is the figure's, not an old draft. */\n if (this.asset !== this.formFor) {\n this.formFor = this.asset\n this.stored = this.asset ? slotLayoutFormOf(this.asset, this.partId) : undefined\n this.form = this.stored?.form\n }\n }\n\n render() {\n const asset = this.asset\n const stored = this.stored\n const form = this.form\n if (!asset || !stored || !form) return nothing\n const parts = asset.document.model.nodes.filter(n => n.op === 'place@1').map(n => n.id)\n const changed = JSON.stringify(form) !== JSON.stringify(stored.form)\n return html`\n <div form>\n <span>${i18next.t('figure.label.slot-layout-name')}</span>\n <input .value=${form.label} placeholder=${i18next.t('figure.label.slot-layout')} ?disabled=${this.locked} @change=${(e: Event) => this.edit({ label: (e.target as HTMLInputElement).value })} />\n <span>${i18next.t('figure.label.slot-layout-role')}</span>\n <select ?disabled=${this.locked} @change=${(e: Event) => this.edit({ role: (e.target as HTMLSelectElement).value as 'seat' | 'grip' })}>\n <option value=\"seat\" ?selected=${form.role === 'seat'}>${i18next.t('figure.label.place-seat')}</option>\n <option value=\"grip\" ?selected=${form.role === 'grip'}>${i18next.t('figure.label.place-grip')}</option>\n </select>\n </div>\n\n <h4>${i18next.t('figure.label.slot-anchors')}</h4>\n <ul>\n ${form.anchors.map(\n (a, i) => html`<li>\n <input .value=${a.id} aria-label=${i18next.t('figure.label.slot-anchor-id')} ?disabled=${this.locked} @change=${(e: Event) => this.anchor(i, { id: (e.target as HTMLInputElement).value.trim() })} />\n <select aria-label=${i18next.t('figure.label.part')} ?disabled=${this.locked} @change=${(e: Event) => this.anchor(i, { part: (e.target as HTMLSelectElement).value })}>\n ${parts.map(p => html`<option value=${p} ?selected=${p === a.part}>${p}</option>`)}\n </select>\n <select aria-label=${i18next.t('figure.label.face')} ?disabled=${this.locked} @change=${(e: Event) => this.anchor(i, { face: (e.target as HTMLSelectElement).value as SlotAnchorFace })}>\n ${(['top', 'bottom'] as const).map(f => html`<option value=${f} ?selected=${f === a.face}>${i18next.t('figure.label.face-' + f)}</option>`)}\n </select>\n <button ?disabled=${this.locked || form.anchors.length <= 1} title=${i18next.t('figure.button.remove-slot-anchor')} @click=${() => this.edit({ anchors: form.anchors.filter((_, k) => k !== i) })}>\n <md-icon>close</md-icon>\n </button>\n </li>`\n )}\n </ul>\n <div actions>\n ${(['top', 'bottom'] as const).map(\n face => html`<button ?disabled=${this.locked || !this.partId} @click=${() => this.addAnchor(face)}>\n <md-icon>add</md-icon>${i18next.t(face === 'top' ? 'figure.button.add-slot-anchor-top' : 'figure.button.add-slot-anchor-bottom', { part: this.partId })}\n </button>`\n )}\n </div>\n <small hint>${i18next.t('figure.text.slot-anchor-pick')}</small>\n\n <ox-slot-layout-editor .value=${stored.layout} .options=${this.editorOptions(asset, form, stored.layout)} @change=${(e: Event) => this.apply((e.target as { value?: SlotLayout }).value)}></ox-slot-layout-editor>\n\n <div actions>\n ${stored.layout && changed\n ? html`<button ?disabled=${this.locked} @click=${() => this.apply(stored.layout)}><md-icon>check</md-icon>${i18next.t('figure.button.apply-slot-anchors')}</button>`\n : nothing}\n ${stored.layout\n ? html`<button ?disabled=${this.locked} @click=${() => this.command({ kind: 'remove-slot-layout' })}><md-icon>delete</md-icon>${i18next.t('figure.button.remove-slot-layout')}</button>`\n : nothing}\n </div>\n `\n }\n\n /*\n The editor's options, made again only when what they are made from changes: the editor starts its draft again when its\n starting layout changes, so a new object every render would throw the author's edits away.\n */\n private editorOptions(asset: FigureAsset, form: SlotLayoutForm, layout: SlotLayout | undefined) {\n const key = JSON.stringify([form.anchors, !!layout])\n if (this.options?.key === key && this.options.asset === asset) return this.options.value\n const geometry = compileFigureAsset(asset).evaluate().geometry as never\n const anchorFaces = anchorFacesOf(form.anchors, geometry)\n const value = {\n canUseDefault: false,\n presets: slotPresetsOf(form.anchors),\n /* The first anchor's face is the size a preset is laid out over, the room over it the slot height: no number to type. */\n presetSize: startSizeOf(form.anchors, anchorFaces, anchorRoomOf(form.anchors, geometry)),\n /* No layout yet: the whole face is one slot, shown at once and put in on Apply. */\n startFrom: 'single',\n anchors: form.anchors.map(a => ({ id: a.id, label: `${a.id} · ${a.part} ${i18next.t('figure.label.face-' + a.face)}` })),\n anchorFaces,\n validate: (layout: SlotLayout) => figureSlotIssues(layout, form.anchors.map(a => a.id)),\n issueText: (issue: { code: string; path: string }) =>\n issue.code === 'ACCEPTS_EMPTY' ? `${issue.path}: ${i18next.t('figure.text.slot-accepts-empty-list')}` : undefined\n }\n this.options = { key, asset, value }\n return value\n }\n\n private edit(patch: Partial<SlotLayoutForm>) {\n this.form = { ...this.form!, ...patch }\n }\n\n private anchor(i: number, patch: Partial<SlotAnchor>) {\n this.edit({ anchors: this.form!.anchors.map((a, k) => (k === i ? { ...a, ...patch } : a)) })\n }\n\n /** A new anchor on the selected part's face: what an author picks on the canvas comes here. */\n private addAnchor(face: SlotAnchorFace) {\n const anchors = this.form!.anchors\n this.edit({ anchors: [...anchors, { id: anchorIdFor(this.partId, anchors.map(a => a.id)), part: this.partId, face }] })\n }\n\n /** The whole layout with the anchors and name as they stand: one command, one step. */\n private apply(layout: SlotLayout | undefined) {\n if (!layout || !this.form) return\n this.command(slotLayoutCommandOf(this.form, layout, i18next.t('figure.label.slot-layout')))\n }\n\n private command(action: object) {\n this.dispatchEvent(new CustomEvent('command', { detail: { action }, bubbles: true, composed: true }))\n }\n}\n"]}
1
+ {"version":3,"file":"figure-slot-layout-panel.js","sourceRoot":"","sources":["../../client/modeller/figure-slot-layout-panel.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AACpD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAClE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,4BAA4B,CAAA;AACnC,OAAO,6BAA6B,CAAA;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,gEAAgE,CAAA;AAChG,OAAO,EAAE,kBAAkB,EAAqC,MAAM,wBAAwB,CAAA;AAE9F,OAAO,EACL,aAAa,EACb,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,WAAW,EAIZ,MAAM,uBAAuB,CAAA;AAE9B;;;;;;;GAOG;AAEI,IAAM,qBAAqB,GAA3B,MAAM,qBAAsB,SAAQ,QAAQ,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC;IAAjE;;QAmEL,oEAAoE;QACxD,WAAM,GAAG,EAAE,CAAA;QACM,WAAM,GAAG,KAAK,CAAA;IAgI7C,CAAC;IApMC;;;MAGE;aACK,WAAM,GAAG,CAAC,eAAe,EAAE,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DpC,CAAC,AA3DW,CA2DX;IAiBF,UAAU;QACR,gHAAgH;QAChH,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,CAAC,OAAO,EAAE,CAAC;YAChC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAA;YACzB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;YAChF,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,IAAI,CAAA;QAC/B,CAAC;IACH,CAAC;IAED,MAAM;QACJ,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAA;QACxB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAA;QACtB,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI;YAAE,OAAO,OAAO,CAAA;QAC9C,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;QACvF,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QACpE,OAAO,IAAI,CAAA;;gBAEC,OAAO,CAAC,CAAC,CAAC,+BAA+B,CAAC;wBAClC,IAAI,CAAC,KAAK,gBAAgB,OAAO,CAAC,CAAC,CAAC,0BAA0B,CAAC,cAAc,IAAI,CAAC,MAAM,YAAY,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,KAAK,EAAG,CAAC,CAAC,MAA2B,CAAC,KAAK,EAAE,CAAC;gBACpL,OAAO,CAAC,CAAC,CAAC,+BAA+B,CAAC;4BAC9B,IAAI,CAAC,MAAM,YAAY,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,EAAG,CAAC,CAAC,MAA4B,CAAC,KAAwB,EAAE,CAAC;2CACnG,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,yBAAyB,CAAC;2CAC5D,IAAI,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,yBAAyB,CAAC;;;;YAI3F,OAAO,CAAC,CAAC,CAAC,2BAA2B,CAAC;;UAExC,IAAI,CAAC,OAAO,CAAC,GAAG,CAChB,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAA;4BACI,CAAC,CAAC,EAAE,eAAe,OAAO,CAAC,CAAC,CAAC,6BAA6B,CAAC,cAAc,IAAI,CAAC,MAAM,YAAY,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,EAAG,CAAC,CAAC,MAA2B,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;iCAC5K,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,cAAc,IAAI,CAAC,MAAM,YAAY,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,IAAI,EAAG,CAAC,CAAC,MAA4B,CAAC,KAAK,EAAE,CAAC;gBACjK,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAA,iBAAiB,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC;;iCAE/D,OAAO,CAAC,CAAC,CAAC,mBAAmB,CAAC,cAAc,IAAI,CAAC,MAAM,YAAY,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,IAAI,EAAG,CAAC,CAAC,MAA4B,CAAC,KAAuB,EAAE,CAAC;gBAClL,CAAC,KAAK,EAAE,QAAQ,CAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAA,iBAAiB,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC,oBAAoB,GAAG,CAAC,CAAC,WAAW,CAAC;;gCAEzH,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC,UAAU,OAAO,CAAC,CAAC,CAAC,kCAAkC,CAAC,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;;;gBAG7L,CACP;;;UAGE,CAAC,KAAK,EAAE,QAAQ,CAAW,CAAC,GAAG,CAChC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAA,yBAAyB,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;oCAC3E,OAAO,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,mCAAmC,CAAC,CAAC,CAAC,sCAAsC,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;oBAC/I,CACX;;oBAEW,OAAO,CAAC,CAAC,CAAC,8BAA8B,CAAC;;sCAEvB,MAAM,CAAC,MAAM,aAAa,IAAI,CAAC,aAAa,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAE,CAAC,CAAC,MAAiC,CAAC,KAAK,CAAC;;;UAGpL,MAAM,CAAC,MAAM,IAAI,OAAO;YACxB,CAAC,CAAC,IAAI,CAAA,yBAAyB,IAAI,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,4BAA4B,OAAO,CAAC,CAAC,CAAC,kCAAkC,CAAC,WAAW;YACxK,CAAC,CAAC,OAAO;UACT,MAAM,CAAC,MAAM;YACb,CAAC,CAAC,IAAI,CAAA,yBAAyB,IAAI,CAAC,MAAM,WAAW,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC,6BAA6B,OAAO,CAAC,CAAC,CAAC,kCAAkC,CAAC,WAAW;YAC5L,CAAC,CAAC,OAAO;;KAEd,CAAA;IACH,CAAC;IAED;;;MAGE;IACM,aAAa,CAAC,KAAkB,EAAE,IAAoB,EAAE,MAA8B;QAC5F,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;QACpD,IAAI,IAAI,CAAC,OAAO,EAAE,GAAG,KAAK,GAAG,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,KAAK,KAAK;YAAE,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,CAAA;QACxF,MAAM,QAAQ,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAiB,CAAA;QACvE,MAAM,WAAW,GAAG,aAAa,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;QACzD,MAAM,KAAK,GAAG;YACZ,aAAa,EAAE,KAAK;YACpB,OAAO,EAAE,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC;YACpC,yHAAyH;YACzH,UAAU,EAAE,WAAW,CAAC,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YACxF,mFAAmF;YACnF,SAAS,EAAE,QAAQ;YACnB,oHAAoH;YACpH,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC,oBAAoB,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;YACpJ,WAAW;YACX,QAAQ,EAAE,CAAC,MAAkB,EAAE,EAAE,CAAC,gBAAgB,CAAC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACvF,SAAS,EAAE,CAAC,KAAqC,EAAE,EAAE,CACnD,KAAK,CAAC,IAAI,KAAK,eAAe,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,qCAAqC,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS;SACpH,CAAA;QACD,IAAI,CAAC,OAAO,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,CAAA;QACpC,OAAO,KAAK,CAAA;IACd,CAAC;IAEO,IAAI,CAAC,KAA8B;QACzC,IAAI,CAAC,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,IAAK,EAAE,GAAG,KAAK,EAAE,CAAA;IACzC,CAAC;IAEO,MAAM,CAAC,CAAS,EAAE,KAA0B;QAClD,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,IAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IAC9F,CAAC;IAED,+FAA+F;IACvF,SAAS,CAAC,IAAoB;QACpC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAK,CAAC,OAAO,CAAA;QAClC,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,OAAO,EAAE,EAAE,EAAE,EAAE,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,CAAA;IACzH,CAAC;IAED,uFAAuF;IAC/E,KAAK,CAAC,MAA8B;QAC1C,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE,OAAM;QACjC,IAAI,CAAC,OAAO,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAA;IAC7F,CAAC;IAEO,OAAO,CAAC,MAAc;QAC5B,IAAI,CAAC,aAAa,CAAC,IAAI,WAAW,CAAC,SAAS,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAA;IACvG,CAAC;;AAlI+B;IAA/B,QAAQ,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;;oDAAoB;AAEvC;IAAX,QAAQ,EAAE;;qDAAY;AACM;IAA5B,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;;qDAAe;AAG1B;IAAhB,KAAK,EAAE;;mDAA8B;AAxE3B,qBAAqB;IADjC,aAAa,CAAC,0BAA0B,CAAC;GAC7B,qBAAqB,CAqMjC","sourcesContent":["import { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { i18next, localize } from '@operato/i18n'\nimport '@material/web/icon/icon.js'\nimport '@operato/slot-layout-editor'\nimport { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js'\nimport { compileFigureAsset, type FigureAsset, type SlotLayout } from '@hatiolab/figure-model'\n\nimport {\n anchorFacesOf,\n anchorRoomOf,\n anchorIdFor,\n figureSlotIssues,\n slotLayoutCommandOf,\n slotLayoutFormOf,\n slotPresetsOf,\n startSizeOf,\n type SlotAnchor,\n type SlotAnchorFace,\n type SlotLayoutForm\n} from './slot-layout-host.js'\n\n/**\n * A figure's slot layout (ADR-0118): places made by a rule -- anchors on parts' tops or bottoms, tiers on them, slots in\n * the tiers. The tiers and slots are edited in the shared editor (`ox-slot-layout-editor`, the one fmsim hosts); this\n * panel owns what only the modeller knows: which part's face each anchor is, the layout's name and what its slots are.\n * Every change goes out as one `set-slot-layout` command -- one step of the history, refused by figure-model in its words.\n *\n * The layout here is the only one: a scene or a run never overrides it (ADR-0118 decision 8), so there is no \"default\".\n */\n@customElement('figure-slot-layout-panel')\nexport class FigureSlotLayoutPanel extends localize(i18next)(LitElement) {\n /*\n The panel's controls, and the shared editor given the same (sweep 2026-10-27 M2): its own 12px, boxed 24px fields and\n right-aligned labels at 34% stood under the panel's 11.5px, 26px underlined fields and 72px labels.\n */\n static styles = [SidePanelStyles, css`\n :host {\n display: flex;\n flex-direction: column;\n gap: 6px;\n }\n ox-slot-layout-editor {\n --slot-layout-font-size: var(--ui-t-small, 11.5px);\n --slot-layout-label-column: var(--figure-label-width);\n --slot-layout-label-align: left;\n --property-editor-field-height: var(--figure-control-height);\n --slot-layout-field-border: 0 solid transparent;\n --slot-layout-field-border-bottom: 1px solid var(--md-sys-color-outline-variant, #c4c7c5);\n --slot-layout-field-radius: 0;\n --slot-layout-field-background: transparent;\n --property-editor-label-color: var(--md-sys-color-on-surface-variant);\n }\n div[form] {\n display: grid;\n grid-template-columns: var(--figure-label-width) minmax(0, 1fr);\n gap: 4px 8px;\n align-items: center;\n }\n ul {\n list-style: none;\n margin: 0;\n padding: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n }\n li {\n display: grid;\n grid-template-columns: 1fr 1fr auto auto;\n gap: 4px;\n align-items: center;\n }\n input,\n select {\n min-width: 0;\n font: inherit;\n }\n div[actions] {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n }\n button {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n font: inherit;\n }\n md-icon {\n --md-icon-size: 16px;\n }\n small[hint] {\n color: var(--md-sys-color-on-surface-variant);\n }\n `]\n\n @property({ attribute: false }) asset?: FigureAsset\n /** The part selected on the canvas: what a new anchor stands on. */\n @property() partId = ''\n @property({ type: Boolean }) locked = false\n\n /** The name, role and anchors being edited; started again from the figure whenever the figure changes. */\n @state() private form?: SlotLayoutForm\n private formFor?: FigureAsset\n private options?: { key: string; asset: FigureAsset; value: object }\n /*\n The figure's layout, read once per figure: the editor starts its draft again whenever its value changes, so a value\n read again every render would throw the author's edits away.\n */\n private stored?: ReturnType<typeof slotLayoutFormOf>\n\n willUpdate() {\n /* A figure changed under the panel (an undo, another edit): what is shown is the figure's, not an old draft. */\n if (this.asset !== this.formFor) {\n this.formFor = this.asset\n this.stored = this.asset ? slotLayoutFormOf(this.asset, this.partId) : undefined\n this.form = this.stored?.form\n }\n }\n\n render() {\n const asset = this.asset\n const stored = this.stored\n const form = this.form\n if (!asset || !stored || !form) return nothing\n const parts = asset.document.model.nodes.filter(n => n.op === 'place@1').map(n => n.id)\n const changed = JSON.stringify(form) !== JSON.stringify(stored.form)\n return html`\n <div form>\n <span>${i18next.t('figure.label.slot-layout-name')}</span>\n <input .value=${form.label} placeholder=${i18next.t('figure.label.slot-layout')} ?disabled=${this.locked} @change=${(e: Event) => this.edit({ label: (e.target as HTMLInputElement).value })} />\n <span>${i18next.t('figure.label.slot-layout-role')}</span>\n <select ?disabled=${this.locked} @change=${(e: Event) => this.edit({ role: (e.target as HTMLSelectElement).value as 'seat' | 'grip' })}>\n <option value=\"seat\" ?selected=${form.role === 'seat'}>${i18next.t('figure.label.place-seat')}</option>\n <option value=\"grip\" ?selected=${form.role === 'grip'}>${i18next.t('figure.label.place-grip')}</option>\n </select>\n </div>\n\n <h4>${i18next.t('figure.label.slot-anchors')}</h4>\n <ul>\n ${form.anchors.map(\n (a, i) => html`<li>\n <input .value=${a.id} aria-label=${i18next.t('figure.label.slot-anchor-id')} ?disabled=${this.locked} @change=${(e: Event) => this.anchor(i, { id: (e.target as HTMLInputElement).value.trim() })} />\n <select aria-label=${i18next.t('figure.label.part')} ?disabled=${this.locked} @change=${(e: Event) => this.anchor(i, { part: (e.target as HTMLSelectElement).value })}>\n ${parts.map(p => html`<option value=${p} ?selected=${p === a.part}>${p}</option>`)}\n </select>\n <select aria-label=${i18next.t('figure.label.face')} ?disabled=${this.locked} @change=${(e: Event) => this.anchor(i, { face: (e.target as HTMLSelectElement).value as SlotAnchorFace })}>\n ${(['top', 'bottom'] as const).map(f => html`<option value=${f} ?selected=${f === a.face}>${i18next.t('figure.label.face-' + f)}</option>`)}\n </select>\n <button ?disabled=${this.locked || form.anchors.length <= 1} title=${i18next.t('figure.button.remove-slot-anchor')} @click=${() => this.edit({ anchors: form.anchors.filter((_, k) => k !== i) })}>\n <md-icon>delete</md-icon>\n </button>\n </li>`\n )}\n </ul>\n <div actions>\n ${(['top', 'bottom'] as const).map(\n face => html`<button act ?disabled=${this.locked || !this.partId} @click=${() => this.addAnchor(face)}>\n <md-icon>add</md-icon>${i18next.t(face === 'top' ? 'figure.button.add-slot-anchor-top' : 'figure.button.add-slot-anchor-bottom', { part: this.partId })}\n </button>`\n )}\n </div>\n <small hint>${i18next.t('figure.text.slot-anchor-pick')}</small>\n\n <ox-slot-layout-editor .value=${stored.layout} .options=${this.editorOptions(asset, form, stored.layout)} @change=${(e: Event) => this.apply((e.target as { value?: SlotLayout }).value)}></ox-slot-layout-editor>\n\n <div actions>\n ${stored.layout && changed\n ? html`<button act ?disabled=${this.locked} @click=${() => this.apply(stored.layout)}><md-icon>check</md-icon>${i18next.t('figure.button.apply-slot-anchors')}</button>`\n : nothing}\n ${stored.layout\n ? html`<button act ?disabled=${this.locked} @click=${() => this.command({ kind: 'remove-slot-layout' })}><md-icon>delete</md-icon>${i18next.t('figure.button.remove-slot-layout')}</button>`\n : nothing}\n </div>\n `\n }\n\n /*\n The editor's options, made again only when what they are made from changes: the editor starts its draft again when its\n starting layout changes, so a new object every render would throw the author's edits away.\n */\n private editorOptions(asset: FigureAsset, form: SlotLayoutForm, layout: SlotLayout | undefined) {\n const key = JSON.stringify([form.anchors, !!layout])\n if (this.options?.key === key && this.options.asset === asset) return this.options.value\n const geometry = compileFigureAsset(asset).evaluate().geometry as never\n const anchorFaces = anchorFacesOf(form.anchors, geometry)\n const value = {\n canUseDefault: false,\n presets: slotPresetsOf(form.anchors),\n /* The first anchor's face is the size a preset is laid out over, the room over it the slot height: no number to type. */\n presetSize: startSizeOf(form.anchors, anchorFaces, anchorRoomOf(form.anchors, geometry)),\n /* No layout yet: the whole face is one slot, shown at once and put in on Apply. */\n startFrom: 'single',\n /* The face names its part: an anchor named as its part is not named twice (「tub · tub 윗면」, sweep 2026-10-27 M5). */\n anchors: form.anchors.map(a => ({ id: a.id, label: `${a.id === a.part ? '' : `${a.id} · `}${a.part} ${i18next.t('figure.label.face-' + a.face)}` })),\n anchorFaces,\n validate: (layout: SlotLayout) => figureSlotIssues(layout, form.anchors.map(a => a.id)),\n issueText: (issue: { code: string; path: string }) =>\n issue.code === 'ACCEPTS_EMPTY' ? `${issue.path}: ${i18next.t('figure.text.slot-accepts-empty-list')}` : undefined\n }\n this.options = { key, asset, value }\n return value\n }\n\n private edit(patch: Partial<SlotLayoutForm>) {\n this.form = { ...this.form!, ...patch }\n }\n\n private anchor(i: number, patch: Partial<SlotAnchor>) {\n this.edit({ anchors: this.form!.anchors.map((a, k) => (k === i ? { ...a, ...patch } : a)) })\n }\n\n /** A new anchor on the selected part's face: what an author picks on the canvas comes here. */\n private addAnchor(face: SlotAnchorFace) {\n const anchors = this.form!.anchors\n this.edit({ anchors: [...anchors, { id: anchorIdFor(this.partId, anchors.map(a => a.id)), part: this.partId, face }] })\n }\n\n /** The whole layout with the anchors and name as they stand: one command, one step. */\n private apply(layout: SlotLayout | undefined) {\n if (!layout || !this.form) return\n this.command(slotLayoutCommandOf(this.form, layout, i18next.t('figure.label.slot-layout')))\n }\n\n private command(action: object) {\n this.dispatchEvent(new CustomEvent('command', { detail: { action }, bubbles: true, composed: true }))\n }\n}\n"]}
@@ -709,7 +709,10 @@ let FigureVerdict = class FigureVerdict extends localize(i18next)(LitElement) {
709
709
  ? html `<p quiet>${i18next.t(this.asking ? 'figure.text.verdict-asking' : 'figure.text.verdict-waiting')}</p>`
710
710
  : blocking.length
711
711
  ? html `<p>${i18next.t('figure.text.cannot-release-now')}</p>`
712
- : html `<p clear>${i18next.t('figure.text.nothing-blocks-release')}</p>`}
712
+ : this.revision && !this.revision.asset.appearance.length
713
+ ? /* No part: nothing to judge, not 「nothing blocks」 (sweep 2026-10-27 U24). */
714
+ html `<p quiet>${i18next.t('figure.text.release-needs-a-part')}</p>`
715
+ : html `<p clear>${i18next.t('figure.text.nothing-blocks-release')}</p>`}
713
716
  ${blocking.length
714
717
  ? html `<ul gate>
715
718
  <li head>${i18next.t('figure.text.must-fix-to-release')}</li>
@@ -1 +1 @@
1
- {"version":3,"file":"figure-verdict.js","sourceRoot":"","sources":["../../client/modeller/figure-verdict.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'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\nimport { LIMITS, FIGURE_PER_INSTANCE } from '@hatiolab/figure-model'\n\nimport { inspectFigureDraft } from '../graphql/index.js'\nimport type { FigureInspection } from '../types.js'\nimport { gateFindingStyles, renderGateFinding } from './gate-findings.js'\nimport { MEASURED } from './scene-budget.js'\nimport type { FigureRevision } from './revision.js'\nimport { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js'\nimport { CURVE_SIZE, curveLayout, gradeBoundsOf, shortNumber, verdictMeasureOf } from './maturity.js'\nimport { newestAnswer } from './newest-answer.js'\nimport type { FigureBudgetUse, FigureMaturityAxis, FigureReport } from './maturity.js'\n\n/** How long an edit settles before the server is asked again. One question per pause, not one per keystroke. */\nexport const VERDICT_SETTLE_MS = 400\n/** How long the figure rests before its report is measured again. */\nconst MEASURE_SETTLE_MS = 200\n\n/**\n * 성숙도 — the modeller's verdict while editing.\n *\n * It shows, as the author edits: how many fit on one screen with the grade beside it and the budget that\n * decided the grade, the grade scale, six maturity axes as a radar and a list, the budget bars, the drawing cost,\n * the reuse trend, and the findings. An earlier tab kept only the count and the findings (user, 2026-09-24:\n * 「분석부분도 많이 부족하고, 왜 이렇게 너프되었는지」).\n *\n * ## What is computed where\n *\n * The numbers come from `maturity.ts`, which reads the evaluated asset the way the renderer draws it — the\n * screen calls and shows, it does not count. The count uses the same `capacityFrom` the catalogue cards use, so the\n * tab and the card cannot disagree.\n *\n * The findings do not come from here: they come from the server's release door (`inspectFigureDraft`), the same\n * door and the same sentences as the release panel. A second judgement on the screen would say something different\n * the first time either changed. The release judgement is the server's, so that section is the server's answer.\n *\n * ## The grade\n *\n * figure-model's `figureScoreOf`, which the catalogue uses too: headroom against placing `LIMITS.screenInstances` of the\n * figure on one screen (chief architect, 2026-09-24) -- the screen's measured groups and its triangle target shared\n * per instance -- and the rule limits for independently moved parts and transparent materials, decided by the\n * tightest. The two budgets has no field for are left out and the tab says so.\n */\n/** A per-instance share of the screen is not a whole number; what an instance may draw is the whole part of it. */\nconst limitOf = (use: FigureBudgetUse) => Math.floor(use.limit).toLocaleString()\n\n@customElement('figure-verdict')\nexport class FigureVerdict extends localize(i18next)(LitElement) {\n static styles = [\n ScrollbarStyles,\n SidePanelStyles,\n gateFindingStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n }\n section p {\n margin: 0;\n }\n\n /* ── How many fit ───────────────────────────────────────────────\n The value of low poly is how many can stand on one screen, so that answer leads. The grade says whether\n the shape keeps inside its declared limits, so it is the small badge beside it. */\n p[lead],\n p[basis],\n p[quiet] {\n font-size: var(--ui-t-micro, 11px);\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 div[verdict] {\n display: flex;\n align-items: baseline;\n gap: 6px;\n }\n span[capacity] {\n font-size: var(--ui-t-hero, 26px);\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: var(--ui-t-title, 15px);\n font-weight: 600;\n color: var(--md-sys-color-primary);\n }\n /* The badge says what it measures (headroom), so its number is not read as a score out of 100. */\n span[grade] {\n display: flex;\n align-items: baseline;\n gap: 5px;\n margin-left: auto;\n padding: 3px 10px;\n font-size: var(--ui-t-small, 11.5px);\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 display: inline;\n margin: 0;\n font-size: var(--ui-t-micro, 11px);\n font-weight: 500;\n color: inherit;\n }\n /* C keeps within the limit. Red is for over it (D) only; red on a kept limit asks for a fix nothing needs. */\n span[grade][tight] {\n color: var(--md-sys-color-on-tertiary-container);\n background-color: var(--md-sys-color-tertiary-container);\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 p[because] {\n font-size: var(--ui-t-small, 11.5px);\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 /* The grade scale. Not folded away: it is compared against every time, not learned once. */\n p[scale] {\n display: flex;\n flex-wrap: wrap;\n gap: 2px 10px;\n font-size: var(--ui-t-micro, 11px);\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] {\n color: var(--md-sys-color-on-surface);\n }\n p[scale] span[now] b {\n color: var(--md-sys-color-primary);\n }\n\n /* ── Maturity radar ─────────────────────────────────────────────\n Only the measured axes are drawn; an unmeasured one drawn as a spoke reads as a dent, which is a zero. */\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 /* svg-units: the radar's own coordinates (its viewBox), drawn to the chart's size -- not a page size. */\n font-size: 5.2px;\n fill: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n p[unmeasured] {\n font-size: var(--ui-t-micro, 11px);\n line-height: 1.5;\n color: var(--md-sys-color-tertiary);\n }\n\n /* ── Axes and budgets ───────────────────────────────────────────\n Not merged into one number: merged, 「what to fix」 disappears. */\n ul[axes],\n ul[budgets] {\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 ul[budgets] li {\n display: grid;\n grid-template-columns: 1fr auto;\n gap: 2px 8px;\n font-size: var(--ui-t-small, 11.5px);\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: var(--ui-t-micro, 11px);\n line-height: 1.5;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n ul[axes] li[blocked] em {\n color: var(--md-sys-color-tertiary);\n }\n span[reading] {\n font-family: var(--ui-mono, ui-monospace, monospace);\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\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 /* ── Drawing cost ─────────────────────────────────────────────── */\n dl[metrics] {\n margin: 0;\n display: grid;\n grid-template-columns: 1fr auto;\n gap: 4px 8px;\n font-size: var(--ui-t-small, 11.5px);\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(--ui-mono, ui-monospace, monospace);\n }\n\n /* ── Trend ──────────────────────────────────────────────────────\n The chart's natural size is 680px; in a 300px side its words are 4px. The side holds a button, the chart\n opens at its own size. */\n button[expand] {\n justify-self: start;\n padding: 4px 10px;\n font: inherit;\n font-size: var(--ui-t-small, 11.5px);\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 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: 12px;\n background-color: color-mix(in srgb, var(--md-sys-color-scrim, black) 32%, transparent);\n }\n div[sheet] > figure {\n max-width: 100%;\n max-height: 100%;\n margin: 0;\n padding: 12px;\n overflow: auto;\n color: var(--md-sys-color-on-surface);\n background-color: var(--md-sys-color-surface-container-lowest);\n border-radius: 6px;\n box-shadow: 0 8px 32px color-mix(in srgb, var(--md-sys-color-shadow, black) 28%, transparent);\n }\n div[sheet] svg {\n display: block;\n /* Not shrunk below its natural size — a narrow window scrolls instead. */\n min-width: 680px;\n font-family: inherit;\n font-size: var(--ui-t-micro, 11px);\n fill: currentColor;\n }\n div[sheet] svg [grid] {\n stroke: currentColor;\n stroke-opacity: 0.12;\n }\n div[sheet] svg [muted] {\n opacity: 0.55;\n }\n div[sheet] svg path[series] {\n fill: none;\n stroke-width: 2;\n stroke-linejoin: round;\n }\n div[sheet] svg [series='triangles'] {\n stroke: var(--md-sys-color-error);\n fill: var(--md-sys-color-error);\n }\n div[sheet] svg [series='drawCalls'] {\n stroke: var(--md-sys-color-tertiary);\n fill: var(--md-sys-color-tertiary);\n }\n div[sheet] svg [series='geometries'] {\n stroke: var(--md-sys-color-primary);\n fill: var(--md-sys-color-primary);\n }\n div[sheet] svg [series='materials'] {\n stroke: var(--md-sys-color-secondary);\n fill: var(--md-sys-color-secondary);\n }\n div[sheet] svg path[series],\n div[sheet] svg line[series] {\n fill: none;\n }\n /* A legend value is written in its line's colour, not outlined in it. */\n div[sheet] svg text[series] {\n stroke: none;\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: 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 /* ── Release verdict ───────────────────────────────────────────── */\n p[clear] {\n color: var(--md-sys-color-primary);\n font-weight: 600;\n }\n p[failed] {\n color: var(--md-sys-color-error);\n }\n button[fit] {\n align-self: flex-start;\n margin-top: 4px;\n padding: 4px 10px;\n font: inherit;\n color: var(--md-sys-color-on-secondary-container);\n background: var(--md-sys-color-secondary-container);\n border: none;\n border-radius: 999em;\n cursor: pointer;\n }\n `\n ]\n\n /** The figure at the version on screen. A version whose text is another is a new question. */\n @property({ attribute: false }) revision?: FigureRevision\n /* The text last judged: a save hands out the same version again as a new object, which asks nothing new. */\n private judged?: string\n /** The saved row, if any — the server reads its type and last release from it. */\n @property({ type: String }) figureId?: string\n /** Changing the type changes the verdict (a temporary type is refused), so it is a reason to ask again. */\n @property({ type: String }) figureType?: string\n\n /** The report over the source being edited. Absent when nothing is drawn, or the format refuses the source. */\n @state() private report?: FigureReport\n /** Whether the trend chart is open at its own size. */\n @state() private expanded = false\n @state() private inspection?: FigureInspection\n @state() private failure = ''\n @state() private asking = false\n\n private timer?: ReturnType<typeof setTimeout>\n /** Answers can come back out of order; only the newest question's answer is shown. */\n private answers = newestAnswer<FigureInspection>()\n\n disconnectedCallback() {\n clearTimeout(this.timer)\n clearTimeout(this.measureTimer)\n super.disconnectedCallback()\n }\n\n /** The report is measured once the figure has settled: it is read beside the work, and each measure compiles the figure several times. */\n private measureTimer?: ReturnType<typeof setTimeout>\n updated(changes: Map<string, unknown>) {\n const text = changes.has('revision') ? this.revision?.text : this.judged\n const changed = text !== this.judged\n if (changed) {\n this.judged = text\n clearTimeout(this.measureTimer)\n if (this.report === undefined && !this.measureTimer) this.measure()\n else this.measureTimer = setTimeout(() => this.measure(), MEASURE_SETTLE_MS)\n }\n if (changed || changes.has('figureId') || changes.has('figureType')) this.schedule()\n /* What blocks release, told to the page so the bar can say it beside 「발행」 (first 15 minutes, 2026-10-16). */\n if (changes.has('inspection'))\n this.dispatchEvent(new CustomEvent('release-verdict', { detail: { blocking: (this.inspection?.findings ?? []).filter(finding => finding.blocking) } }))\n }\n\n private measure() {\n const { report, told } = verdictMeasureOf(this.revision?.asset)\n this.report = report\n if (!report) this.expanded = false\n this.dispatchEvent(new CustomEvent('capacity-changed', { detail: told }))\n }\n\n private schedule() {\n clearTimeout(this.timer)\n if (!this.revision) {\n this.inspection = undefined\n return\n }\n this.timer = setTimeout(() => this.ask(), VERDICT_SETTLE_MS)\n }\n\n private async ask() {\n const source = this.revision!.text\n this.asking = true\n await this.answers(\n () => inspectFigureDraft(source, this.figureId),\n outcome => {\n this.asking = false\n if ('answer' in outcome) {\n this.inspection = outcome.answer\n this.failure = ''\n } else {\n /* The server's reason as it gave it — the screen does not make one up. The last answer is dropped with it. */\n this.inspection = undefined\n this.failure = outcome.failure instanceof Error ? outcome.failure.message : String(outcome.failure)\n }\n }\n )\n }\n\n render() {\n /*\n With nothing drawn the report is guidance, not a verdict: the sections below have meaning only over parts,\n and a number drawn from nothing reads as zero, which reads as bad. The release verdict stays — a new figure\n is already refused for its undeclared space, and the way out is offered there.\n */\n const report = this.report\n if (!report) {\n return html`\n <section>\n <h3>${i18next.t('figure.label.maturity')}</h3>\n <p quiet>${i18next.t('figure.text.report-appears-when-you-add-a-part')}</p>\n </section>\n ${this.renderGate()}\n `\n }\n return html`\n ${this.renderVerdict(report)} ${this.renderAxes(report)} ${this.renderBudgets(report)} ${this.renderMetrics(report)}\n ${this.renderCurve()} ${this.renderGate()} ${this.renderSheet(report)}\n `\n }\n\n /**\n * The head — how many fit, with the grade beside it, the budget that decided it, the scale, and the basis.\n *\n * The count's denominator is measured (2026-09-18, Apple M5) and says so with the machine and the date; the\n * triangle side is still the design document's target and says that.\n */\n private renderVerdict(report: FigureReport) {\n const { capacity, score } = report\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', { target: LIMITS.screenInstances })}\n >\n ${score.grade}\n <small>${i18next.t('figure.text.headroom-percent', { percent: 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.toLocaleString()} / ${limitOf(score.tightest)} (${Math.round(score.tightest.ratio * 100)}%)\n </p>\n <p basis>\n ${i18next.t('figure.text.grade-target', {\n target: LIMITS.screenInstances,\n groups: Math.floor(FIGURE_PER_INSTANCE.groups),\n triangles: Math.floor(FIGURE_PER_INSTANCE.triangles).toLocaleString()\n })}\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 /** A · B · C · D and where this figure stands, drawn from the bounds the grade is computed with. */\n private renderGradeScale(now: string) {\n return html`\n <p scale>\n <span>${i18next.t('figure.text.grade-scale-lead')}</span>\n ${gradeBoundsOf().map(([grade, bound]) => html`<span ?now=${grade === now}><b>${grade}</b> ${bound}</span>`)}\n </p>\n `\n }\n\n /**\n * Maturity by axis — a radar of the measured axes, a line naming the unmeasured ones, and the list.\n *\n * Scale is left out of the list: it leads the tab, and the same number twice reads as two different things.\n */\n private renderAxes(report: FigureReport) {\n const measured = report.axes.filter(axis => axis.ratio !== undefined)\n const unmeasured = report.axes.filter(axis => axis.ratio === undefined)\n return html`\n <section>\n <h3>${i18next.t('figure.label.by-axis')}</h3>\n <div radar>${this.renderRadar(measured)}</div>\n ${unmeasured.length\n ? html`<p unmeasured>\n ${i18next.t('figure.text.axes-not-measurable-yet', {\n axes: unmeasured.map(axis => i18next.t('figure.label.axis-' + axis.key)).join(' · ')\n })}\n </p>`\n : nothing}\n <ul axes>\n ${report.axes.filter(axis => axis.key !== 'scale').map(axis => this.renderAxis(axis))}\n </ul>\n </section>\n `\n }\n\n /** The radar: rings at a third, two thirds and full, short names so the left edge is not cut. */\n private renderRadar(axes: FigureMaturityAxis[]) {\n const cx = 60\n const cy = 46\n const r = 28\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 const clamp = (ratio?: number) => Math.max(0.04, Math.min(1, ratio ?? 0))\n const points = axes.map((axis, index) => at(index, clamp(axis.ratio)).map(n => n.toFixed(1)).join(',')).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, clamp(axis.ratio))\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`<text x=${x.toFixed(1)} y=${(y + 1.8).toFixed(1)} text-anchor=${anchor}>${i18next.t('figure.label.axis-' + axis.key + '-short')}</text>`\n })}\n </svg>\n `\n }\n\n private renderAxis(axis: FigureMaturityAxis) {\n const name = i18next.t('figure.label.axis-' + axis.key)\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 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>` : nothing}\n </li>\n `\n }\n\n /** The budget bars. The one closest to its limit is coloured — it decided the grade. */\n private renderBudgets(report: FigureReport) {\n const { score } = report\n return html`\n <section>\n <h3>${i18next.t('figure.label.budgets')}</h3>\n <ul budgets>\n ${score.budgets.map(\n use => html`\n <li>\n <span>${i18next.t('figure.label.budget-' + use.key)}</span>\n <span>${use.used.toLocaleString()} / ${limitOf(use)}</span>\n <div bar><i ?tight=${use.key === score.tightest.key} style=\"width:${Math.round(Math.min(1, use.ratio) * 100)}%\"></i></div>\n </li>\n `\n )}\n </ul>\n <p quiet>${i18next.t('figure.text.budgets-not-in')}</p>\n </section>\n `\n }\n\n private renderMetrics(report: FigureReport) {\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>${report.cost.triangles.toLocaleString()}</dd>\n <dt>${i18next.t('figure.label.distinct-shapes')}</dt>\n <dd>${report.distinctShapes}</dd>\n <dt>${i18next.t('figure.label.distinct-materials')}</dt>\n <dd>${report.distinctMaterials}</dd>\n </dl>\n </section>\n `\n }\n\n private renderCurve() {\n return html`\n <section>\n <h3>${i18next.t('figure.label.reuse-trend')}</h3>\n <button expand @click=${() => (this.expanded = true)}>${i18next.t('figure.button.see-the-trend-chart')}</button>\n </section>\n `\n }\n\n /**\n * The trend at its own size: both axes logarithmic, the growing lines against the flat ones, and a\n * legend with each line's value at the last count.\n */\n private renderSheet(report: FigureReport) {\n if (!this.expanded) return nothing\n const layout = curveLayout(report.curve)\n if (!layout) return nothing\n const { width, height, pad } = CURVE_SIZE\n const plotW = width - pad.left - pad.right\n const plotH = height - pad.top - pad.bottom\n const last = report.curve[report.curve.length - 1]!\n const label = (key: string) =>\n i18next.t(\n {\n triangles: 'figure.label.triangles',\n drawCalls: 'figure.label.draw-calls',\n geometries: 'figure.label.vertex-buffers',\n materials: 'figure.label.distinct-materials'\n }[key]!\n )\n\n return html`\n <div sheet @click=${() => (this.expanded = false)}>\n <figure @click=${(e: Event) => e.stopPropagation()}>\n ${svg`\n <svg viewBox=\"0 0 ${width} ${height}\" width=${width} height=${height} role=\"img\">\n <text x=${pad.left} y=\"22\" font-size=\"13\" font-weight=\"600\">${i18next.t('figure.text.trend-chart-title')}</text>\n <text x=${pad.left} y=\"38\" muted>${i18next.t('figure.text.trend-chart-lead')}</text>\n ${layout.yTicks.map(\n tick => svg`\n <line grid x1=${pad.left} y1=${tick.y.toFixed(1)} x2=${(pad.left + plotW).toFixed(1)} y2=${tick.y.toFixed(1)}></line>\n <text muted x=${pad.left - 8} y=${(tick.y + 3.5).toFixed(1)} text-anchor=\"end\">${tick.label}</text>\n `\n )}\n ${layout.xTicks.map(\n tick => svg`\n <line grid x1=${tick.x.toFixed(1)} y1=${pad.top} x2=${tick.x.toFixed(1)} y2=${(pad.top + plotH).toFixed(1)}></line>\n <text muted x=${tick.x.toFixed(1)} y=${(pad.top + plotH + 16).toFixed(1)} text-anchor=\"middle\">${tick.label}</text>\n `\n )}\n <text muted x=${(pad.left + plotW / 2).toFixed(1)} y=${height - 8} text-anchor=\"middle\">${i18next.t('figure.label.instance-count')}</text>\n ${layout.lines.map(\n line => svg`<path series=${line.key} d=${line.d} stroke-dasharray=${line.dashed ? '3 7' : 'none'}></path>`\n )}\n <g transform=\"translate(${width - pad.right + 14}, ${pad.top - 6})\">\n <text x=\"0\" y=\"0\" font-weight=\"600\">${i18next.t('figure.text.trend-at-count', { n: shortNumber(last.instances) })}</text>\n ${layout.lines.map((line, i) => {\n const y = 24 + i * 34\n return svg`\n <line series=${line.key} x1=\"0\" y1=${y - 4} x2=\"18\" y2=${y - 4} stroke-width=\"2\" stroke-dasharray=${line.dashed ? '3 7' : 'none'}></line>\n <text x=\"24\" y=${y}>${label(line.key)}</text>\n <text series=${line.key} x=\"24\" y=${y + 12} font-weight=\"600\">\n ${line.last.toLocaleString()}${line.flat ? ` · ${i18next.t('figure.text.trend-stays')}` : ''}\n </text>\n `\n })}\n ${layout.overlap !== undefined\n ? svg`<text muted x=\"0\" y=${24 + layout.lines.length * 34 + 6}>${i18next.t('figure.text.trend-flat-lines-overlap', { value: layout.overlap.toLocaleString() })}</text>`\n : nothing}\n </g>\n </svg>\n `}\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 private renderGate() {\n const findings = this.inspection?.findings ?? []\n const blocking = findings.filter(finding => finding.blocking)\n const advisory = findings.filter(finding => !finding.blocking)\n return html`\n <section>\n <h3>${i18next.t('figure.label.release-verdict')}</h3>\n ${this.failure\n ? html`<p failed role=\"alert\">${i18next.t('figure.text.verdict-not-received', { reason: this.failure })}</p>`\n : !this.inspection\n ? html`<p quiet>${i18next.t(this.asking ? 'figure.text.verdict-asking' : 'figure.text.verdict-waiting')}</p>`\n : blocking.length\n ? html`<p>${i18next.t('figure.text.cannot-release-now')}</p>`\n : html`<p clear>${i18next.t('figure.text.nothing-blocks-release')}</p>`}\n ${blocking.length\n ? html`<ul gate>\n <li head>${i18next.t('figure.text.must-fix-to-release')}</li>\n ${blocking.map(finding => renderGateFinding(finding, true, nothing, this.partNames()))}\n </ul>`\n : nothing}\n ${advisory.length\n ? html`<ul gate>\n <li head quiet>${i18next.t('figure.text.does-not-block')}</li>\n ${advisory.map(finding => renderGateFinding(finding, false, nothing, this.partNames()))}\n </ul>`\n : nothing}\n </section>\n `\n }\n\n private partNames(): string[] {\n return (this.revision?.asset.appearance ?? []).map(look => look.target)\n }\n}\n"]}
1
+ {"version":3,"file":"figure-verdict.js","sourceRoot":"","sources":["../../client/modeller/figure-verdict.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'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\nimport { LIMITS, FIGURE_PER_INSTANCE } from '@hatiolab/figure-model'\n\nimport { inspectFigureDraft } from '../graphql/index.js'\nimport type { FigureInspection } from '../types.js'\nimport { gateFindingStyles, renderGateFinding } from './gate-findings.js'\nimport { MEASURED } from './scene-budget.js'\nimport type { FigureRevision } from './revision.js'\nimport { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js'\nimport { CURVE_SIZE, curveLayout, gradeBoundsOf, shortNumber, verdictMeasureOf } from './maturity.js'\nimport { newestAnswer } from './newest-answer.js'\nimport type { FigureBudgetUse, FigureMaturityAxis, FigureReport } from './maturity.js'\n\n/** How long an edit settles before the server is asked again. One question per pause, not one per keystroke. */\nexport const VERDICT_SETTLE_MS = 400\n/** How long the figure rests before its report is measured again. */\nconst MEASURE_SETTLE_MS = 200\n\n/**\n * 성숙도 — the modeller's verdict while editing.\n *\n * It shows, as the author edits: how many fit on one screen with the grade beside it and the budget that\n * decided the grade, the grade scale, six maturity axes as a radar and a list, the budget bars, the drawing cost,\n * the reuse trend, and the findings. An earlier tab kept only the count and the findings (user, 2026-09-24:\n * 「분석부분도 많이 부족하고, 왜 이렇게 너프되었는지」).\n *\n * ## What is computed where\n *\n * The numbers come from `maturity.ts`, which reads the evaluated asset the way the renderer draws it — the\n * screen calls and shows, it does not count. The count uses the same `capacityFrom` the catalogue cards use, so the\n * tab and the card cannot disagree.\n *\n * The findings do not come from here: they come from the server's release door (`inspectFigureDraft`), the same\n * door and the same sentences as the release panel. A second judgement on the screen would say something different\n * the first time either changed. The release judgement is the server's, so that section is the server's answer.\n *\n * ## The grade\n *\n * figure-model's `figureScoreOf`, which the catalogue uses too: headroom against placing `LIMITS.screenInstances` of the\n * figure on one screen (chief architect, 2026-09-24) -- the screen's measured groups and its triangle target shared\n * per instance -- and the rule limits for independently moved parts and transparent materials, decided by the\n * tightest. The two budgets has no field for are left out and the tab says so.\n */\n/** A per-instance share of the screen is not a whole number; what an instance may draw is the whole part of it. */\nconst limitOf = (use: FigureBudgetUse) => Math.floor(use.limit).toLocaleString()\n\n@customElement('figure-verdict')\nexport class FigureVerdict extends localize(i18next)(LitElement) {\n static styles = [\n ScrollbarStyles,\n SidePanelStyles,\n gateFindingStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n }\n section p {\n margin: 0;\n }\n\n /* ── How many fit ───────────────────────────────────────────────\n The value of low poly is how many can stand on one screen, so that answer leads. The grade says whether\n the shape keeps inside its declared limits, so it is the small badge beside it. */\n p[lead],\n p[basis],\n p[quiet] {\n font-size: var(--ui-t-micro, 11px);\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 div[verdict] {\n display: flex;\n align-items: baseline;\n gap: 6px;\n }\n span[capacity] {\n font-size: var(--ui-t-hero, 26px);\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: var(--ui-t-title, 15px);\n font-weight: 600;\n color: var(--md-sys-color-primary);\n }\n /* The badge says what it measures (headroom), so its number is not read as a score out of 100. */\n span[grade] {\n display: flex;\n align-items: baseline;\n gap: 5px;\n margin-left: auto;\n padding: 3px 10px;\n font-size: var(--ui-t-small, 11.5px);\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 display: inline;\n margin: 0;\n font-size: var(--ui-t-micro, 11px);\n font-weight: 500;\n color: inherit;\n }\n /* C keeps within the limit. Red is for over it (D) only; red on a kept limit asks for a fix nothing needs. */\n span[grade][tight] {\n color: var(--md-sys-color-on-tertiary-container);\n background-color: var(--md-sys-color-tertiary-container);\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 p[because] {\n font-size: var(--ui-t-small, 11.5px);\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 /* The grade scale. Not folded away: it is compared against every time, not learned once. */\n p[scale] {\n display: flex;\n flex-wrap: wrap;\n gap: 2px 10px;\n font-size: var(--ui-t-micro, 11px);\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] {\n color: var(--md-sys-color-on-surface);\n }\n p[scale] span[now] b {\n color: var(--md-sys-color-primary);\n }\n\n /* ── Maturity radar ─────────────────────────────────────────────\n Only the measured axes are drawn; an unmeasured one drawn as a spoke reads as a dent, which is a zero. */\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 /* svg-units: the radar's own coordinates (its viewBox), drawn to the chart's size -- not a page size. */\n font-size: 5.2px;\n fill: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n p[unmeasured] {\n font-size: var(--ui-t-micro, 11px);\n line-height: 1.5;\n color: var(--md-sys-color-tertiary);\n }\n\n /* ── Axes and budgets ───────────────────────────────────────────\n Not merged into one number: merged, 「what to fix」 disappears. */\n ul[axes],\n ul[budgets] {\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 ul[budgets] li {\n display: grid;\n grid-template-columns: 1fr auto;\n gap: 2px 8px;\n font-size: var(--ui-t-small, 11.5px);\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: var(--ui-t-micro, 11px);\n line-height: 1.5;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n ul[axes] li[blocked] em {\n color: var(--md-sys-color-tertiary);\n }\n span[reading] {\n font-family: var(--ui-mono, ui-monospace, monospace);\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\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 /* ── Drawing cost ─────────────────────────────────────────────── */\n dl[metrics] {\n margin: 0;\n display: grid;\n grid-template-columns: 1fr auto;\n gap: 4px 8px;\n font-size: var(--ui-t-small, 11.5px);\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(--ui-mono, ui-monospace, monospace);\n }\n\n /* ── Trend ──────────────────────────────────────────────────────\n The chart's natural size is 680px; in a 300px side its words are 4px. The side holds a button, the chart\n opens at its own size. */\n button[expand] {\n justify-self: start;\n padding: 4px 10px;\n font: inherit;\n font-size: var(--ui-t-small, 11.5px);\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 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: 12px;\n background-color: color-mix(in srgb, var(--md-sys-color-scrim, black) 32%, transparent);\n }\n div[sheet] > figure {\n max-width: 100%;\n max-height: 100%;\n margin: 0;\n padding: 12px;\n overflow: auto;\n color: var(--md-sys-color-on-surface);\n background-color: var(--md-sys-color-surface-container-lowest);\n border-radius: 6px;\n box-shadow: 0 8px 32px color-mix(in srgb, var(--md-sys-color-shadow, black) 28%, transparent);\n }\n div[sheet] svg {\n display: block;\n /* Not shrunk below its natural size — a narrow window scrolls instead. */\n min-width: 680px;\n font-family: inherit;\n font-size: var(--ui-t-micro, 11px);\n fill: currentColor;\n }\n div[sheet] svg [grid] {\n stroke: currentColor;\n stroke-opacity: 0.12;\n }\n div[sheet] svg [muted] {\n opacity: 0.55;\n }\n div[sheet] svg path[series] {\n fill: none;\n stroke-width: 2;\n stroke-linejoin: round;\n }\n div[sheet] svg [series='triangles'] {\n stroke: var(--md-sys-color-error);\n fill: var(--md-sys-color-error);\n }\n div[sheet] svg [series='drawCalls'] {\n stroke: var(--md-sys-color-tertiary);\n fill: var(--md-sys-color-tertiary);\n }\n div[sheet] svg [series='geometries'] {\n stroke: var(--md-sys-color-primary);\n fill: var(--md-sys-color-primary);\n }\n div[sheet] svg [series='materials'] {\n stroke: var(--md-sys-color-secondary);\n fill: var(--md-sys-color-secondary);\n }\n div[sheet] svg path[series],\n div[sheet] svg line[series] {\n fill: none;\n }\n /* A legend value is written in its line's colour, not outlined in it. */\n div[sheet] svg text[series] {\n stroke: none;\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: 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 /* ── Release verdict ───────────────────────────────────────────── */\n p[clear] {\n color: var(--md-sys-color-primary);\n font-weight: 600;\n }\n p[failed] {\n color: var(--md-sys-color-error);\n }\n button[fit] {\n align-self: flex-start;\n margin-top: 4px;\n padding: 4px 10px;\n font: inherit;\n color: var(--md-sys-color-on-secondary-container);\n background: var(--md-sys-color-secondary-container);\n border: none;\n border-radius: 999em;\n cursor: pointer;\n }\n `\n ]\n\n /** The figure at the version on screen. A version whose text is another is a new question. */\n @property({ attribute: false }) revision?: FigureRevision\n /* The text last judged: a save hands out the same version again as a new object, which asks nothing new. */\n private judged?: string\n /** The saved row, if any — the server reads its type and last release from it. */\n @property({ type: String }) figureId?: string\n /** Changing the type changes the verdict (a temporary type is refused), so it is a reason to ask again. */\n @property({ type: String }) figureType?: string\n\n /** The report over the source being edited. Absent when nothing is drawn, or the format refuses the source. */\n @state() private report?: FigureReport\n /** Whether the trend chart is open at its own size. */\n @state() private expanded = false\n @state() private inspection?: FigureInspection\n @state() private failure = ''\n @state() private asking = false\n\n private timer?: ReturnType<typeof setTimeout>\n /** Answers can come back out of order; only the newest question's answer is shown. */\n private answers = newestAnswer<FigureInspection>()\n\n disconnectedCallback() {\n clearTimeout(this.timer)\n clearTimeout(this.measureTimer)\n super.disconnectedCallback()\n }\n\n /** The report is measured once the figure has settled: it is read beside the work, and each measure compiles the figure several times. */\n private measureTimer?: ReturnType<typeof setTimeout>\n updated(changes: Map<string, unknown>) {\n const text = changes.has('revision') ? this.revision?.text : this.judged\n const changed = text !== this.judged\n if (changed) {\n this.judged = text\n clearTimeout(this.measureTimer)\n if (this.report === undefined && !this.measureTimer) this.measure()\n else this.measureTimer = setTimeout(() => this.measure(), MEASURE_SETTLE_MS)\n }\n if (changed || changes.has('figureId') || changes.has('figureType')) this.schedule()\n /* What blocks release, told to the page so the bar can say it beside 「발행」 (first 15 minutes, 2026-10-16). */\n if (changes.has('inspection'))\n this.dispatchEvent(new CustomEvent('release-verdict', { detail: { blocking: (this.inspection?.findings ?? []).filter(finding => finding.blocking) } }))\n }\n\n private measure() {\n const { report, told } = verdictMeasureOf(this.revision?.asset)\n this.report = report\n if (!report) this.expanded = false\n this.dispatchEvent(new CustomEvent('capacity-changed', { detail: told }))\n }\n\n private schedule() {\n clearTimeout(this.timer)\n if (!this.revision) {\n this.inspection = undefined\n return\n }\n this.timer = setTimeout(() => this.ask(), VERDICT_SETTLE_MS)\n }\n\n private async ask() {\n const source = this.revision!.text\n this.asking = true\n await this.answers(\n () => inspectFigureDraft(source, this.figureId),\n outcome => {\n this.asking = false\n if ('answer' in outcome) {\n this.inspection = outcome.answer\n this.failure = ''\n } else {\n /* The server's reason as it gave it — the screen does not make one up. The last answer is dropped with it. */\n this.inspection = undefined\n this.failure = outcome.failure instanceof Error ? outcome.failure.message : String(outcome.failure)\n }\n }\n )\n }\n\n render() {\n /*\n With nothing drawn the report is guidance, not a verdict: the sections below have meaning only over parts,\n and a number drawn from nothing reads as zero, which reads as bad. The release verdict stays — a new figure\n is already refused for its undeclared space, and the way out is offered there.\n */\n const report = this.report\n if (!report) {\n return html`\n <section>\n <h3>${i18next.t('figure.label.maturity')}</h3>\n <p quiet>${i18next.t('figure.text.report-appears-when-you-add-a-part')}</p>\n </section>\n ${this.renderGate()}\n `\n }\n return html`\n ${this.renderVerdict(report)} ${this.renderAxes(report)} ${this.renderBudgets(report)} ${this.renderMetrics(report)}\n ${this.renderCurve()} ${this.renderGate()} ${this.renderSheet(report)}\n `\n }\n\n /**\n * The head — how many fit, with the grade beside it, the budget that decided it, the scale, and the basis.\n *\n * The count's denominator is measured (2026-09-18, Apple M5) and says so with the machine and the date; the\n * triangle side is still the design document's target and says that.\n */\n private renderVerdict(report: FigureReport) {\n const { capacity, score } = report\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', { target: LIMITS.screenInstances })}\n >\n ${score.grade}\n <small>${i18next.t('figure.text.headroom-percent', { percent: 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.toLocaleString()} / ${limitOf(score.tightest)} (${Math.round(score.tightest.ratio * 100)}%)\n </p>\n <p basis>\n ${i18next.t('figure.text.grade-target', {\n target: LIMITS.screenInstances,\n groups: Math.floor(FIGURE_PER_INSTANCE.groups),\n triangles: Math.floor(FIGURE_PER_INSTANCE.triangles).toLocaleString()\n })}\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 /** A · B · C · D and where this figure stands, drawn from the bounds the grade is computed with. */\n private renderGradeScale(now: string) {\n return html`\n <p scale>\n <span>${i18next.t('figure.text.grade-scale-lead')}</span>\n ${gradeBoundsOf().map(([grade, bound]) => html`<span ?now=${grade === now}><b>${grade}</b> ${bound}</span>`)}\n </p>\n `\n }\n\n /**\n * Maturity by axis — a radar of the measured axes, a line naming the unmeasured ones, and the list.\n *\n * Scale is left out of the list: it leads the tab, and the same number twice reads as two different things.\n */\n private renderAxes(report: FigureReport) {\n const measured = report.axes.filter(axis => axis.ratio !== undefined)\n const unmeasured = report.axes.filter(axis => axis.ratio === undefined)\n return html`\n <section>\n <h3>${i18next.t('figure.label.by-axis')}</h3>\n <div radar>${this.renderRadar(measured)}</div>\n ${unmeasured.length\n ? html`<p unmeasured>\n ${i18next.t('figure.text.axes-not-measurable-yet', {\n axes: unmeasured.map(axis => i18next.t('figure.label.axis-' + axis.key)).join(' · ')\n })}\n </p>`\n : nothing}\n <ul axes>\n ${report.axes.filter(axis => axis.key !== 'scale').map(axis => this.renderAxis(axis))}\n </ul>\n </section>\n `\n }\n\n /** The radar: rings at a third, two thirds and full, short names so the left edge is not cut. */\n private renderRadar(axes: FigureMaturityAxis[]) {\n const cx = 60\n const cy = 46\n const r = 28\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 const clamp = (ratio?: number) => Math.max(0.04, Math.min(1, ratio ?? 0))\n const points = axes.map((axis, index) => at(index, clamp(axis.ratio)).map(n => n.toFixed(1)).join(',')).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, clamp(axis.ratio))\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`<text x=${x.toFixed(1)} y=${(y + 1.8).toFixed(1)} text-anchor=${anchor}>${i18next.t('figure.label.axis-' + axis.key + '-short')}</text>`\n })}\n </svg>\n `\n }\n\n private renderAxis(axis: FigureMaturityAxis) {\n const name = i18next.t('figure.label.axis-' + axis.key)\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 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>` : nothing}\n </li>\n `\n }\n\n /** The budget bars. The one closest to its limit is coloured — it decided the grade. */\n private renderBudgets(report: FigureReport) {\n const { score } = report\n return html`\n <section>\n <h3>${i18next.t('figure.label.budgets')}</h3>\n <ul budgets>\n ${score.budgets.map(\n use => html`\n <li>\n <span>${i18next.t('figure.label.budget-' + use.key)}</span>\n <span>${use.used.toLocaleString()} / ${limitOf(use)}</span>\n <div bar><i ?tight=${use.key === score.tightest.key} style=\"width:${Math.round(Math.min(1, use.ratio) * 100)}%\"></i></div>\n </li>\n `\n )}\n </ul>\n <p quiet>${i18next.t('figure.text.budgets-not-in')}</p>\n </section>\n `\n }\n\n private renderMetrics(report: FigureReport) {\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>${report.cost.triangles.toLocaleString()}</dd>\n <dt>${i18next.t('figure.label.distinct-shapes')}</dt>\n <dd>${report.distinctShapes}</dd>\n <dt>${i18next.t('figure.label.distinct-materials')}</dt>\n <dd>${report.distinctMaterials}</dd>\n </dl>\n </section>\n `\n }\n\n private renderCurve() {\n return html`\n <section>\n <h3>${i18next.t('figure.label.reuse-trend')}</h3>\n <button expand @click=${() => (this.expanded = true)}>${i18next.t('figure.button.see-the-trend-chart')}</button>\n </section>\n `\n }\n\n /**\n * The trend at its own size: both axes logarithmic, the growing lines against the flat ones, and a\n * legend with each line's value at the last count.\n */\n private renderSheet(report: FigureReport) {\n if (!this.expanded) return nothing\n const layout = curveLayout(report.curve)\n if (!layout) return nothing\n const { width, height, pad } = CURVE_SIZE\n const plotW = width - pad.left - pad.right\n const plotH = height - pad.top - pad.bottom\n const last = report.curve[report.curve.length - 1]!\n const label = (key: string) =>\n i18next.t(\n {\n triangles: 'figure.label.triangles',\n drawCalls: 'figure.label.draw-calls',\n geometries: 'figure.label.vertex-buffers',\n materials: 'figure.label.distinct-materials'\n }[key]!\n )\n\n return html`\n <div sheet @click=${() => (this.expanded = false)}>\n <figure @click=${(e: Event) => e.stopPropagation()}>\n ${svg`\n <svg viewBox=\"0 0 ${width} ${height}\" width=${width} height=${height} role=\"img\">\n <text x=${pad.left} y=\"22\" font-size=\"13\" font-weight=\"600\">${i18next.t('figure.text.trend-chart-title')}</text>\n <text x=${pad.left} y=\"38\" muted>${i18next.t('figure.text.trend-chart-lead')}</text>\n ${layout.yTicks.map(\n tick => svg`\n <line grid x1=${pad.left} y1=${tick.y.toFixed(1)} x2=${(pad.left + plotW).toFixed(1)} y2=${tick.y.toFixed(1)}></line>\n <text muted x=${pad.left - 8} y=${(tick.y + 3.5).toFixed(1)} text-anchor=\"end\">${tick.label}</text>\n `\n )}\n ${layout.xTicks.map(\n tick => svg`\n <line grid x1=${tick.x.toFixed(1)} y1=${pad.top} x2=${tick.x.toFixed(1)} y2=${(pad.top + plotH).toFixed(1)}></line>\n <text muted x=${tick.x.toFixed(1)} y=${(pad.top + plotH + 16).toFixed(1)} text-anchor=\"middle\">${tick.label}</text>\n `\n )}\n <text muted x=${(pad.left + plotW / 2).toFixed(1)} y=${height - 8} text-anchor=\"middle\">${i18next.t('figure.label.instance-count')}</text>\n ${layout.lines.map(\n line => svg`<path series=${line.key} d=${line.d} stroke-dasharray=${line.dashed ? '3 7' : 'none'}></path>`\n )}\n <g transform=\"translate(${width - pad.right + 14}, ${pad.top - 6})\">\n <text x=\"0\" y=\"0\" font-weight=\"600\">${i18next.t('figure.text.trend-at-count', { n: shortNumber(last.instances) })}</text>\n ${layout.lines.map((line, i) => {\n const y = 24 + i * 34\n return svg`\n <line series=${line.key} x1=\"0\" y1=${y - 4} x2=\"18\" y2=${y - 4} stroke-width=\"2\" stroke-dasharray=${line.dashed ? '3 7' : 'none'}></line>\n <text x=\"24\" y=${y}>${label(line.key)}</text>\n <text series=${line.key} x=\"24\" y=${y + 12} font-weight=\"600\">\n ${line.last.toLocaleString()}${line.flat ? ` · ${i18next.t('figure.text.trend-stays')}` : ''}\n </text>\n `\n })}\n ${layout.overlap !== undefined\n ? svg`<text muted x=\"0\" y=${24 + layout.lines.length * 34 + 6}>${i18next.t('figure.text.trend-flat-lines-overlap', { value: layout.overlap.toLocaleString() })}</text>`\n : nothing}\n </g>\n </svg>\n `}\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 private renderGate() {\n const findings = this.inspection?.findings ?? []\n const blocking = findings.filter(finding => finding.blocking)\n const advisory = findings.filter(finding => !finding.blocking)\n return html`\n <section>\n <h3>${i18next.t('figure.label.release-verdict')}</h3>\n ${this.failure\n ? html`<p failed role=\"alert\">${i18next.t('figure.text.verdict-not-received', { reason: this.failure })}</p>`\n : !this.inspection\n ? html`<p quiet>${i18next.t(this.asking ? 'figure.text.verdict-asking' : 'figure.text.verdict-waiting')}</p>`\n : blocking.length\n ? html`<p>${i18next.t('figure.text.cannot-release-now')}</p>`\n : this.revision && !this.revision.asset.appearance.length\n ? /* No part: nothing to judge, not 「nothing blocks」 (sweep 2026-10-27 U24). */\n html`<p quiet>${i18next.t('figure.text.release-needs-a-part')}</p>`\n : html`<p clear>${i18next.t('figure.text.nothing-blocks-release')}</p>`}\n ${blocking.length\n ? html`<ul gate>\n <li head>${i18next.t('figure.text.must-fix-to-release')}</li>\n ${blocking.map(finding => renderGateFinding(finding, true, nothing, this.partNames()))}\n </ul>`\n : nothing}\n ${advisory.length\n ? html`<ul gate>\n <li head quiet>${i18next.t('figure.text.does-not-block')}</li>\n ${advisory.map(finding => renderGateFinding(finding, false, nothing, this.partNames()))}\n </ul>`\n : nothing}\n </section>\n `\n }\n\n private partNames(): string[] {\n return (this.revision?.asset.appearance ?? []).map(look => look.target)\n }\n}\n"]}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * A unit as the screen names it: the graph's codes (deg, percent, count …) are not words a person reads, and a unit
3
+ * typed by the author (rpm) stays as typed (sweep 2026-10-27 U9).
4
+ */
5
+ export declare function unitWord(unit: string | undefined): string;
@@ -0,0 +1,12 @@
1
+ import { i18next } from '@operato/i18n';
2
+ /**
3
+ * A unit as the screen names it: the graph's codes (deg, percent, count …) are not words a person reads, and a unit
4
+ * typed by the author (rpm) stays as typed (sweep 2026-10-27 U9).
5
+ */
6
+ export function unitWord(unit) {
7
+ if (!unit)
8
+ return '';
9
+ const key = `figure.label.unit-${unit}`;
10
+ return i18next.exists(key) ? i18next.t(key) : unit;
11
+ }
12
+ //# sourceMappingURL=unit-words.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unit-words.js","sourceRoot":"","sources":["../../client/modeller/unit-words.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAEvC;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAwB;IAC/C,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAA;IACpB,MAAM,GAAG,GAAG,qBAAqB,IAAI,EAAE,CAAA;IACvC,OAAO,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AACpD,CAAC","sourcesContent":["import { i18next } from '@operato/i18n'\n\n/**\n * A unit as the screen names it: the graph's codes (deg, percent, count …) are not words a person reads, and a unit\n * typed by the author (rpm) stays as typed (sweep 2026-10-27 U9).\n */\nexport function unitWord(unit: string | undefined): string {\n if (!unit) return ''\n const key = `figure.label.unit-${unit}`\n return i18next.exists(key) ? i18next.t(key) : unit\n}\n"]}
@@ -13,7 +13,7 @@ declare const FigureListPageBase: (new (...args: any[]) => {
13
13
  /**
14
14
  * Figure 카탈로그.
15
15
  *
16
- * 카드를 고르면 상세 패널에서 저장본과 발행판을 살펴본다. 크기와 움직임을 시험한 뒤
16
+ * 카드를 고르면 상세 패널에서 저장본과 발행 버전을 살펴본다. 크기와 움직임을 시험한 뒤
17
17
  * 「편집 화면 열기」로 저작면에 들어간다. 목록 질의는 자산 원본을 싣지 않는다.
18
18
  *
19
19
  * ## 왜 손으로 만든 카드가 아니라 격자인가
@@ -56,7 +56,7 @@ const FigureListPageBase = p13n(localize(i18next)(PageView));
56
56
  /**
57
57
  * Figure 카탈로그.
58
58
  *
59
- * 카드를 고르면 상세 패널에서 저장본과 발행판을 살펴본다. 크기와 움직임을 시험한 뒤
59
+ * 카드를 고르면 상세 패널에서 저장본과 발행 버전을 살펴본다. 크기와 움직임을 시험한 뒤
60
60
  * 「편집 화면 열기」로 저작면에 들어간다. 목록 질의는 자산 원본을 싣지 않는다.
61
61
  *
62
62
  * ## 왜 손으로 만든 카드가 아니라 격자인가
@@ -284,7 +284,7 @@ let FigureListPage = class FigureListPage extends FigureListPageBase {
284
284
  editable: false,
285
285
  /*
286
286
  **발행된 것에는 아무 말도 하지 않는다.** 카탈로그에 있는 것은 대개 발행된 것이라,
287
- 카드마다 「발행됨」이 붙으면 그 말이 아무것도 가르지 않고 자리만 먹는다. 판 번호도
287
+ 카드마다 「발행됨」이 붙으면 그 말이 아무것도 가르지 않고 자리만 먹는다. 버전 번호도
288
288
  고를 때 쓰는 값이 아니다 — 이력 탭에 있다.
289
289
 
290
290
  표 모드에서는 칸에 값이 있어야 하므로 그때는 발행됨도 적는다(`wide` 가 아니라 label