@things-factory/figure-ui 10.1.245 → 10.1.247

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 (127) hide show
  1. package/client/modeller/align.ts +51 -13
  2. package/client/modeller/clips.ts +51 -1
  3. package/client/modeller/data-interface.ts +16 -0
  4. package/client/modeller/editor-styles.ts +6 -0
  5. package/client/modeller/editor.ts +112 -25
  6. package/client/modeller/fasten-form.ts +8 -1
  7. package/client/modeller/fasten-geometry.ts +24 -2
  8. package/client/modeller/figure-clips.ts +137 -4
  9. package/client/modeller/figure-fasten-dialog.ts +1 -0
  10. package/client/modeller/figure-fasten-drawing.ts +11 -5
  11. package/client/modeller/figure-links.ts +25 -0
  12. package/client/modeller/figure-material-panel.ts +54 -4
  13. package/client/modeller/figure-parts.ts +7 -2
  14. package/client/modeller/figure-pipe-panel.ts +215 -0
  15. package/client/modeller/figure-preview.ts +125 -4
  16. package/client/modeller/figure-section-editor.ts +36 -3
  17. package/client/modeller/links.ts +24 -2
  18. package/client/modeller/material-edit.ts +9 -0
  19. package/client/modeller/maturity.ts +15 -4
  20. package/client/modeller/palette.ts +9 -0
  21. package/client/modeller/pipe-path.ts +21 -0
  22. package/client/modeller/refusals.ts +66 -1
  23. package/client/modeller/section-controls.ts +2 -1
  24. package/client/modeller/section-drawing.ts +20 -1
  25. package/client/modeller/starting-shape.ts +8 -5
  26. package/dist-client/modeller/align.d.ts +28 -7
  27. package/dist-client/modeller/align.js +37 -12
  28. package/dist-client/modeller/align.js.map +1 -1
  29. package/dist-client/modeller/clips.d.ts +24 -0
  30. package/dist-client/modeller/clips.js +53 -1
  31. package/dist-client/modeller/clips.js.map +1 -1
  32. package/dist-client/modeller/data-interface.d.ts +6 -0
  33. package/dist-client/modeller/data-interface.js +17 -0
  34. package/dist-client/modeller/data-interface.js.map +1 -1
  35. package/dist-client/modeller/editor-styles.js +6 -0
  36. package/dist-client/modeller/editor-styles.js.map +1 -1
  37. package/dist-client/modeller/editor.d.ts +10 -1
  38. package/dist-client/modeller/editor.js +117 -26
  39. package/dist-client/modeller/editor.js.map +1 -1
  40. package/dist-client/modeller/fasten-form.d.ts +2 -0
  41. package/dist-client/modeller/fasten-form.js +5 -1
  42. package/dist-client/modeller/fasten-form.js.map +1 -1
  43. package/dist-client/modeller/fasten-geometry.d.ts +8 -1
  44. package/dist-client/modeller/fasten-geometry.js +22 -1
  45. package/dist-client/modeller/fasten-geometry.js.map +1 -1
  46. package/dist-client/modeller/figure-clips.d.ts +9 -0
  47. package/dist-client/modeller/figure-clips.js +137 -4
  48. package/dist-client/modeller/figure-clips.js.map +1 -1
  49. package/dist-client/modeller/figure-fasten-dialog.js +1 -0
  50. package/dist-client/modeller/figure-fasten-dialog.js.map +1 -1
  51. package/dist-client/modeller/figure-fasten-drawing.d.ts +3 -1
  52. package/dist-client/modeller/figure-fasten-drawing.js +13 -5
  53. package/dist-client/modeller/figure-fasten-drawing.js.map +1 -1
  54. package/dist-client/modeller/figure-links.d.ts +5 -0
  55. package/dist-client/modeller/figure-links.js +22 -0
  56. package/dist-client/modeller/figure-links.js.map +1 -1
  57. package/dist-client/modeller/figure-material-panel.d.ts +2 -0
  58. package/dist-client/modeller/figure-material-panel.js +53 -4
  59. package/dist-client/modeller/figure-material-panel.js.map +1 -1
  60. package/dist-client/modeller/figure-parts.d.ts +1 -1
  61. package/dist-client/modeller/figure-parts.js +5 -1
  62. package/dist-client/modeller/figure-parts.js.map +1 -1
  63. package/dist-client/modeller/figure-pipe-panel.d.ts +29 -0
  64. package/dist-client/modeller/figure-pipe-panel.js +221 -0
  65. package/dist-client/modeller/figure-pipe-panel.js.map +1 -0
  66. package/dist-client/modeller/figure-preview.d.ts +8 -0
  67. package/dist-client/modeller/figure-preview.js +128 -4
  68. package/dist-client/modeller/figure-preview.js.map +1 -1
  69. package/dist-client/modeller/figure-section-editor.d.ts +5 -0
  70. package/dist-client/modeller/figure-section-editor.js +33 -3
  71. package/dist-client/modeller/figure-section-editor.js.map +1 -1
  72. package/dist-client/modeller/links.d.ts +6 -0
  73. package/dist-client/modeller/links.js +17 -2
  74. package/dist-client/modeller/links.js.map +1 -1
  75. package/dist-client/modeller/material-edit.d.ts +8 -0
  76. package/dist-client/modeller/material-edit.js +8 -0
  77. package/dist-client/modeller/material-edit.js.map +1 -1
  78. package/dist-client/modeller/maturity.js +16 -5
  79. package/dist-client/modeller/maturity.js.map +1 -1
  80. package/dist-client/modeller/palette.js +9 -0
  81. package/dist-client/modeller/palette.js.map +1 -1
  82. package/dist-client/modeller/pipe-path.d.ts +19 -0
  83. package/dist-client/modeller/pipe-path.js +14 -0
  84. package/dist-client/modeller/pipe-path.js.map +1 -0
  85. package/dist-client/modeller/refusals.d.ts +12 -1
  86. package/dist-client/modeller/refusals.js +67 -0
  87. package/dist-client/modeller/refusals.js.map +1 -1
  88. package/dist-client/modeller/section-controls.js +2 -1
  89. package/dist-client/modeller/section-controls.js.map +1 -1
  90. package/dist-client/modeller/section-drawing.d.ts +5 -0
  91. package/dist-client/modeller/section-drawing.js +19 -1
  92. package/dist-client/modeller/section-drawing.js.map +1 -1
  93. package/dist-client/modeller/starting-shape.d.ts +9 -2
  94. package/dist-client/modeller/starting-shape.js +8 -3
  95. package/dist-client/modeller/starting-shape.js.map +1 -1
  96. package/dist-client/tsconfig.tsbuildinfo +1 -1
  97. package/package.json +8 -8
  98. package/test/align.test.ts +28 -6
  99. package/test/browser/editing-page.js +21 -1
  100. package/test/browser/editing.check.mjs +124 -0
  101. package/test/browser/links.check.mjs +49 -8
  102. package/test/browser/modeller.check.mjs +27 -1
  103. package/test/browser/part-ids.check.mjs +60 -3
  104. package/test/browser/parts.check.mjs +2 -2
  105. package/test/browser/places-mesh.check.mjs +14 -8
  106. package/test/browser/screen.check.mjs +54 -1
  107. package/test/browser/section-page.js +7 -1
  108. package/test/browser/section.check.mjs +81 -0
  109. package/test/browser/side-panel-sweep.check.mjs +13 -0
  110. package/test/clips.test.ts +30 -1
  111. package/test/data-motion.test.ts +14 -1
  112. package/test/fasten-geometry.test.ts +13 -2
  113. package/test/joint-frames.test.ts +12 -2
  114. package/test/links.test.ts +24 -0
  115. package/test/material.test.ts +15 -1
  116. package/test/maturity.test.ts +19 -1
  117. package/test/palette-icons.test.ts +2 -1
  118. package/test/pipe-panel.test.ts +33 -0
  119. package/test/refusals.test.ts +29 -0
  120. package/test/revision.test.ts +1 -1
  121. package/test/section-editor.test.ts +17 -1
  122. package/translations/en.json +86 -3
  123. package/translations/es.json +86 -3
  124. package/translations/ja.json +86 -3
  125. package/translations/ko.json +86 -3
  126. package/translations/ms.json +86 -3
  127. package/translations/zh.json +86 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"figure-pipe-panel.js","sourceRoot":"","sources":["../../client/modeller/figure-pipe-panel.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\nimport { live } from 'lit/directives/live.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { FIGURE_SWEEP_PIECE_LIMIT, type FigureEvaluatedShape, type FigurePipeRequest } from '@hatiolab/figure-model'\nimport { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js'\nimport { bendWordOf, piecesOf, QUARTERS, type PanelPiece } from './pipe-path.js'\n\ntype Body = { id: string; shape: FigureEvaluatedShape }\n/**\n * 관 — a pipe's or a duct's section, wall and path (ADR-0100 §16.2), each change one `set-pipe` command, one step of the\n * history. The path is its pieces in order: a straight run, so long; a bend, of a radius, so many degrees, toward one of\n * four directions across the pipe -- each said as the figure's axis it turns to there. What the kernel refuses (a bend\n * tighter than the section, a wall too thick, a path through itself) is said by the editor, with the number it takes.\n */\n@customElement('figure-pipe-panel')\nexport class FigurePipePanel extends localize(i18next)(LitElement) {\n static styles = [\n SidePanelStyles,\n css`\n :host {\n display: block;\n }\n div[pipe] {\n display: grid;\n gap: 8px;\n }\n ol[pieces] {\n display: grid;\n gap: 6px;\n margin: 0;\n padding: 0;\n list-style: none;\n }\n ol[pieces] li {\n display: grid;\n grid-template-columns: 20px minmax(0, 1fr) 30px;\n gap: 4px 6px;\n align-items: center;\n padding: 6px 0;\n border-top: 1px dashed var(--md-sys-color-outline-variant);\n }\n ol[pieces] li > b {\n font-variant-numeric: tabular-nums;\n opacity: 0.7;\n }\n ol[pieces] li div[form] {\n grid-column: 2;\n }\n ol[pieces] li button[act] {\n width: 30px;\n min-height: var(--figure-control-height);\n margin: 0;\n padding: 0;\n }\n div[pair] {\n display: flex;\n gap: 6px;\n }\n div[pair] > button {\n flex: 1;\n }\n md-icon {\n font-size: 16px;\n width: 16px;\n height: 16px;\n }\n `\n ]\n\n @property({ attribute: false }) body?: Body\n @property({ type: Boolean }) locked = false\n\n private send(request: FigurePipeRequest) {\n this.dispatchEvent(new CustomEvent('command', { detail: { action: { kind: 'set-pipe', part: this.body!.id, ...request } }, bubbles: true, composed: true }))\n }\n\n /** A number field: sent on change, put back when it is not a number. */\n private number(label: string, now: number, set: (value: number) => void, options: { min?: number; step?: string; note?: string } = {}) {\n return html`<span>${label}</span>\n <div>\n <input\n type=\"number\"\n step=${options.step ?? 'any'}\n min=${options.min ?? 0}\n aria-label=${label}\n ?disabled=${this.locked}\n .value=${live(String(Math.round(now * 1000) / 1000))}\n @change=${(e: Event) => {\n const input = e.target as HTMLInputElement\n const value = input.valueAsNumber\n if (!Number.isFinite(value)) {\n input.value = String(now)\n return\n }\n set(value)\n }}\n />\n ${options.note ? html`<small>${options.note}</small>` : nothing}\n </div>`\n }\n\n /**\n * Its end's size: the same as its start's until changed, when it narrows or widens to it evenly along its length\n * (ADR-0100 §16.2.9) -- a bar thick below and thin above. 「한 굵기로」 makes it one size all along again.\n */\n private renderEnd(sweep: NonNullable<FigureEvaluatedShape['sweep']>, round: boolean) {\n const s = sweep.section,\n to = sweep.to\n const same = html`<span></span>\n <div>\n <button act end-same ?disabled=${this.locked} @click=${() => this.send(round ? { endRadius: null } : { endWidth: null, endDepth: null })}>\n ${i18next.t('figure.button.pipe-end-same')}\n </button>\n </div>`\n if (round) {\n const now = to?.kind === 'ellipse' ? 2 * to.radius.x! : s.kind === 'ellipse' ? 2 * s.radius.x! : 0\n return html`${this.number(i18next.t('figure.label.pipe-end-diameter'), now, value => this.send({ endRadius: value / 2 }), { note: to ? '' : i18next.t('figure.text.pipe-end-same') })}\n ${to ? same : nothing}`\n }\n if (s.kind !== 'rectangle') return nothing\n const end = to?.kind === 'rectangle' ? to.size : s.size\n return html`${this.number(i18next.t('figure.label.pipe-end-width'), end.x!, value => this.send({ endWidth: value }), { note: to ? '' : i18next.t('figure.text.pipe-end-same') })}\n ${this.number(i18next.t('figure.label.pipe-end-depth'), end.z!, value => this.send({ endDepth: value }))}\n ${to ? same : nothing}`\n }\n\n render() {\n const sweep = this.body?.shape.sweep\n if (!sweep) return nothing\n const s = sweep.section\n const round = s.kind === 'ellipse'\n const pieces = piecesOf(sweep)\n const withPiece = (i: number, piece: PanelPiece) => this.send({ path: pieces.map((p, j) => (j === i ? piece : p)) })\n const radius = round ? s.radius.x ?? s.radius.z ?? 0 : 0\n /* The group's heading is the part's properties' own, as a box's size group's is: here only what is in it. */\n return html`<div pipe>\n <div form>\n <span>${i18next.t('figure.label.pipe-section')}</span>\n <select\n aria-label=${i18next.t('figure.label.pipe-section')}\n ?disabled=${this.locked}\n @change=${(e: Event) => {\n const to = (e.target as HTMLSelectElement).value\n if (to === 'round' && !round) this.send({ radius: Math.min(s.kind === 'rectangle' ? s.size.x! : 0, s.kind === 'rectangle' ? s.size.z! : 0) / 2 })\n if (to === 'square' && round) this.send({ width: 2 * radius, depth: 2 * radius, round: 0 })\n }}\n >\n <option value=\"round\" ?selected=${round}>${i18next.t('figure.label.pipe-section-round')}</option>\n <option value=\"square\" ?selected=${!round}>${i18next.t('figure.label.pipe-section-square')}</option>\n </select>\n ${round\n ? this.number(i18next.t('figure.label.pipe-diameter'), 2 * radius, value => this.send({ radius: value / 2 }))\n : s.kind === 'rectangle'\n ? html`${this.number(i18next.t('figure.label.pipe-width'), s.size.x!, value => this.send({ width: value }))}\n ${this.number(i18next.t('figure.label.pipe-depth'), s.size.z!, value => this.send({ depth: value }))}\n ${this.number(i18next.t('figure.label.pipe-round'), s.corner?.x ?? 0, value => this.send({ round: value }))}`\n : nothing}\n ${this.renderEnd(sweep, round)}\n ${this.number(i18next.t('figure.label.pipe-wall'), sweep.wall ?? 0, value => this.send({ wall: value }), { note: i18next.t('figure.text.pipe-wall-zero') })}\n </div>\n <ol pieces aria-label=${i18next.t('figure.label.pipe-path')}>\n ${pieces.map(\n (p, i) => html`<li>\n <b>${i + 1}</b>\n <div form>\n ${'line' in p\n ? this.number(i18next.t('figure.label.pipe-line-length'), p.line, value => withPiece(i, { line: value }))\n : html`${this.number(i18next.t('figure.label.pipe-bend-radius'), p.bend.radius, value => withPiece(i, { bend: { ...p.bend, radius: value } }))}\n ${this.number(i18next.t('figure.label.pipe-bend-angle'), p.bend.angle, value => withPiece(i, { bend: { ...p.bend, angle: Math.round(value) } }), { min: 1, step: '1' })}\n <span>${i18next.t('figure.label.pipe-bend-toward')}</span>\n <select\n aria-label=${i18next.t('figure.label.pipe-bend-toward')}\n ?disabled=${this.locked}\n @change=${(e: Event) => withPiece(i, { bend: { ...p.bend, toward: Number((e.target as HTMLSelectElement).value) } })}\n >\n ${[...new Set([...QUARTERS, p.bend.toward])].map(\n t => html`<option value=${t} ?selected=${t === p.bend.toward}>${bendWordOf(sweep, i, t) || `${t}°`}</option>`\n )}\n </select>`}\n </div>\n <button\n act\n ?disabled=${this.locked || pieces.length <= 1}\n title=${i18next.t('figure.button.pipe-remove-piece')}\n aria-label=${i18next.t('figure.button.pipe-remove-piece')}\n @click=${() => this.send({ path: pieces.filter((_, j) => j !== i) })}\n >\n <md-icon>close</md-icon>\n </button>\n </li>`\n )}\n </ol>\n <div pair>\n <button act add-line ?disabled=${this.locked || pieces.length >= FIGURE_SWEEP_PIECE_LIMIT} @click=${() => this.send({ path: [...pieces, { line: 100 }] })}>\n <md-icon>add</md-icon>${i18next.t('figure.button.pipe-add-line')}\n </button>\n <button\n act\n add-bend\n ?disabled=${this.locked || pieces.length >= FIGURE_SWEEP_PIECE_LIMIT}\n @click=${() => {\n /* A bend wider than the section, toward its first quarter: 90° of twice the section's reach. */\n const reach = round ? radius : Math.hypot(s.kind === 'rectangle' ? s.size.x! : 0, s.kind === 'rectangle' ? s.size.z! : 0) / 2\n this.send({ path: [...pieces, { bend: { radius: Math.ceil(2 * reach), angle: 90, toward: 0 } }] })\n }}\n >\n <md-icon>add</md-icon>${i18next.t('figure.button.pipe-add-bend')}\n </button>\n </div>\n </div>`\n }\n}\n"]}
