@things-factory/figure-ui 10.1.74 → 10.1.76

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 (244) hide show
  1. package/client/figure-assistant.ts +3 -3
  2. package/client/graphql/{v3-store.ts → store.ts} +6 -6
  3. package/client/modeller/{v3-ai-proposal.ts → ai-proposal.ts} +8 -8
  4. package/client/modeller/{v3-align.ts → align.ts} +14 -14
  5. package/client/modeller/{v3-canvas.ts → canvas.ts} +13 -13
  6. package/client/modeller/{v3-clips.ts → clips.ts} +5 -5
  7. package/client/modeller/{v3-controls.ts → controls.ts} +2 -2
  8. package/client/modeller/{v3-editor.ts → editor.ts} +137 -126
  9. package/client/modeller/{figure-v3-capability.ts → figure-capability-panel.ts} +7 -7
  10. package/client/modeller/{figure-v3-clips.ts → figure-clips.ts} +10 -10
  11. package/client/modeller/{figure-v3-controls.ts → figure-controls.ts} +9 -9
  12. package/client/modeller/{v3-figure-facts.ts → figure-facts.ts} +11 -11
  13. package/client/modeller/{figure-v3-first-save.ts → figure-first-save.ts} +3 -3
  14. package/client/modeller/figure-history-panel.ts +1 -1
  15. package/client/modeller/{figure-v3-links.ts → figure-links.ts} +35 -35
  16. package/client/modeller/{figure-v3-material.ts → figure-material-panel.ts} +20 -20
  17. package/client/modeller/{figure-v3-parts.ts → figure-parts.ts} +15 -15
  18. package/client/modeller/{figure-v3-preview.ts → figure-preview.ts} +14 -14
  19. package/client/modeller/{figure-v3-properties.ts → figure-properties.ts} +25 -25
  20. package/client/modeller/{figure-v3-recipe-catalog.ts → figure-recipe-catalog.ts} +10 -10
  21. package/client/modeller/{figure-v3-verdict.ts → figure-verdict.ts} +24 -24
  22. package/client/modeller/gate-findings.ts +2 -2
  23. package/client/modeller/{v3-gizmo.ts → gizmo.ts} +11 -11
  24. package/client/modeller/{v3-joint-drag.ts → joint-drag.ts} +11 -11
  25. package/client/modeller/{v3-joint-fan.ts → joint-fan.ts} +13 -13
  26. package/client/modeller/{v3-links.ts → links.ts} +59 -59
  27. package/client/modeller/{v3-live.ts → live.ts} +9 -9
  28. package/client/modeller/{v3-maturity.ts → maturity.ts} +65 -65
  29. package/client/modeller/modeller-route.ts +1 -1
  30. package/client/modeller/{v3-occupancy.ts → occupancy.ts} +6 -6
  31. package/client/modeller/{v3-palette.ts → palette.ts} +3 -3
  32. package/client/modeller/{v3-preview-model.ts → preview-model.ts} +8 -8
  33. package/client/modeller/{v3-product-session.ts → product-session.ts} +25 -25
  34. package/client/modeller/{v3-recipe-source.ts → recipe-source.ts} +2 -2
  35. package/client/modeller/{v3-recipes.ts → recipes.ts} +9 -9
  36. package/client/modeller/{v3-refusals.ts → refusals.ts} +62 -13
  37. package/client/modeller/{v3-renderer.ts → renderer.ts} +16 -16
  38. package/client/modeller/{v3-stage-model.ts → stage-model.ts} +15 -15
  39. package/client/modeller/{v3-thumbnail.ts → thumbnail.ts} +8 -8
  40. package/client/pages/figure-list-page.ts +4 -4
  41. package/client/pages/{figure-v3-modeller-page.ts → figure-modeller-page.ts} +37 -37
  42. package/client/route.ts +1 -5
  43. package/dist-client/figure-assistant.js +3 -3
  44. package/dist-client/figure-assistant.js.map +1 -1
  45. package/dist-client/graphql/store.d.ts +3 -0
  46. package/dist-client/graphql/store.js +39 -0
  47. package/dist-client/graphql/store.js.map +1 -0
  48. package/dist-client/modeller/ai-proposal.d.ts +51 -0
  49. package/dist-client/modeller/ai-proposal.js +64 -0
  50. package/dist-client/modeller/ai-proposal.js.map +1 -0
  51. package/dist-client/modeller/align.d.ts +30 -0
  52. package/dist-client/modeller/align.js +75 -0
  53. package/dist-client/modeller/align.js.map +1 -0
  54. package/dist-client/modeller/canvas.d.ts +72 -0
  55. package/dist-client/modeller/canvas.js +379 -0
  56. package/dist-client/modeller/canvas.js.map +1 -0
  57. package/dist-client/modeller/clips.d.ts +39 -0
  58. package/dist-client/modeller/clips.js +58 -0
  59. package/dist-client/modeller/clips.js.map +1 -0
  60. package/dist-client/modeller/controls.d.ts +28 -0
  61. package/dist-client/modeller/controls.js +28 -0
  62. package/dist-client/modeller/controls.js.map +1 -0
  63. package/dist-client/modeller/editor.d.ts +203 -0
  64. package/dist-client/modeller/editor.js +1526 -0
  65. package/dist-client/modeller/editor.js.map +1 -0
  66. package/dist-client/modeller/fields.d.ts +45 -0
  67. package/dist-client/modeller/fields.js +83 -0
  68. package/dist-client/modeller/fields.js.map +1 -0
  69. package/dist-client/modeller/figure-capability-panel.d.ts +22 -0
  70. package/dist-client/modeller/figure-capability-panel.js +141 -0
  71. package/dist-client/modeller/figure-capability-panel.js.map +1 -0
  72. package/dist-client/modeller/figure-clips.d.ts +31 -0
  73. package/dist-client/modeller/figure-clips.js +268 -0
  74. package/dist-client/modeller/figure-clips.js.map +1 -0
  75. package/dist-client/modeller/figure-controls.d.ts +36 -0
  76. package/dist-client/modeller/figure-controls.js +226 -0
  77. package/dist-client/modeller/figure-controls.js.map +1 -0
  78. package/dist-client/modeller/figure-facts.d.ts +35 -0
  79. package/dist-client/modeller/figure-facts.js +55 -0
  80. package/dist-client/modeller/figure-facts.js.map +1 -0
  81. package/dist-client/modeller/figure-first-save.d.ts +20 -0
  82. package/dist-client/modeller/figure-first-save.js +118 -0
  83. package/dist-client/modeller/figure-first-save.js.map +1 -0
  84. package/dist-client/modeller/figure-history-panel.d.ts +1 -1
  85. package/dist-client/modeller/figure-history-panel.js.map +1 -1
  86. package/dist-client/modeller/figure-links.d.ts +77 -0
  87. package/dist-client/modeller/figure-links.js +649 -0
  88. package/dist-client/modeller/figure-links.js.map +1 -0
  89. package/dist-client/modeller/figure-material-panel.d.ts +39 -0
  90. package/dist-client/modeller/figure-material-panel.js +323 -0
  91. package/dist-client/modeller/figure-material-panel.js.map +1 -0
  92. package/dist-client/modeller/figure-parts.d.ts +69 -0
  93. package/dist-client/modeller/figure-parts.js +559 -0
  94. package/dist-client/modeller/figure-parts.js.map +1 -0
  95. package/dist-client/modeller/figure-preview.d.ts +34 -0
  96. package/dist-client/modeller/figure-preview.js +346 -0
  97. package/dist-client/modeller/figure-preview.js.map +1 -0
  98. package/dist-client/modeller/figure-properties.d.ts +45 -0
  99. package/dist-client/modeller/figure-properties.js +239 -0
  100. package/dist-client/modeller/figure-properties.js.map +1 -0
  101. package/dist-client/modeller/figure-recipe-catalog.d.ts +38 -0
  102. package/dist-client/modeller/figure-recipe-catalog.js +399 -0
  103. package/dist-client/modeller/figure-recipe-catalog.js.map +1 -0
  104. package/dist-client/modeller/figure-verdict.d.ts +64 -0
  105. package/dist-client/modeller/figure-verdict.js +787 -0
  106. package/dist-client/modeller/figure-verdict.js.map +1 -0
  107. package/dist-client/modeller/first-save.d.ts +17 -0
  108. package/dist-client/modeller/first-save.js +26 -0
  109. package/dist-client/modeller/first-save.js.map +1 -0
  110. package/dist-client/modeller/gate-findings.d.ts +2 -2
  111. package/dist-client/modeller/gate-findings.js +2 -2
  112. package/dist-client/modeller/gate-findings.js.map +1 -1
  113. package/dist-client/modeller/gizmo.d.ts +72 -0
  114. package/dist-client/modeller/gizmo.js +111 -0
  115. package/dist-client/modeller/gizmo.js.map +1 -0
  116. package/dist-client/modeller/help.d.ts +18 -0
  117. package/dist-client/modeller/help.js +37 -0
  118. package/dist-client/modeller/help.js.map +1 -0
  119. package/dist-client/modeller/joint-drag.d.ts +19 -0
  120. package/dist-client/modeller/joint-drag.js +97 -0
  121. package/dist-client/modeller/joint-drag.js.map +1 -0
  122. package/dist-client/modeller/joint-fan.d.ts +9 -0
  123. package/dist-client/modeller/joint-fan.js +276 -0
  124. package/dist-client/modeller/joint-fan.js.map +1 -0
  125. package/dist-client/modeller/keys.d.ts +22 -0
  126. package/dist-client/modeller/keys.js +26 -0
  127. package/dist-client/modeller/keys.js.map +1 -0
  128. package/dist-client/modeller/links.d.ts +267 -0
  129. package/dist-client/modeller/links.js +480 -0
  130. package/dist-client/modeller/links.js.map +1 -0
  131. package/dist-client/modeller/live.d.ts +37 -0
  132. package/dist-client/modeller/live.js +68 -0
  133. package/dist-client/modeller/live.js.map +1 -0
  134. package/dist-client/modeller/maturity.d.ts +120 -0
  135. package/dist-client/modeller/maturity.js +313 -0
  136. package/dist-client/modeller/maturity.js.map +1 -0
  137. package/dist-client/modeller/modeller-route.d.ts +1 -1
  138. package/dist-client/modeller/modeller-route.js +1 -1
  139. package/dist-client/modeller/modeller-route.js.map +1 -1
  140. package/dist-client/modeller/occupancy.d.ts +18 -0
  141. package/dist-client/modeller/occupancy.js +24 -0
  142. package/dist-client/modeller/occupancy.js.map +1 -0
  143. package/dist-client/modeller/palette.d.ts +7 -0
  144. package/dist-client/modeller/palette.js +46 -0
  145. package/dist-client/modeller/palette.js.map +1 -0
  146. package/dist-client/modeller/preview-model.d.ts +47 -0
  147. package/dist-client/modeller/preview-model.js +68 -0
  148. package/dist-client/modeller/preview-model.js.map +1 -0
  149. package/dist-client/modeller/product-session.d.ts +510 -0
  150. package/dist-client/modeller/product-session.js +157 -0
  151. package/dist-client/modeller/product-session.js.map +1 -0
  152. package/dist-client/modeller/recipe-source.d.ts +8 -0
  153. package/dist-client/modeller/recipe-source.js +14 -0
  154. package/dist-client/modeller/recipe-source.js.map +1 -0
  155. package/dist-client/modeller/recipes.d.ts +37 -0
  156. package/dist-client/modeller/recipes.js +103 -0
  157. package/dist-client/modeller/recipes.js.map +1 -0
  158. package/dist-client/modeller/refusals.d.ts +68 -0
  159. package/dist-client/modeller/refusals.js +142 -0
  160. package/dist-client/modeller/refusals.js.map +1 -0
  161. package/dist-client/modeller/renderer.d.ts +40 -0
  162. package/dist-client/modeller/renderer.js +73 -0
  163. package/dist-client/modeller/renderer.js.map +1 -0
  164. package/dist-client/modeller/stage-model.d.ts +39 -0
  165. package/dist-client/modeller/stage-model.js +147 -0
  166. package/dist-client/modeller/stage-model.js.map +1 -0
  167. package/dist-client/modeller/thumbnail.d.ts +3 -0
  168. package/dist-client/modeller/thumbnail.js +75 -0
  169. package/dist-client/modeller/thumbnail.js.map +1 -0
  170. package/dist-client/modeller/v3-clips.d.ts +1 -1
  171. package/dist-client/modeller/v3-editor.d.ts +5 -0
  172. package/dist-client/modeller/v3-editor.js +21 -10
  173. package/dist-client/modeller/v3-editor.js.map +1 -1
  174. package/dist-client/modeller/v3-product-session.d.ts +31 -0
  175. package/dist-client/modeller/v3-refusals.d.ts +37 -5
  176. package/dist-client/modeller/v3-refusals.js +59 -16
  177. package/dist-client/modeller/v3-refusals.js.map +1 -1
  178. package/dist-client/pages/figure-list-page.d.ts +1 -1
  179. package/dist-client/pages/figure-list-page.js +4 -4
  180. package/dist-client/pages/figure-list-page.js.map +1 -1
  181. package/dist-client/pages/figure-modeller-page.d.ts +102 -0
  182. package/dist-client/pages/figure-modeller-page.js +548 -0
  183. package/dist-client/pages/figure-modeller-page.js.map +1 -0
  184. package/dist-client/route.d.ts +1 -1
  185. package/dist-client/route.js +1 -5
  186. package/dist-client/route.js.map +1 -1
  187. package/dist-client/tsconfig.tsbuildinfo +1 -1
  188. package/docs/product-cutover.md +25 -0
  189. package/package.json +5 -5
  190. package/test/{v3-ai-proposal.test.ts → ai-proposal.test.ts} +6 -6
  191. package/test/{v3-align.test.ts → align.test.ts} +8 -8
  192. package/test/browser/modeller-page.js +30 -30
  193. package/test/browser/modeller.check.mjs +17 -16
  194. package/test/browser/serve.mjs +1 -1
  195. package/test/browser/thumbnail-page.js +6 -6
  196. package/test/{v3-clips.test.ts → clips.test.ts} +18 -18
  197. package/test/{v3-controls.test.ts → controls.test.ts} +15 -15
  198. package/test/{v3-fields.test.ts → fields.test.ts} +13 -13
  199. package/test/figure-assistant-surface.test.ts +3 -3
  200. package/test/{v3-first-save.test.ts → first-save.test.ts} +10 -10
  201. package/test/fixtures/joint-column.json +2 -2
  202. package/test/fixtures/joint-roller.json +2 -2
  203. package/test/fixtures/robot-arm-6dof.json +2 -2
  204. package/test/{v3-gizmo.test.ts → gizmo.test.ts} +33 -33
  205. package/test/{v3-joint-drag.test.ts → joint-drag.test.ts} +17 -17
  206. package/test/{v3-joint-fan.test.ts → joint-fan.test.ts} +18 -18
  207. package/test/joints.ts +6 -6
  208. package/test/{v3-keys.test.ts → keys.test.ts} +2 -2
  209. package/test/{v3-layout.test.ts → layout.test.ts} +8 -8
  210. package/test/{v3-links.test.ts → links.test.ts} +201 -201
  211. package/test/{v3-live.test.ts → live.test.ts} +18 -18
  212. package/test/{v3-material.test.ts → material.test.ts} +12 -12
  213. package/test/{v3-maturity.test.ts → maturity.test.ts} +74 -74
  214. package/test/modeller-route.test.ts +5 -6
  215. package/test/{v3-palette-icons.test.ts → palette-icons.test.ts} +1 -1
  216. package/test/{v3-parts-wiring.test.ts → parts-wiring.test.ts} +11 -7
  217. package/test/{v3-preview.test.ts → preview.test.ts} +12 -12
  218. package/test/{v3-product-session.test.ts → product-session.test.ts} +17 -17
  219. package/test/{v3-product-write.test.ts → product-write.test.ts} +20 -20
  220. package/test/{v3-properties.test.ts → properties.test.ts} +24 -24
  221. package/test/{v3-recipes.test.ts → recipes.test.ts} +10 -10
  222. package/test/refusals.test.ts +166 -0
  223. package/test/{v3-release-panel.test.ts → release-panel.test.ts} +21 -21
  224. package/test/renderer.test.ts +24 -0
  225. package/test/resolve-ts-siblings.mjs +1 -1
  226. package/test/{v3-scene-canvas.test.ts → scene-canvas.test.ts} +6 -6
  227. package/test/{v3-stage-model.test.ts → stage-model.test.ts} +5 -5
  228. package/test/{v3-theme.test.ts → theme.test.ts} +4 -4
  229. package/test/{v3-thumbnail.test.ts → thumbnail.test.ts} +4 -4
  230. package/test/{v3-verdict.test.ts → verdict.test.ts} +17 -17
  231. package/test/{v3-view.test.ts → view.test.ts} +2 -2
  232. package/things-factory.config.js +2 -3
  233. package/translations/en.json +15 -7
  234. package/translations/ja.json +15 -7
  235. package/translations/ko.json +15 -7
  236. package/translations/ms.json +15 -7
  237. package/translations/zh.json +15 -7
  238. package/docs/v3-product-cutover.md +0 -25
  239. package/test/v3-refusals.test.ts +0 -136
  240. package/test/v3-renderer.test.ts +0 -24
  241. /package/client/modeller/{v3-fields.ts → fields.ts} +0 -0
  242. /package/client/modeller/{v3-first-save.ts → first-save.ts} +0 -0
  243. /package/client/modeller/{v3-help.ts → help.ts} +0 -0
  244. /package/client/modeller/{v3-keys.ts → keys.ts} +0 -0
