@things-factory/figure-ui 10.1.26 → 10.1.27

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 (34) hide show
  1. package/client/modeller/figure-animations.ts +172 -24
  2. package/client/modeller/figure-inspector.ts +143 -3
  3. package/client/modeller/figure-preview.ts +2 -2
  4. package/client/modeller/figure-source.ts +16 -4
  5. package/client/modeller/figure-view.ts +20 -0
  6. package/client/modeller/joint-edits.ts +201 -0
  7. package/dist-client/modeller/figure-animations.d.ts +14 -0
  8. package/dist-client/modeller/figure-animations.js +151 -17
  9. package/dist-client/modeller/figure-animations.js.map +1 -1
  10. package/dist-client/modeller/figure-inspector.d.ts +11 -0
  11. package/dist-client/modeller/figure-inspector.js +116 -2
  12. package/dist-client/modeller/figure-inspector.js.map +1 -1
  13. package/dist-client/modeller/figure-preview.js +2 -2
  14. package/dist-client/modeller/figure-preview.js.map +1 -1
  15. package/dist-client/modeller/figure-source.d.ts +8 -0
  16. package/dist-client/modeller/figure-source.js +8 -4
  17. package/dist-client/modeller/figure-source.js.map +1 -1
  18. package/dist-client/modeller/figure-view.d.ts +16 -0
  19. package/dist-client/modeller/figure-view.js +15 -0
  20. package/dist-client/modeller/figure-view.js.map +1 -1
  21. package/dist-client/modeller/joint-edits.d.ts +29 -0
  22. package/dist-client/modeller/joint-edits.js +175 -0
  23. package/dist-client/modeller/joint-edits.js.map +1 -0
  24. package/dist-client/tsconfig.tsbuildinfo +1 -1
  25. package/dist-server/tsconfig.tsbuildinfo +1 -1
  26. package/package.json +3 -3
  27. package/test/figure-source.test.ts +32 -0
  28. package/test/joint-edits.test.ts +130 -0
  29. package/test/preview-board-depth.test.ts +27 -0
  30. package/translations/en.json +24 -0
  31. package/translations/ja.json +24 -0
  32. package/translations/ko.json +24 -0
  33. package/translations/ms.json +24 -0
  34. package/translations/zh.json +24 -0