@@ -37,6 +37,10 @@ export declare class FigurePreview extends FigurePreview_base {
37
37
  private setupPart;
38
38
  /** One figure stretched by sliders, or the eight ways of growing side by side. */
39
39
  private way;
40
+ /** Where the camera looks from; a new scene starts in perspective. */
41
+ private looking;
42
+ /** The posing controls folded to their one button. */
43
+ private controlsFolded;
40
44
  /** The size the one figure is tried at; the authored size when the figure stands up. */
41
45
  private trying?;
42
46
  private board;
@@ -52,6 +56,7 @@ export declare class FigurePreview extends FigurePreview_base {
52
56
  private registered?;
53
57
  private watcher?;
54
58
  render(): import("lit-html").TemplateResult<1>;
59
+ private lookFrom;
55
60
  /** The one figure's size: a slider per axis the figure lets change, and what it is at the size tried. */
56
61
  private renderSizes;
57
62
  private followTags;
@@ -67,6 +72,9 @@ export declare class FigurePreview extends FigurePreview_base {
67
72
  private move;
68
73
  private renderDial;
69
74
  private drive;
75
+ private release;
76
+ /** Every value tried here let go: the figure stands in its default pose, and its clips move it again. Nothing is saved. */
77
+ private clearTried;
70
78
  private give;
71
79
  private poseAsDefault;
72
80
  private tellInstances;
@@ -7,11 +7,14 @@ import * as THREE from 'three';
7
7
  import { compileFigureAsset } from '@hatiolab/figure-model';
8
8
  import { create, figureLegendSourcesChanged, registerFigure, unregisterFigure } from '@hatiolab/things-scene';
9
9
  import { DEFAULT_VIEW, previewBoardDepth, sceneLook, WORKBENCH } from '@things-factory/figure-viewer/dist-client/figure-view.js';
10
+ import { parametersForClip } from '@things-factory/figure-viewer/dist-client/detail-motion.js';
11
+ import { controlsOf } from '@things-factory/figure-viewer/dist-client/controls.js';
10
12
  import { dialShape } from './angle-dial.js';
11
- import { domainOf, motionWrittenByData, typedValueOf, valueRowsOf } from './data-interface.js';
13
+ import { dataValueAt, domainOf, motionWrittenByData, typedValueOf, valueRowsOf } from './data-interface.js';
12
14
  import { derivedOf } from './revision.js';
13
15
  import { authoredSizeOf, bodyAtSize, PREVIEW_FACTOR, PREVIEW_WAYS, previewClampsOf, previewInstances, previewOneInstance, previewTypeOf, setupPartOf, sizeSpanOf, sizeWithinRange } from '@things-factory/figure-viewer/dist-client/preview-model.js';
14
16
  import { previewSizeWordsOf } from './preview-size.js';
17
+ const PREVIEW_VIEWS = ['perspective', 'front', 'right', 'top'];
15
18
  let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
16
19
  constructor() {
17
20
  super(...arguments);
@@ -42,6 +45,10 @@ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
42
45
  this.setupPart = '';
43
46
  /** One figure stretched by sliders, or the eight ways of growing side by side. */
44
47
  this.way = 'one';
48
+ /** Where the camera looks from; a new scene starts in perspective. */
49
+ this.looking = 'perspective';
50
+ /** The posing controls folded to their one button. */
51
+ this.controlsFolded = false;
45
52
  this.board = { width: 0, height: 0 };
46
53
  /* The eight variants named over each one, where the camera shows it (sweep 2026-10-27 M4). */
47
54
  this.tags = [];
@@ -146,6 +153,23 @@ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
146
153
  cursor: pointer;
147
154
  opacity: 0.7;
148
155
  }
156
+ div[legend] button[view] {
157
+ padding: 0 6px;
158
+ font: inherit;
159
+ color: inherit;
160
+ background: none;
161
+ border: none;
162
+ border-radius: 4px;
163
+ cursor: pointer;
164
+ opacity: 0.7;
165
+ }
166
+ div[legend] span[views] {
167
+ display: flex;
168
+ gap: 2px;
169
+ padding-left: 6px;
170
+ border-left: 1px solid rgba(255, 255, 255, 0.22);
171
+ }
172
+ div[legend] button[view][aria-pressed='true'],
149
173
  div[legend] button[way][aria-pressed='true'] {
150
174
  opacity: 1;
151
175
  background-color: rgba(255, 255, 255, 0.18);
@@ -196,7 +220,7 @@ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
196
220
  div[clips] {
197
221
  margin-left: auto;
198
222
  display: grid;
199
- grid-template-columns: auto 20px 96px 34px;
223
+ grid-template-columns: auto 20px 96px 44px;
200
224
  gap: 6px 8px;
201
225
  align-items: center;
202
226
  padding: 8px 10px;
@@ -239,6 +263,20 @@ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
239
263
  fill: none;
240
264
  stroke: rgba(255, 255, 255, 0.35);
241
265
  }
266
+ /* Folded, the controls are one button: what they covered -- a leg, say -- can be seen (robot dog 2026-11-03). */
267
+ div[clips] button[fold-controls] {
268
+ justify-self: end;
269
+ padding: 0 4px;
270
+ font: inherit;
271
+ color: inherit;
272
+ background: none;
273
+ border: none;
274
+ cursor: pointer;
275
+ opacity: 0.75;
276
+ }
277
+ div[clips] button[fold-controls]:hover {
278
+ opacity: 1;
279
+ }
242
280
  div[clips] button[pose] {
243
281
  align-self: stretch;
244
282
  padding: 4px 8px;
@@ -275,6 +313,17 @@ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
275
313
  grid-column: 3 / -1;
276
314
  width: auto;
277
315
  }
316
+ /* A control's value, typed where the slider cannot land on it (a step of the range's hundredth, robot dog 2026-11-03). */
317
+ div[clips] input[typed] {
318
+ width: 100%;
319
+ padding: 0 3px;
320
+ text-align: right;
321
+ font-variant-numeric: tabular-nums;
322
+ }
323
+ div[clips] label[sampled] output {
324
+ grid-column: 3 / -1;
325
+ text-align: left;
326
+ }
278
327
  div[clips] output {
279
328
  font-variant-numeric: tabular-nums;
280
329
  text-align: right;
@@ -328,6 +377,9 @@ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
328
377
  ? html `<div cannot>${this.cannot}</div>`
329
378
  : html `<div legend>
330
379
  ${['one', 'eight'].map(way => html `<button way=${way} aria-pressed=${String(this.way === way)} @click=${() => this.chooseWay(way)}>${i18next.t(`figure.label.preview-way-${way}`)}</button>`)}
380
+ <span views>
381
+ ${PREVIEW_VIEWS.map(view => html `<button view=${view} aria-pressed=${String(this.looking === view)} @click=${() => this.lookFrom(view)}>${i18next.t(`figure.label.preview-view-${view}`)}</button>`)}
382
+ </span>
331
383
  ${this.way === 'one' ? nothing : PREVIEW_WAYS.map(way => {
332
384
  const clamps = clampsByWay[way.name] ?? [];
333
385
  return html `<span>
@@ -348,6 +400,10 @@ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
348
400
  </div>` : nothing}
349
401
  ${controls.length + clips.length + (asset?.motionGroups?.length ?? 0) + (asset ? valueRowsOf(asset).length : 0) ? this.renderDrivers(asset, controls, clips) : nothing}</div>`}`;
350
402
  }
403
+ lookFrom(view) {
404
+ this.scene?.root?.setCameraView?.(view);
405
+ this.looking = view;
406
+ }
351
407
  /** The one figure's size: a slider per axis the figure lets change, and what it is at the size tried. */
352
408
  renderSizes(asset, size) {
353
409
  const say = (key, params) => i18next.t(key, params);
@@ -440,16 +496,29 @@ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
440
496
  this.scene?.root?.fitCameraToModel?.();
441
497
  }
442
498
  renderDrivers(asset, controls, clips) {
499
+ const steps = new Map(controlsOf(asset).map(c => [c.id, c.step]));
443
500
  const changed = controls.filter(c => this.giving[c.id] !== undefined && this.giving[c.id] !== asset.stateDefaults[c.id]);
501
+ const fold = html `<button fold-controls aria-expanded=${String(!this.controlsFolded)} @click=${() => (this.controlsFolded = !this.controlsFolded)}>
502
+ ${i18next.t(this.controlsFolded ? 'figure.button.controls-unfold' : 'figure.button.controls-fold')}
503
+ </button>`;
504
+ if (this.controlsFolded)
505
+ return html `<div clips folded>${fold}</div>`;
444
506
  return html `<div clips>
507
+ ${fold}
445
508
  ${changed.length
446
509
  ? html `<button pose title=${i18next.t('figure.text.pose-as-default-explained')} @click=${() => this.poseAsDefault()}>
447
510
  ${i18next.t('figure.button.pose-as-default')}
448
511
  </button>`
449
512
  : nothing}
513
+ ${Object.keys(this.giving).length
514
+ ? html `<button clear-tried title=${i18next.t('figure.text.clear-tried-explained')} @click=${() => this.clearTried()}>
515
+ ${i18next.t('figure.button.clear-tried')}
516
+ </button>`
517
+ : nothing}
450
518
  ${controls.map(control => {
451
519
  const value = this.giving[control.id] ?? asset.stateDefaults[control.id] ?? control.min;
452
- const step = Math.max((control.max - control.min) / 100, 0.01);
520
+ /* The step the editor's controls take (\`controlsOf\`): a degree for an angle, a hundredth of the range otherwise. */
521
+ const step = steps.get(control.id) ?? (control.max - control.min) / 100;
453
522
  const label = asset.stateInputs?.[control.id]?.label ?? control.id;
454
523
  return html `<label>
455
524
  <span>${label} <span drive>${unitWord(control.unit)}</span></span>
@@ -462,7 +531,20 @@ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
462
531
  .value=${String(value)}
463
532
  @input=${(e) => this.give(control.id, Number(e.target.value))}
464
533
  />
465
- <output>${Math.round(value)}</output>
534
+ <input
535
+ typed
536
+ type="number"
537
+ step="any"
538
+ min=${control.min}
539
+ max=${control.max}
540
+ aria-label=${label}
541
+ .value=${String(Math.round(value * 100) / 100)}
542
+ @change=${(e) => {
543
+ const typed = e.target.valueAsNumber;
544
+ if (Number.isFinite(typed))
545
+ this.give(control.id, Math.min(Math.max(typed, control.min), control.max));
546
+ }}
547
+ />
466
548
  </label>`;
467
549
  })}
468
550
  ${clips.map(clip => {
@@ -506,6 +588,16 @@ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
506
588
  renderDataValue(row) {
507
589
  const node = row.node;
508
590
  const label = row.label ?? row.path;
591
+ /*
592
+ The data tab's sample, when it gives the row, is what the figure shows: a value given here is not read. Said, and
593
+ the field not offered, rather than one that changes nothing (robot dog 2026-11-03).
594
+ */
595
+ const sampled = this.sample === null || this.sample === undefined ? undefined : dataValueAt(this.sample, row.path);
596
+ if (sampled !== undefined)
597
+ return html `<label sampled title=${i18next.t('figure.text.data-value-from-sample')}>
598
+ <span>${label} <span drive>${i18next.t('figure.label.data-value-from-sample')}</span></span>
599
+ <output>${typeof sampled === 'object' ? JSON.stringify(sampled) : String(sampled)}</output>
600
+ </label>`;
509
601
  const fallback = 'default' in node ? node.default : undefined;
510
602
  const value = this.valuing[row.path] ?? fallback;
511
603
  if (node.kind === 'number') {
@@ -545,6 +637,7 @@ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
545
637
  }
546
638
  move(group, playing) {
547
639
  this.moving = { ...this.moving, [group]: playing };
640
+ this.release(playing.clip);
548
641
  this.tellInstances('motion', Object.fromEntries(Object.entries(this.moving).map(([id, m]) => [id, { ...m, paused: false }])));
549
642
  }
550
643
  renderDial(control, value) {
@@ -560,8 +653,30 @@ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
560
653
  }
561
654
  drive(clip, value) {
562
655
  this.driving = { ...this.driving, [clip]: value };
656
+ if (value)
657
+ this.release(clip);
563
658
  this.tellInstances('clips', this.driving);
564
659
  }
660
+ /*
661
+ A value given here wins over the clips for its control (things-scene's \`parameters\`), so a value left from trying held
662
+ the control still while a clip played (robot dog, 2026-11-03). A clip played lets go of the controls it drives, as
663
+ the detail view does (\`parametersForClip\`).
664
+ */
665
+ release(clip) {
666
+ const asset = this.asset;
667
+ if (!asset)
668
+ return;
669
+ const next = parametersForClip(asset, this.giving, clip);
670
+ if (Object.keys(next).length === Object.keys(this.giving).length)
671
+ return;
672
+ this.giving = next;
673
+ this.tellInstances('parameters', this.giving);
674
+ }
675
+ /** Every value tried here let go: the figure stands in its default pose, and its clips move it again. Nothing is saved. */
676
+ clearTried() {
677
+ this.giving = {};
678
+ this.tellInstances('parameters', this.giving);
679
+ }
565
680
  give(id, value) {
566
681
  this.giving = { ...this.giving, [id]: value };
567
682
  this.tellInstances('parameters', this.giving);
@@ -714,6 +829,7 @@ let FigurePreview = class FigurePreview extends localize(i18next)(LitElement) {
714
829
  mode: 0
715
830
  });
716
831
  this.standing = signature;
832
+ this.looking = 'perspective';
717
833
  this.scene.resize?.();
718
834
  this.scene.fit?.('ratio');
719
835
  this.scene.root?.fitCameraToModel?.();
@@ -796,6 +912,14 @@ __decorate([
796
912
  state(),
797
913
  __metadata("design:type", String)
798
914
  ], FigurePreview.prototype, "way", void 0);
915
+ __decorate([
916
+ state(),
917
+ __metadata("design:type", String)
918
+ ], FigurePreview.prototype, "looking", void 0);
919
+ __decorate([
920
+ state(),
921
+ __metadata("design:type", Object)
922
+ ], FigurePreview.prototype, "controlsFolded", void 0);
799
923
  __decorate([
800
924
  state(),
801
925
  __metadata("design:type", Object)