@@ -3,8 +3,8 @@ import { customElement, property } from 'lit/decorators.js'
3
3
  import { live } from 'lit/directives/live.js'
4
4
 
5
5
  import { i18next, localize } from '@operato/i18n'
6
- import { v3BindingsOf } from '@hatiolab/figure-model'
7
- import type { FigureCapability, V3Asset } from '@hatiolab/figure-model'
6
+ import { figureBindingsOf } from '@hatiolab/figure-model'
7
+ import type { FigureCapability, FigureAsset } from '@hatiolab/figure-model'
8
8
  import { SidePanelStyles } from './side-panel-styles.js'
9
9
 
10
10
  /*
@@ -32,8 +32,8 @@ export function rungOf(names: readonly string[] | undefined): Rung | null {
32
32
  * holding things, to passing them on, and every place things are held, whatever part it is on. A place is not drawn,
33
33
  * so the list is the only way to find one; choosing a row selects its part, where the place is edited.
34
34
  */
35
- @customElement('figure-v3-capability')
36
- export class FigureV3Capability extends localize(i18next)(LitElement) {
35
+ @customElement('figure-capability-panel')
36
+ export class FigureCapabilityPanel extends localize(i18next)(LitElement) {
37
37
  static styles = [SidePanelStyles, css`
38
38
  :host {
39
39
  display: block;
@@ -84,7 +84,7 @@ export class FigureV3Capability extends localize(i18next)(LitElement) {
84
84
  }
85
85
  `]
86
86
 
87
- @property({ attribute: false }) asset?: V3Asset
87
+ @property({ attribute: false }) asset?: FigureAsset
88
88
  /** The selected part, whose places are marked. */
89
89
  @property() selected = ''
90
90
  @property({ type: Boolean }) locked = false
@@ -94,7 +94,7 @@ export class FigureV3Capability extends localize(i18next)(LitElement) {
94
94
  if (!asset) return nothing
95
95
  const names = asset.document.capabilities.names ?? []
96
96
  const rung = rungOf(names)
97
- const places = v3BindingsOf(asset)
97
+ const places = figureBindingsOf(asset)
98
98
  return html`<section>
99
99
  <h3>${i18next.t('figure.label.what-this-does')}</h3>
100
100
  ${(['none', 'hold', 'flow'] as const).map(
@@ -128,7 +128,7 @@ export class FigureV3Capability extends localize(i18next)(LitElement) {
128
128
  }
129
129
 
130
130
  private setRung(which: Rung) {
131
- this.dispatchEvent(new CustomEvent('v3-part-edit', { detail: { edit: { kind: 'set-capabilities', names: [...RUNGS[which]] } }, bubbles: true, composed: true }))
131
+ this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit: { kind: 'set-capabilities', names: [...RUNGS[which]] } }, bubbles: true, composed: true }))
132
132
  }
133
133
 
134
134
  private pick(part: string) {
@@ -4,11 +4,11 @@ import { css, html, LitElement, nothing } from 'lit'
4
4
  import { customElement, property, state } from 'lit/decorators.js'
5
5
 
6
6
  import { i18next, localize } from '@operato/i18n'
7
- import type { V3Asset } from '@hatiolab/figure-model'
7
+ import type { FigureAsset } from '@hatiolab/figure-model'
8
8
 
9
- import { clipsOf, poseAt, trackEdit, undrivenOf, withKey, withoutKey, type Clip, type ClipTrack } from './v3-clips.js'
9
+ import { clipsOf, poseAt, trackEdit, undrivenOf, withKey, withoutKey, type Clip, type ClipTrack } from './clips.js'
10
10
  import { SidePanelStyles } from './side-panel-styles.js'
11
- import { HelpToggles } from './v3-help.js'
11
+ import { HelpToggles } from './help.js'
12
12
 
13
13
  /**
14
14
  * 클립 — controls played by keys over time. A clip is one clock; each track plays one
@@ -16,8 +16,8 @@ import { HelpToggles } from './v3-help.js'
16
16
  * is added at the scrubbed moment with the control's value there, so a pose is made with the controls' sliders and
17
17
  * then kept as a key. Every change is one part edit.
18
18
  */
19
- @customElement('figure-v3-clips')
20
- export class FigureV3Clips extends localize(i18next)(LitElement) {
19
+ @customElement('figure-clips')
20
+ export class FigureClips extends localize(i18next)(LitElement) {
21
21
  private readonly help = new HelpToggles(this)
22
22
  static styles = [SidePanelStyles, css`
23
23
  :host {
@@ -91,7 +91,7 @@ export class FigureV3Clips extends localize(i18next)(LitElement) {
91
91
  }
92
92
  `]
93
93
 
94
- @property({ attribute: false }) asset?: V3Asset
94
+ @property({ attribute: false }) asset?: FigureAsset
95
95
  /** The values the editor holds now, by input id -- what a new key takes. */
96
96
  @property({ attribute: false }) values: Record<string, number> = {}
97
97
  @property({ type: Boolean }) locked = false
@@ -184,7 +184,7 @@ export class FigureV3Clips extends localize(i18next)(LitElement) {
184
184
  </div>`
185
185
  }
186
186
 
187
- private renderAdd(asset: V3Asset, clips: Clip[]) {
187
+ private renderAdd(asset: FigureAsset, clips: Clip[]) {
188
188
  const free = undrivenOf(asset)
189
189
  if (!free.length) return clips.length ? nothing : html`<p hint>${i18next.t('figure.text.no-controls')}</p>`
190
190
  const a = this.adding
@@ -241,13 +241,13 @@ export class FigureV3Clips extends localize(i18next)(LitElement) {
241
241
  if (!changes.length) return
242
242
  if (live) {
243
243
  const values = Object.fromEntries(changes.map(c => [c.input, c.value]))
244
- this.dispatchEvent(new CustomEvent('v3-states-live', { detail: { values }, bubbles: true, composed: true }))
244
+ this.dispatchEvent(new CustomEvent('states-live', { detail: { values }, bubbles: true, composed: true }))
245
245
  return
246
246
  }
247
- this.dispatchEvent(new CustomEvent('v3-states', { detail: { changes }, bubbles: true, composed: true }))
247
+ this.dispatchEvent(new CustomEvent('states', { detail: { changes }, bubbles: true, composed: true }))
248
248
  }
249
249
 
250
250
  private edit(edit: unknown) {
251
- this.dispatchEvent(new CustomEvent('v3-part-edit', { detail: { edit }, bubbles: true, composed: true }))
251
+ this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit }, bubbles: true, composed: true }))
252
252
  }
253
253
  }
