@things-factory/figure-ui 10.1.147 → 10.1.150

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 (210) hide show
  1. package/client/bootstrap.ts +10 -2
  2. package/client/graphql/index.ts +20 -0
  3. package/client/modeller/canvas.ts +6 -2
  4. package/client/modeller/carrier-declaration.ts +63 -0
  5. package/client/modeller/editor.ts +62 -27
  6. package/client/modeller/figure-carrier.ts +117 -0
  7. package/client/modeller/figure-cavity-drawing.ts +3 -9
  8. package/client/modeller/figure-first-save.ts +4 -7
  9. package/client/modeller/figure-history-panel.ts +2 -3
  10. package/client/modeller/figure-links.ts +46 -60
  11. package/client/modeller/figure-material-panel.ts +4 -14
  12. package/client/modeller/figure-mesh-choice.ts +68 -0
  13. package/client/modeller/figure-parts.ts +23 -1
  14. package/client/modeller/figure-preview.ts +2 -2
  15. package/client/modeller/figure-properties.ts +5 -3
  16. package/client/modeller/figure-section-editor.ts +12 -33
  17. package/client/modeller/figure-section-panel.ts +6 -7
  18. package/client/modeller/figure-slot-layout-panel.ts +208 -0
  19. package/client/modeller/figure-verdict.ts +21 -31
  20. package/client/modeller/first-save.ts +23 -0
  21. package/client/modeller/links.ts +52 -1
  22. package/client/modeller/material-edit.ts +38 -0
  23. package/client/modeller/maturity.ts +28 -0
  24. package/client/modeller/mesh-import.ts +77 -0
  25. package/client/modeller/modeller-route.ts +9 -0
  26. package/client/modeller/mounting-part.ts +15 -0
  27. package/client/modeller/newest-answer.ts +21 -0
  28. package/client/modeller/preview-model.ts +5 -0
  29. package/client/modeller/refusals.ts +168 -82
  30. package/client/modeller/section-controls.ts +25 -1
  31. package/client/modeller/section-drawing.ts +43 -1
  32. package/client/modeller/slot-layout-host.ts +140 -0
  33. package/client/pages/figure-modeller-page.ts +6 -5
  34. package/client/viewparts/detail-route.ts +7 -0
  35. package/client/viewparts/figure-detail-dock.ts +1 -3
  36. package/dist-client/bootstrap.d.ts +1 -1
  37. package/dist-client/bootstrap.js +9 -2
  38. package/dist-client/bootstrap.js.map +1 -1
  39. package/dist-client/graphql/index.d.ts +5 -0
  40. package/dist-client/graphql/index.js +19 -0
  41. package/dist-client/graphql/index.js.map +1 -1
  42. package/dist-client/modeller/canvas.d.ts +2 -0
  43. package/dist-client/modeller/canvas.js +10 -2
  44. package/dist-client/modeller/canvas.js.map +1 -1
  45. package/dist-client/modeller/carrier-declaration.d.ts +31 -0
  46. package/dist-client/modeller/carrier-declaration.js +53 -0
  47. package/dist-client/modeller/carrier-declaration.js.map +1 -0
  48. package/dist-client/modeller/editor.d.ts +13 -0
  49. package/dist-client/modeller/editor.js +62 -27
  50. package/dist-client/modeller/editor.js.map +1 -1
  51. package/dist-client/modeller/figure-carrier.d.ts +26 -0
  52. package/dist-client/modeller/figure-carrier.js +123 -0
  53. package/dist-client/modeller/figure-carrier.js.map +1 -0
  54. package/dist-client/modeller/figure-cavity-drawing.js +3 -11
  55. package/dist-client/modeller/figure-cavity-drawing.js.map +1 -1
  56. package/dist-client/modeller/figure-first-save.d.ts +4 -0
  57. package/dist-client/modeller/figure-first-save.js +5 -8
  58. package/dist-client/modeller/figure-first-save.js.map +1 -1
  59. package/dist-client/modeller/figure-history-panel.js +2 -4
  60. package/dist-client/modeller/figure-history-panel.js.map +1 -1
  61. package/dist-client/modeller/figure-links.d.ts +4 -1
  62. package/dist-client/modeller/figure-links.js +47 -57
  63. package/dist-client/modeller/figure-links.js.map +1 -1
  64. package/dist-client/modeller/figure-material-panel.d.ts +0 -1
  65. package/dist-client/modeller/figure-material-panel.js +4 -14
  66. package/dist-client/modeller/figure-material-panel.js.map +1 -1
  67. package/dist-client/modeller/figure-mesh-choice.d.ts +16 -0
  68. package/dist-client/modeller/figure-mesh-choice.js +75 -0
  69. package/dist-client/modeller/figure-mesh-choice.js.map +1 -0
  70. package/dist-client/modeller/figure-parts.d.ts +1 -1
  71. package/dist-client/modeller/figure-parts.js +22 -0
  72. package/dist-client/modeller/figure-parts.js.map +1 -1
  73. package/dist-client/modeller/figure-preview.js +2 -2
  74. package/dist-client/modeller/figure-preview.js.map +1 -1
  75. package/dist-client/modeller/figure-properties.d.ts +2 -1
  76. package/dist-client/modeller/figure-properties.js +5 -3
  77. package/dist-client/modeller/figure-properties.js.map +1 -1
  78. package/dist-client/modeller/figure-section-editor.d.ts +2 -2
  79. package/dist-client/modeller/figure-section-editor.js +12 -33
  80. package/dist-client/modeller/figure-section-editor.js.map +1 -1
  81. package/dist-client/modeller/figure-section-panel.js +6 -7
  82. package/dist-client/modeller/figure-section-panel.js.map +1 -1
  83. package/dist-client/modeller/figure-slot-layout-panel.d.ts +36 -0
  84. package/dist-client/modeller/figure-slot-layout-panel.js +198 -0
  85. package/dist-client/modeller/figure-slot-layout-panel.js.map +1 -0
  86. package/dist-client/modeller/figure-verdict.d.ts +1 -1
  87. package/dist-client/modeller/figure-verdict.js +19 -37
  88. package/dist-client/modeller/figure-verdict.js.map +1 -1
  89. package/dist-client/modeller/first-save.d.ts +10 -0
  90. package/dist-client/modeller/first-save.js +16 -0
  91. package/dist-client/modeller/first-save.js.map +1 -1
  92. package/dist-client/modeller/links.d.ts +26 -1
  93. package/dist-client/modeller/links.js +43 -0
  94. package/dist-client/modeller/links.js.map +1 -1
  95. package/dist-client/modeller/material-edit.d.ts +11 -0
  96. package/dist-client/modeller/material-edit.js +28 -0
  97. package/dist-client/modeller/material-edit.js.map +1 -0
  98. package/dist-client/modeller/maturity.d.ts +15 -0
  99. package/dist-client/modeller/maturity.js +23 -0
  100. package/dist-client/modeller/maturity.js.map +1 -1
  101. package/dist-client/modeller/mesh-import.d.ts +47 -0
  102. package/dist-client/modeller/mesh-import.js +47 -0
  103. package/dist-client/modeller/mesh-import.js.map +1 -0
  104. package/dist-client/modeller/modeller-route.d.ts +5 -0
  105. package/dist-client/modeller/modeller-route.js +9 -0
  106. package/dist-client/modeller/modeller-route.js.map +1 -1
  107. package/dist-client/modeller/mounting-part.d.ts +14 -0
  108. package/dist-client/modeller/mounting-part.js +10 -0
  109. package/dist-client/modeller/mounting-part.js.map +1 -0
  110. package/dist-client/modeller/newest-answer.d.ts +12 -0
  111. package/dist-client/modeller/newest-answer.js +21 -0
  112. package/dist-client/modeller/newest-answer.js.map +1 -0
  113. package/dist-client/modeller/preview-model.d.ts +2 -0
  114. package/dist-client/modeller/preview-model.js +4 -0
  115. package/dist-client/modeller/preview-model.js.map +1 -1
  116. package/dist-client/modeller/refusals.d.ts +26 -5
  117. package/dist-client/modeller/refusals.js +184 -86
  118. package/dist-client/modeller/refusals.js.map +1 -1
  119. package/dist-client/modeller/section-controls.d.ts +17 -1
  120. package/dist-client/modeller/section-controls.js +18 -0
  121. package/dist-client/modeller/section-controls.js.map +1 -1
  122. package/dist-client/modeller/section-drawing.d.ts +24 -1
  123. package/dist-client/modeller/section-drawing.js +42 -0
  124. package/dist-client/modeller/section-drawing.js.map +1 -1
  125. package/dist-client/modeller/slot-layout-host.d.ts +81 -0
  126. package/dist-client/modeller/slot-layout-host.js +105 -0
  127. package/dist-client/modeller/slot-layout-host.js.map +1 -0
  128. package/dist-client/pages/figure-modeller-page.js +5 -4
  129. package/dist-client/pages/figure-modeller-page.js.map +1 -1
  130. package/dist-client/tsconfig.tsbuildinfo +1 -1
  131. package/dist-client/viewparts/detail-route.d.ts +5 -0
  132. package/dist-client/viewparts/detail-route.js +8 -0
  133. package/dist-client/viewparts/detail-route.js.map +1 -0
  134. package/dist-client/viewparts/figure-detail-dock.d.ts +0 -1
  135. package/dist-client/viewparts/figure-detail-dock.js +1 -3
  136. package/dist-client/viewparts/figure-detail-dock.js.map +1 -1
  137. package/package.json +9 -8
  138. package/test/align.test.ts +0 -9
  139. package/test/browser/assistant-stand-in.js +32 -0
  140. package/test/browser/build.check.mjs +77 -0
  141. package/test/browser/build.mjs +31 -6
  142. package/test/browser/editing-page.js +224 -0
  143. package/test/browser/editing.check.mjs +550 -0
  144. package/test/browser/links-page.js +113 -0
  145. package/test/browser/links.check.mjs +568 -0
  146. package/test/browser/modeller.check.mjs +21 -0
  147. package/test/browser/parts-page.js +120 -0
  148. package/test/browser/parts.check.mjs +328 -0
  149. package/test/browser/places-mesh-page.js +36 -0
  150. package/test/browser/places-mesh.check.mjs +239 -0
  151. package/test/browser/product-page.check.mjs +682 -0
  152. package/test/browser/product-page.js +276 -0
  153. package/test/browser/screen-page.js +112 -0
  154. package/test/browser/screen-product-page.js +62 -0
  155. package/test/browser/screen.check.mjs +1003 -0
  156. package/test/browser/section-page.js +256 -0
  157. package/test/browser/section.check.mjs +719 -0
  158. package/test/browser/serve.mjs +20 -12
  159. package/test/carrier-declaration.test.ts +69 -0
  160. package/test/cavity-drawing.test.ts +2 -18
  161. package/test/clip-ai-proposal.test.ts +1 -5
  162. package/test/clip-consent.test.ts +0 -5
  163. package/test/clips.test.ts +0 -7
  164. package/test/command-preview.test.ts +0 -68
  165. package/test/controls.test.ts +0 -9
  166. package/test/detail-dock.test.ts +6 -25
  167. package/test/face-mapping.test.ts +1 -20
  168. package/test/fasten-drawing.test.ts +0 -23
  169. package/test/fields.test.ts +6 -33
  170. package/test/figure-assistant-surface.test.ts +32 -38
  171. package/test/first-minute.test.ts +3 -55
  172. package/test/first-save-suggest.test.ts +11 -8
  173. package/test/first-save.test.ts +4 -26
  174. package/test/gizmo.test.ts +0 -25
  175. package/test/joint-fan.test.ts +0 -10
  176. package/test/keys.test.ts +0 -7
  177. package/test/layout.test.ts +4 -73
  178. package/test/links.test.ts +48 -67
  179. package/test/live.test.ts +0 -34
  180. package/test/material.test.ts +17 -26
  181. package/test/maturity.test.ts +13 -16
  182. package/test/mesh-import.test.ts +76 -0
  183. package/test/modeller-route.test.ts +3 -19
  184. package/test/package-download.test.ts +6 -7
  185. package/test/parts-wiring.test.ts +9 -51
  186. package/test/preview.test.ts +5 -46
  187. package/test/properties.test.ts +11 -26
  188. package/test/proposal-record.test.ts +2 -19
  189. package/test/recipes.test.ts +0 -15
  190. package/test/refusals.test.ts +257 -151
  191. package/test/release-entry.test.ts +1 -9
  192. package/test/release-panel.test.ts +1 -22
  193. package/test/resize-with-placement.test.ts +0 -32
  194. package/test/revert-choice.test.ts +1 -22
  195. package/test/revert-keeping.test.ts +1 -12
  196. package/test/save-landed.test.ts +16 -14
  197. package/test/scene-canvas.test.ts +2 -13
  198. package/test/section-editor.test.ts +30 -83
  199. package/test/section-panel.test.ts +22 -17
  200. package/test/slot-layout-host.test.ts +117 -0
  201. package/test/theme.test.ts +5 -9
  202. package/test/verdict.test.ts +44 -41
  203. package/test/view.test.ts +5 -12
  204. package/translations/en.json +61 -1
  205. package/translations/es.json +61 -1
  206. package/translations/ja.json +61 -1
  207. package/translations/ko.json +61 -1
  208. package/translations/ms.json +61 -1
  209. package/translations/zh.json +61 -1
  210. package/test/thumbnail.test.ts +0 -29
