@things-factory/figure-ui 10.1.265 → 10.1.266
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.
- package/client/modeller/align.ts +13 -1
- package/client/modeller/clips.ts +90 -1
- package/client/modeller/editor-styles.ts +36 -0
- package/client/modeller/editor.ts +53 -6
- package/client/modeller/figure-clips.ts +82 -34
- package/client/modeller/joint-drag.ts +32 -2
- package/dist-client/modeller/align.d.ts +5 -0
- package/dist-client/modeller/align.js +10 -1
- package/dist-client/modeller/align.js.map +1 -1
- package/dist-client/modeller/clips.d.ts +56 -4
- package/dist-client/modeller/clips.js +89 -0
- package/dist-client/modeller/clips.js.map +1 -1
- package/dist-client/modeller/editor-styles.js +36 -0
- package/dist-client/modeller/editor-styles.js.map +1 -1
- package/dist-client/modeller/editor.d.ts +7 -0
- package/dist-client/modeller/editor.js +58 -5
- package/dist-client/modeller/editor.js.map +1 -1
- package/dist-client/modeller/figure-clips.d.ts +13 -1
- package/dist-client/modeller/figure-clips.js +87 -34
- package/dist-client/modeller/figure-clips.js.map +1 -1
- package/dist-client/modeller/joint-drag.d.ts +21 -2
- package/dist-client/modeller/joint-drag.js +20 -1
- package/dist-client/modeller/joint-drag.js.map +1 -1
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/test/align.test.ts +18 -0
- package/test/clips.test.ts +83 -0
- package/test/joint-drag.test.ts +49 -0
- package/test/joint-frames.test.ts +3 -2
- package/translations/en.json +22 -2
- package/translations/es.json +22 -2
- package/translations/ja.json +22 -2
- package/translations/ko.json +22 -2
- package/translations/ms.json +22 -2
- package/translations/zh.json +22 -2
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import '@material/web/icon/icon.js';
|
|
2
2
|
import { LitElement, nothing } from 'lit';
|
|
3
|
+
import type { PropertyValues } from 'lit';
|
|
3
4
|
import type { FigureAsset } from '@hatiolab/figure-model';
|
|
4
5
|
declare const FigureClips_base: (new (...args: any[]) => LitElement) & typeof LitElement;
|
|
5
6
|
/**
|
|
@@ -9,7 +10,11 @@ declare const FigureClips_base: (new (...args: any[]) => LitElement) & typeof Li
|
|
|
9
10
|
* then kept as a key. Every change is one part edit.
|
|
10
11
|
*
|
|
11
12
|
* Clips of one motion group play one at a time on the same controls -- idle, walk, run (ADR-0051 §3.2): only clips of
|
|
12
|
-
* one group may play the same control
|
|
13
|
+
* one group may play the same control. A new clip on a control another clip plays is put in a group as it is made --
|
|
14
|
+
* that clip's, or one made of the two -- and the panel says so before the button is pressed (review 2026-11-09).
|
|
15
|
+
*
|
|
16
|
+
* 「이 자세 기억하기」 keeps the pose the figure stands in now at the scrubbed moment, every control that moved, in one
|
|
17
|
+
* step. What moved is read against the pose the clip was last shown or kept in (`base`).
|
|
13
18
|
*/
|
|
14
19
|
export declare class FigureClips extends FigureClips_base {
|
|
15
20
|
private readonly help;
|
|
@@ -24,8 +29,13 @@ export declare class FigureClips extends FigureClips_base {
|
|
|
24
29
|
private grouping;
|
|
25
30
|
/** The track whose copy is being set up: onto which control, how many seconds later. */
|
|
26
31
|
private copying?;
|
|
32
|
+
/** Per clip, the pose it was last shown or kept in: a control that differs from it now has been moved by the person. */
|
|
33
|
+
private base;
|
|
34
|
+
protected willUpdate(changed: PropertyValues): void;
|
|
27
35
|
render(): import("lit-html").TemplateResult<1> | typeof nothing;
|
|
28
36
|
private renderClip;
|
|
37
|
+
/** 「이 자세 기억하기」: every control moved since the clip's pose was last shown or kept, as keys at this moment, one step. */
|
|
38
|
+
private renderRemember;
|
|
29
39
|
private renderTrack;
|
|
30
40
|
/**
|
|
31
41
|
* A track onto a control -- itself, or another -- moved round its loop by some seconds: one leg's curve given to the
|
|
@@ -46,5 +56,7 @@ export declare class FigureClips extends FigureClips_base {
|
|
|
46
56
|
/** A key's moment or value typed: one edit of the track; a moment the track cannot take puts the field back. */
|
|
47
57
|
private changeKey;
|
|
48
58
|
private edit;
|
|
59
|
+
/** Several edits as one step of the history. */
|
|
60
|
+
private edits;
|
|
49
61
|
}
|
|
50
62
|
export {};
|
|
@@ -4,7 +4,7 @@ import { css, html, LitElement, nothing } from 'lit';
|
|
|
4
4
|
import { customElement, property, state } from 'lit/decorators.js';
|
|
5
5
|
import { i18next, localize } from '@operato/i18n';
|
|
6
6
|
import { unitWord } from './unit-words.js';
|
|
7
|
-
import { clipGroupsOf, withKeyChanged, clipsOf, copiedTrackEdit, copyTargetsOf, freeClipNameOf, freeGroupIdOf, groupEdit, poseAt, shiftable, trackEdit, undrivenOf, withKey, withoutKey } from './clips.js';
|
|
7
|
+
import { clipGroupsOf, withKeyChanged, clipsOf, copiedTrackEdit, copyTargetsOf, freeClipNameOf, freeGroupIdOf, groupEdit, newClipEdits, newTrackKeys, poseAt, rememberedPoseEdits, shiftable, shiftOffKeyOf, trackEdit, undrivenOf, withKey, withoutKey } from './clips.js';
|
|
8
8
|
import { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js';
|
|
9
9
|
import { HelpToggles } from './help.js';
|
|
10
10
|
/** A value as a person reads it: at most three decimals, the float's last digits (14.399999999999999) left out. */
|
|
@@ -18,7 +18,11 @@ const typed = (value) => String(Math.round(value * 1000) / 1000);
|
|
|
18
18
|
* then kept as a key. Every change is one part edit.
|
|
19
19
|
*
|
|
20
20
|
* Clips of one motion group play one at a time on the same controls -- idle, walk, run (ADR-0051 §3.2): only clips of
|
|
21
|
-
* one group may play the same control
|
|
21
|
+
* one group may play the same control. A new clip on a control another clip plays is put in a group as it is made --
|
|
22
|
+
* that clip's, or one made of the two -- and the panel says so before the button is pressed (review 2026-11-09).
|
|
23
|
+
*
|
|
24
|
+
* 「이 자세 기억하기」 keeps the pose the figure stands in now at the scrubbed moment, every control that moved, in one
|
|
25
|
+
* step. What moved is read against the pose the clip was last shown or kept in (`base`).
|
|
22
26
|
*/
|
|
23
27
|
let FigureClips = class FigureClips extends localize(i18next)(LitElement) {
|
|
24
28
|
constructor() {
|
|
@@ -29,8 +33,10 @@ let FigureClips = class FigureClips extends localize(i18next)(LitElement) {
|
|
|
29
33
|
this.locked = false;
|
|
30
34
|
/** Where each clip is scrubbed to, in seconds. */
|
|
31
35
|
this.at = {};
|
|
32
|
-
this.adding = { state: '', clip: '', name: '', duration: 2
|
|
36
|
+
this.adding = { state: '', clip: '', name: '', duration: 2 };
|
|
33
37
|
this.grouping = { clip: '', label: '' };
|
|
38
|
+
/** Per clip, the pose it was last shown or kept in: a control that differs from it now has been moved by the person. */
|
|
39
|
+
this.base = {};
|
|
34
40
|
}
|
|
35
41
|
static { this.styles = [SidePanelStyles, css `
|
|
36
42
|
:host {
|
|
@@ -70,6 +76,11 @@ let FigureClips = class FigureClips extends localize(i18next)(LitElement) {
|
|
|
70
76
|
min-width: 0;
|
|
71
77
|
overflow-wrap: anywhere;
|
|
72
78
|
}
|
|
79
|
+
/* How it moves between keys: its own row under the head, as wide as the track, its words not cut. */
|
|
80
|
+
div[track-head] select[interpolation] {
|
|
81
|
+
grid-row: 3;
|
|
82
|
+
grid-column: 1 / -1;
|
|
83
|
+
}
|
|
73
84
|
div[track-head] button[act] {
|
|
74
85
|
width: 30px;
|
|
75
86
|
min-height: var(--figure-control-height);
|
|
@@ -144,6 +155,15 @@ let FigureClips = class FigureClips extends localize(i18next)(LitElement) {
|
|
|
144
155
|
height: 16px;
|
|
145
156
|
}
|
|
146
157
|
`]; }
|
|
158
|
+
willUpdate(changed) {
|
|
159
|
+
if (!changed.has('asset') || !this.asset)
|
|
160
|
+
return;
|
|
161
|
+
/* A clip seen for the first time takes the pose the figure stands in now as where its moves are read from. */
|
|
162
|
+
const names = clipsOf(this.asset).map(c => c.name);
|
|
163
|
+
const fresh = names.filter(n => !this.base[n]);
|
|
164
|
+
if (fresh.length)
|
|
165
|
+
this.base = { ...Object.fromEntries(Object.entries(this.base).filter(([n]) => names.includes(n))), ...Object.fromEntries(fresh.map(n => [n, { ...this.values }])) };
|
|
166
|
+
}
|
|
147
167
|
render() {
|
|
148
168
|
const asset = this.asset;
|
|
149
169
|
if (!asset)
|
|
@@ -202,9 +222,23 @@ let FigureClips = class FigureClips extends localize(i18next)(LitElement) {
|
|
|
202
222
|
/>s
|
|
203
223
|
</label>
|
|
204
224
|
</div>
|
|
225
|
+
${this.renderRemember(clip, at)}
|
|
205
226
|
${clip.tracks.map(track => this.renderTrack(clip, track, at))}
|
|
206
227
|
</section>`;
|
|
207
228
|
}
|
|
229
|
+
/** 「이 자세 기억하기」: every control moved since the clip's pose was last shown or kept, as keys at this moment, one step. */
|
|
230
|
+
renderRemember(clip, at) {
|
|
231
|
+
const { edits, skipped } = rememberedPoseEdits(this.asset, clip.name, at, this.values, this.base[clip.name] ?? this.values);
|
|
232
|
+
const label = (id) => this.asset.stateInputs?.[id]?.label ?? id;
|
|
233
|
+
return html `<button act remember-pose ?disabled=${this.locked || !edits.length} title=${edits.length ? '' : i18next.t('figure.text.remember-pose-nothing')}
|
|
234
|
+
@click=${() => {
|
|
235
|
+
this.edits(edits);
|
|
236
|
+
this.base = { ...this.base, [clip.name]: { ...this.values } };
|
|
237
|
+
}}>
|
|
238
|
+
<md-icon>photo_camera</md-icon>${i18next.t('figure.button.remember-pose', { seconds: at.toFixed(2) })}
|
|
239
|
+
</button>
|
|
240
|
+
${skipped.length ? html `<p hint>${i18next.t('figure.text.remember-pose-skipped', { controls: skipped.map(label).join(', ') })}</p>` : nothing}`;
|
|
241
|
+
}
|
|
208
242
|
renderTrack(clip, track, at) {
|
|
209
243
|
const current = this.values[track.state];
|
|
210
244
|
return html `<div track>
|
|
@@ -218,6 +252,15 @@ let FigureClips = class FigureClips extends localize(i18next)(LitElement) {
|
|
|
218
252
|
<option value="wrap" ?selected=${track.loop === 'wrap'}>${i18next.t('figure.label.clip-loop-wrap')}</option>
|
|
219
253
|
<option value="hold" ?selected=${track.loop === 'hold'}>${i18next.t('figure.label.clip-loop-hold')}</option>
|
|
220
254
|
</select>
|
|
255
|
+
<select
|
|
256
|
+
interpolation
|
|
257
|
+
aria-label=${i18next.t('figure.label.clip-interpolation')}
|
|
258
|
+
title=${i18next.t('figure.label.clip-interpolation')}
|
|
259
|
+
?disabled=${this.locked}
|
|
260
|
+
@change=${(e) => this.edit(trackEdit(clip, track, { interpolation: e.target.value }))}
|
|
261
|
+
>
|
|
262
|
+
${['linear', 'smooth', 'step'].map(i => html `<option value=${i} ?selected=${track.interpolation === i}>${i18next.t(`figure.label.clip-interpolation-${i}`)}</option>`)}
|
|
263
|
+
</select>
|
|
221
264
|
<button act copy-track ?disabled=${this.locked} title=${i18next.t('figure.button.copy-track')} aria-label=${i18next.t('figure.button.copy-track')}
|
|
222
265
|
@click=${() => (this.copying = this.copying?.clip === clip.name && this.copying.state === track.state ? undefined : { clip: clip.name, state: track.state, target: track.state, seconds: 0 })}>
|
|
223
266
|
<md-icon>content_copy</md-icon>
|
|
@@ -279,6 +322,8 @@ let FigureClips = class FigureClips extends localize(i18next)(LitElement) {
|
|
|
279
322
|
const moves = shiftable(track);
|
|
280
323
|
const seconds = moves && Number.isFinite(c.seconds) ? c.seconds : 0;
|
|
281
324
|
const same = c.target === track.state && !seconds;
|
|
325
|
+
/* A smooth track goes round only onto one of its keys: said, with the moments it can go to, and not applied. */
|
|
326
|
+
const fits = moves ? shiftOffKeyOf(track, clip.duration, seconds) : null;
|
|
282
327
|
return html `<div copy-form>
|
|
283
328
|
<div form>
|
|
284
329
|
<span>${i18next.t('figure.label.copy-track-onto')}</span>
|
|
@@ -292,8 +337,9 @@ let FigureClips = class FigureClips extends localize(i18next)(LitElement) {
|
|
|
292
337
|
<small>/ ${typed(clip.duration)}s</small>
|
|
293
338
|
</label>
|
|
294
339
|
</div>
|
|
340
|
+
${fits ? html `<p hint off-key>${i18next.t('figure.text.copy-track-off-key', { seconds: fits.map(typed).join(', ') })}</p>` : nothing}
|
|
295
341
|
<div pair>
|
|
296
|
-
<button act ?disabled=${this.locked || same}
|
|
342
|
+
<button act ?disabled=${this.locked || same || !!fits}
|
|
297
343
|
@click=${() => {
|
|
298
344
|
this.edit(copiedTrackEdit(asset, clip, track, c.target, seconds));
|
|
299
345
|
this.copying = undefined;
|
|
@@ -305,10 +351,12 @@ let FigureClips = class FigureClips extends localize(i18next)(LitElement) {
|
|
|
305
351
|
renderAdd(asset, clips) {
|
|
306
352
|
const a = this.adding;
|
|
307
353
|
const joining = clips.find(c => c.name === a.clip);
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
354
|
+
/*
|
|
355
|
+
The controls a track can take. Joining a clip: those it may play. A new clip: any control -- one another clip
|
|
356
|
+
plays puts the new clip in a group with it, said below before the button is pressed (review 2026-11-09: the
|
|
357
|
+
controls used to vanish from the list, and the group had to be designed first).
|
|
358
|
+
*/
|
|
359
|
+
const free = joining ? undrivenOf(asset, joining.name) : asset.document.model.inputs.filter(i => i.role === 'state').map(i => i.id);
|
|
312
360
|
const stateId = free.includes(a.state) ? a.state : free[0];
|
|
313
361
|
const name = joining ? joining.name : a.name.trim();
|
|
314
362
|
const input = asset.document.model.inputs.find(i => i.id === stateId);
|
|
@@ -316,6 +364,15 @@ let FigureClips = class FigureClips extends localize(i18next)(LitElement) {
|
|
|
316
364
|
/* A new clip takes a name no clip has: the same name would rewrite that clip's track, not add one. */
|
|
317
365
|
const taken = !joining && clips.some(c => c.name === name);
|
|
318
366
|
const ready = !!name && !taken && duration > 0 && !!input;
|
|
367
|
+
const join = !joining && input && name ? newClipEdits(asset, stateId, name, duration, []).join : undefined;
|
|
368
|
+
const add = (keys) => {
|
|
369
|
+
if (joining)
|
|
370
|
+
this.edit({ kind: 'set-driver', state: stateId, clip: name, keys });
|
|
371
|
+
else
|
|
372
|
+
this.edits(newClipEdits(asset, stateId, name, duration, keys).edits);
|
|
373
|
+
/* The name was this clip's; the next new clip is named again. */
|
|
374
|
+
this.adding = { ...a, name: '', state: '' };
|
|
375
|
+
};
|
|
319
376
|
return html `<section><h3>${i18next.t('figure.label.add-track')}</h3>
|
|
320
377
|
<div form>
|
|
321
378
|
<span>${i18next.t('figure.label.controls')}</span>
|
|
@@ -327,13 +384,6 @@ let FigureClips = class FigureClips extends localize(i18next)(LitElement) {
|
|
|
327
384
|
<option value="" ?selected=${!joining}>${i18next.t('figure.label.new-clip')}</option>
|
|
328
385
|
${clips.map(c => html `<option value=${c.name} ?selected=${c === joining}>${c.name}</option>`)}
|
|
329
386
|
</select>
|
|
330
|
-
${joining || !groups.length
|
|
331
|
-
? nothing
|
|
332
|
-
: html `<span>${i18next.t('figure.label.motion-group')}</span>
|
|
333
|
-
<select @change=${(e) => (this.adding = { ...a, group: e.target.value })}>
|
|
334
|
-
<option value="" ?selected=${!group}>${i18next.t('figure.label.no-motion-group')}</option>
|
|
335
|
-
${groups.map(g => html `<option value=${g.id} ?selected=${g === group}>${g.label}</option>`)}
|
|
336
|
-
</select>`}
|
|
337
387
|
${joining
|
|
338
388
|
? nothing
|
|
339
389
|
: html `<span>${i18next.t('figure.label.clip-name')}</span>
|
|
@@ -341,26 +391,17 @@ let FigureClips = class FigureClips extends localize(i18next)(LitElement) {
|
|
|
341
391
|
<span>${i18next.t('figure.label.clip-duration')}</span>
|
|
342
392
|
<input type="number" min="0.1" step="any" .value=${String(a.duration)} @change=${(e) => (this.adding = { ...a, duration: e.target.valueAsNumber })} />`}
|
|
343
393
|
</div>
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
state: stateId,
|
|
351
|
-
clip: name,
|
|
352
|
-
...(joining ? {} : { duration }),
|
|
353
|
-
...(group ? { group: group.id } : {}),
|
|
354
|
-
keys: [
|
|
355
|
-
{ seconds: 0, value: input.min },
|
|
356
|
-
{ seconds: duration, value: input.max }
|
|
357
|
-
]
|
|
358
|
-
});
|
|
359
|
-
/* The name was this clip's; the next new clip is named again. */
|
|
360
|
-
this.adding = { ...a, name: '', state: '' };
|
|
361
|
-
}}
|
|
362
|
-
>
|
|
394
|
+
${join?.kind === 'new-group'
|
|
395
|
+
? html `<p hint track-join>${i18next.t('figure.text.track-makes-group', { clip: join.clip, name, group: join.label })}</p>`
|
|
396
|
+
: join?.kind === 'group'
|
|
397
|
+
? html `<p hint track-join>${i18next.t('figure.text.track-joins-group', { name, group: join.label })}</p>`
|
|
398
|
+
: nothing}
|
|
399
|
+
<button act ?disabled=${this.locked || !ready} @click=${() => add(newTrackKeys(input, this.values[stateId], duration))}>
|
|
363
400
|
<md-icon>add</md-icon>${i18next.t('figure.button.add-track')}
|
|
401
|
+
</button>
|
|
402
|
+
<button act range-track ?disabled=${this.locked || !ready} title=${i18next.t('figure.text.add-track-range-explained')}
|
|
403
|
+
@click=${() => add(newTrackKeys(input, this.values[stateId], duration, 'range'))}>
|
|
404
|
+
<md-icon>swap_horiz</md-icon>${i18next.t('figure.button.add-track-range')}
|
|
364
405
|
</button></section>`;
|
|
365
406
|
}
|
|
366
407
|
/**
|
|
@@ -474,6 +515,8 @@ let FigureClips = class FigureClips extends localize(i18next)(LitElement) {
|
|
|
474
515
|
return;
|
|
475
516
|
}
|
|
476
517
|
this.dispatchEvent(new CustomEvent('states', { detail: { changes }, bubbles: true, composed: true }));
|
|
518
|
+
/* The clip's pose shown: what moves from here is the person's. */
|
|
519
|
+
this.base = { ...this.base, [clip.name]: { ...this.values, ...Object.fromEntries(changes.map(c => [c.input, c.value])) } };
|
|
477
520
|
}
|
|
478
521
|
/** A key's moment or value typed: one edit of the track; a moment the track cannot take puts the field back. */
|
|
479
522
|
changeKey(clip, track, index, patch, e) {
|
|
@@ -489,6 +532,12 @@ let FigureClips = class FigureClips extends localize(i18next)(LitElement) {
|
|
|
489
532
|
edit(edit) {
|
|
490
533
|
this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit }, bubbles: true, composed: true }));
|
|
491
534
|
}
|
|
535
|
+
/** Several edits as one step of the history. */
|
|
536
|
+
edits(edits) {
|
|
537
|
+
if (edits.length === 1)
|
|
538
|
+
return this.edit(edits[0]);
|
|
539
|
+
this.dispatchEvent(new CustomEvent('part-edits', { detail: { edits }, bubbles: true, composed: true }));
|
|
540
|
+
}
|
|
492
541
|
};
|
|
493
542
|
__decorate([
|
|
494
543
|
property({ attribute: false }),
|
|
@@ -518,6 +567,10 @@ __decorate([
|
|
|
518
567
|
state(),
|
|
519
568
|
__metadata("design:type", Object)
|
|
520
569
|
], FigureClips.prototype, "copying", void 0);
|
|
570
|
+
__decorate([
|
|
571
|
+
state(),
|
|
572
|
+
__metadata("design:type", Object)
|
|
573
|
+
], FigureClips.prototype, "base", void 0);
|
|
521
574
|
FigureClips = __decorate([
|
|
522
575
|
customElement('figure-clips')
|
|
523
576
|
], FigureClips);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"figure-clips.js","sourceRoot":"","sources":["../../client/modeller/figure-clips.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { unitWord } from './unit-words.js'\nimport type { FigureAsset } from '@hatiolab/figure-model'\n\nimport { clipGroupsOf, withKeyChanged, clipsOf, copiedTrackEdit, copyTargetsOf, freeClipNameOf, freeGroupIdOf, groupEdit, poseAt, shiftable, trackEdit, undrivenOf, withKey, withoutKey, type Clip, type ClipGroup, type ClipTrack } from './clips.js'\nimport { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js'\nimport { HelpToggles } from './help.js'\n\n/** A value as a person reads it: at most three decimals, the float's last digits (14.399999999999999) left out. */\nconst shown = (value: number) => value.toLocaleString(undefined, { maximumFractionDigits: 3 })\n/* A number field's value: no grouping, to a thousandth. */\nconst typed = (value: number) => String(Math.round(value * 1000) / 1000)\n\n/**\n * 클립 — controls played by keys over time. A clip is one clock; each track plays one\n * control. Scrubbing a clip shows its pose at that moment (one batch of input changes, not saved as the default); a key\n * is added at the scrubbed moment with the control's value there, so a pose is made with the controls' sliders and\n * then kept as a key. Every change is one part edit.\n *\n * Clips of one motion group play one at a time on the same controls -- idle, walk, run (ADR-0051 §3.2): only clips of\n * one group may play the same control, so a new clip is put in a group as it is made when it is to take one.\n */\n@customElement('figure-clips')\nexport class FigureClips extends localize(i18next)(LitElement) {\n private readonly help = new HelpToggles(this)\n static styles = [SidePanelStyles, css`\n :host {\n display: block;\n }\n section[clip] {\n display: grid;\n gap: 8px;\n padding: 8px;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 8px;\n }\n div[row] {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 72px;\n gap: 6px;\n align-items: center;\n }\n div[track] {\n display: grid;\n gap: 4px;\n padding-top: 6px;\n border-top: 1px dashed var(--md-sys-color-outline-variant);\n }\n /*\n The track's name on its own line, then how it repeats and the button that removes it. A flex row let the shared\n full-width select and button squeeze the name to one letter a line (user, 2026-09-24).\n */\n div[track-head] {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 30px 30px;\n gap: 4px 6px;\n align-items: center;\n }\n div[track-head] strong {\n grid-column: 1 / -1;\n min-width: 0;\n overflow-wrap: anywhere;\n }\n div[track-head] button[act] {\n width: 30px;\n min-height: var(--figure-control-height);\n margin: 0;\n padding: 0;\n }\n /* A track copied onto a control, moved round its loop: under its head, in the panel's form look. */\n div[copy-form] {\n display: grid;\n gap: 6px;\n padding: 6px 8px;\n border-radius: 6px;\n background: var(--md-sys-color-surface-container);\n }\n div[copy-form] div[pair] {\n display: flex;\n gap: 6px;\n justify-content: flex-end;\n }\n div[keys] {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n }\n span[key] {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 0 2px 0 8px;\n border-radius: 999em;\n background: var(--md-sys-color-surface-container);\n font-variant-numeric: tabular-nums;\n }\n /* A key's moment and value, typed in the chip: as narrow as their numbers, on the chip's ground. */\n span[key] input {\n width: 44px;\n min-width: 0;\n height: 20px;\n padding: 0 2px;\n font: inherit;\n text-align: right;\n font-variant-numeric: tabular-nums;\n color: inherit;\n background: transparent;\n border: none;\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n span[key] input[readonly] {\n border-bottom-color: transparent;\n }\n label[at] {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n font-variant-numeric: tabular-nums;\n }\n label[at] input {\n width: 52px;\n min-width: 0;\n text-align: right;\n }\n span[key] button {\n width: 22px;\n height: 22px;\n padding: 0;\n border: none;\n background: none;\n }\n md-icon {\n font-size: 16px;\n width: 16px;\n height: 16px;\n }\n `]\n\n @property({ attribute: false }) asset?: FigureAsset\n /** The values the editor holds now, by input id -- what a new key takes. */\n @property({ attribute: false }) values: Record<string, number> = {}\n @property({ type: Boolean }) locked = false\n\n /** Where each clip is scrubbed to, in seconds. */\n @state() private at: Record<string, number> = {}\n @state() private adding = { state: '', clip: '', name: '', duration: 2, group: '' }\n @state() private grouping = { clip: '', label: '' }\n /** The track whose copy is being set up: onto which control, how many seconds later. */\n @state() private copying?: { clip: string; state: string; target: string; seconds: number }\n\n render() {\n const asset = this.asset\n if (!asset) return nothing\n const clips = clipsOf(asset)\n /* Nothing to play yet: said inside the section it belongs to, with the section's own margins. */\n const empty = !clips.length && !undrivenOf(asset).length && !asset.motionGroups?.length\n return html`\n <section>\n <h3>${i18next.t('figure.label.clips')}${this.help.button('figure.text.clips-explained')}</h3>\n ${this.help.hint('figure.text.clips-explained')}\n ${clips.map(clip => this.renderClip(clip))}\n ${empty ? html`<p hint>${i18next.t('figure.text.no-clips')}</p>` : nothing}\n </section>\n ${empty ? nothing : this.renderAdd(asset, clips)} ${this.renderGroups(asset)}\n `\n }\n\n private renderClip(clip: Clip) {\n const at = Math.min(this.at[clip.name] ?? 0, clip.duration)\n const number = (e: Event) => (e.target as HTMLInputElement).valueAsNumber\n /* A copy plays the same controls: only clips of one motion group may (ADR-0051 §3.2). */\n const grouped = !!this.asset?.motionGroups?.some(g => g.clips.includes(clip.name))\n return html`<section clip>\n <div form>\n <span>${i18next.t('figure.label.clip-name')}</span>\n <input .value=${clip.name} ?disabled=${this.locked} @change=${(e: Event) => this.edit({ kind: 'set-clip', clip: clip.name, name: (e.target as HTMLInputElement).value })} />\n <span>${i18next.t('figure.label.clip-duration')}</span>\n <input type=\"number\" min=\"0.1\" step=\"any\" .value=${String(clip.duration)} ?disabled=${this.locked} @change=${(e: Event) => this.edit({ kind: 'set-clip', clip: clip.name, duration: number(e) })} />\n </div>\n <button act copy-clip ?disabled=${this.locked || !grouped} title=${i18next.t(grouped ? 'figure.text.copy-clip-explained' : 'figure.text.copy-clip-needs-group')}\n @click=${() => this.edit({ kind: 'copy-clip', clip: clip.name, name: freeClipNameOf(this.asset!, clip.name) })}>\n <md-icon>content_copy</md-icon>${i18next.t('figure.button.copy-clip')}\n </button>\n <div row>\n <input\n type=\"range\"\n min=\"0\"\n max=${clip.duration}\n step=${clip.duration / 100}\n .value=${String(at)}\n ?disabled=${this.locked}\n aria-label=${i18next.t('figure.label.clip-time')}\n @input=${(e: Event) => this.scrub(clip, number(e), true)}\n @change=${(e: Event) => this.scrub(clip, number(e))}\n />\n <label at>\n <input\n type=\"number\"\n min=\"0\"\n max=${clip.duration}\n step=\"any\"\n .value=${String(Math.round(at * 1000) / 1000)}\n ?disabled=${this.locked}\n aria-label=${i18next.t('figure.label.clip-time')}\n @change=${(e: Event) => this.scrub(clip, Math.min(Math.max(number(e), 0), clip.duration))}\n />s\n </label>\n </div>\n ${clip.tracks.map(track => this.renderTrack(clip, track, at))}\n </section>`\n }\n\n private renderTrack(clip: Clip, track: ClipTrack, at: number) {\n const current = this.values[track.state]\n return html`<div track>\n <div track-head>\n <strong>${track.label} <small>(${unitWord(track.unit)})</small></strong>\n <select\n aria-label=${i18next.t('figure.label.clip-loop')}\n ?disabled=${this.locked}\n @change=${(e: Event) => this.edit(trackEdit(clip, track, { loop: (e.target as HTMLSelectElement).value as 'wrap' | 'hold' }))}\n >\n <option value=\"wrap\" ?selected=${track.loop === 'wrap'}>${i18next.t('figure.label.clip-loop-wrap')}</option>\n <option value=\"hold\" ?selected=${track.loop === 'hold'}>${i18next.t('figure.label.clip-loop-hold')}</option>\n </select>\n <button act copy-track ?disabled=${this.locked} title=${i18next.t('figure.button.copy-track')} aria-label=${i18next.t('figure.button.copy-track')}\n @click=${() => (this.copying = this.copying?.clip === clip.name && this.copying.state === track.state ? undefined : { clip: clip.name, state: track.state, target: track.state, seconds: 0 })}>\n <md-icon>content_copy</md-icon>\n </button>\n <button act ?disabled=${this.locked} title=${i18next.t('figure.button.remove-track')} @click=${() => this.edit({ kind: 'remove-driver', state: track.state, clip: clip.name })}>\n <md-icon>close</md-icon>\n </button>\n </div>\n ${this.copying?.clip === clip.name && this.copying.state === track.state ? this.renderCopy(clip, track) : nothing}\n <div keys>\n ${track.keys.map(\n (key, i) => html`<span key\n ><input\n type=\"number\"\n step=\"any\"\n min=\"0\"\n max=${clip.duration}\n ?readonly=${i === 0}\n ?disabled=${this.locked}\n title=${i === 0 ? i18next.t('figure.text.key-starts-the-clip') : ''}\n aria-label=${`${i18next.t('figure.label.key-seconds')} ${i + 1}`}\n .value=${typed(key.seconds)}\n @change=${(e: Event) => this.changeKey(clip, track, i, { seconds: (e.target as HTMLInputElement).valueAsNumber }, e)}\n />s →\n <input\n type=\"number\"\n step=\"any\"\n ?disabled=${this.locked}\n aria-label=${`${i18next.t('figure.label.key-value')} ${i + 1}`}\n .value=${typed(key.value)}\n @change=${(e: Event) => this.changeKey(clip, track, i, { value: (e.target as HTMLInputElement).valueAsNumber }, e)}\n />\n <button\n ?disabled=${this.locked || !withoutKey(track.keys, i)}\n title=${i18next.t('figure.button.remove-key')}\n aria-label=${i18next.t('figure.button.remove-key')}\n @click=${() => this.edit(trackEdit(clip, track, { keys: withoutKey(track.keys, i)! }))}\n >\n <md-icon>close</md-icon>\n </button></span\n >`\n )}\n </div>\n <button\n act\n ?disabled=${this.locked || current === undefined}\n @click=${() => this.edit(trackEdit(clip, track, { keys: withKey(track.keys, { seconds: Math.round(at * 1000) / 1000, value: current! }) }))}\n >\n <md-icon>add</md-icon>${i18next.t('figure.button.add-key-here', { seconds: at.toFixed(2), value: current === undefined ? '' : shown(current) })}\n </button>\n </div>`\n }\n\n /**\n * A track onto a control -- itself, or another -- moved round its loop by some seconds: one leg's curve given to the\n * next on its own beat (robot dog 2026-11-03). Only a wrapping track moves round; any track is copied.\n */\n private renderCopy(clip: Clip, track: ClipTrack) {\n const c = this.copying!\n const asset = this.asset!\n const targets = copyTargetsOf(asset, clip.name)\n const moves = shiftable(track)\n const seconds = moves && Number.isFinite(c.seconds) ? c.seconds : 0\n const same = c.target === track.state && !seconds\n return html`<div copy-form>\n <div form>\n <span>${i18next.t('figure.label.copy-track-onto')}</span>\n <select aria-label=${i18next.t('figure.label.copy-track-onto')} @change=${(e: Event) => (this.copying = { ...c, target: (e.target as HTMLSelectElement).value })}>\n ${targets.map(id => html`<option value=${id} ?selected=${id === c.target}>${id === track.state ? i18next.t('figure.label.copy-track-itself') : (asset.stateInputs?.[id]?.label ?? id)}</option>`)}\n </select>\n <span>${i18next.t('figure.label.copy-track-later')}</span>\n <label at title=${moves ? '' : i18next.t('figure.text.copy-track-no-loop')}>\n <input type=\"number\" step=\"any\" aria-label=${i18next.t('figure.label.copy-track-later')} ?disabled=${!moves} .value=${typed(seconds)}\n @change=${(e: Event) => (this.copying = { ...c, seconds: (e.target as HTMLInputElement).valueAsNumber })} />s\n <small>/ ${typed(clip.duration)}s</small>\n </label>\n </div>\n <div pair>\n <button act ?disabled=${this.locked || same}\n @click=${() => {\n this.edit(copiedTrackEdit(asset, clip, track, c.target, seconds))\n this.copying = undefined\n }}>${i18next.t(c.target === track.state ? 'figure.button.shift-track' : 'figure.button.copy-track-apply')}</button>\n <button act @click=${() => (this.copying = undefined)}>${i18next.t('figure.button.cancel')}</button>\n </div>\n </div>`\n }\n\n private renderAdd(asset: FigureAsset, clips: Clip[]) {\n const a = this.adding\n const joining = clips.find(c => c.name === a.clip)\n const { groups } = clipGroupsOf(asset)\n const group = joining ? undefined : groups.find(g => g.id === a.group)\n /* The controls this clip may take: not played by it yet, and by no clip outside its group. */\n const free = undrivenOf(asset, joining?.name ?? '', group?.id)\n const stateId = free.includes(a.state) ? a.state : free[0]\n const name = joining ? joining.name : a.name.trim()\n const input = asset.document.model.inputs.find(i => i.id === stateId)\n const duration = joining ? joining.duration : a.duration\n /* A new clip takes a name no clip has: the same name would rewrite that clip's track, not add one. */\n const taken = !joining && clips.some(c => c.name === name)\n const ready = !!name && !taken && duration > 0 && !!input\n return html`<section><h3>${i18next.t('figure.label.add-track')}</h3>\n <div form>\n <span>${i18next.t('figure.label.controls')}</span>\n <select ?disabled=${!free.length} @change=${(e: Event) => (this.adding = { ...a, state: (e.target as HTMLSelectElement).value })}>\n ${free.map(id => html`<option value=${id} ?selected=${id === stateId}>${asset.stateInputs?.[id]?.label ?? id}</option>`)}\n </select>\n <span>${i18next.t('figure.label.clip')}</span>\n <select @change=${(e: Event) => (this.adding = { ...a, clip: (e.target as HTMLSelectElement).value })}>\n <option value=\"\" ?selected=${!joining}>${i18next.t('figure.label.new-clip')}</option>\n ${clips.map(c => html`<option value=${c.name} ?selected=${c === joining}>${c.name}</option>`)}\n </select>\n ${joining || !groups.length\n ? nothing\n : html`<span>${i18next.t('figure.label.motion-group')}</span>\n <select @change=${(e: Event) => (this.adding = { ...a, group: (e.target as HTMLSelectElement).value })}>\n <option value=\"\" ?selected=${!group}>${i18next.t('figure.label.no-motion-group')}</option>\n ${groups.map(g => html`<option value=${g.id} ?selected=${g === group}>${g.label}</option>`)}\n </select>`}\n ${joining\n ? nothing\n : html`<span>${i18next.t('figure.label.clip-name')}</span>\n <input .value=${a.name} placeholder=\"cycle\" @input=${(e: Event) => (this.adding = { ...a, name: (e.target as HTMLInputElement).value })} />\n <span>${i18next.t('figure.label.clip-duration')}</span>\n <input type=\"number\" min=\"0.1\" step=\"any\" .value=${String(a.duration)} @change=${(e: Event) => (this.adding = { ...a, duration: (e.target as HTMLInputElement).valueAsNumber })} />`}\n </div>\n <button\n act\n ?disabled=${this.locked || !ready}\n @click=${() => {\n this.edit({\n kind: 'set-driver',\n state: stateId,\n clip: name,\n ...(joining ? {} : { duration }),\n ...(group ? { group: group.id } : {}),\n keys: [\n { seconds: 0, value: input!.min },\n { seconds: duration, value: input!.max }\n ]\n })\n /* The name was this clip's; the next new clip is named again. */\n this.adding = { ...a, name: '', state: '' }\n }}\n >\n <md-icon>add</md-icon>${i18next.t('figure.button.add-track')}\n </button></section>`\n }\n\n /**\n * The motion groups: a name, the clip that plays until another is chosen, how long a change of clip blends, and the\n * clips each holds. A group is made from a clip in none; a clip in none joins one here. Every change is one edit.\n */\n private renderGroups(asset: FigureAsset) {\n const { groups, free } = clipGroupsOf(asset)\n if (!groups.length && !free.length) return nothing\n const g = this.grouping\n const first = free.includes(g.clip) ? g.clip : free[0]\n return html`<section>\n <h3>${i18next.t('figure.label.motion-groups')}${this.help.button('figure.text.motion-groups-explained')}</h3>\n ${this.help.hint('figure.text.motion-groups-explained')}\n ${groups.map(group => this.renderGroup(group, free))}\n ${free.length\n ? html`<div form>\n <span>${i18next.t('figure.label.motion-group-name')}</span>\n <input .value=${g.label} placeholder=${i18next.t('figure.label.motion-group')} @input=${(e: Event) => (this.grouping = { ...g, label: (e.target as HTMLInputElement).value })} />\n <span>${i18next.t('figure.label.clip')}</span>\n <select @change=${(e: Event) => (this.grouping = { ...g, clip: (e.target as HTMLSelectElement).value })}>\n ${free.map(c => html`<option value=${c} ?selected=${c === first}>${c}</option>`)}\n </select>\n </div>\n <button\n act\n ?disabled=${this.locked || !first || !g.label.trim()}\n @click=${() => {\n this.edit({ kind: 'set-motion-group', group: { id: freeGroupIdOf(asset), label: g.label.trim(), clips: [first!], defaultClip: first!, transitionSeconds: 0.2 } })\n this.grouping = { clip: '', label: '' }\n }}\n >\n <md-icon>add</md-icon>${i18next.t('figure.button.add-motion-group')}\n </button>`\n : nothing}\n </section>`\n }\n\n private renderGroup(group: ClipGroup, free: string[]) {\n const value = (e: Event) => (e.target as HTMLInputElement | HTMLSelectElement).value\n return html`<section clip>\n <div track-head>\n <strong>${group.label}</strong>\n <button act ?disabled=${this.locked} title=${i18next.t('figure.button.remove-motion-group')} @click=${() => this.edit({ kind: 'remove-motion-group', id: group.id })}>\n <md-icon>close</md-icon>\n </button>\n </div>\n <div form>\n <span>${i18next.t('figure.label.motion-group-name')}</span>\n <input .value=${group.label} ?disabled=${this.locked} @change=${(e: Event) => value(e).trim() && this.edit(groupEdit(group, { label: value(e).trim() }))} />\n <span>${i18next.t('figure.label.motion-group-default')}</span>\n <select ?disabled=${this.locked} @change=${(e: Event) => this.edit(groupEdit(group, { defaultClip: value(e) }))}>\n ${group.clips.map(c => html`<option value=${c} ?selected=${c === group.defaultClip}>${c}</option>`)}\n </select>\n <span>${i18next.t('figure.label.motion-group-transition')}</span>\n <input\n type=\"number\"\n min=\"0\"\n step=\"any\"\n .value=${String(group.transitionSeconds)}\n ?disabled=${this.locked}\n @change=${(e: Event) => this.edit(groupEdit(group, { transitionSeconds: (e.target as HTMLInputElement).valueAsNumber }))}\n />\n </div>\n <div keys>\n ${group.clips.map(\n c => html`<span key\n >${c}\n <button\n ?disabled=${this.locked || group.clips.length < 2}\n title=${i18next.t('figure.button.remove-clip-from-group')}\n aria-label=${i18next.t('figure.button.remove-clip-from-group')}\n @click=${() => {\n const clips = group.clips.filter(x => x !== c)\n this.edit(groupEdit(group, { clips, defaultClip: group.defaultClip === c ? clips[0]! : group.defaultClip }))\n }}\n >\n <md-icon>close</md-icon>\n </button></span\n >`\n )}\n </div>\n ${free.length\n ? html`<select\n aria-label=${i18next.t('figure.button.add-clip-to-group')}\n ?disabled=${this.locked}\n @change=${(e: Event) => {\n const c = value(e)\n if (c) this.edit(groupEdit(group, { clips: [...group.clips, c] }))\n ;(e.target as HTMLSelectElement).value = ''\n }}\n >\n <option value=\"\" selected>${i18next.t('figure.button.add-clip-to-group')}</option>\n ${free.map(c => html`<option value=${c}>${c}</option>`)}\n </select>`\n : nothing}\n </section>`\n }\n\n /** Show the clip's pose at a moment: one batch of input changes, not saved as the default. */\n /** Show the clip's pose at a moment. While the bar is dragged the pose is live (drawn, not recorded); the release\n * applies it as one batch of input changes. */\n private scrub(clip: Clip, seconds: number, live = false) {\n if (!this.asset || !Number.isFinite(seconds)) return\n this.at = { ...this.at, [clip.name]: seconds }\n const changes = poseAt(this.asset, clip.name, seconds)\n if (!changes.length) return\n if (live) {\n const values = Object.fromEntries(changes.map(c => [c.input, c.value]))\n this.dispatchEvent(new CustomEvent('states-live', { detail: { values }, bubbles: true, composed: true }))\n return\n }\n this.dispatchEvent(new CustomEvent('states', { detail: { changes }, bubbles: true, composed: true }))\n }\n\n /** A key's moment or value typed: one edit of the track; a moment the track cannot take puts the field back. */\n private changeKey(clip: Clip, track: ClipTrack, index: number, patch: Partial<{ seconds: number; value: number }>, e: Event) {\n const keys = withKeyChanged(track.keys, index, patch, clip.duration)\n if (!keys) {\n const field = e.target as HTMLInputElement\n const was = track.keys[index]!\n field.value = 'seconds' in patch ? typed(was.seconds) : typed(was.value)\n return\n }\n this.edit(trackEdit(clip, track, { keys }))\n }\n\n private edit(edit: unknown) {\n this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit }, bubbles: true, composed: true }))\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"figure-clips.js","sourceRoot":"","sources":["../../client/modeller/figure-clips.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\n\nimport { css, html, LitElement, nothing } from 'lit'\nimport type { PropertyValues } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { unitWord } from './unit-words.js'\nimport type { FigureAsset } from '@hatiolab/figure-model'\n\nimport { clipGroupsOf, withKeyChanged, clipsOf, copiedTrackEdit, copyTargetsOf, freeClipNameOf, freeGroupIdOf, groupEdit, newClipEdits, newTrackKeys, poseAt, rememberedPoseEdits, shiftable, shiftOffKeyOf, trackEdit, undrivenOf, withKey, withoutKey, type Clip, type ClipGroup, type ClipKey, type ClipTrack } from './clips.js'\nimport { SidePanelStyles } from '@things-factory/figure-viewer/dist-client/side-panel-styles.js'\nimport { HelpToggles } from './help.js'\n\n/** A value as a person reads it: at most three decimals, the float's last digits (14.399999999999999) left out. */\nconst shown = (value: number) => value.toLocaleString(undefined, { maximumFractionDigits: 3 })\n/* A number field's value: no grouping, to a thousandth. */\nconst typed = (value: number) => String(Math.round(value * 1000) / 1000)\n\n/**\n * 클립 — controls played by keys over time. A clip is one clock; each track plays one\n * control. Scrubbing a clip shows its pose at that moment (one batch of input changes, not saved as the default); a key\n * is added at the scrubbed moment with the control's value there, so a pose is made with the controls' sliders and\n * then kept as a key. Every change is one part edit.\n *\n * Clips of one motion group play one at a time on the same controls -- idle, walk, run (ADR-0051 §3.2): only clips of\n * one group may play the same control. A new clip on a control another clip plays is put in a group as it is made --\n * that clip's, or one made of the two -- and the panel says so before the button is pressed (review 2026-11-09).\n *\n * 「이 자세 기억하기」 keeps the pose the figure stands in now at the scrubbed moment, every control that moved, in one\n * step. What moved is read against the pose the clip was last shown or kept in (`base`).\n */\n@customElement('figure-clips')\nexport class FigureClips extends localize(i18next)(LitElement) {\n private readonly help = new HelpToggles(this)\n static styles = [SidePanelStyles, css`\n :host {\n display: block;\n }\n section[clip] {\n display: grid;\n gap: 8px;\n padding: 8px;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 8px;\n }\n div[row] {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 72px;\n gap: 6px;\n align-items: center;\n }\n div[track] {\n display: grid;\n gap: 4px;\n padding-top: 6px;\n border-top: 1px dashed var(--md-sys-color-outline-variant);\n }\n /*\n The track's name on its own line, then how it repeats and the button that removes it. A flex row let the shared\n full-width select and button squeeze the name to one letter a line (user, 2026-09-24).\n */\n div[track-head] {\n display: grid;\n grid-template-columns: minmax(0, 1fr) 30px 30px;\n gap: 4px 6px;\n align-items: center;\n }\n div[track-head] strong {\n grid-column: 1 / -1;\n min-width: 0;\n overflow-wrap: anywhere;\n }\n /* How it moves between keys: its own row under the head, as wide as the track, its words not cut. */\n div[track-head] select[interpolation] {\n grid-row: 3;\n grid-column: 1 / -1;\n }\n div[track-head] button[act] {\n width: 30px;\n min-height: var(--figure-control-height);\n margin: 0;\n padding: 0;\n }\n /* A track copied onto a control, moved round its loop: under its head, in the panel's form look. */\n div[copy-form] {\n display: grid;\n gap: 6px;\n padding: 6px 8px;\n border-radius: 6px;\n background: var(--md-sys-color-surface-container);\n }\n div[copy-form] div[pair] {\n display: flex;\n gap: 6px;\n justify-content: flex-end;\n }\n div[keys] {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n }\n span[key] {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n padding: 0 2px 0 8px;\n border-radius: 999em;\n background: var(--md-sys-color-surface-container);\n font-variant-numeric: tabular-nums;\n }\n /* A key's moment and value, typed in the chip: as narrow as their numbers, on the chip's ground. */\n span[key] input {\n width: 44px;\n min-width: 0;\n height: 20px;\n padding: 0 2px;\n font: inherit;\n text-align: right;\n font-variant-numeric: tabular-nums;\n color: inherit;\n background: transparent;\n border: none;\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n span[key] input[readonly] {\n border-bottom-color: transparent;\n }\n label[at] {\n display: inline-flex;\n align-items: center;\n gap: 2px;\n font-variant-numeric: tabular-nums;\n }\n label[at] input {\n width: 52px;\n min-width: 0;\n text-align: right;\n }\n span[key] button {\n width: 22px;\n height: 22px;\n padding: 0;\n border: none;\n background: none;\n }\n md-icon {\n font-size: 16px;\n width: 16px;\n height: 16px;\n }\n `]\n\n @property({ attribute: false }) asset?: FigureAsset\n /** The values the editor holds now, by input id -- what a new key takes. */\n @property({ attribute: false }) values: Record<string, number> = {}\n @property({ type: Boolean }) locked = false\n\n /** Where each clip is scrubbed to, in seconds. */\n @state() private at: Record<string, number> = {}\n @state() private adding = { state: '', clip: '', name: '', duration: 2 }\n @state() private grouping = { clip: '', label: '' }\n /** The track whose copy is being set up: onto which control, how many seconds later. */\n @state() private copying?: { clip: string; state: string; target: string; seconds: number }\n /** Per clip, the pose it was last shown or kept in: a control that differs from it now has been moved by the person. */\n @state() private base: Record<string, Record<string, number>> = {}\n\n protected willUpdate(changed: PropertyValues) {\n if (!changed.has('asset') || !this.asset) return\n /* A clip seen for the first time takes the pose the figure stands in now as where its moves are read from. */\n const names = clipsOf(this.asset).map(c => c.name)\n const fresh = names.filter(n => !this.base[n])\n if (fresh.length) this.base = { ...Object.fromEntries(Object.entries(this.base).filter(([n]) => names.includes(n))), ...Object.fromEntries(fresh.map(n => [n, { ...this.values }])) }\n }\n\n render() {\n const asset = this.asset\n if (!asset) return nothing\n const clips = clipsOf(asset)\n /* Nothing to play yet: said inside the section it belongs to, with the section's own margins. */\n const empty = !clips.length && !undrivenOf(asset).length && !asset.motionGroups?.length\n return html`\n <section>\n <h3>${i18next.t('figure.label.clips')}${this.help.button('figure.text.clips-explained')}</h3>\n ${this.help.hint('figure.text.clips-explained')}\n ${clips.map(clip => this.renderClip(clip))}\n ${empty ? html`<p hint>${i18next.t('figure.text.no-clips')}</p>` : nothing}\n </section>\n ${empty ? nothing : this.renderAdd(asset, clips)} ${this.renderGroups(asset)}\n `\n }\n\n private renderClip(clip: Clip) {\n const at = Math.min(this.at[clip.name] ?? 0, clip.duration)\n const number = (e: Event) => (e.target as HTMLInputElement).valueAsNumber\n /* A copy plays the same controls: only clips of one motion group may (ADR-0051 §3.2). */\n const grouped = !!this.asset?.motionGroups?.some(g => g.clips.includes(clip.name))\n return html`<section clip>\n <div form>\n <span>${i18next.t('figure.label.clip-name')}</span>\n <input .value=${clip.name} ?disabled=${this.locked} @change=${(e: Event) => this.edit({ kind: 'set-clip', clip: clip.name, name: (e.target as HTMLInputElement).value })} />\n <span>${i18next.t('figure.label.clip-duration')}</span>\n <input type=\"number\" min=\"0.1\" step=\"any\" .value=${String(clip.duration)} ?disabled=${this.locked} @change=${(e: Event) => this.edit({ kind: 'set-clip', clip: clip.name, duration: number(e) })} />\n </div>\n <button act copy-clip ?disabled=${this.locked || !grouped} title=${i18next.t(grouped ? 'figure.text.copy-clip-explained' : 'figure.text.copy-clip-needs-group')}\n @click=${() => this.edit({ kind: 'copy-clip', clip: clip.name, name: freeClipNameOf(this.asset!, clip.name) })}>\n <md-icon>content_copy</md-icon>${i18next.t('figure.button.copy-clip')}\n </button>\n <div row>\n <input\n type=\"range\"\n min=\"0\"\n max=${clip.duration}\n step=${clip.duration / 100}\n .value=${String(at)}\n ?disabled=${this.locked}\n aria-label=${i18next.t('figure.label.clip-time')}\n @input=${(e: Event) => this.scrub(clip, number(e), true)}\n @change=${(e: Event) => this.scrub(clip, number(e))}\n />\n <label at>\n <input\n type=\"number\"\n min=\"0\"\n max=${clip.duration}\n step=\"any\"\n .value=${String(Math.round(at * 1000) / 1000)}\n ?disabled=${this.locked}\n aria-label=${i18next.t('figure.label.clip-time')}\n @change=${(e: Event) => this.scrub(clip, Math.min(Math.max(number(e), 0), clip.duration))}\n />s\n </label>\n </div>\n ${this.renderRemember(clip, at)}\n ${clip.tracks.map(track => this.renderTrack(clip, track, at))}\n </section>`\n }\n\n /** 「이 자세 기억하기」: every control moved since the clip's pose was last shown or kept, as keys at this moment, one step. */\n private renderRemember(clip: Clip, at: number) {\n const { edits, skipped } = rememberedPoseEdits(this.asset!, clip.name, at, this.values, this.base[clip.name] ?? this.values)\n const label = (id: string) => this.asset!.stateInputs?.[id]?.label ?? id\n return html`<button act remember-pose ?disabled=${this.locked || !edits.length} title=${edits.length ? '' : i18next.t('figure.text.remember-pose-nothing')}\n @click=${() => {\n this.edits(edits)\n this.base = { ...this.base, [clip.name]: { ...this.values } }\n }}>\n <md-icon>photo_camera</md-icon>${i18next.t('figure.button.remember-pose', { seconds: at.toFixed(2) })}\n </button>\n ${skipped.length ? html`<p hint>${i18next.t('figure.text.remember-pose-skipped', { controls: skipped.map(label).join(', ') })}</p>` : nothing}`\n }\n\n private renderTrack(clip: Clip, track: ClipTrack, at: number) {\n const current = this.values[track.state]\n return html`<div track>\n <div track-head>\n <strong>${track.label} <small>(${unitWord(track.unit)})</small></strong>\n <select\n aria-label=${i18next.t('figure.label.clip-loop')}\n ?disabled=${this.locked}\n @change=${(e: Event) => this.edit(trackEdit(clip, track, { loop: (e.target as HTMLSelectElement).value as 'wrap' | 'hold' }))}\n >\n <option value=\"wrap\" ?selected=${track.loop === 'wrap'}>${i18next.t('figure.label.clip-loop-wrap')}</option>\n <option value=\"hold\" ?selected=${track.loop === 'hold'}>${i18next.t('figure.label.clip-loop-hold')}</option>\n </select>\n <select\n interpolation\n aria-label=${i18next.t('figure.label.clip-interpolation')}\n title=${i18next.t('figure.label.clip-interpolation')}\n ?disabled=${this.locked}\n @change=${(e: Event) => this.edit(trackEdit(clip, track, { interpolation: (e.target as HTMLSelectElement).value as ClipTrack['interpolation'] }))}\n >\n ${(['linear', 'smooth', 'step'] as const).map(i => html`<option value=${i} ?selected=${track.interpolation === i}>${i18next.t(`figure.label.clip-interpolation-${i}`)}</option>`)}\n </select>\n <button act copy-track ?disabled=${this.locked} title=${i18next.t('figure.button.copy-track')} aria-label=${i18next.t('figure.button.copy-track')}\n @click=${() => (this.copying = this.copying?.clip === clip.name && this.copying.state === track.state ? undefined : { clip: clip.name, state: track.state, target: track.state, seconds: 0 })}>\n <md-icon>content_copy</md-icon>\n </button>\n <button act ?disabled=${this.locked} title=${i18next.t('figure.button.remove-track')} @click=${() => this.edit({ kind: 'remove-driver', state: track.state, clip: clip.name })}>\n <md-icon>close</md-icon>\n </button>\n </div>\n ${this.copying?.clip === clip.name && this.copying.state === track.state ? this.renderCopy(clip, track) : nothing}\n <div keys>\n ${track.keys.map(\n (key, i) => html`<span key\n ><input\n type=\"number\"\n step=\"any\"\n min=\"0\"\n max=${clip.duration}\n ?readonly=${i === 0}\n ?disabled=${this.locked}\n title=${i === 0 ? i18next.t('figure.text.key-starts-the-clip') : ''}\n aria-label=${`${i18next.t('figure.label.key-seconds')} ${i + 1}`}\n .value=${typed(key.seconds)}\n @change=${(e: Event) => this.changeKey(clip, track, i, { seconds: (e.target as HTMLInputElement).valueAsNumber }, e)}\n />s →\n <input\n type=\"number\"\n step=\"any\"\n ?disabled=${this.locked}\n aria-label=${`${i18next.t('figure.label.key-value')} ${i + 1}`}\n .value=${typed(key.value)}\n @change=${(e: Event) => this.changeKey(clip, track, i, { value: (e.target as HTMLInputElement).valueAsNumber }, e)}\n />\n <button\n ?disabled=${this.locked || !withoutKey(track.keys, i)}\n title=${i18next.t('figure.button.remove-key')}\n aria-label=${i18next.t('figure.button.remove-key')}\n @click=${() => this.edit(trackEdit(clip, track, { keys: withoutKey(track.keys, i)! }))}\n >\n <md-icon>close</md-icon>\n </button></span\n >`\n )}\n </div>\n <button\n act\n ?disabled=${this.locked || current === undefined}\n @click=${() => this.edit(trackEdit(clip, track, { keys: withKey(track.keys, { seconds: Math.round(at * 1000) / 1000, value: current! }) }))}\n >\n <md-icon>add</md-icon>${i18next.t('figure.button.add-key-here', { seconds: at.toFixed(2), value: current === undefined ? '' : shown(current) })}\n </button>\n </div>`\n }\n\n /**\n * A track onto a control -- itself, or another -- moved round its loop by some seconds: one leg's curve given to the\n * next on its own beat (robot dog 2026-11-03). Only a wrapping track moves round; any track is copied.\n */\n private renderCopy(clip: Clip, track: ClipTrack) {\n const c = this.copying!\n const asset = this.asset!\n const targets = copyTargetsOf(asset, clip.name)\n const moves = shiftable(track)\n const seconds = moves && Number.isFinite(c.seconds) ? c.seconds : 0\n const same = c.target === track.state && !seconds\n /* A smooth track goes round only onto one of its keys: said, with the moments it can go to, and not applied. */\n const fits = moves ? shiftOffKeyOf(track, clip.duration, seconds) : null\n return html`<div copy-form>\n <div form>\n <span>${i18next.t('figure.label.copy-track-onto')}</span>\n <select aria-label=${i18next.t('figure.label.copy-track-onto')} @change=${(e: Event) => (this.copying = { ...c, target: (e.target as HTMLSelectElement).value })}>\n ${targets.map(id => html`<option value=${id} ?selected=${id === c.target}>${id === track.state ? i18next.t('figure.label.copy-track-itself') : (asset.stateInputs?.[id]?.label ?? id)}</option>`)}\n </select>\n <span>${i18next.t('figure.label.copy-track-later')}</span>\n <label at title=${moves ? '' : i18next.t('figure.text.copy-track-no-loop')}>\n <input type=\"number\" step=\"any\" aria-label=${i18next.t('figure.label.copy-track-later')} ?disabled=${!moves} .value=${typed(seconds)}\n @change=${(e: Event) => (this.copying = { ...c, seconds: (e.target as HTMLInputElement).valueAsNumber })} />s\n <small>/ ${typed(clip.duration)}s</small>\n </label>\n </div>\n ${fits ? html`<p hint off-key>${i18next.t('figure.text.copy-track-off-key', { seconds: fits.map(typed).join(', ') })}</p>` : nothing}\n <div pair>\n <button act ?disabled=${this.locked || same || !!fits}\n @click=${() => {\n this.edit(copiedTrackEdit(asset, clip, track, c.target, seconds))\n this.copying = undefined\n }}>${i18next.t(c.target === track.state ? 'figure.button.shift-track' : 'figure.button.copy-track-apply')}</button>\n <button act @click=${() => (this.copying = undefined)}>${i18next.t('figure.button.cancel')}</button>\n </div>\n </div>`\n }\n\n private renderAdd(asset: FigureAsset, clips: Clip[]) {\n const a = this.adding\n const joining = clips.find(c => c.name === a.clip)\n /*\n The controls a track can take. Joining a clip: those it may play. A new clip: any control -- one another clip\n plays puts the new clip in a group with it, said below before the button is pressed (review 2026-11-09: the\n controls used to vanish from the list, and the group had to be designed first).\n */\n const free = joining ? undrivenOf(asset, joining.name) : asset.document.model.inputs.filter(i => i.role === 'state').map(i => i.id)\n const stateId = free.includes(a.state) ? a.state : free[0]\n const name = joining ? joining.name : a.name.trim()\n const input = asset.document.model.inputs.find(i => i.id === stateId)\n const duration = joining ? joining.duration : a.duration\n /* A new clip takes a name no clip has: the same name would rewrite that clip's track, not add one. */\n const taken = !joining && clips.some(c => c.name === name)\n const ready = !!name && !taken && duration > 0 && !!input\n const join = !joining && input && name ? newClipEdits(asset, stateId!, name, duration, []).join : undefined\n const add = (keys: ClipKey[]) => {\n if (joining) this.edit({ kind: 'set-driver', state: stateId, clip: name, keys })\n else this.edits(newClipEdits(asset, stateId!, name, duration, keys).edits)\n /* The name was this clip's; the next new clip is named again. */\n this.adding = { ...a, name: '', state: '' }\n }\n return html`<section><h3>${i18next.t('figure.label.add-track')}</h3>\n <div form>\n <span>${i18next.t('figure.label.controls')}</span>\n <select ?disabled=${!free.length} @change=${(e: Event) => (this.adding = { ...a, state: (e.target as HTMLSelectElement).value })}>\n ${free.map(id => html`<option value=${id} ?selected=${id === stateId}>${asset.stateInputs?.[id]?.label ?? id}</option>`)}\n </select>\n <span>${i18next.t('figure.label.clip')}</span>\n <select @change=${(e: Event) => (this.adding = { ...a, clip: (e.target as HTMLSelectElement).value })}>\n <option value=\"\" ?selected=${!joining}>${i18next.t('figure.label.new-clip')}</option>\n ${clips.map(c => html`<option value=${c.name} ?selected=${c === joining}>${c.name}</option>`)}\n </select>\n ${joining\n ? nothing\n : html`<span>${i18next.t('figure.label.clip-name')}</span>\n <input .value=${a.name} placeholder=\"cycle\" @input=${(e: Event) => (this.adding = { ...a, name: (e.target as HTMLInputElement).value })} />\n <span>${i18next.t('figure.label.clip-duration')}</span>\n <input type=\"number\" min=\"0.1\" step=\"any\" .value=${String(a.duration)} @change=${(e: Event) => (this.adding = { ...a, duration: (e.target as HTMLInputElement).valueAsNumber })} />`}\n </div>\n ${join?.kind === 'new-group'\n ? html`<p hint track-join>${i18next.t('figure.text.track-makes-group', { clip: join.clip, name, group: join.label })}</p>`\n : join?.kind === 'group'\n ? html`<p hint track-join>${i18next.t('figure.text.track-joins-group', { name, group: join.label })}</p>`\n : nothing}\n <button act ?disabled=${this.locked || !ready} @click=${() => add(newTrackKeys(input!, this.values[stateId!], duration))}>\n <md-icon>add</md-icon>${i18next.t('figure.button.add-track')}\n </button>\n <button act range-track ?disabled=${this.locked || !ready} title=${i18next.t('figure.text.add-track-range-explained')}\n @click=${() => add(newTrackKeys(input!, this.values[stateId!], duration, 'range'))}>\n <md-icon>swap_horiz</md-icon>${i18next.t('figure.button.add-track-range')}\n </button></section>`\n }\n\n /**\n * The motion groups: a name, the clip that plays until another is chosen, how long a change of clip blends, and the\n * clips each holds. A group is made from a clip in none; a clip in none joins one here. Every change is one edit.\n */\n private renderGroups(asset: FigureAsset) {\n const { groups, free } = clipGroupsOf(asset)\n if (!groups.length && !free.length) return nothing\n const g = this.grouping\n const first = free.includes(g.clip) ? g.clip : free[0]\n return html`<section>\n <h3>${i18next.t('figure.label.motion-groups')}${this.help.button('figure.text.motion-groups-explained')}</h3>\n ${this.help.hint('figure.text.motion-groups-explained')}\n ${groups.map(group => this.renderGroup(group, free))}\n ${free.length\n ? html`<div form>\n <span>${i18next.t('figure.label.motion-group-name')}</span>\n <input .value=${g.label} placeholder=${i18next.t('figure.label.motion-group')} @input=${(e: Event) => (this.grouping = { ...g, label: (e.target as HTMLInputElement).value })} />\n <span>${i18next.t('figure.label.clip')}</span>\n <select @change=${(e: Event) => (this.grouping = { ...g, clip: (e.target as HTMLSelectElement).value })}>\n ${free.map(c => html`<option value=${c} ?selected=${c === first}>${c}</option>`)}\n </select>\n </div>\n <button\n act\n ?disabled=${this.locked || !first || !g.label.trim()}\n @click=${() => {\n this.edit({ kind: 'set-motion-group', group: { id: freeGroupIdOf(asset), label: g.label.trim(), clips: [first!], defaultClip: first!, transitionSeconds: 0.2 } })\n this.grouping = { clip: '', label: '' }\n }}\n >\n <md-icon>add</md-icon>${i18next.t('figure.button.add-motion-group')}\n </button>`\n : nothing}\n </section>`\n }\n\n private renderGroup(group: ClipGroup, free: string[]) {\n const value = (e: Event) => (e.target as HTMLInputElement | HTMLSelectElement).value\n return html`<section clip>\n <div track-head>\n <strong>${group.label}</strong>\n <button act ?disabled=${this.locked} title=${i18next.t('figure.button.remove-motion-group')} @click=${() => this.edit({ kind: 'remove-motion-group', id: group.id })}>\n <md-icon>close</md-icon>\n </button>\n </div>\n <div form>\n <span>${i18next.t('figure.label.motion-group-name')}</span>\n <input .value=${group.label} ?disabled=${this.locked} @change=${(e: Event) => value(e).trim() && this.edit(groupEdit(group, { label: value(e).trim() }))} />\n <span>${i18next.t('figure.label.motion-group-default')}</span>\n <select ?disabled=${this.locked} @change=${(e: Event) => this.edit(groupEdit(group, { defaultClip: value(e) }))}>\n ${group.clips.map(c => html`<option value=${c} ?selected=${c === group.defaultClip}>${c}</option>`)}\n </select>\n <span>${i18next.t('figure.label.motion-group-transition')}</span>\n <input\n type=\"number\"\n min=\"0\"\n step=\"any\"\n .value=${String(group.transitionSeconds)}\n ?disabled=${this.locked}\n @change=${(e: Event) => this.edit(groupEdit(group, { transitionSeconds: (e.target as HTMLInputElement).valueAsNumber }))}\n />\n </div>\n <div keys>\n ${group.clips.map(\n c => html`<span key\n >${c}\n <button\n ?disabled=${this.locked || group.clips.length < 2}\n title=${i18next.t('figure.button.remove-clip-from-group')}\n aria-label=${i18next.t('figure.button.remove-clip-from-group')}\n @click=${() => {\n const clips = group.clips.filter(x => x !== c)\n this.edit(groupEdit(group, { clips, defaultClip: group.defaultClip === c ? clips[0]! : group.defaultClip }))\n }}\n >\n <md-icon>close</md-icon>\n </button></span\n >`\n )}\n </div>\n ${free.length\n ? html`<select\n aria-label=${i18next.t('figure.button.add-clip-to-group')}\n ?disabled=${this.locked}\n @change=${(e: Event) => {\n const c = value(e)\n if (c) this.edit(groupEdit(group, { clips: [...group.clips, c] }))\n ;(e.target as HTMLSelectElement).value = ''\n }}\n >\n <option value=\"\" selected>${i18next.t('figure.button.add-clip-to-group')}</option>\n ${free.map(c => html`<option value=${c}>${c}</option>`)}\n </select>`\n : nothing}\n </section>`\n }\n\n /** Show the clip's pose at a moment: one batch of input changes, not saved as the default. */\n /** Show the clip's pose at a moment. While the bar is dragged the pose is live (drawn, not recorded); the release\n * applies it as one batch of input changes. */\n private scrub(clip: Clip, seconds: number, live = false) {\n if (!this.asset || !Number.isFinite(seconds)) return\n this.at = { ...this.at, [clip.name]: seconds }\n const changes = poseAt(this.asset, clip.name, seconds)\n if (!changes.length) return\n if (live) {\n const values = Object.fromEntries(changes.map(c => [c.input, c.value]))\n this.dispatchEvent(new CustomEvent('states-live', { detail: { values }, bubbles: true, composed: true }))\n return\n }\n this.dispatchEvent(new CustomEvent('states', { detail: { changes }, bubbles: true, composed: true }))\n /* The clip's pose shown: what moves from here is the person's. */\n this.base = { ...this.base, [clip.name]: { ...this.values, ...Object.fromEntries(changes.map(c => [c.input, c.value])) } }\n }\n\n /** A key's moment or value typed: one edit of the track; a moment the track cannot take puts the field back. */\n private changeKey(clip: Clip, track: ClipTrack, index: number, patch: Partial<{ seconds: number; value: number }>, e: Event) {\n const keys = withKeyChanged(track.keys, index, patch, clip.duration)\n if (!keys) {\n const field = e.target as HTMLInputElement\n const was = track.keys[index]!\n field.value = 'seconds' in patch ? typed(was.seconds) : typed(was.value)\n return\n }\n this.edit(trackEdit(clip, track, { keys }))\n }\n\n private edit(edit: unknown) {\n this.dispatchEvent(new CustomEvent('part-edit', { detail: { edit }, bubbles: true, composed: true }))\n }\n\n /** Several edits as one step of the history. */\n private edits(edits: unknown[]) {\n if (edits.length === 1) return this.edit(edits[0])\n this.dispatchEvent(new CustomEvent('part-edits', { detail: { edits }, bubbles: true, composed: true }))\n }\n}\n"]}
|
|
@@ -11,9 +11,28 @@ export type JointDrag = {
|
|
|
11
11
|
joint: FigureJoint;
|
|
12
12
|
} | {
|
|
13
13
|
kind: 'refused';
|
|
14
|
-
reason: 'mimic' | 'fixed-turn' | 'origin-follows' | 'turned-slide' | 'off-axis' | 'several-axes';
|
|
14
|
+
reason: 'mimic' | 'fixed-turn' | 'origin-follows' | 'turned-slide' | 'off-axis' | 'several-axes' | 'place-off';
|
|
15
15
|
joint: string;
|
|
16
16
|
leader?: string;
|
|
17
17
|
axis?: string;
|
|
18
18
|
};
|
|
19
|
-
export declare function jointDragOf(asset: FigureAsset, id: string, part: FigureRenderPart, result: GizmoResult, values: Record<string, number
|
|
19
|
+
export declare function jointDragOf(asset: FigureAsset, id: string, part: FigureRenderPart, result: GizmoResult, values: Record<string, number>, options?: {
|
|
20
|
+
place?: boolean;
|
|
21
|
+
}): JointDrag | null;
|
|
22
|
+
/**
|
|
23
|
+
* What a drag on the part does, said before it is dragged (review 2026-11-09: 「왜 안 움직이지?」): which handle changes
|
|
24
|
+
* its pose, or why none does and where it is moved from instead. Null for a part on no joint, or on a fixed one.
|
|
25
|
+
*/
|
|
26
|
+
export type JointHandle = {
|
|
27
|
+
kind: 'turn' | 'slide';
|
|
28
|
+
joint: string;
|
|
29
|
+
} | {
|
|
30
|
+
kind: 'mimic';
|
|
31
|
+
joint: string;
|
|
32
|
+
leader: string;
|
|
33
|
+
leaderPart?: string;
|
|
34
|
+
} | {
|
|
35
|
+
kind: 'several-axes';
|
|
36
|
+
joint: string;
|
|
37
|
+
};
|
|
38
|
+
export declare function jointHandleOf(asset: FigureAsset, part: string): JointHandle | null;
|
|
@@ -21,7 +21,7 @@ function jointFrameRotation(j, a, part, angle) {
|
|
|
21
21
|
const turn = a?.type === 'revolute' ? new THREE.Matrix4().makeRotationAxis(unit(a.axis), THREE.MathUtils.degToRad(angle)) : new THREE.Matrix4();
|
|
22
22
|
return now.multiply(own.invert()).multiply(turn.invert());
|
|
23
23
|
}
|
|
24
|
-
export function jointDragOf(asset, id, part, result, values) {
|
|
24
|
+
export function jointDragOf(asset, id, part, result, values, options = {}) {
|
|
25
25
|
const j = asset.joints?.find(joint => joint.body1.part === id);
|
|
26
26
|
/* A size is the part's own, not the joint's: a scale drag goes to the part's measures (the editor drops the shift). */
|
|
27
27
|
if (!j || result.scale || (!result.rotation && !result.position))
|
|
@@ -78,6 +78,9 @@ export function jointDragOf(asset, id, part, result, values) {
|
|
|
78
78
|
return { kind: 'value', input: stateId, unit: a.travel ? 'ratio' : 'mm', value: round(value, a.travel ? 0.001 : 1) };
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
|
+
/* A joint that moves is posed by a drag; its place is moved only while placing is on. */
|
|
82
|
+
if (a && !options.place)
|
|
83
|
+
return { kind: 'refused', reason: 'place-off', joint: j.id };
|
|
81
84
|
/* Moving the joint's origin: the change in the frame it is placed in, before `origin.parentRotate` turns the joint frame. */
|
|
82
85
|
const local = moved.clone().applyMatrix4(frame.clone().multiply(rotateMatrix(j).invert()).invert());
|
|
83
86
|
const origin = { ...(j.origin ?? {}) };
|
|
@@ -117,4 +120,20 @@ export function jointDragOf(asset, id, part, result, values) {
|
|
|
117
120
|
}
|
|
118
121
|
return { kind: 'joint', joint: { ...j, origin } };
|
|
119
122
|
}
|
|
123
|
+
export function jointHandleOf(asset, part) {
|
|
124
|
+
const j = asset.joints?.find(joint => joint.body1.part === part);
|
|
125
|
+
if (!j)
|
|
126
|
+
return null;
|
|
127
|
+
const axes = figureMotionsOf(j);
|
|
128
|
+
if (!axes.length)
|
|
129
|
+
return null;
|
|
130
|
+
if (axes.length > 1)
|
|
131
|
+
return { kind: 'several-axes', joint: j.id };
|
|
132
|
+
const a = axes[0];
|
|
133
|
+
if (a.mimic) {
|
|
134
|
+
const leader = figureMimicTermsOf(a.mimic).sum[0].joint;
|
|
135
|
+
return { kind: 'mimic', joint: j.id, leader, leaderPart: asset.joints?.find(o => o.id === leader)?.body1.part };
|
|
136
|
+
}
|
|
137
|
+
return { kind: a.type === 'revolute' ? 'turn' : 'slide', joint: j.id };
|
|
138
|
+
}
|
|
120
139
|
//# sourceMappingURL=joint-drag.js.map
|