@@ -4,9 +4,9 @@ import { css, html, LitElement, nothing } from 'lit'
4
4
  import { customElement, property, state } from 'lit/decorators.js'
5
5
 
6
6
  import { i18next, localize } from '@operato/i18n'
7
- import type { V3Asset } from '@hatiolab/figure-model'
7
+ import type { FigureAsset } from '@hatiolab/figure-model'
8
8
 
9
- import { controlsOf, poseAsDefault, poseDiffers, type Control } from './v3-controls.js'
9
+ import { controlsOf, poseAsDefault, poseDiffers, type Control } from './controls.js'
10
10
  import { dialShape } from './angle-dial.js'
11
11
  import { SidePanelStyles } from './side-panel-styles.js'
12
12
 
@@ -15,12 +15,12 @@ import { SidePanelStyles } from './side-panel-styles.js'
15
15
  * with a slider to try it, its name, range and travel time, and a button that keeps the pose being looked at as the
16
16
  * pose it stands in when placed.
17
17
  *
18
- * Trying a value is an input change (`v3-state`, not saved as the default); naming, the range and the travel time are
18
+ * Trying a value is an input change (`state`, not saved as the default); naming, the range and the travel time are
19
19
  * one `set-state-input` part edit each; keeping the pose is one `set-state-defaults` edit. A control is made with