@@ -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, figureCostOf } 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 './side-panel-styles.js'\nimport { budgetOf, CURVE_SIZE, curveLayout, GRADE_SCALE, shortNumber, figureReportOf } from './maturity.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: 0.74rem;\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: 2.1rem;\n font-weight: 800;\n line-height: 1;\n letter-spacing: -0.01em;\n color: var(--md-sys-color-primary);\n }\n span[unit] {\n font-size: 0.9rem;\n font-weight: 600;\n color: var(--md-sys-color-primary);\n }\n /* 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: 0.76rem;\n font-weight: 700;\n color: var(--md-sys-color-on-primary-container);\n background-color: var(--md-sys-color-primary-container);\n border-radius: 999em;\n }\n span[grade] small {\n display: inline;\n margin: 0;\n font-size: 0.68rem;\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: 0.78rem;\n line-height: 1.6;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n p[because] strong {\n color: var(--md-sys-color-on-surface);\n }\n /* 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: 0.7rem;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n p[scale] b {\n font-weight: 700;\n }\n p[scale] span[now] {\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 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: 0.7rem;\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: 0.75rem;\n }\n ul[axes] li[blocked] {\n opacity: 0.7;\n }\n ul[axes] em {\n grid-column: 1 / -1;\n font-style: normal;\n font-size: 0.68rem;\n line-height: 1.5;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n ul[axes] li[blocked] em {\n color: var(--md-sys-color-tertiary);\n }\n span[reading] {\n font-family: var(--mono-font, monospace);\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n 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: 0.78rem;\n }\n dl[metrics] dt {\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n dl[metrics] dd {\n margin: 0;\n text-align: right;\n font-family: var(--mono-font, monospace);\n }\n\n /* ── 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: 0.74rem;\n color: var(--md-sys-color-on-surface);\n background: none;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 6px;\n cursor: pointer;\n }\n button[expand]:hover {\n background-color: var(--md-sys-color-surface-container);\n }\n 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: 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 /** Bodies in the asset, drawn or hidden. With none there is nothing to fit the space to, so the button is not offered. */\n @state() private bodies = 0\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 asked = 0\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 }\n\n private measure() {\n let report: FigureReport | undefined\n let bodies = 0\n try {\n const asset = this.revision?.asset\n const cost = asset ? figureCostOf(asset) : undefined\n bodies = cost ? cost.groups + cost.hidden : 0\n report = asset ? figureReportOf(asset) : undefined\n } catch {\n /* A source the format refuses has no report; the server's finding below says why. */\n report = undefined\n }\n this.report = report\n this.bodies = bodies\n if (!report) this.expanded = false\n this.dispatchEvent(new CustomEvent('capacity-changed', { detail: { instances: report?.capacity.instances, budget: budgetOf(report) } }))\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 question = ++this.asked\n const source = this.revision!.text\n this.asking = true\n try {\n const inspection = await inspectFigureDraft(source, this.figureId)\n if (question !== this.asked) return\n this.inspection = inspection\n this.failure = ''\n } catch (error) {\n if (question !== this.asked) return\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 = error instanceof Error ? error.message : String(error)\n } finally {\n if (question === this.asked) this.asking = false\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 const bounds = [...GRADE_SCALE.map(([grade, bound]) => [grade, `≤ ${bound * 100}%`]), ['D', '> 100%']]\n return html`\n <p scale>\n <span>${i18next.t('figure.text.grade-scale-lead')}</span>\n ${bounds.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, this.actionsFor(finding.code)))}\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))}\n </ul>`\n : nothing}\n </section>\n `\n }\n\n /** The same way out the release panel offers for the same two findings — declare the space from the parts. */\n private actionsFor(code: string) {\n if (code !== 'part-outside-occupancy' && code !== 'occupancy-undeclared') return nothing\n /* A new figure with no parts is refused as undeclared too, but fitting needs parts to measure (seen 2026-09-24). */\n if (!this.bodies) return nothing\n return html`<button fit @click=${this.fit}>${i18next.t('figure.button.fit-base-to-parts')}</button>`\n }\n\n private fit = () => {\n this.dispatchEvent(new CustomEvent('fit-base-to-parts', { bubbles: true, composed: true }))\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 './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: 0.74rem;\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: 2.1rem;\n font-weight: 800;\n line-height: 1;\n letter-spacing: -0.01em;\n color: var(--md-sys-color-primary);\n }\n span[unit] {\n font-size: 0.9rem;\n font-weight: 600;\n color: var(--md-sys-color-primary);\n }\n /* 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: 0.76rem;\n font-weight: 700;\n color: var(--md-sys-color-on-primary-container);\n background-color: var(--md-sys-color-primary-container);\n border-radius: 999em;\n }\n span[grade] small {\n display: inline;\n margin: 0;\n font-size: 0.68rem;\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: 0.78rem;\n line-height: 1.6;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n p[because] strong {\n color: var(--md-sys-color-on-surface);\n }\n /* 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: 0.7rem;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n p[scale] b {\n font-weight: 700;\n }\n p[scale] span[now] {\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 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: 0.7rem;\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: 0.75rem;\n }\n ul[axes] li[blocked] {\n opacity: 0.7;\n }\n ul[axes] em {\n grid-column: 1 / -1;\n font-style: normal;\n font-size: 0.68rem;\n line-height: 1.5;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n ul[axes] li[blocked] em {\n color: var(--md-sys-color-tertiary);\n }\n span[reading] {\n font-family: var(--mono-font, monospace);\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n 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: 0.78rem;\n }\n dl[metrics] dt {\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n dl[metrics] dd {\n margin: 0;\n text-align: right;\n font-family: var(--mono-font, monospace);\n }\n\n /* ── 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: 0.74rem;\n color: var(--md-sys-color-on-surface);\n background: none;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 6px;\n cursor: pointer;\n }\n button[expand]:hover {\n background-color: var(--md-sys-color-surface-container);\n }\n 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: 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 /** Bodies in the asset, drawn or hidden. With none there is nothing to fit the space to, so the button is not offered. */\n @state() private bodies = 0\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 }\n\n private measure() {\n const { report, bodies, told } = verdictMeasureOf(this.revision?.asset)\n this.report = report\n this.bodies = bodies\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, this.actionsFor(finding.code)))}\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))}\n </ul>`\n : nothing}\n </section>\n `\n }\n\n /** The same way out the release panel offers for the same two findings — declare the space from the parts. */\n private actionsFor(code: string) {\n if (code !== 'part-outside-occupancy' && code !== 'occupancy-undeclared') return nothing\n /* A new figure with no parts is refused as undeclared too, but fitting needs parts to measure (seen 2026-09-24). */\n if (!this.bodies) return nothing\n return html`<button fit @click=${this.fit}>${i18next.t('figure.button.fit-base-to-parts')}</button>`\n }\n\n private fit = () => {\n this.dispatchEvent(new CustomEvent('fit-base-to-parts', { bubbles: true, composed: true }))\n }\n}\n"]}
@@ -12,6 +12,16 @@ export declare function releasableType(type: string): boolean;
12
12
  * shape (`figure-` and eight), which the release gate refuses; never one this domain already uses.
13
13
  */
14
14
  export declare function suggestTypeOf(name: string, taken: readonly string[], random?: () => number): string;
15
+ /**
16
+ * The identifier the first save's question shows, given the one it opens on (Q-D3). The identifier is not the name:
17
+ * renaming does not change it, and a retried first save opens on the one answered before. A new one is offered only when
18
+ * there is none, or when an offered one is found taken -- told by the server, or in the list; one the author typed is
19
+ * kept as typed, and its refusal said. `suggested` is the identifier now on offer, absent when that is unchanged.
20
+ */
21
+ export declare function offeredTypeOf(type: string, name: string, taken: readonly string[], random?: () => number): {
22
+ type: string;
23
+ suggested?: string;
24
+ };
15
25
  /** Why the first save cannot go on with this type, as an i18n key, or null when it can. */
16
26
  export declare function firstSaveRefusalOf(type: string, taken: readonly string[]): {
17
27
  key: string;
@@ -32,6 +32,22 @@ export function suggestTypeOf(name, taken, random = Math.random) {
32
32
  return made;
33
33
  }
34
34
  }
35
+ /** The shape of an identifier the modeller offers (`suggestTypeOf`'s random form). */
36
+ const OFFERED = /^fig-[0-9a-z]{6}$/;
37
+ /**
38
+ * The identifier the first save's question shows, given the one it opens on (Q-D3). The identifier is not the name:
39
+ * renaming does not change it, and a retried first save opens on the one answered before. A new one is offered only when
40
+ * there is none, or when an offered one is found taken -- told by the server, or in the list; one the author typed is
41
+ * kept as typed, and its refusal said. `suggested` is the identifier now on offer, absent when that is unchanged.
42
+ */
43
+ export function offeredTypeOf(type, name, taken, random = Math.random) {
44
+ const offeredAndTaken = OFFERED.test(type) && taken.includes(type);
45
+ if (!type || offeredAndTaken) {
46
+ const made = suggestTypeOf(name, taken, random);
47
+ return { type: made, suggested: made };
48
+ }
49
+ return OFFERED.test(type) ? { type, suggested: type } : { type };
50
+ }
35
51
  /** Why the first save cannot go on with this type, as an i18n key, or null when it can. */
36
52
  export function firstSaveRefusalOf(type, taken) {
37
53
  if (!type)
@@ -1 +1 @@
1
- {"version":3,"file":"first-save.js","sourceRoot":"","sources":["../../client/modeller/first-save.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAErF;;;;GAIG;AAEH,+GAA+G;AAC/G,MAAM,UAAU,MAAM,CAAC,GAAW;IAChC,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA;AACrF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,IAAI,WAAW,CAAC,GAAG,IAAI,IAAI,CAAC,MAAM,IAAI,WAAW,CAAC,GAAG,CAAA;AAChI,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,KAAwB,EAAE,SAAuB,IAAI,CAAC,MAAM;IACtG,MAAM,QAAQ,GAAG,2BAA2B,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IAClF,IAAI,QAAQ,IAAI,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAA;IACtF,MAAM,QAAQ,GAAG,sCAAsC,CAAA;IACvD,SAAS,CAAC;QACR,MAAM,IAAI,GAAG,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAA;QAChH,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAA;IAChE,CAAC;AACH,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,KAAwB;IACvE,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,GAAG,EAAE,+BAA+B,EAAE,CAAA;IAC1D,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,GAAG,EAAE,qCAAqC,EAAE,IAAI,EAAE,CAAA;IACrF,OAAO,IAAI,CAAA;AACb,CAAC","sourcesContent":["import { isPlaceholderType, TYPE_LENGTH, TYPE_PATTERN } from '@hatiolab/figure-model'\n\n/*\n * The first save of a new figure asks for its type and name. The type is the name a board places\n * the figure by; it freezes when the figure is released (ADR-0063 decision 4). The modeller once saved a new figure\n * under a temporary machine name and asked nothing -- the author had to find the field afterwards (user, 2026-09-25).\n */\n\n/** A type as typed, made into the shape a type has: lower-case letters and digits joined by single hyphens. */\nexport function typeOf(raw: string): string {\n return raw.trim().toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '')\n}\n\n/**\n * Whether this name could be released, by the format's own rules (`type-not-identifier`, `type-is-placeholder`).\n * Saving under it is not blocked -- it can still change before release -- but the author hears it now.\n */\nexport function releasableType(type: string): boolean {\n return !isPlaceholderType(type) && TYPE_PATTERN.test(type) && type.length >= TYPE_LENGTH.min && type.length <= TYPE_LENGTH.max\n}\n\n/**\n * An identifier offered for a new figure, so the first save asks for a name and has a valid identifier ready (designer\n * 2026-09-27, Q-D3). A name in plain letters is used as it is when it makes a free, releasable identifier; any other\n * name -- Korean, say -- gets a valid prefix and a random part: no transliteration is guessed. Never the temporary\n * shape (`figure-` and eight), which the release gate refuses; never one this domain already uses.\n */\nexport function suggestTypeOf(name: string, taken: readonly string[], random: () => number = Math.random): string {\n const fromName = /^[A-Za-z][A-Za-z0-9 _-]*$/.test(name.trim()) ? typeOf(name) : ''\n if (fromName && releasableType(fromName) && !taken.includes(fromName)) return fromName\n const alphabet = '0123456789abcdefghijklmnopqrstuvwxyz'\n for (;;) {\n const made = `fig-${Array.from({ length: 6 }, () => alphabet[Math.floor(random() * alphabet.length)]).join('')}`\n if (releasableType(made) && !taken.includes(made)) return made\n }\n}\n\n/** Why the first save cannot go on with this type, as an i18n key, or null when it can. */\nexport function firstSaveRefusalOf(type: string, taken: readonly string[]): { key: string; type?: string } | null {\n if (!type) return { key: 'figure.text.enter-a-type-name' }\n if (taken.includes(type)) return { key: 'figure.text.type-name-already-taken', type }\n return null\n}\n\n/** What the first save asks for. */\nexport interface FirstSave {\n type: string\n name: string\n}\n"]}
1
+ {"version":3,"file":"first-save.js","sourceRoot":"","sources":["../../client/modeller/first-save.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAErF;;;;GAIG;AAEH,+GAA+G;AAC/G,MAAM,UAAU,MAAM,CAAC,GAAW;IAChC,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAA;AACrF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM,IAAI,WAAW,CAAC,GAAG,IAAI,IAAI,CAAC,MAAM,IAAI,WAAW,CAAC,GAAG,CAAA;AAChI,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,KAAwB,EAAE,SAAuB,IAAI,CAAC,MAAM;IACtG,MAAM,QAAQ,GAAG,2BAA2B,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IAClF,IAAI,QAAQ,IAAI,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAA;IACtF,MAAM,QAAQ,GAAG,sCAAsC,CAAA;IACvD,SAAS,CAAC;QACR,MAAM,IAAI,GAAG,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAA;QAChH,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAA;IAChE,CAAC;AACH,CAAC;AAED,sFAAsF;AACtF,MAAM,OAAO,GAAG,mBAAmB,CAAA;AAEnC;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAY,EACZ,IAAY,EACZ,KAAwB,EACxB,SAAuB,IAAI,CAAC,MAAM;IAElC,MAAM,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;IAClE,IAAI,CAAC,IAAI,IAAI,eAAe,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,aAAa,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAA;QAC/C,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAA;IACxC,CAAC;IACD,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAA;AAClE,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,kBAAkB,CAAC,IAAY,EAAE,KAAwB;IACvE,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,GAAG,EAAE,+BAA+B,EAAE,CAAA;IAC1D,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,GAAG,EAAE,qCAAqC,EAAE,IAAI,EAAE,CAAA;IACrF,OAAO,IAAI,CAAA;AACb,CAAC","sourcesContent":["import { isPlaceholderType, TYPE_LENGTH, TYPE_PATTERN } from '@hatiolab/figure-model'\n\n/*\n * The first save of a new figure asks for its type and name. The type is the name a board places\n * the figure by; it freezes when the figure is released (ADR-0063 decision 4). The modeller once saved a new figure\n * under a temporary machine name and asked nothing -- the author had to find the field afterwards (user, 2026-09-25).\n */\n\n/** A type as typed, made into the shape a type has: lower-case letters and digits joined by single hyphens. */\nexport function typeOf(raw: string): string {\n return raw.trim().toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '')\n}\n\n/**\n * Whether this name could be released, by the format's own rules (`type-not-identifier`, `type-is-placeholder`).\n * Saving under it is not blocked -- it can still change before release -- but the author hears it now.\n */\nexport function releasableType(type: string): boolean {\n return !isPlaceholderType(type) && TYPE_PATTERN.test(type) && type.length >= TYPE_LENGTH.min && type.length <= TYPE_LENGTH.max\n}\n\n/**\n * An identifier offered for a new figure, so the first save asks for a name and has a valid identifier ready (designer\n * 2026-09-27, Q-D3). A name in plain letters is used as it is when it makes a free, releasable identifier; any other\n * name -- Korean, say -- gets a valid prefix and a random part: no transliteration is guessed. Never the temporary\n * shape (`figure-` and eight), which the release gate refuses; never one this domain already uses.\n */\nexport function suggestTypeOf(name: string, taken: readonly string[], random: () => number = Math.random): string {\n const fromName = /^[A-Za-z][A-Za-z0-9 _-]*$/.test(name.trim()) ? typeOf(name) : ''\n if (fromName && releasableType(fromName) && !taken.includes(fromName)) return fromName\n const alphabet = '0123456789abcdefghijklmnopqrstuvwxyz'\n for (;;) {\n const made = `fig-${Array.from({ length: 6 }, () => alphabet[Math.floor(random() * alphabet.length)]).join('')}`\n if (releasableType(made) && !taken.includes(made)) return made\n }\n}\n\n/** The shape of an identifier the modeller offers (`suggestTypeOf`'s random form). */\nconst OFFERED = /^fig-[0-9a-z]{6}$/\n\n/**\n * The identifier the first save's question shows, given the one it opens on (Q-D3). The identifier is not the name:\n * renaming does not change it, and a retried first save opens on the one answered before. A new one is offered only when\n * there is none, or when an offered one is found taken -- told by the server, or in the list; one the author typed is\n * kept as typed, and its refusal said. `suggested` is the identifier now on offer, absent when that is unchanged.\n */\nexport function offeredTypeOf(\n type: string,\n name: string,\n taken: readonly string[],\n random: () => number = Math.random\n): { type: string; suggested?: string } {\n const offeredAndTaken = OFFERED.test(type) && taken.includes(type)\n if (!type || offeredAndTaken) {\n const made = suggestTypeOf(name, taken, random)\n return { type: made, suggested: made }\n }\n return OFFERED.test(type) ? { type, suggested: type } : { type }\n}\n\n/** Why the first save cannot go on with this type, as an i18n key, or null when it can. */\nexport function firstSaveRefusalOf(type: string, taken: readonly string[]): { key: string; type?: string } | null {\n if (!type) return { key: 'figure.text.enter-a-type-name' }\n if (taken.includes(type)) return { key: 'figure.text.type-name-already-taken', type }\n return null\n}\n\n/** What the first save asks for. */\nexport interface FirstSave {\n type: string\n name: string\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import type { FigureFollow, FigureSizeRange } from '@hatiolab/figure-model';
2
- import type { FigureAsset, FigureBindingPlace, FigureFace, FigureJoint } from '@hatiolab/figure-model';
2
+ import type { FigureAsset, FigureAuthoringAction, FigureBindingPlace, FigureFace, FigureJoint } from '@hatiolab/figure-model';
3
3
  import { type FigureRevision } from './revision.js';
4
4
  import { type JointAxisVector } from './joint-axis.js';
5
5
  export type Axis = 'x' | 'y' | 'z';
@@ -74,6 +74,12 @@ export declare function partSummaryOf(asset: FigureAsset, part: string, say: (ke
74
74
  export declare function fieldWordsOf(id: string, say: (key: string) => string): string;
75
75
  /** What a part's own measure on an axis is now (a box's side, a cylinder's radius or length), at the design as it stands. */
76
76
  export declare function dimensionNow(revision: FigureRevision, part: string, axis: Axis): number | undefined;
77
+ /**
78
+ * The command a dimension's rule chosen in the size form sends (`choice` as `choiceOf` writes it), or nothing to send.
79
+ * The measure as it stands decides the numbers: a dimension stops following at it, and a share is taken of it, so
80
+ * neither choice changes the part's size. A share needs the figure's size on that axis.
81
+ */
82
+ export declare function followCommandOf(revision: FigureRevision, part: string, axis: Axis, choice: string, now: Follow): FigureAuthoringAction | undefined;
77
83
  /**
78
84
  * How long a part is along one axis now, as it is drawn: the shape's own measure through figure-model's provider (a
79
85
  * cylinder's width is twice its radius), read after any rule it follows -- so a linked measure still says its size.
@@ -133,6 +139,25 @@ export declare function alignAxesOf(asset: FigureAsset, part: string, target: {
133
139
  axis: Axis;
134
140
  edges: boolean;
135
141
  }[];
142
+ /**
143
+ * The faces of its own a part may be fastened by: its outer faces -- on the mounting plane only the ones the plane takes
144
+ * (a bottom or a top on the floor, a back on a wall) -- and, to another part, its centre, which a roller spins about.
145
+ */
146
+ export declare function ownFacesOf(asset: FigureAsset, part: string, toPlane: boolean): Array<FigureFace | 'centre'>;
147
+ /**
148
+ * The axes across the face the fastening form asks about in rows: only where the face drawing (`view`, its axes) cannot
149
+ * set the place -- no drawing at all, an axis it does not draw, a place that follows a position field, or one the
150
+ * figure's size may scale.
151
+ */
152
+ export declare function alignRowsOf(asset: FigureAsset, part: string, aim: {
153
+ part: string;
154
+ face: string;
155
+ } | 'plane', view: {
156
+ axes: readonly Axis[];
157
+ } | undefined, twisted: boolean, alignInput?: Partial<Record<Axis, string>>): {
158
+ axis: Axis;
159
+ edges: boolean;
160
+ }[];
136
161
  /** The controls a part's showing can follow: the figure's state inputs, with their range and label. */
137
162
  export declare function visibilityControlsOf(asset: FigureAsset): Array<{
138
163
  id: string;
@@ -1,5 +1,6 @@
1
1
  import { FIGURE_FACES, figureShapeFaces, figurePartsExtentOf, figureFollowOf, proposeFigureProportion, defaultInstanceSizeRange, foldInstanceSizeRange, figureAttachmentsOf, figureBindingsOf, figureInstanceSizeLimitsOf, figureFollowableAxesOf, figureShapeProviderOf, figureMimicTermsOf } from '@hatiolab/figure-model';
2
2
  import { startingShapeKindOf } from './starting-shape.js';
3
+ import { boxOf } from './align.js';
3
4
  import { graphValuesOf } from './revision.js';
4
5
  import { jointAxisToken, jointAxisVectorOf } from './joint-axis.js';
5
6
  export const AXES = ['x', 'y', 'z'];
@@ -154,6 +155,28 @@ export function dimensionNow(revision, part, axis) {
154
155
  return undefined;
155
156
  }
156
157
  }
158
+ /**
159
+ * The command a dimension's rule chosen in the size form sends (`choice` as `choiceOf` writes it), or nothing to send.
160
+ * The measure as it stands decides the numbers: a dimension stops following at it, and a share is taken of it, so
161
+ * neither choice changes the part's size. A share needs the figure's size on that axis.
162
+ */
163
+ export function followCommandOf(revision, part, axis, choice, now) {
164
+ const following = now.of !== 'own';
165
+ /* The part's own measure on the axis now (a cylinder's radius, not its width), else its extent as drawn. */
166
+ const current = dimensionNow(revision, part, axis) ?? boxOf(revision, part)?.dims[AXES.indexOf(axis)] ?? 100;
167
+ if (choice === 'own')
168
+ return following ? { kind: 'unlink-dimension', part, axis, mm: Math.max(1, Math.round(current)) } : undefined;
169
+ const [of, a, b] = choice.split(':');
170
+ if (of === 'share') {
171
+ const size = revision.asset.designInputs[`size.${a}`];
172
+ if (!size)
173
+ return undefined;
174
+ const times = Math.round((current / size) * 1e6) / 1e6;
175
+ return { kind: 'link-dimension', part, axis, source: { of: 'instance', axis: a }, times, replace: following };
176
+ }
177
+ const source = of === 'instance' ? { of: 'instance', axis: a } : { of: 'part', part: a, axis: b };
178
+ return { kind: 'link-dimension', part, axis, source, replace: following };
179
+ }
157
180
  /**
158
181
  * How long a part is along one axis now, as it is drawn: the shape's own measure through figure-model's provider (a
159
182
  * cylinder's width is twice its radius), read after any rule it follows -- so a linked measure still says its size.
@@ -260,6 +283,26 @@ export function alignAxesOf(asset, part, target, twisted = false) {
260
283
  /* A part twisted about the face's normal has no side level with the target's edges. */
261
284
  return AXES.filter(axis => axis !== along).map(axis => ({ axis, edges: !twisted && OUTER[axis].every(f => theirs.has(f) && mine.has(f)) }));
262
285
  }
286
+ /**
287
+ * The faces of its own a part may be fastened by: its outer faces -- on the mounting plane only the ones the plane takes
288
+ * (a bottom or a top on the floor, a back on a wall) -- and, to another part, its centre, which a roller spins about.
289
+ */
290
+ export function ownFacesOf(asset, part, toPlane) {
291
+ const outer = Object.keys(FIGURE_FACES);
292
+ const plane = mountingPlaneOf(asset);
293
+ return [
294
+ ...facesOf(asset, part).filter(face => outer.includes(face) && (!toPlane || plane.faces.includes(face))),
295
+ ...(toPlane ? [] : ['centre'])
296
+ ];
297
+ }
298
+ /**
299
+ * The axes across the face the fastening form asks about in rows: only where the face drawing (`view`, its axes) cannot
300
+ * set the place -- no drawing at all, an axis it does not draw, a place that follows a position field, or one the
301
+ * figure's size may scale.
302
+ */
303
+ export function alignRowsOf(asset, part, aim, view, twisted, alignInput = {}) {
304
+ return alignAxesOf(asset, part, aim, twisted).filter(({ axis }) => !view || !view.axes.includes(axis) || !!alignInput[axis] || hasInstanceSize(asset, axis));
305
+ }
263
306
  /** The controls a part's showing can follow: the figure's state inputs, with their range and label. */
264
307
  export function visibilityControlsOf(asset) {
265
308
  const labels = asset.stateInputs ?? {};