@@ -1 +1 @@
1
- {"version":3,"file":"figure-animations.js","sourceRoot":"","sources":["../../client/modeller/figure-animations.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing, type TemplateResult } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { live } from 'lit/directives/live.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport { AXES, CHANNEL_PATHS, INTERPOLATIONS, LIMITS } from '@hatiolab/figure-model'\nimport type { ChannelPath, Vec3 } from '@hatiolab/figure-model'\n\nimport type { FigureDraft, PartModel } from './figure-source.js'\n\n/**\n * 이 도형이 **어떻게 움직이는가.**\n *\n * ## 왜 탭 하나가 필요한가\n *\n * 움직임은 형식에 있고 런타임까지 서 있었다 — 검증이 촘촘히 보고, 청사진이 움직이는 부품을\n * 단독 묶음으로 빼고(합치면 따로 못 움직인다), 씬이 frameClock 을 구독해 실제로 돌린다.\n * 미리보기에도 clip 마다 슬라이더가 있었다.\n *\n * **만들 자리만 없었다.** 그래서 움직이는 도형을 얻는 길이 「AI 가 후보로 내놓는 것」 하나였고,\n * 채널 하나를 고치려면 손댈 화면이 없었다.\n *\n * ## 부품이 아니라 도형의 것이다\n *\n * clip 하나가 부품 여럿을 함께 움직인다 — 문 열림은 왼짝과 오른짝이 반대로 미끄러지는 것\n * 하나다. 그래서 부품을 고르고 「이 부품의 움직임」을 적는 형태가 될 수 없고, 속성 탭이 아니라\n * 자기 탭에 산다.\n *\n * ## 트윈은 타임라인을 재생하지 않는다\n *\n * 「문 열기 clip 을 재생하라」가 아니라 **「지금 40% 열려 있다」**다. 그 둘은 다른 것이라\n * 이 탭도 둘로 나뉜다.\n *\n * 애니메이션 시각이 흐른다. 인스턴스가 주는 수는 배속이다 — 도는 롤러\n * 파라미터 값이 자세를 만든다. 인스턴스가 주는 수는 물리량이다 — 1200mm 내려온 호이스트\n *\n * 한동안 뒤엣것이 애니메이션 안에 `drive: 'hold'` 로 숨어 있었다. 형식의 판단은 맞았는데\n * **자리와 이름이 틀려서**, 「길이값을 변수로 노출하라」는 요청에 저작자도 AI 도 이것을\n * 못 찾았다 — 애니메이션 칸에 있을 거라고 생각하지 않는다(ADR-0051).\n */\n\ntype Clip = NonNullable<FigureDraft['animations']>[number]\ntype Parameter = NonNullable<FigureDraft['parameters']>[number]\ntype Channel = Clip['channels'][number]\ntype Keyframe = Channel['keys'][number]\n\n/** 어느 목록의 몇째인가. 채널·키 편집기가 둘을 함께 쓴다. */\ntype MotionKind = 'clip' | 'parameter'\n\n/** A first-success motion: intent first, raw channel editing second. */\ninterface MotionRecipe {\n id: 'conveyor' | 'gate' | 'pusher' | 'lift'\n name: string\n kind: MotionKind\n path: ChannelPath\n end: Vec3\n pivot?: Vec3\n /** 파라미터 레시피만. 인스턴스가 주고받는 물리량이다. */\n range?: Parameter['range']\n}\n\n/*\n 레시피의 `end` 가 곧 그 범위의 끝 자세다 — 리프트가 100mm 올라가는 곡선이면 범위도\n 0~100mm 다. 둘이 어긋나면 저작자가 1200 을 주고도 100 만 올라가는 것을 보게 된다.\n*/\nconst MOTION_RECIPES: readonly MotionRecipe[] = [\n { id: 'conveyor', name: 'conveyor-running', kind: 'clip', path: 'rotation', end: { x: 360, y: 0, z: 0 } },\n {\n id: 'gate',\n name: 'gate-open',\n kind: 'parameter',\n path: 'rotation',\n end: { x: 0, y: 90, z: 0 },\n pivot: { x: 0, y: 0, z: 0 },\n range: { unit: '%', min: 0, max: 100 }\n },\n {\n id: 'pusher',\n name: 'pusher-position',\n kind: 'parameter',\n path: 'translation',\n end: { x: 100, y: 0, z: 0 },\n range: { unit: 'mm', min: 0, max: 100 }\n },\n {\n id: 'lift',\n name: 'lift-height',\n kind: 'parameter',\n path: 'translation',\n end: { x: 0, y: 100, z: 0 },\n range: { unit: 'mm', min: 0, max: 100 }\n }\n]\n\n/** 새 파라미터의 범위. 단위는 저작자가 고쳐 쓴다 — 형식은 단위를 해석하지 않는다. */\nconst NEW_RANGE: Parameter['range'] = { unit: 'mm', min: 0, max: 1000 }\n\n/** 새 clip 의 키 둘. **하나로 만들지 않는다** — 키 하나는 움직임이 아니라 자세다. */\nconst NEW_KEYS: Keyframe[] = [\n { at: 0, value: { x: 0, y: 0, z: 0 } },\n { at: 1, value: { x: 0, y: 0, z: 0 } }\n]\n\n/** `scale` 만 1 에서 시작한다 — 0 은 부품을 지운다. */\nfunction startValue(path: ChannelPath): Vec3 {\n return path === 'scale' ? { x: 1, y: 1, z: 1 } : { x: 0, y: 0, z: 0 }\n}\n\nfunction keysFor(path: ChannelPath): Keyframe[] {\n return NEW_KEYS.map(key => ({ at: key.at, value: startValue(path) }))\n}\n\n/**\n * 이미 쓴 이름을 비켜 간다.\n *\n * **두 목록을 함께 본다.** 인스턴스는 이름 하나로 값을 주므로 애니메이션과 파라미터가\n * 같은 이름을 가지면 어느 쪽에 준 것인지 알 수 없고, 형식이 그것을 오류로 막는다.\n */\nfunction freeName(taken: readonly { name: string }[], stem: string): string {\n const used = new Set(taken.map(one => one.name))\n if (!used.has(stem)) return stem\n for (let n = 2; ; n++) if (!used.has(`${stem}-${n}`)) return `${stem}-${n}`\n}\n\n@customElement('figure-animations')\nexport class FigureAnimations extends localize(i18next)(LitElement) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow-y: auto;\n background-color: var(--md-sys-color-surface-container-lowest);\n color: var(--md-sys-color-on-surface);\n font: var(--label-font, inherit);\n font-size: 0.76rem;\n }\n\n section {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-medium, 8px);\n padding: var(--spacing-large, 12px);\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n\n /* 다른 탭들과 같은 눈금이다 */\n h3 {\n margin: 0 0 2px 0;\n font-size: var(--ui-t-micro, 11px);\n font-weight: 700;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n\n p[quiet] {\n margin: 0;\n font-size: 0.72rem;\n line-height: 1.5;\n color: var(--md-sys-color-on-surface-variant);\n }\n\n div[recipes] { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }\n button[recipe] { min-height: 54px; align-items: flex-start; flex-direction: column; text-align: left; }\n button[recipe] strong { font-size: 0.74rem; }\n button[recipe] span { color: var(--md-sys-color-on-surface-variant); font-size: 0.68rem; line-height: 1.35; }\n\n /* ── clip ─────────────────────────────────────────────────────── */\n\n div[clip] {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-medium, 8px);\n padding: 8px;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 4px;\n }\n div[clip][on] {\n border-color: var(--md-sys-color-primary);\n background-color: var(--md-sys-color-surface-container-low);\n }\n\n div[head] {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n div[head] input[name] {\n flex: 1;\n min-width: 0;\n }\n\n /* ── channel ──────────────────────────────────────────────────── */\n\n div[channel] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 6px 8px;\n border-left: 2px solid var(--md-sys-color-outline-variant);\n background-color: var(--md-sys-color-surface-container-lowest);\n }\n div[channel][orphan] {\n border-left-color: var(--md-sys-color-error);\n }\n\n div[row] {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n div[row] > label {\n flex: none;\n min-width: 3.2em;\n color: var(--md-sys-color-on-surface-variant);\n }\n\n /* ── keyframe ─────────────────────────────────────────────────── */\n\n table[keys] {\n width: 100%;\n border-collapse: collapse;\n }\n table[keys] th {\n padding: 0 2px 2px;\n font-size: 0.68rem;\n font-weight: 600;\n text-align: left;\n color: var(--md-sys-color-on-surface-variant);\n }\n table[keys] td {\n padding: 1px 2px;\n }\n table[keys] input {\n width: 100%;\n min-width: 0;\n }\n table[keys] td[drop] {\n width: 1.6em;\n }\n\n input,\n select {\n box-sizing: border-box;\n padding: 3px 5px;\n font: inherit;\n font-size: 0.74rem;\n color: var(--md-sys-color-on-surface);\n background-color: var(--md-sys-color-surface-container-lowest);\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 3px;\n }\n input:focus,\n select:focus {\n outline: none;\n border-color: var(--md-sys-color-primary);\n }\n input[bad] {\n border-color: var(--md-sys-color-error);\n }\n\n button {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n padding: 3px 8px;\n font: inherit;\n font-size: 0.72rem;\n color: var(--md-sys-color-on-surface);\n background-color: var(--md-sys-color-surface-container);\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 3px;\n cursor: pointer;\n }\n button:hover:not(:disabled) {\n background-color: var(--md-sys-color-surface-container-high);\n }\n button:disabled {\n opacity: 0.4;\n cursor: default;\n }\n button[plain] {\n padding: 1px 4px;\n background: none;\n border: none;\n color: var(--md-sys-color-on-surface-variant);\n }\n button[plain]:hover:not(:disabled) {\n color: var(--md-sys-color-error);\n background: none;\n }\n button md-icon {\n font-size: 14px;\n width: 14px;\n height: 14px;\n }\n\n /* ── 예산 ─────────────────────────────────────────────────────── */\n\n div[budget] {\n display: flex;\n align-items: baseline;\n gap: 6px;\n }\n div[budget] strong {\n font-size: 0.86rem;\n font-weight: 700;\n }\n div[budget][over] strong {\n color: var(--md-sys-color-error);\n }\n\n p[warn] {\n margin: 0;\n font-size: 0.7rem;\n line-height: 1.5;\n color: var(--md-sys-color-error);\n }\n `\n ]\n\n @property({ type: Object }) draft?: FigureDraft\n @property({ type: Array }) parts: PartModel[] = []\n\n /**\n * 펼쳐 둔 것. 이름이 아니라 **목록과 자리**로 잡는다 — 이름은 편집 중에 바뀐다.\n *\n * 목록이 둘이므로 자리 하나로는 모자란다. `clip:0` 과 `parameter:0` 은 다른 것이다.\n */\n @state() private open = ''\n @state() private recipeTarget = ''\n\n private get clips(): Clip[] {\n return this.draft?.animations ?? []\n }\n\n private get parameters(): Parameter[] {\n return this.draft?.parameters ?? []\n }\n\n /** 두 목록의 이름을 한자리에서 본다 — 인스턴스가 이름 하나로 값을 준다. */\n private get allNames(): { name: string }[] {\n return [...this.clips, ...this.parameters]\n }\n\n private channelsOf(kind: MotionKind, at: number): Channel[] {\n return (kind === 'clip' ? this.clips[at]?.channels : this.parameters[at]?.clip?.channels) ?? []\n }\n\n /** 부품 이름 — 채널이 이것을 가리킨다. */\n private get partNames(): string[] {\n return this.parts.map(part => part.name).filter(name => !!name)\n }\n\n /**\n * 몇 부품이 움직이나 — 채널이 가리키는 **서로 다른 부품**의 수.\n *\n * clip 수가 아니다. 한 부품을 세 clip 이 움직여도 그 부품 하나가 단독 묶음이 될 뿐이다.\n * 청사진이 묶음을 가르는 기준과 같은 셈이어야 화면의 수와 판정의 수가 맞는다.\n */\n private get movingParts(): number {\n const moving = new Set<string>()\n for (const clip of this.clips) for (const channel of clip.channels) moving.add(channel.target)\n for (const parameter of this.parameters) {\n for (const channel of parameter.clip?.channels ?? []) moving.add(channel.target)\n }\n return moving.size\n }\n\n render(): TemplateResult {\n if (!this.draft) return html``\n\n const nameless = this.partNames.length === 0\n\n return html`\n <section>\n <h3>${i18next.t('figure.label.animation')}</h3>\n </section>\n\n ${this.renderRecipes()}\n\n <section>\n <h3>${i18next.t('figure.label.parameters')}</h3>\n <p quiet>${i18next.t('figure.text.parameter-is-a-value-not-a-timeline')}</p>\n ${this.parameters.map((parameter, at) => this.renderParameter(parameter, at))}\n <button @click=${() => this.addParameter()} ?disabled=${nameless}>\n <md-icon>add</md-icon>${i18next.t('figure.button.add-parameter')}\n </button>\n </section>\n\n <section>\n <h3>${i18next.t('figure.label.clips')}</h3>\n <p quiet>${i18next.t('figure.text.clip-is-time-running')}</p>\n ${this.clips.map((clip, at) => this.renderClip(clip, at))}\n <button @click=${() => this.addClip()} ?disabled=${nameless}>\n <md-icon>add</md-icon>${i18next.t('figure.button.add-clip')}\n </button>\n ${nameless ? html`<p quiet>${i18next.t('figure.text.animation-needs-a-named-part')}</p>` : nothing}\n </section>\n\n ${this.movingParts === 0 ? nothing : this.renderBudget()}\n `\n }\n\n /**\n * 빈 화면 — **이 탭이 무엇인지 가르치는 자리다.**\n *\n * 「clip 을 추가하세요」라고만 쓰면 처음 여는 사람은 clip 이 무엇인지 모른 채 단추를 누른다.\n * 그래서 무엇을 만들 수 있는지 예를 들고, 그것이 어떻게 움직이는지(사실이 들어온다)를 적는다.\n */\n private renderRecipes(): TemplateResult {\n return html`\n <section>\n <h3>${i18next.t('figure.label.motion-intent')}</h3>\n <p quiet>${i18next.t('figure.text.motion-intent-help')}</p>\n ${this.partNames.length\n ? html`<select .value=${this.recipeTarget} @change=${(e: Event) => (this.recipeTarget = (e.target as HTMLSelectElement).value)}>\n ${this.partNames.map(name => html`<option value=${name}>${name}</option>`)}\n </select>\n <div recipes>\n ${MOTION_RECIPES.map(recipe => html`\n <button recipe @click=${() => this.addRecipe(recipe)}>\n <strong>${i18next.t('figure.label.recipe-' + recipe.id)}</strong>\n <span>${i18next.t('figure.text.recipe-' + recipe.id)}</span>\n </button>\n `)}\n </div>`\n : html`<p quiet>${i18next.t('figure.text.animation-needs-a-named-part')}</p>`}\n </section>\n `\n }\n\n /** 이름이 다른 것과 겹치나. 두 목록을 함께 본다 — 인스턴스는 이름 하나로 값을 준다. */\n private taken(kind: MotionKind, at: number, name: string): boolean {\n const mine = kind === 'clip' ? this.clips[at] : this.parameters[at]\n return this.allNames.some(one => one !== mine && one.name === name)\n }\n\n private renderClip(clip: Clip, at: number): TemplateResult {\n const key = `clip:${at}`\n const on = this.open === key\n const duplicate = this.taken('clip', at, clip.name)\n const nameless = !clip.name?.trim()\n\n return html`\n <div clip ?on=${on}>\n <div head>\n <button plain @click=${() => (this.open = on ? '' : key)} title=${i18next.t('figure.label.channels')}>\n <md-icon>${on ? 'expand_more' : 'chevron_right'}</md-icon>\n </button>\n <input\n name\n .value=${live(clip.name ?? '')}\n ?bad=${duplicate || nameless}\n placeholder=${i18next.t('figure.label.clip-name')}\n title=${duplicate ? i18next.t('figure.text.clip-name-taken') : i18next.t('figure.text.clip-name-is-how-it-is-driven')}\n @change=${(e: Event) => this.renameClip(at, (e.target as HTMLInputElement).value)}\n />\n <button plain @click=${() => this.removeClip(at)} title=${i18next.t('figure.button.remove')}>\n <md-icon>close</md-icon>\n </button>\n </div>\n\n ${duplicate ? html`<p warn>${i18next.t('figure.text.clip-name-taken')}</p>` : nothing}\n ${nameless ? html`<p warn>${i18next.t('figure.text.clip-needs-a-name')}</p>` : nothing}\n ${on ? this.renderChannels('clip', at) : nothing}\n </div>\n `\n }\n\n /**\n * 파라미터 하나 — **이름·범위·자세.**\n *\n * 범위가 화면에 있어야 하는 이유는 그것이 **인스턴스와 주고받는 말**이기 때문이다.\n * 곡선은 0~1 이고 인스턴스는 mm 로 준다. 그 사이를 런타임이 맵하는데, 무엇부터 무엇\n * 까지인지 저작자가 정하지 않으면 값을 줄 수가 없다.\n */\n private renderParameter(parameter: Parameter, at: number): TemplateResult {\n const key = `parameter:${at}`\n const on = this.open === key\n const duplicate = this.taken('parameter', at, parameter.name)\n const nameless = !parameter.name?.trim()\n const range = parameter.range ?? NEW_RANGE\n const backwards = !(range.max > range.min)\n const slowness = parameter.clip?.duration ?? 0\n\n return html`\n <div clip ?on=${on}>\n <div head>\n <button plain @click=${() => (this.open = on ? '' : key)} title=${i18next.t('figure.label.channels')}>\n <md-icon>${on ? 'expand_more' : 'chevron_right'}</md-icon>\n </button>\n <input\n name\n .value=${live(parameter.name ?? '')}\n ?bad=${duplicate || nameless}\n placeholder=${i18next.t('figure.label.parameter-name')}\n title=${duplicate\n ? i18next.t('figure.text.clip-name-taken')\n : i18next.t('figure.text.parameter-name-is-how-a-value-arrives')}\n @change=${(e: Event) => this.renameParameter(at, (e.target as HTMLInputElement).value)}\n />\n <button plain @click=${() => this.removeParameter(at)} title=${i18next.t('figure.button.remove')}>\n <md-icon>close</md-icon>\n </button>\n </div>\n\n ${duplicate ? html`<p warn>${i18next.t('figure.text.clip-name-taken')}</p>` : nothing}\n ${nameless ? html`<p warn>${i18next.t('figure.text.parameter-needs-a-name')}</p>` : nothing}\n\n <div row>\n <label>${i18next.t('figure.label.parameter-range')}</label>\n <input\n type=\"number\"\n step=\"1\"\n ?bad=${backwards}\n .value=${live(String(range.min))}\n aria-label=\"min\"\n @change=${(e: Event) => this.setRange(at, { min: Number((e.target as HTMLInputElement).value) || 0 })}\n />\n <input\n type=\"number\"\n step=\"1\"\n ?bad=${backwards}\n .value=${live(String(range.max))}\n aria-label=\"max\"\n @change=${(e: Event) => this.setRange(at, { max: Number((e.target as HTMLInputElement).value) || 0 })}\n />\n <input\n unit\n .value=${live(range.unit ?? '')}\n placeholder=\"mm\"\n aria-label=\"unit\"\n title=${i18next.t('figure.text.unit-is-a-word-not-a-rule')}\n @change=${(e: Event) => this.setRange(at, { unit: (e.target as HTMLInputElement).value.trim() })}\n />\n </div>\n ${backwards ? html`<p warn>${i18next.t('figure.text.range-needs-room')}</p>` : nothing}\n\n <div row>\n <label>${i18next.t('figure.label.parameter-default')}</label>\n <input\n type=\"number\"\n step=\"1\"\n .value=${live(String(parameter.default ?? range.min))}\n @change=${(e: Event) => this.setDefault(at, Number((e.target as HTMLInputElement).value) || 0)}\n />\n </div>\n\n <div row>\n <label>${i18next.t('figure.label.parameter-duration')}</label>\n <input\n type=\"number\"\n step=\"0.1\"\n min=\"0\"\n ?bad=${slowness < 0}\n .value=${live(parameter.clip?.duration === undefined ? '' : String(parameter.clip.duration))}\n placeholder=\"0\"\n aria-label=\"duration\"\n @change=${(e: Event) => this.setDuration(at, (e.target as HTMLInputElement).value)}\n />\n </div>\n <p quiet>${i18next.t('figure.text.parameter-duration-empty-is-instant')}</p>\n\n ${on ? this.renderChannels('parameter', at) : nothing}\n </div>\n `\n }\n\n private renderChannels(kind: MotionKind, at: number): TemplateResult {\n const channels = this.channelsOf(kind, at)\n\n return html`\n <p quiet>${i18next.t(kind === 'clip' ? 'figure.text.clip-is-time-running' : 'figure.text.parameter-curve-is-the-value-axis')}</p>\n\n ${channels.length === 0 ? html`<p warn>${i18next.t('figure.text.clip-needs-a-channel')}</p>` : nothing}\n ${channels.map((channel, j) => this.renderChannel(kind, channel, at, j))}\n\n <button @click=${() => this.addChannel(kind, at)}>\n <md-icon>add</md-icon>${i18next.t('figure.button.add-channel')}\n </button>\n `\n }\n\n /**\n * 채널 하나 — 어느 부품의 어느 속성을 움직이나.\n *\n * 없는 부품을 가리키는 채널은 붉게 낸다. 부품 이름을 바꾸면 그 순간 이렇게 되는데,\n * 검증은 저장할 때 말하고 여기서는 **그 자리에서** 보여 준다.\n */\n private renderChannel(kind: MotionKind, channel: Channel, at: number, j: number): TemplateResult {\n const orphan = !this.partNames.includes(channel.target)\n const turning = channel.path === 'rotation'\n\n return html`\n <div channel ?orphan=${orphan}>\n <div row>\n <label>${i18next.t('figure.label.channel-target')}</label>\n <select\n .value=${live(channel.target ?? '')}\n @change=${(e: Event) => this.setChannel(kind, at, j, { target: (e.target as HTMLSelectElement).value })}\n >\n ${orphan ? html`<option value=${channel.target}>${channel.target}</option>` : nothing}\n ${this.partNames.map(name => html`<option value=${name}>${name}</option>`)}\n </select>\n <button plain @click=${() => this.removeChannel(kind, at, j)} title=${i18next.t('figure.button.remove')}>\n <md-icon>close</md-icon>\n </button>\n </div>\n\n ${orphan ? html`<p warn>${i18next.t('figure.text.channel-target-is-gone')}</p>` : nothing}\n\n <div row>\n <label>${i18next.t('figure.label.channel-path')}</label>\n <select\n .value=${live(channel.path)}\n @change=${(e: Event) => this.setPath(kind, at, j, (e.target as HTMLSelectElement).value as ChannelPath)}\n >\n ${CHANNEL_PATHS.map(path => html`<option value=${path}>${i18next.t('figure.label.path-' + path)}</option>`)}\n </select>\n <select\n .value=${live(channel.interpolation ?? 'linear')}\n title=${i18next.t('figure.text.interpolation-explained')}\n @change=${(e: Event) =>\n this.setChannel(kind, at, j, { interpolation: (e.target as HTMLSelectElement).value as Channel['interpolation'] })}\n >\n ${INTERPOLATIONS.map(\n one => html`<option value=${one}>${i18next.t('figure.label.interpolation-' + one)}</option>`\n )}\n </select>\n </div>\n\n <p quiet>${i18next.t('figure.text.path-' + channel.path + '-unit')}</p>\n\n ${turning ? this.renderPivot(kind, channel, at, j) : nothing}\n ${this.renderKeys(kind, channel, at, j)}\n </div>\n `\n }\n\n /**\n * 회전 중심 — **`rotation` 에서만 뜻이 있다.**\n *\n * 그래서 경로가 rotation 일 때만 낸다. 언제나 내면 저작자가 옮김·배율에도 적고, 검증이\n * 저장할 때 「쓰이지 않는다」고 알린다. 안 보이면 적을 일이 없다.\n */\n private renderPivot(kind: MotionKind, channel: Channel, at: number, j: number): TemplateResult {\n const pivot = channel.pivot\n const on = pivot !== undefined\n\n return html`\n <div row>\n <label>${i18next.t('figure.label.channel-pivot')}</label>\n <button\n @click=${() => this.setChannel(kind, at, j, { pivot: on ? undefined : { x: 0, y: 0, z: 0 } })}\n title=${i18next.t('figure.text.pivot-defaults-to-the-part-centre')}\n >\n ${i18next.t(on ? 'figure.button.pivot-clear' : 'figure.button.pivot-set')}\n </button>\n ${on\n ? AXES.map(\n axis => html`\n <input\n type=\"number\"\n step=\"1\"\n .value=${live(String(pivot![axis]))}\n aria-label=${axis}\n @change=${(e: Event) =>\n this.setChannel(kind, at, j, {\n pivot: { ...pivot!, [axis]: Number((e.target as HTMLInputElement).value) || 0 }\n })}\n />\n `\n )\n : nothing}\n </div>\n `\n }\n\n /**\n * 키프레임 표.\n *\n * **둘 미만으로 못 내려간다.** 하나뿐이면 움직이는 것이 아니라 자세 하나이고, 형식이\n * 오류로 막는다. 저장하고 나서 알려 주는 것보다 지우는 단추를 죽이는 것이 낫다.\n *\n * 시각이 오름차순이어야 하는 것도 형식의 규칙이다. 여기서는 어긋난 줄을 붉게 내고 값을\n * 고치지는 않는다 — 저작자가 3 을 1 로 고치던 중일 수 있다.\n */\n private renderKeys(kind: MotionKind, channel: Channel, at: number, j: number): TemplateResult {\n const keys = channel.keys ?? []\n /*\n Keys on a parameter curve sit on the 0..1 value span (ADR-0051). A key above 1 is unreachable and\n the format refuses it. The screen marks it and leaves the number alone: rewriting what the author\n typed would hide what they wrote.\n */\n const onValues = kind === 'parameter'\n const outside = (key: Keyframe) => onValues && key.at > 1\n\n return html`\n <table keys>\n <tr>\n <th>${i18next.t(onValues ? 'figure.label.key-at-value' : 'figure.label.key-at')}</th>\n ${AXES.map(axis => html`<th>${axis}</th>`)}\n <th></th>\n </tr>\n ${keys.map((key, k) => {\n const backwards = k > 0 && key.at <= (keys[k - 1]!.at ?? 0)\n return html`\n <tr>\n <td>\n <input\n type=\"number\"\n step=${onValues ? '0.05' : '0.1'}\n min=\"0\"\n max=${onValues ? '1' : nothing}\n ?bad=${backwards || key.at < 0 || outside(key)}\n .value=${live(String(key.at))}\n title=${backwards\n ? i18next.t('figure.text.keys-must-rise')\n : outside(key)\n ? i18next.t('figure.text.parameter-key-within-span')\n : ''}\n @change=${(e: Event) =>\n this.setKey(kind, at, j, k, { at: Math.max(0, Number((e.target as HTMLInputElement).value) || 0) })}\n />\n </td>\n ${AXES.map(\n axis => html`\n <td>\n <input\n type=\"number\"\n step=${channel.path === 'scale' ? '0.1' : '1'}\n .value=${live(String(key.value[axis]))}\n aria-label=${axis}\n @change=${(e: Event) =>\n this.setKey(kind, at, j, k, {\n value: { ...key.value, [axis]: Number((e.target as HTMLInputElement).value) || 0 }\n })}\n />\n </td>\n `\n )}\n <td drop>\n <button\n plain\n ?disabled=${keys.length <= 2}\n title=${keys.length <= 2 ? i18next.t('figure.text.two-keys-at-least') : i18next.t('figure.button.remove')}\n @click=${() => this.removeKey(kind, at, j, k)}\n >\n <md-icon>close</md-icon>\n </button>\n </td>\n </tr>\n `\n })}\n </table>\n\n ${keys.some((key, k) => k > 0 && key.at <= (keys[k - 1]!.at ?? 0))\n ? html`<p warn>${i18next.t('figure.text.keys-must-rise')}</p>`\n : nothing}\n ${keys.some(outside) ? html`<p warn>${i18next.t('figure.text.parameter-key-within-span')}</p>` : nothing}\n\n <button @click=${() => this.addKey(kind, at, j)}>\n <md-icon>add</md-icon>${i18next.t('figure.button.add-key')}\n </button>\n `\n }\n\n /**\n * 움직이는 부품 예산.\n *\n * **넘어도 막지 않는다.** 움직이는 부품은 저마다 단독 묶음이라 draw call 이 늘고 프레임마다\n * 갱신이 는다 — 그 대가가 수로 보이면 저작자가 아낀다. 랜드마크 설비 하나는 정교해도 되고,\n * 그 값이 도면 예산에 드러나면 된다.\n */\n private renderBudget(): TemplateResult {\n const used = this.movingParts\n const over = used > LIMITS.animatedParts\n\n return html`\n <section>\n <h3>${i18next.t('figure.label.budget-animations')}</h3>\n <div budget ?over=${over}>\n <strong>${used}</strong>\n <span quiet>/ ${LIMITS.animatedParts}</span>\n </div>\n <p quiet>${i18next.t('figure.text.animated-parts-cost')}</p>\n ${over ? html`<p warn>${i18next.t('figure.text.animated-parts-over')}</p>` : nothing}\n </section>\n `\n }\n\n // ─── 고치기 ───────────────────────────────────────────────────────────────\n\n /**\n * 초안에 실어 올려보낸다.\n *\n * `animations` 는 도형 전체의 것이므로 부품 편집(`update-part`)이 아니라 `update-draft` 로\n * 간다. 빈 배열은 칸을 지운다 — clip 을 다 지운 도형은 `animations: []` 가 아니라 없는 것이다.\n */\n private tell(over: { animations?: Clip[]; parameters?: Parameter[] }): void {\n if (!this.draft) return\n\n const draft: FigureDraft = { ...this.draft, ...over }\n if (!draft.animations?.length) delete draft.animations\n if (!draft.parameters?.length) delete draft.parameters\n\n this.dispatchEvent(new CustomEvent('update-draft', { detail: { draft }, bubbles: true, composed: true }))\n }\n\n private patchClip(at: number, patch: Partial<Clip>): void {\n this.tell({ animations: this.clips.map((clip, i) => (i === at ? { ...clip, ...patch } : clip)) })\n }\n\n private patchParameter(at: number, patch: Partial<Parameter>): void {\n this.tell({ parameters: this.parameters.map((one, i) => (i === at ? { ...one, ...patch } : one)) })\n }\n\n /** 채널 묶음을 통째로 얹는다. **어느 목록이든 같은 자리에 닿는다.** */\n private setChannels(kind: MotionKind, at: number, channels: Channel[]): void {\n if (kind === 'clip') this.patchClip(at, { channels })\n else {\n const parameter = this.parameters[at]\n if (!parameter) return\n this.patchParameter(at, { clip: { ...parameter.clip, channels } })\n }\n }\n\n private patchChannel(kind: MotionKind, at: number, j: number, next: Channel): void {\n this.setChannels(\n kind,\n at,\n this.channelsOf(kind, at).map((channel, i) => (i === j ? next : channel))\n )\n }\n\n private addClip(): void {\n const target = this.partNames[0]\n if (!target) return\n\n const clip: Clip = {\n name: freeName(this.allNames, 'clip-1'),\n channels: [{ target, path: 'translation', keys: keysFor('translation') }]\n }\n\n this.open = `clip:${this.clips.length}`\n this.tell({ animations: [...this.clips, clip] })\n }\n\n private addParameter(): void {\n const target = this.partNames[0]\n if (!target) return\n\n const parameter: Parameter = {\n name: freeName(this.allNames, 'parameter-1'),\n range: { ...NEW_RANGE },\n clip: { channels: [{ target, path: 'translation', keys: keysFor('translation') }] }\n }\n\n this.open = `parameter:${this.parameters.length}`\n this.tell({ parameters: [...this.parameters, parameter] })\n }\n\n /**\n * Recipe creates a valid, editable two-pose motion; it never saves or publishes the Figure.\n *\n * 어느 목록으로 가는지는 레시피가 안다 — 도는 롤러는 애니메이션이고 열리는 문은\n * 파라미터다. 저작자에게 그 갈래를 먼저 고르게 하지 않는 이유가 이것이다.\n */\n private addRecipe(recipe: MotionRecipe): void {\n const target = this.recipeTarget || this.partNames[0]\n if (!target) return\n\n const channel: Channel = {\n target,\n path: recipe.path,\n keys: [{ at: 0, value: startValue(recipe.path) }, { at: 1, value: { ...recipe.end } }]\n }\n if (recipe.pivot) channel.pivot = { ...recipe.pivot }\n\n const name = freeName(this.allNames, recipe.name)\n\n if (recipe.kind === 'clip') {\n this.open = `clip:${this.clips.length}`\n this.tell({ animations: [...this.clips, { name, channels: [channel] }] })\n return\n }\n\n this.open = `parameter:${this.parameters.length}`\n this.tell({\n parameters: [...this.parameters, { name, range: { ...(recipe.range ?? NEW_RANGE) }, clip: { channels: [channel] } }]\n })\n }\n\n private renameClip(at: number, name: string): void {\n this.patchClip(at, { name: name.trim() })\n }\n\n private renameParameter(at: number, name: string): void {\n this.patchParameter(at, { name: name.trim() })\n }\n\n private setRange(at: number, patch: Partial<Parameter['range']>): void {\n const parameter = this.parameters[at]\n if (!parameter) return\n this.patchParameter(at, { range: { ...(parameter.range ?? NEW_RANGE), ...patch } })\n }\n\n /**\n * Transition time. Clearing the input removes the field, which means instant. 0 is instant too, but\n * a stored 0 and a missing field are different sources, so an empty input is never saved as 0.\n */\n private setDuration(at: number, raw: string): void {\n const parameter = this.parameters[at]\n if (!parameter) return\n const { duration: _dropped, ...rest } = parameter.clip\n const text = raw.trim()\n const clip = text === '' || !Number.isFinite(Number(text)) ? rest : { ...rest, duration: Number(text) }\n this.patchParameter(at, { clip })\n }\n\n private setDefault(at: number, value: number): void {\n this.patchParameter(at, { default: value })\n }\n\n private removeClip(at: number): void {\n this.open = ''\n this.tell({ animations: this.clips.filter((_, i) => i !== at) })\n }\n\n private removeParameter(at: number): void {\n this.open = ''\n this.tell({ parameters: this.parameters.filter((_, i) => i !== at) })\n }\n\n private addChannel(kind: MotionKind, at: number): void {\n const target = this.partNames[0]\n if (!target) return\n\n this.setChannels(kind, at, [\n ...this.channelsOf(kind, at),\n { target, path: 'translation', keys: keysFor('translation') }\n ])\n }\n\n private setChannel(kind: MotionKind, at: number, j: number, patch: Partial<Channel>): void {\n const channel = this.channelsOf(kind, at)[j]\n if (!channel) return\n\n const next: Channel = { ...channel, ...patch }\n /* `undefined` 를 얹는 것은 지우는 뜻이다. 남겨 두면 저장 형식에 빈 칸이 실린다. */\n if ('pivot' in patch && patch.pivot === undefined) delete next.pivot\n this.patchChannel(kind, at, j, next)\n }\n\n /**\n * 경로를 바꾼다 — **값까지 함께 옮긴다.**\n *\n * 옮김·회전의 0 은 「제자리」인데 배율의 0 은 **부품을 지운다.** 경로만 바꾸고 값을 그대로\n * 두면 저작자는 부품이 사라진 것을 보고 도구가 고장 난 줄 안다. 그래서 옮김·회전 ↔ 배율을\n * 건널 때 시작값을 그 경로의 제자리로 되돌린다. 시각은 지킨다 — 저작자가 짠 박자다.\n */\n private setPath(kind: MotionKind, at: number, j: number, path: ChannelPath): void {\n const channel = this.channelsOf(kind, at)[j]\n if (!channel) return\n\n const crossing = (channel.path === 'scale') !== (path === 'scale')\n const next: Channel = {\n ...channel,\n path,\n keys: crossing ? channel.keys.map(key => ({ at: key.at, value: startValue(path) })) : channel.keys\n }\n /* 회전이 아니면 회전 중심은 쓰이지 않는다. 남겨 두면 검증이 「쓰이지 않는다」고 알린다. */\n if (path !== 'rotation') delete next.pivot\n\n this.patchChannel(kind, at, j, next)\n }\n\n private removeChannel(kind: MotionKind, at: number, j: number): void {\n this.setChannels(\n kind,\n at,\n this.channelsOf(kind, at).filter((_, i) => i !== j)\n )\n }\n\n /** 마지막 키에서 1 초 뒤. 값은 그 키를 그대로 받는다 — 붙여 놓고 고치는 것이 짜기 쉽다. */\n private addKey(kind: MotionKind, at: number, j: number): void {\n const channel = this.channelsOf(kind, at)[j]\n if (!channel) return\n\n const last = channel.keys[channel.keys.length - 1]\n\n /*\n A parameter curve ends at 1, so appending a key would make it unreachable. Insert it between the last two keys.\n */\n if (kind === 'parameter' && channel.keys.length >= 2) {\n const before = channel.keys[channel.keys.length - 2]!\n const middle: Keyframe = { at: (before.at + last!.at) / 2, value: { ...before.value } }\n this.patchChannel(kind, at, j, { ...channel, keys: [...channel.keys.slice(0, -1), middle, last!] })\n return\n }\n\n const key: Keyframe = { at: (last?.at ?? 0) + 1, value: { ...(last?.value ?? startValue(channel.path)) } }\n this.patchChannel(kind, at, j, { ...channel, keys: [...channel.keys, key] })\n }\n\n private setKey(kind: MotionKind, at: number, j: number, k: number, patch: Partial<Keyframe>): void {\n const channel = this.channelsOf(kind, at)[j]\n if (!channel) return\n this.patchChannel(kind, at, j, {\n ...channel,\n keys: channel.keys.map((key, i) => (i === k ? { ...key, ...patch } : key))\n })\n }\n\n /** 둘 미만으로 내려가지 않는다 — 단추가 이미 죽어 있지만 밖에서 불릴 수 있다. */\n private removeKey(kind: MotionKind, at: number, j: number, k: number): void {\n const channel = this.channelsOf(kind, at)[j]\n if (!channel || channel.keys.length <= 2) return\n this.patchChannel(kind, at, j, { ...channel, keys: channel.keys.filter((_, i) => i !== k) })\n }\n}\n"]}
1
+ {"version":3,"file":"figure-animations.js","sourceRoot":"","sources":["../../client/modeller/figure-animations.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing, type TemplateResult } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { live } from 'lit/directives/live.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport { AXES, CHANNEL_PATHS, INTERPOLATIONS, LIMITS } from '@hatiolab/figure-model'\nimport type { ChannelPath, JointChannel, PartChannel, Vec3 } from '@hatiolab/figure-model'\n\nimport type { FigureDraft, PartModel } from './figure-source.js'\n\n/**\n * 이 도형이 **어떻게 움직이는가.**\n *\n * ## 왜 탭 하나가 필요한가\n *\n * 움직임은 형식에 있고 런타임까지 서 있었다 — 검증이 촘촘히 보고, 청사진이 움직이는 부품을\n * 단독 묶음으로 빼고(합치면 따로 못 움직인다), 씬이 frameClock 을 구독해 실제로 돌린다.\n * 미리보기에도 clip 마다 슬라이더가 있었다.\n *\n * **만들 자리만 없었다.** 그래서 움직이는 도형을 얻는 길이 「AI 가 후보로 내놓는 것」 하나였고,\n * 채널 하나를 고치려면 손댈 화면이 없었다.\n *\n * ## 부품이 아니라 도형의 것이다\n *\n * clip 하나가 부품 여럿을 함께 움직인다 — 문 열림은 왼짝과 오른짝이 반대로 미끄러지는 것\n * 하나다. 그래서 부품을 고르고 「이 부품의 움직임」을 적는 형태가 될 수 없고, 속성 탭이 아니라\n * 자기 탭에 산다.\n *\n * ## 트윈은 타임라인을 재생하지 않는다\n *\n * 「문 열기 clip 을 재생하라」가 아니라 **「지금 40% 열려 있다」**다. 그 둘은 다른 것이라\n * 이 탭도 둘로 나뉜다.\n *\n * 애니메이션 시각이 흐른다. 인스턴스가 주는 수는 배속이다 — 도는 롤러\n * 파라미터 값이 자세를 만든다. 인스턴스가 주는 수는 물리량이다 — 1200mm 내려온 호이스트\n *\n * 한동안 뒤엣것이 애니메이션 안에 `drive: 'hold'` 로 숨어 있었다. 형식의 판단은 맞았는데\n * **자리와 이름이 틀려서**, 「길이값을 변수로 노출하라」는 요청에 저작자도 AI 도 이것을\n * 못 찾았다 — 애니메이션 칸에 있을 거라고 생각하지 않는다(ADR-0051).\n */\n\ntype Clip = NonNullable<FigureDraft['animations']>[number]\ntype Parameter = NonNullable<FigureDraft['parameters']>[number]\ntype Channel = Clip['channels'][number]\ntype Keyframe = PartChannel['keys'][number]\ntype JointKey = JointChannel['keys'][number]\n\n/** A channel that drives a joint names the joint and carries one number per key (ADR-0066). */\nfunction isJointChannel(channel: Channel): channel is JointChannel {\n return channel.path === undefined\n}\n\n/** 어느 목록의 몇째인가. 채널·키 편집기가 둘을 함께 쓴다. */\ntype MotionKind = 'clip' | 'parameter'\n\n/** A first-success motion: intent first, raw channel editing second. */\ninterface MotionRecipe {\n id: 'conveyor' | 'gate' | 'pusher' | 'lift'\n name: string\n kind: MotionKind\n path: ChannelPath\n end: Vec3\n pivot?: Vec3\n /** 파라미터 레시피만. 인스턴스가 주고받는 물리량이다. */\n range?: Parameter['range']\n}\n\n/*\n 레시피의 `end` 가 곧 그 범위의 끝 자세다 — 리프트가 100mm 올라가는 곡선이면 범위도\n 0~100mm 다. 둘이 어긋나면 저작자가 1200 을 주고도 100 만 올라가는 것을 보게 된다.\n*/\nconst MOTION_RECIPES: readonly MotionRecipe[] = [\n { id: 'conveyor', name: 'conveyor-running', kind: 'clip', path: 'rotation', end: { x: 360, y: 0, z: 0 } },\n {\n id: 'gate',\n name: 'gate-open',\n kind: 'parameter',\n path: 'rotation',\n end: { x: 0, y: 90, z: 0 },\n pivot: { x: 0, y: 0, z: 0 },\n range: { unit: '%', min: 0, max: 100 }\n },\n {\n id: 'pusher',\n name: 'pusher-position',\n kind: 'parameter',\n path: 'translation',\n end: { x: 100, y: 0, z: 0 },\n range: { unit: 'mm', min: 0, max: 100 }\n },\n {\n id: 'lift',\n name: 'lift-height',\n kind: 'parameter',\n path: 'translation',\n end: { x: 0, y: 100, z: 0 },\n range: { unit: 'mm', min: 0, max: 100 }\n }\n]\n\n/** 새 파라미터의 범위. 단위는 저작자가 고쳐 쓴다 — 형식은 단위를 해석하지 않는다. */\nconst NEW_RANGE: Parameter['range'] = { unit: 'mm', min: 0, max: 1000 }\n\n/** 새 clip 의 키 둘. **하나로 만들지 않는다** — 키 하나는 움직임이 아니라 자세다. */\nconst NEW_KEYS: Keyframe[] = [\n { at: 0, value: { x: 0, y: 0, z: 0 } },\n { at: 1, value: { x: 0, y: 0, z: 0 } }\n]\n\n/** `scale` 만 1 에서 시작한다 — 0 은 부품을 지운다. */\nfunction startValue(path: ChannelPath): Vec3 {\n return path === 'scale' ? { x: 1, y: 1, z: 1 } : { x: 0, y: 0, z: 0 }\n}\n\nfunction keysFor(path: ChannelPath): Keyframe[] {\n return NEW_KEYS.map(key => ({ at: key.at, value: startValue(path) }))\n}\n\n/**\n * 이미 쓴 이름을 비켜 간다.\n *\n * **두 목록을 함께 본다.** 인스턴스는 이름 하나로 값을 주므로 애니메이션과 파라미터가\n * 같은 이름을 가지면 어느 쪽에 준 것인지 알 수 없고, 형식이 그것을 오류로 막는다.\n */\nfunction freeName(taken: readonly { name: string }[], stem: string): string {\n const used = new Set(taken.map(one => one.name))\n if (!used.has(stem)) return stem\n for (let n = 2; ; n++) if (!used.has(`${stem}-${n}`)) return `${stem}-${n}`\n}\n\n@customElement('figure-animations')\nexport class FigureAnimations extends localize(i18next)(LitElement) {\n static styles = [\n ScrollbarStyles,\n css`\n :host {\n display: flex;\n flex-direction: column;\n min-height: 0;\n overflow-y: auto;\n background-color: var(--md-sys-color-surface-container-lowest);\n color: var(--md-sys-color-on-surface);\n font: var(--label-font, inherit);\n font-size: 0.76rem;\n }\n\n section {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-medium, 8px);\n padding: var(--spacing-large, 12px);\n border-bottom: 1px solid var(--md-sys-color-outline-variant);\n }\n\n /* 다른 탭들과 같은 눈금이다 */\n h3 {\n margin: 0 0 2px 0;\n font-size: var(--ui-t-micro, 11px);\n font-weight: 700;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--md-sys-color-on-surface-variant, var(--md-sys-color-on-surface));\n }\n\n p[quiet] {\n margin: 0;\n font-size: 0.72rem;\n line-height: 1.5;\n color: var(--md-sys-color-on-surface-variant);\n }\n\n div[recipes] { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }\n button[recipe] { min-height: 54px; align-items: flex-start; flex-direction: column; text-align: left; }\n button[recipe] strong { font-size: 0.74rem; }\n button[recipe] span { color: var(--md-sys-color-on-surface-variant); font-size: 0.68rem; line-height: 1.35; }\n\n /* ── clip ─────────────────────────────────────────────────────── */\n\n div[clip] {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-medium, 8px);\n padding: 8px;\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 4px;\n }\n div[clip][on] {\n border-color: var(--md-sys-color-primary);\n background-color: var(--md-sys-color-surface-container-low);\n }\n\n div[head] {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n div[head] input[name] {\n flex: 1;\n min-width: 0;\n }\n\n /* ── channel ──────────────────────────────────────────────────── */\n\n div[channel] {\n display: flex;\n flex-direction: column;\n gap: 6px;\n padding: 6px 8px;\n border-left: 2px solid var(--md-sys-color-outline-variant);\n background-color: var(--md-sys-color-surface-container-lowest);\n }\n div[channel][orphan] {\n border-left-color: var(--md-sys-color-error);\n }\n\n div[row] {\n display: flex;\n align-items: center;\n gap: 6px;\n }\n div[row] > label {\n flex: none;\n min-width: 3.2em;\n color: var(--md-sys-color-on-surface-variant);\n }\n\n /* ── keyframe ─────────────────────────────────────────────────── */\n\n table[keys] {\n width: 100%;\n border-collapse: collapse;\n }\n table[keys] th {\n padding: 0 2px 2px;\n font-size: 0.68rem;\n font-weight: 600;\n text-align: left;\n color: var(--md-sys-color-on-surface-variant);\n }\n table[keys] td {\n padding: 1px 2px;\n }\n table[keys] input {\n width: 100%;\n min-width: 0;\n }\n table[keys] td[drop] {\n width: 1.6em;\n }\n\n input,\n select {\n box-sizing: border-box;\n padding: 3px 5px;\n font: inherit;\n font-size: 0.74rem;\n color: var(--md-sys-color-on-surface);\n background-color: var(--md-sys-color-surface-container-lowest);\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 3px;\n }\n input:focus,\n select:focus {\n outline: none;\n border-color: var(--md-sys-color-primary);\n }\n input[bad] {\n border-color: var(--md-sys-color-error);\n }\n\n button {\n display: inline-flex;\n align-items: center;\n gap: 3px;\n padding: 3px 8px;\n font: inherit;\n font-size: 0.72rem;\n color: var(--md-sys-color-on-surface);\n background-color: var(--md-sys-color-surface-container);\n border: 1px solid var(--md-sys-color-outline-variant);\n border-radius: 3px;\n cursor: pointer;\n }\n button:hover:not(:disabled) {\n background-color: var(--md-sys-color-surface-container-high);\n }\n button:disabled {\n opacity: 0.4;\n cursor: default;\n }\n button[plain] {\n padding: 1px 4px;\n background: none;\n border: none;\n color: var(--md-sys-color-on-surface-variant);\n }\n button[plain]:hover:not(:disabled) {\n color: var(--md-sys-color-error);\n background: none;\n }\n button md-icon {\n font-size: 14px;\n width: 14px;\n height: 14px;\n }\n\n /* ── 예산 ─────────────────────────────────────────────────────── */\n\n div[budget] {\n display: flex;\n align-items: baseline;\n gap: 6px;\n }\n div[budget] strong {\n font-size: 0.86rem;\n font-weight: 700;\n }\n div[budget][over] strong {\n color: var(--md-sys-color-error);\n }\n\n p[warn] {\n margin: 0;\n font-size: 0.7rem;\n line-height: 1.5;\n color: var(--md-sys-color-error);\n }\n `\n ]\n\n @property({ type: Object }) draft?: FigureDraft\n @property({ type: Array }) parts: PartModel[] = []\n\n /**\n * 펼쳐 둔 것. 이름이 아니라 **목록과 자리**로 잡는다 — 이름은 편집 중에 바뀐다.\n *\n * 목록이 둘이므로 자리 하나로는 모자란다. `clip:0` 과 `parameter:0` 은 다른 것이다.\n */\n @state() private open = ''\n @state() private recipeTarget = ''\n\n private get clips(): Clip[] {\n return this.draft?.animations ?? []\n }\n\n private get parameters(): Parameter[] {\n return this.draft?.parameters ?? []\n }\n\n /** 두 목록의 이름을 한자리에서 본다 — 인스턴스가 이름 하나로 값을 준다. */\n private get allNames(): { name: string }[] {\n return [...this.clips, ...this.parameters]\n }\n\n private channelsOf(kind: MotionKind, at: number): Channel[] {\n return (kind === 'clip' ? this.clips[at]?.channels : this.parameters[at]?.clip?.channels) ?? []\n }\n\n /** 부품 이름 — 채널이 이것을 가리킨다. */\n private get partNames(): string[] {\n return this.parts.map(part => part.name).filter(name => !!name)\n }\n\n /** Joints a channel can drive instead of a part (ADR-0066). */\n private get joints(): NonNullable<FigureDraft['joints']> {\n return this.draft?.joints ?? []\n }\n\n /**\n * 몇 부품이 움직이나 — 채널이 가리키는 **서로 다른 부품**의 수.\n *\n * clip 수가 아니다. 한 부품을 세 clip 이 움직여도 그 부품 하나가 단독 묶음이 될 뿐이다.\n * 청사진이 묶음을 가르는 기준과 같은 셈이어야 화면의 수와 판정의 수가 맞는다.\n */\n private get movingParts(): number {\n const moving = new Set<string>()\n for (const clip of this.clips) for (const channel of clip.channels) moving.add(channel.target)\n for (const parameter of this.parameters) {\n for (const channel of parameter.clip?.channels ?? []) moving.add(channel.target)\n }\n return moving.size\n }\n\n render(): TemplateResult {\n if (!this.draft) return html``\n\n const nameless = this.partNames.length === 0\n\n return html`\n <section>\n <h3>${i18next.t('figure.label.animation')}</h3>\n </section>\n\n ${this.renderRecipes()}\n\n <section>\n <h3>${i18next.t('figure.label.parameters')}</h3>\n <p quiet>${i18next.t('figure.text.parameter-is-a-value-not-a-timeline')}</p>\n ${this.parameters.map((parameter, at) => this.renderParameter(parameter, at))}\n <button @click=${() => this.addParameter()} ?disabled=${nameless}>\n <md-icon>add</md-icon>${i18next.t('figure.button.add-parameter')}\n </button>\n </section>\n\n <section>\n <h3>${i18next.t('figure.label.clips')}</h3>\n <p quiet>${i18next.t('figure.text.clip-is-time-running')}</p>\n ${this.clips.map((clip, at) => this.renderClip(clip, at))}\n <button @click=${() => this.addClip()} ?disabled=${nameless}>\n <md-icon>add</md-icon>${i18next.t('figure.button.add-clip')}\n </button>\n ${nameless ? html`<p quiet>${i18next.t('figure.text.animation-needs-a-named-part')}</p>` : nothing}\n </section>\n\n ${this.movingParts === 0 ? nothing : this.renderBudget()}\n `\n }\n\n /**\n * 빈 화면 — **이 탭이 무엇인지 가르치는 자리다.**\n *\n * 「clip 을 추가하세요」라고만 쓰면 처음 여는 사람은 clip 이 무엇인지 모른 채 단추를 누른다.\n * 그래서 무엇을 만들 수 있는지 예를 들고, 그것이 어떻게 움직이는지(사실이 들어온다)를 적는다.\n */\n private renderRecipes(): TemplateResult {\n return html`\n <section>\n <h3>${i18next.t('figure.label.motion-intent')}</h3>\n <p quiet>${i18next.t('figure.text.motion-intent-help')}</p>\n ${this.partNames.length\n ? html`<select .value=${this.recipeTarget} @change=${(e: Event) => (this.recipeTarget = (e.target as HTMLSelectElement).value)}>\n ${this.partNames.map(name => html`<option value=${name}>${name}</option>`)}\n </select>\n <div recipes>\n ${MOTION_RECIPES.map(recipe => html`\n <button recipe @click=${() => this.addRecipe(recipe)}>\n <strong>${i18next.t('figure.label.recipe-' + recipe.id)}</strong>\n <span>${i18next.t('figure.text.recipe-' + recipe.id)}</span>\n </button>\n `)}\n </div>`\n : html`<p quiet>${i18next.t('figure.text.animation-needs-a-named-part')}</p>`}\n </section>\n `\n }\n\n /** 이름이 다른 것과 겹치나. 두 목록을 함께 본다 — 인스턴스는 이름 하나로 값을 준다. */\n private taken(kind: MotionKind, at: number, name: string): boolean {\n const mine = kind === 'clip' ? this.clips[at] : this.parameters[at]\n return this.allNames.some(one => one !== mine && one.name === name)\n }\n\n private renderClip(clip: Clip, at: number): TemplateResult {\n const key = `clip:${at}`\n const on = this.open === key\n const duplicate = this.taken('clip', at, clip.name)\n const nameless = !clip.name?.trim()\n\n return html`\n <div clip ?on=${on}>\n <div head>\n <button plain @click=${() => (this.open = on ? '' : key)} title=${i18next.t('figure.label.channels')}>\n <md-icon>${on ? 'expand_more' : 'chevron_right'}</md-icon>\n </button>\n <input\n name\n .value=${live(clip.name ?? '')}\n ?bad=${duplicate || nameless}\n placeholder=${i18next.t('figure.label.clip-name')}\n title=${duplicate ? i18next.t('figure.text.clip-name-taken') : i18next.t('figure.text.clip-name-is-how-it-is-driven')}\n @change=${(e: Event) => this.renameClip(at, (e.target as HTMLInputElement).value)}\n />\n <button plain @click=${() => this.removeClip(at)} title=${i18next.t('figure.button.remove')}>\n <md-icon>close</md-icon>\n </button>\n </div>\n\n ${duplicate ? html`<p warn>${i18next.t('figure.text.clip-name-taken')}</p>` : nothing}\n ${nameless ? html`<p warn>${i18next.t('figure.text.clip-needs-a-name')}</p>` : nothing}\n ${on ? this.renderChannels('clip', at) : nothing}\n </div>\n `\n }\n\n /**\n * 파라미터 하나 — **이름·범위·자세.**\n *\n * 범위가 화면에 있어야 하는 이유는 그것이 **인스턴스와 주고받는 말**이기 때문이다.\n * 곡선은 0~1 이고 인스턴스는 mm 로 준다. 그 사이를 런타임이 맵하는데, 무엇부터 무엇\n * 까지인지 저작자가 정하지 않으면 값을 줄 수가 없다.\n */\n private renderParameter(parameter: Parameter, at: number): TemplateResult {\n const key = `parameter:${at}`\n const on = this.open === key\n const duplicate = this.taken('parameter', at, parameter.name)\n const nameless = !parameter.name?.trim()\n const range = parameter.range ?? NEW_RANGE\n const backwards = !(range.max > range.min)\n const slowness = parameter.clip?.duration ?? 0\n\n return html`\n <div clip ?on=${on}>\n <div head>\n <button plain @click=${() => (this.open = on ? '' : key)} title=${i18next.t('figure.label.channels')}>\n <md-icon>${on ? 'expand_more' : 'chevron_right'}</md-icon>\n </button>\n <input\n name\n .value=${live(parameter.name ?? '')}\n ?bad=${duplicate || nameless}\n placeholder=${i18next.t('figure.label.parameter-name')}\n title=${duplicate\n ? i18next.t('figure.text.clip-name-taken')\n : i18next.t('figure.text.parameter-name-is-how-a-value-arrives')}\n @change=${(e: Event) => this.renameParameter(at, (e.target as HTMLInputElement).value)}\n />\n <button plain @click=${() => this.removeParameter(at)} title=${i18next.t('figure.button.remove')}>\n <md-icon>close</md-icon>\n </button>\n </div>\n\n ${duplicate ? html`<p warn>${i18next.t('figure.text.clip-name-taken')}</p>` : nothing}\n ${nameless ? html`<p warn>${i18next.t('figure.text.parameter-needs-a-name')}</p>` : nothing}\n\n <div row>\n <label>${i18next.t('figure.label.parameter-range')}</label>\n <input\n type=\"number\"\n step=\"1\"\n ?bad=${backwards}\n .value=${live(String(range.min))}\n aria-label=\"min\"\n @change=${(e: Event) => this.setRange(at, { min: Number((e.target as HTMLInputElement).value) || 0 })}\n />\n <input\n type=\"number\"\n step=\"1\"\n ?bad=${backwards}\n .value=${live(String(range.max))}\n aria-label=\"max\"\n @change=${(e: Event) => this.setRange(at, { max: Number((e.target as HTMLInputElement).value) || 0 })}\n />\n <input\n unit\n .value=${live(range.unit ?? '')}\n placeholder=\"mm\"\n aria-label=\"unit\"\n title=${i18next.t('figure.text.unit-is-a-word-not-a-rule')}\n @change=${(e: Event) => this.setRange(at, { unit: (e.target as HTMLInputElement).value.trim() })}\n />\n </div>\n ${backwards ? html`<p warn>${i18next.t('figure.text.range-needs-room')}</p>` : nothing}\n\n <div row>\n <label>${i18next.t('figure.label.parameter-default')}</label>\n <input\n type=\"number\"\n step=\"1\"\n .value=${live(String(parameter.default ?? range.min))}\n @change=${(e: Event) => this.setDefault(at, Number((e.target as HTMLInputElement).value) || 0)}\n />\n </div>\n\n <div row>\n <label>${i18next.t('figure.label.parameter-duration')}</label>\n <input\n type=\"number\"\n step=\"0.1\"\n min=\"0\"\n ?bad=${slowness < 0}\n .value=${live(parameter.clip?.duration === undefined ? '' : String(parameter.clip.duration))}\n placeholder=\"0\"\n aria-label=\"duration\"\n @change=${(e: Event) => this.setDuration(at, (e.target as HTMLInputElement).value)}\n />\n </div>\n <p quiet>${i18next.t('figure.text.parameter-duration-empty-is-instant')}</p>\n\n ${on ? this.renderChannels('parameter', at) : nothing}\n </div>\n `\n }\n\n private renderChannels(kind: MotionKind, at: number): TemplateResult {\n const channels = this.channelsOf(kind, at)\n\n return html`\n <p quiet>${i18next.t(kind === 'clip' ? 'figure.text.clip-is-time-running' : 'figure.text.parameter-curve-is-the-value-axis')}</p>\n\n ${channels.length === 0 ? html`<p warn>${i18next.t('figure.text.clip-needs-a-channel')}</p>` : nothing}\n ${channels.map((channel, j) => this.renderChannel(kind, channel, at, j))}\n\n <button @click=${() => this.addChannel(kind, at)}>\n <md-icon>add</md-icon>${i18next.t('figure.button.add-channel')}\n </button>\n `\n }\n\n /**\n * 채널 하나 — 어느 부품의 어느 속성을 움직이나.\n *\n * 없는 부품을 가리키는 채널은 붉게 낸다. 부품 이름을 바꾸면 그 순간 이렇게 되는데,\n * 검증은 저장할 때 말하고 여기서는 **그 자리에서** 보여 준다.\n */\n private renderChannel(kind: MotionKind, channel: Channel, at: number, j: number): TemplateResult {\n const joint = this.joints.find(one => one.name === channel.target)\n const orphan = !this.partNames.includes(channel.target) && !joint\n const target = html`\n <div row>\n <label>${i18next.t('figure.label.channel-target')}</label>\n <select\n .value=${live(channel.target ?? '')}\n @change=${(e: Event) => this.retarget(kind, at, j, (e.target as HTMLSelectElement).value)}\n >\n ${orphan ? html`<option value=${channel.target}>${channel.target}</option>` : nothing}\n <optgroup label=${i18next.t('figure.label.channel-target-parts')}>\n ${this.partNames.map(name => html`<option value=${name}>${name}</option>`)}\n </optgroup>\n ${this.joints.length > 0\n ? html`<optgroup label=${i18next.t('figure.label.channel-target-joints')}>\n ${this.joints.map(one => html`<option value=${one.name}>${one.name}</option>`)}\n </optgroup>`\n : nothing}\n </select>\n <button plain @click=${() => this.removeChannel(kind, at, j)} title=${i18next.t('figure.button.remove')}>\n <md-icon>close</md-icon>\n </button>\n </div>\n `\n\n /* A joint channel has no path or pivot: the joint says what moves. Each key is the joint coordinate. */\n if (isJointChannel(channel)) {\n const unit = joint?.type === 'prismatic' ? 'mm' : 'deg'\n return html`\n <div channel ?orphan=${orphan}>\n ${target} ${orphan ? html`<p warn>${i18next.t('figure.text.channel-target-is-gone')}</p>` : nothing}\n <p quiet>${i18next.t('figure.text.joint-channel-value-' + unit)}</p>\n ${this.renderJointKeys(kind, channel, at, j, joint?.limits)}\n </div>\n `\n }\n\n const turning = channel.path === 'rotation'\n\n return html`\n <div channel ?orphan=${orphan}>\n ${target}\n\n ${orphan ? html`<p warn>${i18next.t('figure.text.channel-target-is-gone')}</p>` : nothing}\n\n <div row>\n <label>${i18next.t('figure.label.channel-path')}</label>\n <select\n .value=${live(channel.path)}\n @change=${(e: Event) => this.setPath(kind, at, j, (e.target as HTMLSelectElement).value as ChannelPath)}\n >\n ${CHANNEL_PATHS.map(path => html`<option value=${path}>${i18next.t('figure.label.path-' + path)}</option>`)}\n </select>\n <select\n .value=${live(channel.interpolation ?? 'linear')}\n title=${i18next.t('figure.text.interpolation-explained')}\n @change=${(e: Event) =>\n this.setChannel(kind, at, j, { interpolation: (e.target as HTMLSelectElement).value as Channel['interpolation'] })}\n >\n ${INTERPOLATIONS.map(\n one => html`<option value=${one}>${i18next.t('figure.label.interpolation-' + one)}</option>`\n )}\n </select>\n </div>\n\n <p quiet>${i18next.t('figure.text.path-' + channel.path + '-unit')}</p>\n\n ${turning ? this.renderPivot(kind, channel, at, j) : nothing}\n ${this.renderKeys(kind, channel, at, j)}\n </div>\n `\n }\n\n /**\n * 회전 중심 — **`rotation` 에서만 뜻이 있다.**\n *\n * 그래서 경로가 rotation 일 때만 낸다. 언제나 내면 저작자가 옮김·배율에도 적고, 검증이\n * 저장할 때 「쓰이지 않는다」고 알린다. 안 보이면 적을 일이 없다.\n */\n private renderPivot(kind: MotionKind, channel: PartChannel, at: number, j: number): TemplateResult {\n const pivot = channel.pivot\n const on = pivot !== undefined\n\n return html`\n <div row>\n <label>${i18next.t('figure.label.channel-pivot')}</label>\n <button\n @click=${() => this.setChannel(kind, at, j, { pivot: on ? undefined : { x: 0, y: 0, z: 0 } })}\n title=${i18next.t('figure.text.pivot-defaults-to-the-part-centre')}\n >\n ${i18next.t(on ? 'figure.button.pivot-clear' : 'figure.button.pivot-set')}\n </button>\n ${on\n ? AXES.map(\n axis => html`\n <input\n type=\"number\"\n step=\"1\"\n .value=${live(String(pivot![axis]))}\n aria-label=${axis}\n @change=${(e: Event) =>\n this.setChannel(kind, at, j, {\n pivot: { ...pivot!, [axis]: Number((e.target as HTMLInputElement).value) || 0 }\n })}\n />\n `\n )\n : nothing}\n </div>\n `\n }\n\n /**\n * 키프레임 표.\n *\n * **둘 미만으로 못 내려간다.** 하나뿐이면 움직이는 것이 아니라 자세 하나이고, 형식이\n * 오류로 막는다. 저장하고 나서 알려 주는 것보다 지우는 단추를 죽이는 것이 낫다.\n *\n * 시각이 오름차순이어야 하는 것도 형식의 규칙이다. 여기서는 어긋난 줄을 붉게 내고 값을\n * 고치지는 않는다 — 저작자가 3 을 1 로 고치던 중일 수 있다.\n */\n /**\n * Keys of a joint channel: a position and one joint coordinate each. A value outside the joint's limits\n * is marked and left as typed; the format refuses it on save.\n */\n private renderJointKeys(\n kind: MotionKind,\n channel: JointChannel,\n at: number,\n j: number,\n limits?: { min: number; max: number }\n ): TemplateResult {\n const keys = channel.keys ?? []\n const onValues = kind === 'parameter'\n const beyond = (key: JointKey) => !!limits && (key.value < limits.min || key.value > limits.max)\n\n return html`\n <table keys>\n <tr>\n <th>${i18next.t(onValues ? 'figure.label.key-at-value' : 'figure.label.key-at')}</th>\n <th>${i18next.t('figure.label.joint-value')}</th>\n <th></th>\n </tr>\n ${keys.map((key, k) => {\n const backwards = k > 0 && key.at <= (keys[k - 1]!.at ?? 0)\n return html`\n <tr>\n <td>\n <input\n type=\"number\"\n step=${onValues ? '0.05' : '0.1'}\n min=\"0\"\n max=${onValues ? '1' : nothing}\n ?bad=${backwards || key.at < 0 || (onValues && key.at > 1)}\n .value=${live(String(key.at))}\n @change=${(e: Event) =>\n this.setJointKey(kind, at, j, k, { at: Math.max(0, Number((e.target as HTMLInputElement).value) || 0) })}\n />\n </td>\n <td>\n <input\n type=\"number\"\n step=\"1\"\n ?bad=${beyond(key)}\n .value=${live(String(key.value))}\n title=${beyond(key) ? i18next.t('figure.text.joint-value-beyond-limits') : ''}\n @change=${(e: Event) => this.setJointKey(kind, at, j, k, { value: Number((e.target as HTMLInputElement).value) || 0 })}\n />\n </td>\n <td drop>\n <button\n plain\n ?disabled=${keys.length <= 2}\n title=${keys.length <= 2 ? i18next.t('figure.text.two-keys-at-least') : i18next.t('figure.button.remove')}\n @click=${() => this.removeKey(kind, at, j, k)}\n >\n <md-icon>close</md-icon>\n </button>\n </td>\n </tr>\n `\n })}\n </table>\n ${keys.some(beyond) ? html`<p warn>${i18next.t('figure.text.joint-value-beyond-limits')}</p>` : nothing}\n <button @click=${() => this.addKey(kind, at, j)}>\n <md-icon>add</md-icon>${i18next.t('figure.button.add-key')}\n </button>\n `\n }\n\n private renderKeys(kind: MotionKind, channel: PartChannel, at: number, j: number): TemplateResult {\n const keys = channel.keys ?? []\n /*\n Keys on a parameter curve sit on the 0..1 value span (ADR-0051). A key above 1 is unreachable and\n the format refuses it. The screen marks it and leaves the number alone: rewriting what the author\n typed would hide what they wrote.\n */\n const onValues = kind === 'parameter'\n const outside = (key: Keyframe) => onValues && key.at > 1\n\n return html`\n <table keys>\n <tr>\n <th>${i18next.t(onValues ? 'figure.label.key-at-value' : 'figure.label.key-at')}</th>\n ${AXES.map(axis => html`<th>${axis}</th>`)}\n <th></th>\n </tr>\n ${keys.map((key, k) => {\n const backwards = k > 0 && key.at <= (keys[k - 1]!.at ?? 0)\n return html`\n <tr>\n <td>\n <input\n type=\"number\"\n step=${onValues ? '0.05' : '0.1'}\n min=\"0\"\n max=${onValues ? '1' : nothing}\n ?bad=${backwards || key.at < 0 || outside(key)}\n .value=${live(String(key.at))}\n title=${backwards\n ? i18next.t('figure.text.keys-must-rise')\n : outside(key)\n ? i18next.t('figure.text.parameter-key-within-span')\n : ''}\n @change=${(e: Event) =>\n this.setKey(kind, at, j, k, { at: Math.max(0, Number((e.target as HTMLInputElement).value) || 0) })}\n />\n </td>\n ${AXES.map(\n axis => html`\n <td>\n <input\n type=\"number\"\n step=${channel.path === 'scale' ? '0.1' : '1'}\n .value=${live(String(key.value[axis]))}\n aria-label=${axis}\n @change=${(e: Event) =>\n this.setKey(kind, at, j, k, {\n value: { ...key.value, [axis]: Number((e.target as HTMLInputElement).value) || 0 }\n })}\n />\n </td>\n `\n )}\n <td drop>\n <button\n plain\n ?disabled=${keys.length <= 2}\n title=${keys.length <= 2 ? i18next.t('figure.text.two-keys-at-least') : i18next.t('figure.button.remove')}\n @click=${() => this.removeKey(kind, at, j, k)}\n >\n <md-icon>close</md-icon>\n </button>\n </td>\n </tr>\n `\n })}\n </table>\n\n ${keys.some((key, k) => k > 0 && key.at <= (keys[k - 1]!.at ?? 0))\n ? html`<p warn>${i18next.t('figure.text.keys-must-rise')}</p>`\n : nothing}\n ${keys.some(outside) ? html`<p warn>${i18next.t('figure.text.parameter-key-within-span')}</p>` : nothing}\n\n <button @click=${() => this.addKey(kind, at, j)}>\n <md-icon>add</md-icon>${i18next.t('figure.button.add-key')}\n </button>\n `\n }\n\n /**\n * 움직이는 부품 예산.\n *\n * **넘어도 막지 않는다.** 움직이는 부품은 저마다 단독 묶음이라 draw call 이 늘고 프레임마다\n * 갱신이 는다 — 그 대가가 수로 보이면 저작자가 아낀다. 랜드마크 설비 하나는 정교해도 되고,\n * 그 값이 도면 예산에 드러나면 된다.\n */\n private renderBudget(): TemplateResult {\n const used = this.movingParts\n const over = used > LIMITS.animatedParts\n\n return html`\n <section>\n <h3>${i18next.t('figure.label.budget-animations')}</h3>\n <div budget ?over=${over}>\n <strong>${used}</strong>\n <span quiet>/ ${LIMITS.animatedParts}</span>\n </div>\n <p quiet>${i18next.t('figure.text.animated-parts-cost')}</p>\n ${over ? html`<p warn>${i18next.t('figure.text.animated-parts-over')}</p>` : nothing}\n </section>\n `\n }\n\n // ─── 고치기 ───────────────────────────────────────────────────────────────\n\n /**\n * 초안에 실어 올려보낸다.\n *\n * `animations` 는 도형 전체의 것이므로 부품 편집(`update-part`)이 아니라 `update-draft` 로\n * 간다. 빈 배열은 칸을 지운다 — clip 을 다 지운 도형은 `animations: []` 가 아니라 없는 것이다.\n */\n private tell(over: { animations?: Clip[]; parameters?: Parameter[] }): void {\n if (!this.draft) return\n\n const draft: FigureDraft = { ...this.draft, ...over }\n if (!draft.animations?.length) delete draft.animations\n if (!draft.parameters?.length) delete draft.parameters\n\n this.dispatchEvent(new CustomEvent('update-draft', { detail: { draft }, bubbles: true, composed: true }))\n }\n\n private patchClip(at: number, patch: Partial<Clip>): void {\n this.tell({ animations: this.clips.map((clip, i) => (i === at ? { ...clip, ...patch } : clip)) })\n }\n\n private patchParameter(at: number, patch: Partial<Parameter>): void {\n this.tell({ parameters: this.parameters.map((one, i) => (i === at ? { ...one, ...patch } : one)) })\n }\n\n /** 채널 묶음을 통째로 얹는다. **어느 목록이든 같은 자리에 닿는다.** */\n private setChannels(kind: MotionKind, at: number, channels: Channel[]): void {\n if (kind === 'clip') this.patchClip(at, { channels })\n else {\n const parameter = this.parameters[at]\n if (!parameter) return\n this.patchParameter(at, { clip: { ...parameter.clip, channels } })\n }\n }\n\n private patchChannel(kind: MotionKind, at: number, j: number, next: Channel): void {\n this.setChannels(\n kind,\n at,\n this.channelsOf(kind, at).map((channel, i) => (i === j ? next : channel))\n )\n }\n\n private addClip(): void {\n const target = this.partNames[0]\n if (!target) return\n\n const clip: Clip = {\n name: freeName(this.allNames, 'clip-1'),\n channels: [{ target, path: 'translation', keys: keysFor('translation') }]\n }\n\n this.open = `clip:${this.clips.length}`\n this.tell({ animations: [...this.clips, clip] })\n }\n\n private addParameter(): void {\n const target = this.partNames[0]\n if (!target) return\n\n const parameter: Parameter = {\n name: freeName(this.allNames, 'parameter-1'),\n range: { ...NEW_RANGE },\n clip: { channels: [{ target, path: 'translation', keys: keysFor('translation') }] }\n }\n\n this.open = `parameter:${this.parameters.length}`\n this.tell({ parameters: [...this.parameters, parameter] })\n }\n\n /**\n * Recipe creates a valid, editable two-pose motion; it never saves or publishes the Figure.\n *\n * 어느 목록으로 가는지는 레시피가 안다 — 도는 롤러는 애니메이션이고 열리는 문은\n * 파라미터다. 저작자에게 그 갈래를 먼저 고르게 하지 않는 이유가 이것이다.\n */\n private addRecipe(recipe: MotionRecipe): void {\n const target = this.recipeTarget || this.partNames[0]\n if (!target) return\n\n const channel: Channel = {\n target,\n path: recipe.path,\n keys: [{ at: 0, value: startValue(recipe.path) }, { at: 1, value: { ...recipe.end } }]\n }\n if (recipe.pivot) channel.pivot = { ...recipe.pivot }\n\n const name = freeName(this.allNames, recipe.name)\n\n if (recipe.kind === 'clip') {\n this.open = `clip:${this.clips.length}`\n this.tell({ animations: [...this.clips, { name, channels: [channel] }] })\n return\n }\n\n this.open = `parameter:${this.parameters.length}`\n this.tell({\n parameters: [...this.parameters, { name, range: { ...(recipe.range ?? NEW_RANGE) }, clip: { channels: [channel] } }]\n })\n }\n\n private renameClip(at: number, name: string): void {\n this.patchClip(at, { name: name.trim() })\n }\n\n private renameParameter(at: number, name: string): void {\n this.patchParameter(at, { name: name.trim() })\n }\n\n private setRange(at: number, patch: Partial<Parameter['range']>): void {\n const parameter = this.parameters[at]\n if (!parameter) return\n this.patchParameter(at, { range: { ...(parameter.range ?? NEW_RANGE), ...patch } })\n }\n\n /**\n * Transition time. Clearing the input removes the field, which means instant. 0 is instant too, but\n * a stored 0 and a missing field are different sources, so an empty input is never saved as 0.\n */\n private setDuration(at: number, raw: string): void {\n const parameter = this.parameters[at]\n if (!parameter) return\n const { duration: _dropped, ...rest } = parameter.clip\n const text = raw.trim()\n const clip = text === '' || !Number.isFinite(Number(text)) ? rest : { ...rest, duration: Number(text) }\n this.patchParameter(at, { clip })\n }\n\n private setDefault(at: number, value: number): void {\n this.patchParameter(at, { default: value })\n }\n\n private removeClip(at: number): void {\n this.open = ''\n this.tell({ animations: this.clips.filter((_, i) => i !== at) })\n }\n\n private removeParameter(at: number): void {\n this.open = ''\n this.tell({ parameters: this.parameters.filter((_, i) => i !== at) })\n }\n\n private addChannel(kind: MotionKind, at: number): void {\n const target = this.partNames[0]\n if (!target) return\n\n this.setChannels(kind, at, [\n ...this.channelsOf(kind, at),\n { target, path: 'translation', keys: keysFor('translation') }\n ])\n }\n\n /**\n * Points a channel at another part or joint. Crossing between the two changes the channel's shape: a\n * joint channel has no path and one number per key, a part channel a path and a vector. The key positions\n * are kept, since they are the author's timing; values restart at the rest pose.\n */\n private retarget(kind: MotionKind, at: number, j: number, target: string): void {\n const channel = this.channelsOf(kind, at)[j]\n if (!channel) return\n const toJoint = this.joints.some(one => one.name === target)\n\n if (toJoint && !isJointChannel(channel)) {\n const next: JointChannel = { target, keys: channel.keys.map(key => ({ at: key.at, value: 0 })) }\n if (channel.interpolation !== undefined) next.interpolation = channel.interpolation\n this.patchChannel(kind, at, j, next)\n return\n }\n if (!toJoint && isJointChannel(channel)) {\n const next: PartChannel = { target, path: 'translation', keys: channel.keys.map(key => ({ at: key.at, value: startValue('translation') })) }\n if (channel.interpolation !== undefined) next.interpolation = channel.interpolation\n this.patchChannel(kind, at, j, next)\n return\n }\n this.patchChannel(kind, at, j, { ...channel, target } as Channel)\n }\n\n private setChannel(kind: MotionKind, at: number, j: number, patch: Partial<PartChannel>): void {\n const channel = this.channelsOf(kind, at)[j]\n if (!channel || isJointChannel(channel)) return\n\n const next: PartChannel = { ...channel, ...patch }\n /* `undefined` 를 얹는 것은 지우는 뜻이다. 남겨 두면 저장 형식에 빈 칸이 실린다. */\n if ('pivot' in patch && patch.pivot === undefined) delete next.pivot\n this.patchChannel(kind, at, j, next)\n }\n\n /**\n * 경로를 바꾼다 — **값까지 함께 옮긴다.**\n *\n * 옮김·회전의 0 은 「제자리」인데 배율의 0 은 **부품을 지운다.** 경로만 바꾸고 값을 그대로\n * 두면 저작자는 부품이 사라진 것을 보고 도구가 고장 난 줄 안다. 그래서 옮김·회전 ↔ 배율을\n * 건널 때 시작값을 그 경로의 제자리로 되돌린다. 시각은 지킨다 — 저작자가 짠 박자다.\n */\n private setPath(kind: MotionKind, at: number, j: number, path: ChannelPath): void {\n const channel = this.channelsOf(kind, at)[j]\n if (!channel || isJointChannel(channel)) return\n\n const crossing = (channel.path === 'scale') !== (path === 'scale')\n const next: PartChannel = {\n ...channel,\n path,\n keys: crossing ? channel.keys.map(key => ({ at: key.at, value: startValue(path) })) : channel.keys\n }\n /* 회전이 아니면 회전 중심은 쓰이지 않는다. 남겨 두면 검증이 「쓰이지 않는다」고 알린다. */\n if (path !== 'rotation') delete next.pivot\n\n this.patchChannel(kind, at, j, next)\n }\n\n private removeChannel(kind: MotionKind, at: number, j: number): void {\n this.setChannels(\n kind,\n at,\n this.channelsOf(kind, at).filter((_, i) => i !== j)\n )\n }\n\n /** 마지막 키에서 1 초 뒤. 값은 그 키를 그대로 받는다 — 붙여 놓고 고치는 것이 짜기 쉽다. */\n private addKey(kind: MotionKind, at: number, j: number): void {\n const channel = this.channelsOf(kind, at)[j]\n if (!channel) return\n\n if (isJointChannel(channel)) {\n const keys = channel.keys\n const end = keys[keys.length - 1]\n if (kind === 'parameter' && keys.length >= 2) {\n const before = keys[keys.length - 2]!\n const middle: JointKey = { at: (before.at + end!.at) / 2, value: before.value }\n this.patchChannel(kind, at, j, { ...channel, keys: [...keys.slice(0, -1), middle, end!] })\n return\n }\n this.patchChannel(kind, at, j, { ...channel, keys: [...keys, { at: (end?.at ?? 0) + 1, value: end?.value ?? 0 }] })\n return\n }\n\n const last = channel.keys[channel.keys.length - 1]\n\n /*\n A parameter curve ends at 1, so appending a key would make it unreachable. Insert it between the last two keys.\n */\n if (kind === 'parameter' && channel.keys.length >= 2) {\n const before = channel.keys[channel.keys.length - 2]!\n const middle: Keyframe = { at: (before.at + last!.at) / 2, value: { ...before.value } }\n this.patchChannel(kind, at, j, { ...channel, keys: [...channel.keys.slice(0, -1), middle, last!] })\n return\n }\n\n const key: Keyframe = { at: (last?.at ?? 0) + 1, value: { ...(last?.value ?? startValue(channel.path)) } }\n this.patchChannel(kind, at, j, { ...channel, keys: [...channel.keys, key] })\n }\n\n private setJointKey(kind: MotionKind, at: number, j: number, k: number, patch: Partial<JointKey>): void {\n const channel = this.channelsOf(kind, at)[j]\n if (!channel || !isJointChannel(channel)) return\n this.patchChannel(kind, at, j, { ...channel, keys: channel.keys.map((key, i) => (i === k ? { ...key, ...patch } : key)) })\n }\n\n private setKey(kind: MotionKind, at: number, j: number, k: number, patch: Partial<Keyframe>): void {\n const channel = this.channelsOf(kind, at)[j]\n if (!channel || isJointChannel(channel)) return\n this.patchChannel(kind, at, j, {\n ...channel,\n keys: channel.keys.map((key, i) => (i === k ? { ...key, ...patch } : key))\n })\n }\n\n /** 둘 미만으로 내려가지 않는다 — 단추가 이미 죽어 있지만 밖에서 불릴 수 있다. */\n private removeKey(kind: MotionKind, at: number, j: number, k: number): void {\n const channel = this.channelsOf(kind, at)[j]\n if (!channel || channel.keys.length <= 2) return\n this.patchChannel(kind, at, j, { ...channel, keys: (channel.keys as { at: number }[]).filter((_, i) => i !== k) } as Channel)\n }\n}\n"]}
@@ -72,6 +72,17 @@ export declare class FigureInspector extends FigureInspector_base {
72
72
  * 컨베이어가 길어지면 실을 자리가 늘어나는 것이 그것이고, 여기 적은 값은 안 쓰인다.
73
73
  */
74
74
  private renderRole;
75
+ /**
76
+ * How this part hangs from another and moves relative to it (ADR-0066).
77
+ *
78
+ * The parent is written on the part. The joint says how the part moves relative to that parent, and the
79
+ * parameter it comes with is what drives it; the preview shows that parameter as a slider.
80
+ */
81
+ private renderJoint;
82
+ private setParent;
83
+ private setJointType;
84
+ private setJointAxis;
85
+ private tellDraft;
75
86
  /**
76
87
  * 역할 하나를 켜고 끈다.
77
88
  *
@@ -6,10 +6,23 @@ import { live } from 'lit/directives/live.js';
6
6
  import { i18next, localize } from '@operato/i18n';
7
7
  import { ScrollbarStyles } from '@operato/styles';
8
8
  import { EXTRUDE_PRIMITIVES, MATERIAL_PRESETS, PRIMITIVE_KINDS, SEGMENTED_PRIMITIVES, SEGMENT_PRESETS, SIZING_RULES, trianglesOf } from '@hatiolab/figure-model';
9
- import { ANCHOR_RULES, PART_ROLES, REPEAT_LIMIT, anchorOfPart, repeatPlanOfPart } from '@hatiolab/figure-model';
9
+ import { ANCHOR_RULES, JOINT_TYPES, PART_ROLES, REPEAT_LIMIT, anchorOfPart, repeatPlanOfPart } from '@hatiolab/figure-model';
10
10
  import { activePalette } from '@hatiolab/things-scene';
11
11
  import { partToFigure, partFromFigure } from './figure-source.js';
12
12
  import { canMirror } from './part-edits.js';
13
+ import { jointOf, parentChoices, patchJoint, setJointType } from './joint-edits.js';
14
+ /** Axis choices for a joint. Written as a direction the author reads, stored as a vector. */
15
+ const JOINT_AXES = [
16
+ { key: '+x', axis: { x: 1, y: 0, z: 0 } },
17
+ { key: '-x', axis: { x: -1, y: 0, z: 0 } },
18
+ { key: '+y', axis: { x: 0, y: 1, z: 0 } },
19
+ { key: '-y', axis: { x: 0, y: -1, z: 0 } },
20
+ { key: '+z', axis: { x: 0, y: 0, z: 1 } },
21
+ { key: '-z', axis: { x: 0, y: 0, z: -1 } }
22
+ ];
23
+ function axisKeyOf(axis) {
24
+ return JOINT_AXES.find(one => one.axis.x === axis.x && one.axis.y === axis.y && one.axis.z === axis.z)?.key;
25
+ }
13
26
  /**
14
27
  * 고른 부품의 속성.
15
28
  *
@@ -796,7 +809,7 @@ let FigureInspector = class FigureInspector extends localize(i18next)(LitElement
796
809
  묶음은 아예 나오지 않는다 — 해 둬도 아무 일도 안 일어나는 칸을 보여 주지 않는다.
797
810
  */
798
811
  return html `
799
- ${this.renderFigure(true)} ${this.renderIdentity(shown)} ${this.renderRole(shown)}
812
+ ${this.renderFigure(true)} ${this.renderIdentity(shown)} ${this.renderRole(shown)} ${this.renderJoint(shown)}
800
813
  ${this.renderPlacement(shown)} ${this.renderShape(shown)} ${this.renderMaterial(shown)}
801
814
  ${this.renderBehaviour(shown)}
802
815
  `;
@@ -855,6 +868,107 @@ let FigureInspector = class FigureInspector extends localize(i18next)(LitElement
855
868
  </section>
856
869
  `;
857
870
  }
871
+ /**
872
+ * How this part hangs from another and moves relative to it (ADR-0066).
873
+ *
874
+ * The parent is written on the part. The joint says how the part moves relative to that parent, and the
875
+ * parameter it comes with is what drives it; the preview shows that parameter as a slider.
876
+ */
877
+ renderJoint(part) {
878
+ const joint = jointOf(this.draft, part.name);
879
+ const choices = parentChoices(this.parts, part.name);
880
+ const unit = joint?.type === 'prismatic' ? 'mm' : 'deg';
881
+ const axisKey = joint ? axisKeyOf(joint.axis) : undefined;
882
+ const driver = joint
883
+ ? this.draft?.parameters?.find(one => one.clip?.channels?.some(channel => channel.target === joint.name))
884
+ : undefined;
885
+ return html `
886
+ <section>
887
+ <h3>${i18next.t('figure.label.joint')}${this.help('figure.text.joint-explained')}</h3>
888
+
889
+ <div inline-field>
890
+ <label>${i18next.t('figure.label.joint-parent')}</label>
891
+ <select @change=${(e) => this.setParent(e.target.value)}>
892
+ <option value="" ?selected=${part.parent === undefined}>${i18next.t('figure.label.joint-parent-none')}</option>
893
+ ${part.parent !== undefined && !choices.includes(part.parent)
894
+ ? html `<option value=${part.parent} selected>${part.parent}</option>`
895
+ : nothing}
896
+ ${choices.map(name => html `<option value=${name} ?selected=${name === part.parent}>${name}</option>`)}
897
+ </select>
898
+ </div>
899
+
900
+ <div inline-field>
901
+ <label>${i18next.t('figure.label.joint-type')}</label>
902
+ <select @change=${(e) => this.setJointType(part, e.target.value)}>
903
+ <option value="" ?selected=${!joint}>${i18next.t('figure.label.joint-type-none')}</option>
904
+ ${JOINT_TYPES.map(type => html `<option value=${type} ?selected=${joint?.type === type}>${i18next.t('figure.label.joint-type-' + type)}</option>`)}
905
+ </select>
906
+ </div>
907
+
908
+ ${joint
909
+ ? html `
910
+ <div inline-field>
911
+ <label>${i18next.t('figure.label.joint-axis')}</label>
912
+ <select @change=${(e) => this.setJointAxis(joint.name, e.target.value)}>
913
+ ${axisKey === undefined
914
+ ? html `<option value="" selected>${joint.axis.x}, ${joint.axis.y}, ${joint.axis.z}</option>`
915
+ : nothing}
916
+ ${JOINT_AXES.map(one => html `<option value=${one.key} ?selected=${one.key === axisKey}>${one.key.toUpperCase()}</option>`)}
917
+ </select>
918
+ </div>
919
+
920
+ <div vector-row>
921
+ <label>${i18next.t('figure.label.joint-origin')}</label>
922
+ <div triple>
923
+ ${['x', 'y', 'z'].map(axis => this.number(axis.toUpperCase(), joint.origin[axis], value => this.tellDraft(patchJoint(this.draft, joint.name, { origin: { ...joint.origin, [axis]: value } }))))}
924
+ </div>
925
+ </div>
926
+
927
+ ${joint.limits
928
+ ? html `
929
+ <div vector-row>
930
+ <label>${i18next.t('figure.label.joint-limits-' + unit)}</label>
931
+ <div triple>
932
+ ${this.number(i18next.t('figure.label.joint-limit-min'), joint.limits.min, value => this.tellDraft(patchJoint(this.draft, joint.name, { limits: { ...joint.limits, min: value } })))}
933
+ ${this.number(i18next.t('figure.label.joint-limit-max'), joint.limits.max, value => this.tellDraft(patchJoint(this.draft, joint.name, { limits: { ...joint.limits, max: value } })))}
934
+ </div>
935
+ </div>
936
+ ${joint.limits.min > 0 || joint.limits.max < 0
937
+ ? html `<p warn>${i18next.t('figure.text.joint-limits-must-include-zero')}</p>`
938
+ : nothing}
939
+ `
940
+ : nothing}
941
+
942
+ <p quiet>
943
+ ${driver
944
+ ? i18next.t('figure.text.joint-driven-by', { name: driver.label ?? driver.name })
945
+ : i18next.t('figure.text.joint-not-driven')}
946
+ </p>
947
+ `
948
+ : nothing}
949
+ </section>
950
+ `;
951
+ }
952
+ setParent(name) {
953
+ this.change(part => {
954
+ const { parent: _dropped, ...rest } = part;
955
+ return name === '' ? rest : { ...rest, parent: name };
956
+ });
957
+ }
958
+ setJointType(part, value) {
959
+ if (!this.draft)
960
+ return;
961
+ this.tellDraft(setJointType(this.draft, part, value === '' ? undefined : value));
962
+ }
963
+ setJointAxis(name, key) {
964
+ const choice = JOINT_AXES.find(one => one.key === key);
965
+ if (!choice || !this.draft)
966
+ return;
967
+ this.tellDraft(patchJoint(this.draft, name, { axis: { ...choice.axis } }));
968
+ }
969
+ tellDraft(draft) {
970
+ this.dispatchEvent(new CustomEvent('update-draft', { detail: { draft }, bubbles: true, composed: true }));
971
+ }
858
972
  /**
859
973
  * 역할 하나를 켜고 끈다.
860
974
  *