20
20
  * a motion on a part (「움직임」), which is where it gets its meaning.
21
21
  */
22
- @customElement('figure-v3-controls')
23
- export class FigureV3Controls extends localize(i18next)(LitElement) {
22
+ @customElement('figure-controls')
23
+ export class FigureControls extends localize(i18next)(LitElement) {
24
24
  static styles = [SidePanelStyles, css`
25
25
  :host {
26
26
  display: block;
@@ -96,7 +96,7 @@ export class FigureV3Controls extends localize(i18next)(LitElement) {
96
96
  `]
97
97
 
98
98
  /** The asset being edited. */
99
- @property({ attribute: false }) asset?: V3Asset
99
+ @property({ attribute: false }) asset?: FigureAsset
100
100
  /** The values the editor holds now, by input id. */
101
101
  @property({ attribute: false }) values: Record<string, number> = {}
102
102
  @property({ type: Boolean }) locked = false
@@ -193,7 +193,7 @@ export class FigureV3Controls extends localize(i18next)(LitElement) {
193
193
  private drag(c: Control, value: number) {
194
194
  if (!Number.isFinite(value)) return
195
195
  this.live = { ...this.live, [c.id]: value }
196
- this.dispatchEvent(new CustomEvent('v3-state-live', { detail: { input: c.id, value }, bubbles: true, composed: true }))
196
+ this.dispatchEvent(new CustomEvent('state-live', { detail: { input: c.id, value }, bubbles: true, composed: true }))
197
197
  }
198
198
 
199
199
  /** Try a value: the pose being looked at, clamped to the range. Not saved as the default. The slider sends it on
@@ -203,10 +203,10 @@ export class FigureV3Controls extends localize(i18next)(LitElement) {
203
203
  const clamped = Math.min(Math.max(value, c.min), c.max)
204
204
  const { [c.id]: _released, ...rest } = this.live
205
205
  this.live = rest
206
- this.dispatchEvent(new CustomEvent('v3-state', { detail: { input: c.id, unit: c.unit, value: clamped }, bubbles: true, composed: true }))
206
+ this.dispatchEvent(new CustomEvent('state', { detail: { input: c.id, unit: c.unit, value: clamped }, bubbles: true, composed: true }))
207
207
  }
208
208
 
209
209
  private edit(edit: unknown) {
210
- this.dispatchEvent(new CustomEvent('v3-part-edit', { detail: { edit }, bubbles: true, composed: true }))
210
+ this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit }, bubbles: true, composed: true }))
211
211
  }
212
212
  }
@@ -1,25 +1,25 @@
1
- import { compileV3Asset, parseV3Asset, v3OccupiedBoxesOf, v3WritersOf } from '@hatiolab/figure-model'
2
- import type { V3Asset, V3Face } from '@hatiolab/figure-model'
1
+ import { compileFigureAsset, parseFigureAsset, figureOccupiedBoxesOf, figureWritersOf } from '@hatiolab/figure-model'
2
+ import type { FigureAsset, FigureFace } from '@hatiolab/figure-model'
3
3
 
4
4
  /*
5
- * What the V3 properties tab reads, kept apart from the element so it can be tested without a browser.
5
+ * What the properties tab reads, kept apart from the element so it can be tested without a browser.
6
6
  */
7
7
 
8
8
  export type Placement = 'floor' | 'ceiling' | 'center' | 'wall'
9
9
 
10
10
  /** What the properties tab reads off the asset. Absent parts of the asset read as absent, never as a default. */
11
- export interface V3FigureFacts {
11
+ export interface FigureFigureFacts {
12
12
  name: string
13
13
  parts: string[]
14
14
  declared: boolean
15
15
  placement?: Placement
16
- mounting?: { part: string; face: V3Face }
16
+ mounting?: { part: string; face: FigureFace }
17
17
  /**
18
18
  * Where the figure meets its plane, as its parts stand: the part whose bottom is lowest for a floor, whose top is
19
19
  * highest for a ceiling, whose back is furthest back for a wall. What the mounting face is offered as before one is
20
20
  * chosen -- the first part in the list offered a conveyor's bed, 700 mm up on its legs (walk 1, 2026-09-26).
21
21
  */
22
- suggested?: { part: string; face: V3Face }
22
+ suggested?: { part: string; face: FigureFace }
23
23
  }
24
24
 
25
25
  /**
@@ -29,8 +29,8 @@ export interface V3FigureFacts {
29
29
  * records the face only as that node, so this is where the screen learns which one is chosen. Parts are the placed
30
30
  * bodies (`place@1`), in the order the model lists them.
31
31
  */
32
- export function v3FigureFacts(source: string): V3FigureFacts {
33
- const asset = parseV3Asset(source) as V3Asset & { document: { model: { nodes: Array<{ id: string; op: string }> } } }
32
+ export function figureFigureFacts(source: string): FigureFigureFacts {
33
+ const asset = parseFigureAsset(source) as FigureAsset & { document: { model: { nodes: Array<{ id: string; op: string }> } } }
34
34
  const parts = asset.document.model.nodes.filter(node => node.op === 'place@1').map(node => node.id)
35
35
  const feature = (asset.occupancy?.contact as { surface?: { feature?: string } } | undefined)?.surface?.feature
36
36
  const found = feature?.match(/^(.+)\.mount\.(left|right|bottom|top|back|front)\.value$/)
@@ -39,17 +39,17 @@ export function v3FigureFacts(source: string): V3FigureFacts {
39
39
  parts,
40
40
  declared: !!asset.occupancy,
41
41
  placement: asset.occupancy?.placement as Placement | undefined,
42
- mounting: found ? { part: found[1], face: found[2] as V3Face } : undefined,
42
+ mounting: found ? { part: found[1], face: found[2] as FigureFace } : undefined,
43
43
  suggested: suggestedMountOf(asset, parts)
44
44
  }
45
45
  }
46
46
 
47
- function suggestedMountOf(asset: V3Asset, parts: string[]): { part: string; face: V3Face } | undefined {
47
+ function suggestedMountOf(asset: FigureAsset, parts: string[]): { part: string; face: FigureFace } | undefined {
48
48
  const placement = (asset.occupancy?.placement ?? 'floor') as Placement
49
49
  if (placement === 'center' || !parts.length) return undefined
50
50
  let boxes
51
51
  try {
52
- boxes = v3OccupiedBoxesOf(compileV3Asset(asset).evaluate().geometry, v3WritersOf(asset)).filter(b => parts.includes(b.part))
52
+ boxes = figureOccupiedBoxesOf(compileFigureAsset(asset).evaluate().geometry, figureWritersOf(asset)).filter(b => parts.includes(b.part))
53
53
  } catch {
54
54
  return undefined
55
55
  }
@@ -7,14 +7,14 @@ import { CommonPopupStyles, FormFieldStyles } from '@operato/styles'
7
7
  import '@material/web/button/filled-button.js'
8
8
  import '@material/web/button/text-button.js'
9
9
 
10
- import { firstSaveRefusalOf, releasableType, typeOf, type FirstSave } from './v3-first-save.js'
10
+ import { firstSaveRefusalOf, releasableType, typeOf, type FirstSave } from './first-save.js'
11
11
 
12
12
  /**
13
13
  * The first save of a new figure: its type and its name, asked once, in the suite's popup look.
14
14
  * Closes with the answer, or with nothing when cancelled -- then nothing is saved.
15
15
  */
16
- @customElement('figure-v3-first-save')
17
- export class FigureV3FirstSave extends LitElement {
16
+ @customElement('figure-first-save')
17
+ export class FigureFirstSave extends LitElement {
18
18
  static styles = [
19
19
  FormFieldStyles,
20
20
  CommonPopupStyles,
@@ -210,7 +210,7 @@ export class FigureHistoryPanel extends localize(i18next)(LitElement) {
210
210
  /** 저장하지 않은 것이 있나 — 있으면 발행을 막는다. */
211
211
  @property({ type: Boolean }) dirty = false
212
212
  /**
213
- * 행의 타입. 판정 하나(`type-is-placeholder`)가 이것을 본다 — V3 자산은 타입을 원본에 적지 않아서, 타입을 바꾸면
213
+ * 행의 타입. 판정 하나(`type-is-placeholder`)가 이것을 본다 — 자산은 타입을 원본에 적지 않아서, 타입을 바꾸면
214
214
  * 원본도 dirty 도 그대로다. 그래서 이 값이 바뀌면 판정을 다시 묻는다. 안 그러면 타입을 정한 뒤에도 「임시 타입」
215
215
  * 판정이 남아 발행 단추가 잠긴 채다.
216
216
  */
@@ -4,8 +4,8 @@ import { css, html, LitElement, nothing } from 'lit'
4
4
  import { customElement, property, state } from 'lit/decorators.js'
5
5
 
6
6
  import { i18next, localize } from '@operato/i18n'
7
- import { V3_FACES } from '@hatiolab/figure-model'
8
- import type { V3Asset, V3AuthoringAction, V3DimensionSource, V3Face } from '@hatiolab/figure-model'
7
+ import { FIGURE_FACES } from '@hatiolab/figure-model'
8
+ import type { FigureAsset, FigureAuthoringAction, FigureDimensionSource, FigureFace } from '@hatiolab/figure-model'
9
9
 
10
10
  import {
11
11
  acceptsOf,
@@ -43,17 +43,17 @@ import {
43
43
  type Axis,
44
44
  type Follow,
45
45
  type MotionForm
46
- } from './v3-links.js'
46
+ } from './links.js'
47
47
  import { SidePanelStyles } from './side-panel-styles.js'
48
- import { HelpToggles } from './v3-help.js'
48
+ import { HelpToggles } from './help.js'
49
49
 
50
- const FACES = Object.keys(V3_FACES) as V3Face[]
50
+ const FACES = Object.keys(FIGURE_FACES) as FigureFace[]
51
51
 
52
52
  const freshFasten = () => ({
53
- face: 'bottom' as V3Face | 'centre',
53
+ face: 'bottom' as FigureFace | 'centre',
54
54
  toPlane: false,
55
55
  target: '',
56
- targetFace: 'top' as V3Face,
56
+ targetFace: 'top' as FigureFace,
57
57
  facing: 'meet' as 'meet' | 'flush',
58
58
  gap: 0,
59
59
  twist: 0,
@@ -62,7 +62,7 @@ const freshFasten = () => ({
62
62
  })
63
63
  const freshMotion = (): MotionForm => ({ kind: 'slide', axis: 'x', id: '', min: 0, max: 500, follow: '', multiplier: 1, offset: 0, travel: '', travelPlus: 0 })
64
64
  const freshRow = () => ({ axis: '' as Axis | '', pitch: 200, fills: true, count: 5 })
65
- const freshPlace = () => ({ role: 'grip' as 'seat' | 'grip', face: 'top' as V3Face, label: '', accepts: '', capacity: 1 })
65
+ const freshPlace = () => ({ role: 'grip' as 'seat' | 'grip', face: 'top' as FigureFace, label: '', accepts: '', capacity: 1 })
66
66
 
67
67
  /**
68
68
  * What a part is tied to — its size response, what it is fastened to, how it moves.
@@ -73,12 +73,12 @@ const freshPlace = () => ({ role: 'grip' as 'seat' | 'grip', face: 'top' as V3Fa
73
73
  * parts that come away — this is where they do it. Motion is a joint: a slide or a turn driven by a control.
74
74
  *
75
75
  * The sections are dimensions, placement and joint, in that order. Every
76
- * change is one figure-model authoring command, sent as `v3-command` and run by the editor through the session — one
76
+ * change is one figure-model authoring command, sent as `command` and run by the editor through the session — one
77
77
  * step of the undo history. Choices the command would refuse (a round body fastened, a size following an instance
78
78
  * size the figure does not declare) are not offered, so the author is not sent into a refusal.
79
79
  */
80
- @customElement('figure-v3-links')
81
- export class FigureV3Links extends localize(i18next)(LitElement) {
80
+ @customElement('figure-links')
81
+ export class FigureLinks extends localize(i18next)(LitElement) {
82
82
  private readonly help = new HelpToggles(this)
83
83
  static styles = [SidePanelStyles, css`
84
84
  :host {
@@ -110,7 +110,7 @@ export class FigureV3Links extends localize(i18next)(LitElement) {
110
110
  `]
111
111
 
112
112
  /** The asset being edited. */
113
- @property({ attribute: false }) asset?: V3Asset
113
+ @property({ attribute: false }) asset?: FigureAsset
114
114
  /** The selected part. */
115
115
  @property() partId = ''
116
116
  /** The part's own extent along its axes now, in mm — what a dimension is fixed at when it stops following. */
@@ -166,7 +166,7 @@ export class FigureV3Links extends localize(i18next)(LitElement) {
166
166
  }
167
167
 
168
168
  /** Where things are held on this part: a seat things rest on, or a grip things are held in. */
169
- private renderPlaces(asset: V3Asset) {
169
+ private renderPlaces(asset: FigureAsset) {
170
170
  const faces = placeFacesOf(asset, this.partId)
171
171
  const p = this.place
172
172
  const face = faces.includes(p.face) ? p.face : faces[0]!
@@ -196,7 +196,7 @@ export class FigureV3Links extends localize(i18next)(LitElement) {
196
196
  <option value="grip" ?selected=${p.role === 'grip'}>${roleName('grip')}</option>
197
197
  <option value="seat" ?selected=${p.role === 'seat'}>${roleName('seat')}</option>
198
198
  </select>
199
- <select @change=${(e: Event) => (this.place = { ...p, face: (e.target as HTMLSelectElement).value as V3Face })}>
199
+ <select @change=${(e: Event) => (this.place = { ...p, face: (e.target as HTMLSelectElement).value as FigureFace })}>
200
200
  ${faces.map(one => html`<option value=${one} ?selected=${one === face}>${i18next.t('figure.label.face-' + one)}</option>`)}
201
201
  </select>
202
202
  </div>
@@ -230,12 +230,12 @@ export class FigureV3Links extends localize(i18next)(LitElement) {
230
230
  }
231
231
 
232
232
  /** The figure holds things: `Capacity` and `Holdable`, the ladder's middle rung. One part edit, one undo step. */
233
- private declareHolding(asset: V3Asset) {
233
+ private declareHolding(asset: FigureAsset) {
234
234
  const names = [...new Set([...(asset.document.capabilities.names ?? []), 'Capacity', 'Holdable'])]
235
- this.dispatchEvent(new CustomEvent('v3-part-edit', { detail: { edit: { kind: 'set-capabilities', names } }, bubbles: true, composed: true }))
235
+ this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit: { kind: 'set-capabilities', names } }, bubbles: true, composed: true }))
236
236
  }
237
237
 
238
- private renderDimensions(asset: V3Asset) {
238
+ private renderDimensions(asset: FigureAsset) {
239
239
  const others = asset.appearance.map(look => look.target).filter(one => one !== this.partId && canFollow(asset, one))
240
240
  const round = followableAxes(asset, this.partId).length === 2
241
241
  /* One step for the whole part (figure-model follow-size): the size is declared from the parts if there is none. */
@@ -292,12 +292,12 @@ export class FigureV3Links extends localize(i18next)(LitElement) {
292
292
  private followPlus(axis: Axis, now: Follow, plus: number) {
293
293
  if (now.of !== 'instance' && now.of !== 'part') return
294
294
  if ((now.plus ?? 0) === plus) return
295
- const source: V3DimensionSource = now.of === 'instance' ? { of: 'instance', axis: now.axis } : { of: 'part', part: now.part, axis: now.axis }
295
+ const source: FigureDimensionSource = now.of === 'instance' ? { of: 'instance', axis: now.axis } : { of: 'part', part: now.part, axis: now.axis }
296
296
  const times = now.of === 'instance' ? now.times : (now.times ?? 1)
297
297
  this.command({ kind: 'link-dimension', part: this.partId, axis, source, ...(times !== 1 ? { times } : {}), ...(plus ? { plus } : {}), replace: true })
298
298
  }
299
299
 
300
- private follow(asset: V3Asset, axis: Axis, choice: string, now: Follow) {
300
+ private follow(asset: FigureAsset, axis: Axis, choice: string, now: Follow) {
301
301
  const following = now.of !== 'own'
302
302
  /* The measure as it stands: a dimension stops following at it, and a share is taken of it. */
303
303
  const current = dimensionNow(asset, this.partId, axis) ?? this.dims?.[AXES.indexOf(axis)] ?? 100
@@ -315,7 +315,7 @@ export class FigureV3Links extends localize(i18next)(LitElement) {
315
315
  this.command({ kind: 'link-dimension', part: this.partId, axis, source: { of: 'instance', axis: a as Axis }, times, replace: following })
316
316
  return
317
317
  }
318
- const source: V3DimensionSource = of === 'instance' ? { of: 'instance', axis: a as Axis } : { of: 'part', part: a!, axis: b as Axis }
318
+ const source: FigureDimensionSource = of === 'instance' ? { of: 'instance', axis: a as Axis } : { of: 'part', part: a!, axis: b as Axis }
319
319
  this.command({ kind: 'link-dimension', part: this.partId, axis, source, replace: following })
320
320
  }
321
321
 
@@ -323,7 +323,7 @@ export class FigureV3Links extends localize(i18next)(LitElement) {
323
323
  * Positions worked out from other values, each with the way to
324
324
  * keep it where it is. This is the way out the release gate names when a resize leaves a part in the air.
325
325
  */
326
- private renderPositions(asset: V3Asset) {
326
+ private renderPositions(asset: FigureAsset) {
327
327
  return positionsWorkedOut(asset, this.partId).map(
328
328
  axis => html`<div pair>
329
329
  <span>${axis.toUpperCase()} · ${i18next.t(positionIsShare(asset, this.partId, axis) ? 'figure.label.position-in-proportion' : 'figure.label.position-worked-out')}</span>
@@ -343,14 +343,14 @@ export class FigureV3Links extends localize(i18next)(LitElement) {
343
343
  * A new aim for the fastening: where on the face is filled in as where the part stands now, so fastening it keeps it
344
344
  * there (`placeKeptOf`). The author changes it from there.
345
345
  */
346
- private aimAt(asset: V3Asset, f: ReturnType<typeof freshFasten>) {
346
+ private aimAt(asset: FigureAsset, f: ReturnType<typeof freshFasten>) {
347
347
  const theirFaces = f.target ? facesOf(asset, f.target) : FACES
348
348
  const targetFace = theirFaces.includes(f.targetFace) ? f.targetFace : theirFaces[0]!
349
349
  const aim = f.toPlane ? ('plane' as const) : f.target ? { part: f.target, face: targetFace } : undefined
350
350
  this.fasten = { ...f, ...(aim ? placeKeptOf(asset, this.partId, aim, !!f.twist) : { align: {}, alignMm: {} }) }
351
351
  }
352
352
 
353
- private renderFastening(asset: V3Asset) {
353
+ private renderFastening(asset: FigureAsset) {
354
354
  const held = heldBy(asset, this.partId)
355
355
  const f = this.fasten
356
356
  /* Not a part that hangs from this one: fastening a frame to its own roller would close a loop. */
@@ -359,8 +359,8 @@ export class FigureV3Links extends localize(i18next)(LitElement) {
359
359
  /* On the mounting plane only the faces it takes: a bottom or a top on the floor, a back on a wall. */
360
360
  const plane = mountingPlaneOf(asset)
361
361
  /* Its outer faces, and its centre -- a roller spins about its middle (ADR-0093); the mounting plane takes a face. */
362
- const mineFaces: Array<V3Face | 'centre'> = [
363
- ...(facesOf(asset, this.partId).filter(face => FACES.includes(face as V3Face) && (!f.toPlane || plane.faces.includes(face as V3Face))) as V3Face[]),
362
+ const mineFaces: Array<FigureFace | 'centre'> = [
363
+ ...(facesOf(asset, this.partId).filter(face => FACES.includes(face as FigureFace) && (!f.toPlane || plane.faces.includes(face as FigureFace))) as FigureFace[]),
364
364
  ...(f.toPlane ? [] : (['centre'] as const))
365
365
  ]
366
366
  const myFace = mineFaces.includes(f.face) ? f.face : mineFaces[0]!
@@ -379,7 +379,7 @@ export class FigureV3Links extends localize(i18next)(LitElement) {
379
379
  : nothing}
380
380
  <div form>
381
381
  <span>${i18next.t('figure.label.my-face')}</span>
382
- <select @change=${(e: Event) => (this.fasten = { ...f, face: (e.target as HTMLSelectElement).value as V3Face | 'centre' })}>
382
+ <select @change=${(e: Event) => (this.fasten = { ...f, face: (e.target as HTMLSelectElement).value as FigureFace | 'centre' })}>
383
383
  ${mineFaces.map(face => html`<option value=${face} ?selected=${face === myFace}>${i18next.t('figure.label.face-' + face)}</option>`)}
384
384
  </select>
385
385
  </div>
@@ -396,7 +396,7 @@ export class FigureV3Links extends localize(i18next)(LitElement) {
396
396
  ${targets.map(one => html`<option value=${one} ?selected=${one === f.target}>${one}</option>`)}
397
397
  </select>
398
398
  <span>${i18next.t('figure.label.target-face')}</span>
399
- <select @change=${(e: Event) => this.aimAt(asset, { ...f, targetFace: (e.target as HTMLSelectElement).value as V3Face })}>
399
+ <select @change=${(e: Event) => this.aimAt(asset, { ...f, targetFace: (e.target as HTMLSelectElement).value as FigureFace })}>
400
400
  ${theirFaces.map(face => html`<option value=${face} ?selected=${face === targetFace}>${i18next.t('figure.label.face-' + face)}</option>`)}
401
401
  </select>
402
402
  <span>${i18next.t('figure.label.facing-meet')}</span>
@@ -426,7 +426,7 @@ export class FigureV3Links extends localize(i18next)(LitElement) {
426
426
  twist: f.twist,
427
427
  ...(align ? { align } : {}),
428
428
  replace: !!held
429
- } as V3AuthoringAction)}
429
+ } as FigureAuthoringAction)}
430
430
  >
431
431
  <md-icon>link</md-icon>${i18next.t('figure.button.fasten')}
432
432
  </button>
@@ -468,7 +468,7 @@ export class FigureV3Links extends localize(i18next)(LitElement) {
468
468
  * face, copies a pitch apart filling the parent's length, or a count spread over it. Once made, the row's own section
469
469
  * (the editor's) shows it and takes it away.
470
470
  */
471
- private renderRow(asset: V3Asset) {
471
+ private renderRow(asset: FigureAsset) {
472
472
  const axes = rowAxesOf(asset, this.partId)
473
473
  if (!axes.length) return nothing
474
474
  const r = this.row
@@ -497,7 +497,7 @@ export class FigureV3Links extends localize(i18next)(LitElement) {
497
497
  <button
498
498
  act
499
499
  ?disabled=${this.locked || !ok}
500
- @click=${() => this.command({ kind: 'make-repeat', part: this.partId, axis, pitch: r.pitch, ...(r.fills ? {} : { count: r.count }) } as V3AuthoringAction)}
500
+ @click=${() => this.command({ kind: 'make-repeat', part: this.partId, axis, pitch: r.pitch, ...(r.fills ? {} : { count: r.count }) } as FigureAuthoringAction)}
501
501
  >
502
502
  <md-icon>view_week</md-icon>${i18next.t('figure.button.make-repeat')}
503
503
  </button>
@@ -508,12 +508,12 @@ export class FigureV3Links extends localize(i18next)(LitElement) {
508
508
  * When the part is drawn: always, or while a control is at least a value -- a lamp lit while the gate is open. One
509
509
  * part edit (`set-visibility`), one step. Offered once the figure has a control; a motion is what makes one.
510
510
  */
511
- private renderShown(asset: V3Asset) {
511
+ private renderShown(asset: FigureAsset) {
512
512
  const controls = visibilityControlsOf(asset)
513
513
  if (!controls.length) return nothing
514
514
  const now = shownWhenOf(asset, this.partId)
515
515
  const send = (shownWhen: { input: string; atLeast: number } | null) =>
516
- this.dispatchEvent(new CustomEvent('v3-part-edit', { detail: { edit: { kind: 'set-visibility', target: this.partId, shownWhen } }, bubbles: true, composed: true }))
516
+ this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit: { kind: 'set-visibility', target: this.partId, shownWhen } }, bubbles: true, composed: true }))
517
517
  const first = (id: string) => {
518
518
  const c = controls.find(one => one.id === id)!
519
519
  return Math.round((c.min + (c.max - c.min) * 0.01) * 1000) / 1000
@@ -547,7 +547,7 @@ export class FigureV3Links extends localize(i18next)(LitElement) {
547
547
  </div>`
548
548
  }
549
549
 
550
- private renderMotion(asset: V3Asset) {
550
+ private renderMotion(asset: FigureAsset) {
551
551
  const now = motionOf(asset, this.partId)
552
552
  const joint = asset.joints?.find(j => j.body1.part === this.partId)
553
553
  if (now && !(this.editingMotion && joint)) {
@@ -663,8 +663,8 @@ export class FigureV3Links extends localize(i18next)(LitElement) {
663
663
  this.motion = kind === 'slide' ? { ...this.motion, kind, min: 0, max: 500 } : { ...this.motion, kind, min: -90, max: 90 }
664
664
  }
665
665
 
666
- private command(action: V3AuthoringAction) {
667
- this.dispatchEvent(new CustomEvent('v3-command', { detail: { action }, bubbles: true, composed: true }))
666
+ private command(action: FigureAuthoringAction) {
667
+ this.dispatchEvent(new CustomEvent('command', { detail: { action }, bubbles: true, composed: true }))
668
668
  }
669
669
  }
670
670
 
@@ -2,9 +2,9 @@ import { css, html, LitElement, nothing, svg } from 'lit'
2
2
  import { customElement, property, state } from 'lit/decorators.js'
3
3
 
4
4
  import { i18next, localize } from '@operato/i18n'
5
- import { MATERIAL_PRESETS, SEGMENT_PRESETS, v3TrianglesOf } from '@hatiolab/figure-model'
5
+ import { MATERIAL_PRESETS, SEGMENT_PRESETS, figureTrianglesOf } from '@hatiolab/figure-model'
6
6
  import { activePalette } from '@hatiolab/things-scene'
7
- import type { V3AssetGeometry, V3Material, V3PartEdit } from '@hatiolab/figure-model'
7
+ import type { FigureAssetGeometry, FigureMaterial, FigurePartEdit } from '@hatiolab/figure-model'
8
8
  import { SidePanelStyles } from './side-panel-styles.js'
9
9
 
10
10
  /** The purpose each palette role is for, by its token. */
@@ -27,20 +27,20 @@ const ROUND = new Set(['cylinder', 'ellipticCylinder', 'sphere', 'frustum'])
27
27
  const DEFAULT_SEGMENTS = 12
28
28
 
29
29
  /**
30
- * 재질 — a V3 part's material.
30
+ * 재질 — a part's material.
31
31
  *
32
- * An earlier editor showed the colour role as a raw token (`palette.dark`) in a select and nothing else. The V3 material
32
+ * An earlier editor showed the colour role as a raw token (`palette.dark`) in a select and nothing else. The material
33
33
  * holds the colour role, a preset, transparency and a glow; a round body also has how finely its rim is drawn. This
34
34
  * shows those: painted colours and lit colours as two groups of swatches, each named for what it
35
35
  * is for.
36
36
  *
37
- * Not here, because a V3 material has no place for them: flat shading and casting
37
+ * Not here, because a material has no place for them: flat shading and casting
38
38
  * shadows. The glow's colour comes from the lit colours.
39
39
  *
40
- * Every change leaves as one `v3-part-edit`; the editor runs it through the session, one step of the undo history.
40
+ * Every change leaves as one `part-edit`; the editor runs it through the session, one step of the undo history.
41
41
  */
42
- @customElement('figure-v3-material')
43
- export class FigureV3Material extends localize(i18next)(LitElement) {
42
+ @customElement('figure-material-panel')
43
+ export class FigureMaterialPanel extends localize(i18next)(LitElement) {
44
44
  static styles = [SidePanelStyles, css`
45
45
  :host {
46
46
  display: block;
@@ -154,7 +154,7 @@ export class FigureV3Material extends localize(i18next)(LitElement) {
154
154
  `]
155
155
 
156
156
  /** The selected body as evaluated — its material, its segments and its shape. */
157
- @property({ attribute: false }) body?: V3AssetGeometry & { id: string }
157
+ @property({ attribute: false }) body?: FigureAssetGeometry & { id: string }
158
158
  /** The asset's palette, token → colour. */
159
159
  @property({ attribute: false }) palette: Record<string, string> = {}
160
160
  @property({ type: Boolean }) locked = false
@@ -188,7 +188,7 @@ export class FigureV3Material extends localize(i18next)(LitElement) {
188
188
  <label>${i18next.t('figure.label.preset')}</label>
189
189
  <select
190
190
  ?disabled=${this.locked}
191
- @change=${(e: Event) => this.put({ preset: ((e.target as HTMLSelectElement).value || undefined) as V3Material['preset'] })}
191
+ @change=${(e: Event) => this.put({ preset: ((e.target as HTMLSelectElement).value || undefined) as FigureMaterial['preset'] })}
192
192
  >
193
193
  <option value="" ?selected=${!material.preset}>${i18next.t('figure.label.none')}</option>
194
194
  ${MATERIAL_PRESETS.map(
@@ -229,7 +229,7 @@ export class FigureV3Material extends localize(i18next)(LitElement) {
229
229
  </section>`
230
230
  }
231
231
 
232
- private renderSegments(part: V3AssetGeometry & { id: string }) {
232
+ private renderSegments(part: FigureAssetGeometry & { id: string }) {
233
233
  const provider = (part as { shape?: { provider?: string } }).shape?.provider ?? ''
234
234
  if (!ROUND.has(provider)) return nothing
235
235
  const current = part.segments ?? DEFAULT_SEGMENTS
@@ -246,7 +246,7 @@ export class FigureV3Material extends localize(i18next)(LitElement) {
246
246
  >
247
247
  ${silhouette(preset)}
248
248
  <b>${preset}</b>
249
- <small>${i18next.t('figure.text.n-triangles', { count: v3TrianglesOf({ ...part, segments: preset }) })}</small>
249
+ <small>${i18next.t('figure.text.n-triangles', { count: figureTrianglesOf({ ...part, segments: preset }) })}</small>
250
250
  </button>`
251
251
  )}
252
252
  </div>
@@ -289,10 +289,10 @@ export class FigureV3Material extends localize(i18next)(LitElement) {
289
289
  this.put({ emissive: intensity > 0 ? { token: material.emissive?.token ?? material.token, intensity, on: true } : undefined }, live)
290
290
  }
291
291
 
292
- /** A material change: recorded, or -- while a slider is dragged -- only drawn (`v3-part-live`). */
293
- private put(patch: Partial<V3Material>, live = false) {
294
- const material: V3Material = { ...this.body!.material, ...patch }
295
- for (const key of Object.keys(material) as (keyof V3Material)[]) if (material[key] === undefined) delete material[key]
292
+ /** A material change: recorded, or -- while a slider is dragged -- only drawn (`part-live`). */
293
+ private put(patch: Partial<FigureMaterial>, live = false) {
294
+ const material: FigureMaterial = { ...this.body!.material, ...patch }
295
+ for (const key of Object.keys(material) as (keyof FigureMaterial)[]) if (material[key] === undefined) delete material[key]
296
296
  /* The colours this material names that the asset does not carry yet. */
297
297
  const offered = this.offered()
298
298
  const palette = Object.fromEntries(
@@ -300,13 +300,13 @@ export class FigureV3Material extends localize(i18next)(LitElement) {
300
300
  .filter((token): token is string => !!token && this.palette[token] === undefined && offered[token] !== undefined)
301
301
  .map(token => [token, offered[token]!])
302
302
  )
303
- const edit: V3PartEdit = { kind: 'set-material', target: this.body!.id, material, ...(Object.keys(palette).length ? { palette } : {}) }
304
- if (live) this.dispatchEvent(new CustomEvent('v3-part-live', { detail: { edit }, bubbles: true, composed: true }))
303
+ const edit: FigurePartEdit = { kind: 'set-material', target: this.body!.id, material, ...(Object.keys(palette).length ? { palette } : {}) }
304
+ if (live) this.dispatchEvent(new CustomEvent('part-live', { detail: { edit }, bubbles: true, composed: true }))
305
305
  else this.edit(edit)
306
306
  }
307
307
 
308
- private edit(edit: V3PartEdit) {
309
- this.dispatchEvent(new CustomEvent('v3-part-edit', { detail: { edit }, bubbles: true, composed: true }))
308
+ private edit(edit: FigurePartEdit) {
309
+ this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit }, bubbles: true, composed: true }))
310
310
  }
311
311
  }
312
312