@things-factory/figure-ui 10.1.271 → 10.1.272

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 (79) hide show
  1. package/client/modeller/canvas.ts +4 -2
  2. package/client/modeller/clips.ts +74 -4
  3. package/client/modeller/fasten-form.ts +69 -4
  4. package/client/modeller/figure-cavity-drawing.ts +1 -3
  5. package/client/modeller/figure-clips.ts +101 -8
  6. package/client/modeller/figure-fasten-dialog.ts +41 -30
  7. package/client/modeller/figure-fasten-drawing.ts +3 -1
  8. package/client/modeller/figure-first-save.ts +4 -3
  9. package/client/modeller/figure-links.ts +85 -28
  10. package/client/modeller/figure-preview.ts +41 -3
  11. package/client/modeller/figure-size-editor.ts +7 -2
  12. package/client/modeller/first-save.ts +8 -0
  13. package/client/modeller/focus-on-render.ts +4 -0
  14. package/client/modeller/pivot.ts +76 -0
  15. package/client/modeller/size-response.ts +14 -0
  16. package/client/modeller/stage-model.ts +50 -6
  17. package/dist-client/modeller/canvas.d.ts +1 -0
  18. package/dist-client/modeller/canvas.js +3 -2
  19. package/dist-client/modeller/canvas.js.map +1 -1
  20. package/dist-client/modeller/clips.d.ts +21 -4
  21. package/dist-client/modeller/clips.js +69 -4
  22. package/dist-client/modeller/clips.js.map +1 -1
  23. package/dist-client/modeller/fasten-form.d.ts +8 -0
  24. package/dist-client/modeller/fasten-form.js +64 -5
  25. package/dist-client/modeller/fasten-form.js.map +1 -1
  26. package/dist-client/modeller/figure-cavity-drawing.js +1 -3
  27. package/dist-client/modeller/figure-cavity-drawing.js.map +1 -1
  28. package/dist-client/modeller/figure-clips.d.ts +9 -0
  29. package/dist-client/modeller/figure-clips.js +104 -8
  30. package/dist-client/modeller/figure-clips.js.map +1 -1
  31. package/dist-client/modeller/figure-fasten-dialog.js +39 -24
  32. package/dist-client/modeller/figure-fasten-dialog.js.map +1 -1
  33. package/dist-client/modeller/figure-fasten-drawing.js +3 -1
  34. package/dist-client/modeller/figure-fasten-drawing.js.map +1 -1
  35. package/dist-client/modeller/figure-first-save.js +4 -3
  36. package/dist-client/modeller/figure-first-save.js.map +1 -1
  37. package/dist-client/modeller/figure-links.d.ts +9 -0
  38. package/dist-client/modeller/figure-links.js +89 -35
  39. package/dist-client/modeller/figure-links.js.map +1 -1
  40. package/dist-client/modeller/figure-preview.js +39 -3
  41. package/dist-client/modeller/figure-preview.js.map +1 -1
  42. package/dist-client/modeller/figure-size-editor.js +7 -3
  43. package/dist-client/modeller/figure-size-editor.js.map +1 -1
  44. package/dist-client/modeller/first-save.d.ts +5 -0
  45. package/dist-client/modeller/first-save.js +7 -0
  46. package/dist-client/modeller/first-save.js.map +1 -1
  47. package/dist-client/modeller/focus-on-render.d.ts +2 -0
  48. package/dist-client/modeller/focus-on-render.js +4 -0
  49. package/dist-client/modeller/focus-on-render.js.map +1 -0
  50. package/dist-client/modeller/pivot.d.ts +12 -0
  51. package/dist-client/modeller/pivot.js +59 -0
  52. package/dist-client/modeller/pivot.js.map +1 -0
  53. package/dist-client/modeller/size-response.d.ts +6 -0
  54. package/dist-client/modeller/size-response.js +14 -0
  55. package/dist-client/modeller/size-response.js.map +1 -1
  56. package/dist-client/modeller/stage-model.d.ts +17 -3
  57. package/dist-client/modeller/stage-model.js +44 -6
  58. package/dist-client/modeller/stage-model.js.map +1 -1
  59. package/dist-client/tsconfig.tsbuildinfo +1 -1
  60. package/package.json +4 -4
  61. package/test/browser/editing.check.mjs +6 -5
  62. package/test/browser/section.check.mjs +21 -0
  63. package/test/clips.test.ts +49 -4
  64. package/test/fasten-form.test.ts +44 -0
  65. package/test/first-save.test.ts +11 -1
  66. package/test/pivot.test.ts +57 -0
  67. package/test/size-response.test.ts +10 -2
  68. package/test/stage-model.test.ts +23 -1
  69. package/translations/en.json +8 -0
  70. package/translations/es.json +8 -0
  71. package/translations/ja.json +8 -0
  72. package/translations/ko.json +8 -0
  73. package/translations/ms.json +8 -0
  74. package/translations/zh.json +8 -0
  75. package/tutorial/humanoid/README.md +22 -0
  76. package/tutorial/humanoid/chapters.mjs +247 -0
  77. package/tutorial/humanoid/encode.mjs +26 -0
  78. package/tutorial/humanoid/lib.mjs +197 -0
  79. package/tutorial/humanoid/record.mjs +65 -0
@@ -1,6 +1,6 @@
1
1
  import { FIGURE_FACES, figureFastenKeptGapOf, figureFastenTargetAt, figurePlaneFacingOf, figureSurfaceKeptPlaceOf } from '@hatiolab/figure-model';
2
2
  import { faceViewOf, facesAsDrawnOf } from './fasten-geometry.js';
3
- import { alignOf, alignRowsOf, canFasten, facesOf, fasteningOf, fastenGapOf, hangsFrom, heldBy, mountingPlaneOf, placeKeptOf, surfaceOf } from './links.js';
3
+ import { alignOf, alignAxesOf, alignRowsOf, canFasten, facesOf, fasteningOf, fastenGapOf, hangsFrom, heldBy, mountingPlaneOf, placeKeptOf, surfaceOf } from './links.js';
4
4
  import { standsWhereAdded } from './palette.js';
5
5
  import { ownerOf } from './fields.js';
6
6
  /*
@@ -26,12 +26,59 @@ export function fastenFormOf(revision, part) {
26
26
  const own = fasteningOf(revision, part);
27
27
  if (!own || own.atOrigin) {
28
28
  /* A part still where it was added was put nowhere by the author: fastened, it goes on the face, no gap to keep. */
29
- const pose = revision.geometry.find(g => g.id === part)?.pose;
30
- return !own && standsWhereAdded(pose) ? { ...freshFasten(), gapFrom: 'pressed' } : freshFasten();
29
+ return addedUnplaced(revision, part) ? { ...freshFasten(), gapFrom: 'pressed' } : freshFasten();
31
30
  }
32
31
  /* A gap the record works out is the author's; a number is where the part stands, so aiming again keeps it there. */
33
32
  return { ...freshFasten(), ...own, gapFrom: own.gapKept !== undefined ? 'typed' : 'kept' };
34
33
  }
34
+ /** A part fastened to nothing that still stands where the palette put it: the author has put it nowhere to keep. */
35
+ function addedUnplaced(revision, part) {
36
+ if (fasteningOf(revision, part))
37
+ return false;
38
+ const pose = revision.geometry.find(g => g.id === part)?.pose;
39
+ return standsWhereAdded(pose);
40
+ }
41
+ /**
42
+ * The face a part just added starts on when aimed at `target`: the one asked, unless another part is fastened there
43
+ * already -- then the first face of the target nothing is fastened to (review 2026-11-11: a thigh aimed at a pelvis
44
+ * started on its top, where the body stands, and went inside the body until the bottom was chosen). A part the author
45
+ * has placed keeps the face it stands by: a face holds many parts (rollers and a lid on one frame).
46
+ */
47
+ function freeFaceOf(revision, part, target, asked) {
48
+ const on = (end) => end;
49
+ const joints = revision.asset.joints ?? [];
50
+ const taken = new Set(joints.filter(j => on(j.body0).part === target && on(j.body1).part !== part).map(j => on(j.body0).face));
51
+ /* The face the target itself stands on its own parent by: a thigh hung under a pelvis touches it with its top. */
52
+ let hungBy;
53
+ for (const j of joints)
54
+ if (on(j.body1).part === target && on(j.body0).face && j.facing !== 'flush') {
55
+ hungBy = OPPOSITE[on(j.body0).face];
56
+ taken.add(hungBy);
57
+ }
58
+ /*
59
+ A tall part hung by its side -- an upper arm on a torso -- goes on downward: what is fastened to it starts under its
60
+ bottom end, not on its top beside the shoulder (tutorial run 2026-11-12: a forearm started on the upper arm's top
61
+ and its bottom had to be picked by hand).
62
+ */
63
+ if (hungBy && FIGURE_FACES[hungBy] !== 'y' && !taken.has('bottom') && tallOf(revision, target))
64
+ return 'bottom';
65
+ if (!taken.has(asked))
66
+ return asked;
67
+ /* The face across from the one taken first: a body on the top, legs under the bottom. */
68
+ const across = OPPOSITE[asked];
69
+ const faces = facesOf(revision.asset, target);
70
+ if (faces.includes(across) && !taken.has(across))
71
+ return across;
72
+ return faces.find(face => !taken.has(face)) ?? asked;
73
+ }
74
+ /** Whether a part as drawn is at least half again as tall as it is wide and deep, read off its own faces. */
75
+ function tallOf(revision, part) {
76
+ const faces = revision.geometry.find(g => g.id === part)?.shape?.faces;
77
+ const span = (lo, hi) => (faces?.[hi] && faces?.[lo] ? Math.abs(faces[hi].at - faces[lo].at) : undefined);
78
+ const [x, y, z] = [span('left', 'right'), span('bottom', 'top'), span('back', 'front')];
79
+ return x !== undefined && y !== undefined && z !== undefined && y >= 1.5 * Math.max(x, z);
80
+ }
81
+ const OPPOSITE = { top: 'bottom', bottom: 'top', left: 'right', right: 'left', front: 'back', back: 'front' };
35
82
  /** What a part may be fastened to: every other part that can be, each said whether it would close a loop. */
36
83
  export function fastenTargetsOf(revision, part) {
37
84
  const asset = revision.asset;
@@ -73,7 +120,12 @@ export function aimFasten(revision, part, form, to) {
73
120
  const f = 'plane' in to
74
121
  ? { ...form, toPlane: true, target: '', facing: form.toPlane ? form.facing : (figurePlaneFacingOf(revision.asset) ?? form.facing) }
75
122
  : 'part' in to
76
- ? { ...form, toPlane: false, target: to.part }
123
+ ? {
124
+ ...form,
125
+ toPlane: false,
126
+ target: to.part,
127
+ targetFace: to.part !== form.target && addedUnplaced(revision, part) ? freeFaceOf(revision, part, to.part, form.targetFace) : form.targetFace
128
+ }
77
129
  : { ...form, targetFace: to.targetFace };
78
130
  const theirFaces = f.target ? facesOf(revision.asset, f.target) : FACES;
79
131
  const targetFace = (theirFaces.includes(f.targetFace) ? f.targetFace : theirFaces[0]);
@@ -82,7 +134,13 @@ export function aimFasten(revision, part, form, to) {
82
134
  : f.target
83
135
  ? { part: f.target, face: targetFace }
84
136
  : undefined;
85
- return { ...f, ...(aim ? placeKeptOf(revision, part, aim) : { align: {}, alignMm: {}, alignInput: {} }) };
137
+ /*
138
+ * A part still where the palette put it has no place of the author's to keep: it goes to the face's centre (review
139
+ * 2026-11-11: a shin added at the origin and aimed at a thigh 85 mm off it was put 85 mm off the thigh's centre; an
140
+ * arm aimed at the body's side stood off the face, out of reach of the drawing).
141
+ */
142
+ const centred = { align: {}, alignMm: {}, alignInput: {} };
143
+ return { ...f, ...(aim && !addedUnplaced(revision, part) ? placeKeptOf(revision, part, aim) : centred) };
86
144
  }
87
145
  /** A change the drawing asks: a face, a way, a gap or a place across the face. */
88
146
  export function fastenChanged(revision, part, form, change) {
@@ -177,6 +235,7 @@ function fastenPlanWithout(revision, part, f) {
177
235
  mode,
178
236
  view,
179
237
  alignRows: alignRowsOf(asset, aim, view, f.alignInput),
238
+ alignAxes: alignAxesOf(asset, aim),
180
239
  action,
181
240
  ...(f.toPlane ? {} : { face: { part: f.target, face: targetFace } })
182
241
  };
@@ -1 +1 @@
1
- {"version":3,"file":"fasten-form.js","sourceRoot":"","sources":["../../client/modeller/fasten-form.ts"],"names":[],"mappings":"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","sourcesContent":["import { FIGURE_FACES, figureFastenKeptGapOf, figureFastenTargetAt, figurePlaneFacingOf, figureSurfaceKeptPlaceOf } from '@hatiolab/figure-model'\nimport type { FigureAuthoringAction, FigureFace, FigureSurfacePlace } from '@hatiolab/figure-model'\n\nimport { faceViewOf, facesAsDrawnOf, type FaceView, type FastenMode, type FastenTarget } from './fasten-geometry.js'\nimport type { FastenChange } from './figure-fasten-drawing.js'\nimport {\n alignOf,\n alignRowsOf,\n canFasten,\n facesOf,\n fasteningOf,\n fastenGapOf,\n hangsFrom,\n heldBy,\n mountingPlaneOf,\n placeKeptOf,\n surfaceOf,\n type Alignment,\n type Axis\n} from './links.js'\nimport type { FigureRevision } from './revision.js'\nimport { standsWhereAdded } from './palette.js'\nimport { ownerOf } from './fields.js'\n\n/*\n * A fastening as it is chosen, before it is done: to what, which face, how, where across the face. The fastening window\n * (`figure-fasten-dialog.ts`) holds one and changes it as the author chooses; the attach command is worked out from it\n * only here, so the window, its preview and the panel's 「정렬 고치기」 send the same command for the same choice.\n */\n\nconst FACES = Object.keys(FIGURE_FACES) as FigureFace[]\n\nexport interface FastenForm {\n toPlane: boolean\n target: string\n targetFace: FigureFace\n /** How it meets the face: its near end on it, its far end on it (flush), or its middle (ADR-0140 3.11). */\n facing: FastenMode\n gap: number\n /** The record's gap when it is worked out (a length that follows something): kept until a number is typed. */\n gapKept: unknown\n /**\n * Where the gap came from (ADR-0140 stage 4, 「현재 상태로 붙이기」): `kept` -- the distance the part stands at, worked\n * out again whenever where or how it is fastened changes, so fastening does not move it; `typed` -- the author's\n * number, left as it is; `pressed` -- 0, the part put where the canvas was pressed.\n */\n gapFrom: 'kept' | 'typed' | 'pressed'\n align: Partial<Record<Axis, Alignment>>\n alignMm: Partial<Record<Axis, number>>\n alignInput: Partial<Record<Axis, string>>\n /** On a point of the target's curved surface instead of a face (ADR-0140 3.9): where, as the record says it. */\n surface?: FigureSurfacePlace\n}\n\nexport const freshFasten = (): FastenForm => ({\n toPlane: false,\n target: '',\n targetFace: 'top',\n facing: 'meet',\n gap: 0,\n gapKept: undefined,\n gapFrom: 'kept',\n align: {},\n alignMm: {},\n alignInput: {}\n})\n\n/** The part's own fastening as a form, or a fresh one: a window opens on what the part has (walk 1, 2026-09-26). */\nexport function fastenFormOf(revision: FigureRevision, part: string): FastenForm {\n const own = fasteningOf(revision, part)\n if (!own || own.atOrigin) {\n /* A part still where it was added was put nowhere by the author: fastened, it goes on the face, no gap to keep. */\n const pose = (revision.geometry.find(g => (g as { id: string }).id === part) as { pose?: { r: number[][]; t: number[] } } | undefined)?.pose\n return !own && standsWhereAdded(pose) ? { ...freshFasten(), gapFrom: 'pressed' } : freshFasten()\n }\n /* A gap the record works out is the author's; a number is where the part stands, so aiming again keeps it there. */\n return { ...freshFasten(), ...own, gapFrom: own.gapKept !== undefined ? 'typed' : 'kept' } as FastenForm\n}\n\n/** What a part may be fastened to: every other part that can be, each said whether it would close a loop. */\nexport function fastenTargetsOf(revision: FigureRevision, part: string): Array<{ part: string; loops: boolean }> {\n const asset = revision.asset\n return (\n asset.appearance\n .map(look => look.target)\n .filter(one => one !== part && canFasten(asset, one))\n /* Not a part that hangs from this one: fastening a frame to its own roller would close a loop. */\n .map(one => ({ part: one, loops: hangsFrom(asset, one, part) }))\n )\n}\n\n/**\n * The point of a target's curved surface on the side the part stands on now (ADR-0140 3.9): the kernel's\n * (`figureSurfaceKeptPlaceOf`), or, the part standing on its axis, the surface's first point.\n */\nexport function surfaceKeptOf(revision: FigureRevision, part: string, target: string): FigureSurfacePlace | undefined {\n const surface = surfaceOf(revision.asset, target)\n if (!surface) return undefined\n return (\n figureSurfaceKeptPlaceOf(revision.asset, part, target, { ...revision.inputs }) ??\n (surface.form === 'around' ? { around: 0, along: 'centre' } : { toward: { x: 0, y: 1, z: 0 } })\n )\n}\n\n/**\n * A new aim: the plane, another part, another face of the same part, or a point of its curved surface. Where on the\n * face -- or the surface -- is filled in as where the part stands now, so fastening it keeps it there (`placeKeptOf`,\n * `surfaceKeptOf`); the author changes it from there. A part aimed at a sphere, or beside a cylinder's side within its\n * length, is aimed at the surface: it is fastened as it stands (ADR-0140 3.6).\n */\nexport function aimFasten(\n revision: FigureRevision,\n part: string,\n form: FastenForm,\n to: { plane: true } | { part: string } | { targetFace: FigureFace } | { surface: true }\n): FastenForm {\n if ('surface' in to) return { ...form, surface: surfaceKeptOf(revision, part, form.target), align: {}, alignMm: {}, alignInput: {} }\n if ('part' in to) {\n /* Beside its curved surface -- a sphere's anywhere, a cylinder's side within its length -- or with no face at all. */\n const beside = figureSurfaceKeptPlaceOf(revision.asset, part, to.part, { ...revision.inputs })\n const kept = beside ?? (!facesOf(revision.asset, to.part).length ? surfaceKeptOf(revision, part, to.part) : undefined)\n if (kept) return { ...form, toPlane: false, target: to.part, surface: kept, align: {}, alignMm: {}, alignInput: {} }\n }\n form = { ...form, surface: undefined }\n /* Aimed at the plane, it meets it toward the side the placement uses -- below a ceiling -- until the author says (ADR-0140 3.11). */\n const f: FastenForm =\n 'plane' in to\n ? { ...form, toPlane: true, target: '', facing: form.toPlane ? form.facing : (figurePlaneFacingOf(revision.asset) ?? form.facing) }\n : 'part' in to\n ? { ...form, toPlane: false, target: to.part }\n : { ...form, targetFace: to.targetFace }\n const theirFaces = f.target ? facesOf(revision.asset, f.target) : FACES\n const targetFace = (theirFaces.includes(f.targetFace) ? f.targetFace : theirFaces[0]) as FigureFace\n const aim: FastenTarget | undefined = f.toPlane\n ? 'plane'\n : f.target\n ? { part: f.target, face: targetFace }\n : undefined\n return { ...f, ...(aim ? placeKeptOf(revision, part, aim) : { align: {}, alignMm: {}, alignInput: {} }) }\n}\n\n/** A change the drawing asks: a face, a way, a gap or a place across the face. */\nexport function fastenChanged(\n revision: FigureRevision,\n part: string,\n form: FastenForm,\n change: FastenChange\n): FastenForm {\n const f = form\n if ('targetFace' in change) return keptGapOf(revision, part, aimFasten(revision, part, f, { targetFace: change.targetFace as FigureFace }))\n if ('onSurface' in change) return keptGapOf(revision, part, aimFasten(revision, part, f, { surface: true }))\n if ('surface' in change) return keptGapOf(revision, part, { ...f, surface: change.surface })\n if ('mode' in change) return keptGapOf(revision, part, { ...f, facing: change.mode })\n if ('gap' in change) return { ...f, gap: change.gap, gapKept: undefined, gapFrom: 'typed' }\n return {\n ...f,\n align: { ...f.align, [change.axis]: change.how },\n alignMm: change.how === 'mm' ? { ...f.alignMm, [change.axis]: change.mm ?? 0 } : f.alignMm\n }\n}\n\n/**\n * The form with the gap that keeps the part where it stands (ADR-0140 stage 4, user 2026-10-20 「현재 상태로 붙이기」):\n * figure-model's `figureFastenKeptGapOf` for what it is aimed at and how it meets it. A gap the author typed, or the 0 a\n * canvas press puts, is left as it is. Nothing aimed at yet, the form is as it was.\n */\nexport function keptGapOf(revision: FigureRevision, part: string, form: FastenForm): FastenForm {\n if (form.gapFrom !== 'kept') return form\n const asset = revision.asset\n const theirFaces = form.target ? facesOf(asset, form.target) : FACES\n const targetFace = (theirFaces.includes(form.targetFace) ? form.targetFace : theirFaces[0]) as FigureFace\n const planeWay = figurePlaneFacingOf(asset)\n const mode: FastenMode = form.toPlane ? (mountingPlaneOf(asset).facings.includes(form.facing) ? form.facing : (planeWay ?? 'meet')) : form.facing\n const to = form.toPlane\n ? ('plane' as const)\n : form.target && form.surface && surfaceOf(asset, form.target)\n ? { part: form.target, surface: form.surface }\n : form.target\n ? { part: form.target, face: targetFace }\n : undefined\n if (!to) return form\n return { ...form, gap: figureFastenKeptGapOf(asset, part, to, mode, { ...revision.inputs }), gapKept: undefined }\n}\n\n/** What a form comes to: the face aimed at, the way, the drawing of the face and the command. */\nexport interface FastenPlan {\n /** Nothing is aimed at until a part or the plane is chosen. */\n aim?: FastenTarget\n theirFaces: string[]\n targetFace: FigureFace\n mode: FastenMode\n view?: FaceView\n /** The axes across the face asked in rows: where the drawing cannot set the place. */\n alignRows: { axis: Axis; edges: boolean }[]\n action?: FigureAuthoringAction\n /** The face the command would meet, lit on the canvas while it is tried. */\n face?: { part: string; face: string }\n /** On a point of the target's curved surface: which surface, about which axis, and where (ADR-0140 3.9). */\n surface?: { form: 'around' | 'toward'; axis: Axis; place: FigureSurfacePlace }\n /** The target's own face at each of the drawing's places, as the target is drawn (\\`facesAsDrawnOf\\`). */\n drawnFaces?: Record<FigureFace, FigureFace>\n}\n\nexport function fastenPlanOf(revision: FigureRevision, part: string, f: FastenForm): FastenPlan {\n const plan = fastenPlanWithout(revision, part, f)\n return f.target && !f.toPlane ? { ...plan, drawnFaces: facesAsDrawnOf(revision, f.target) } : plan\n}\n\nfunction fastenPlanWithout(revision: FigureRevision, part: string, f: FastenForm): FastenPlan {\n const asset = revision.asset\n const theirFaces = f.target ? facesOf(asset, f.target) : FACES\n const targetFace = (theirFaces.includes(f.targetFace) ? f.targetFace : theirFaces[0]) as FigureFace\n const aim: FastenTarget | undefined = f.toPlane\n ? 'plane'\n : f.target\n ? { part: f.target, face: targetFace }\n : undefined\n /* The plane takes a part standing on it or hanging below it, a wall only one standing out of it (ADR-0140 3.11). */\n const planeWay = figurePlaneFacingOf(asset)\n const mode: FastenMode = f.toPlane ? (mountingPlaneOf(asset).facings.includes(f.facing) ? f.facing : (planeWay ?? 'meet')) : f.facing\n const surface = !f.toPlane && f.target && f.surface ? surfaceOf(asset, f.target) : undefined\n if (surface) {\n /* On the surface: where is the surface's own words, so no alignment goes with it (ADR-0140 3.9). */\n const action = {\n kind: 'attach',\n part,\n to: { part: f.target, surface: f.surface },\n facing: mode,\n ...fastenGapOf(f),\n replace: !!heldBy(asset, part)\n } as FigureAuthoringAction\n return { theirFaces, targetFace, mode, alignRows: [], action, surface: { ...surface, place: f.surface! } }\n }\n if (!aim) return { theirFaces, targetFace, mode, alignRows: [] }\n const align = alignOf(asset, aim, f.align, f.alignMm, f.alignInput)\n const view = faceViewOf(revision, part, aim, mode)\n const action = {\n kind: 'attach',\n part,\n to: f.toPlane ? { plane: 'mounting-plane' } : { part: f.target, face: targetFace },\n /* On the plane the kernel takes the placement's way when none is said: only another way is said. */\n ...(f.toPlane ? (mode === planeWay ? {} : { facing: mode }) : { facing: mode }),\n ...fastenGapOf(f),\n ...(align ? { align } : {}),\n replace: !!heldBy(asset, part)\n } as FigureAuthoringAction\n return {\n aim,\n theirFaces,\n targetFace,\n mode,\n view,\n alignRows: alignRowsOf(asset, aim, view, f.alignInput),\n action,\n ...(f.toPlane ? {} : { face: { part: f.target, face: targetFace } })\n }\n}\n\ntype Say = (key: string, params?: Record<string, string>) => string\n\n/** 「bin의 윗면에 올려놓기」: what the fastening is, in one line -- the part is the one the window is open on, not named again. */\nexport function fastenSentenceOf(\n form: FastenForm,\n plan: FastenPlan,\n planeWord: string,\n say: Say\n): string {\n const where = plan.surface ? say('figure.label.surface-' + plan.surface.form) : say('figure.label.face-' + plan.targetFace)\n const to = form.toPlane ? planeWord : `${form.target}의 ${where}`\n return say(`figure.text.fasten-sentence-${plan.mode}`, { to })\n}\n\n/**\n * What the folded details hold that is not their default, said while folded; nothing for the default. The gap's default\n * is the one it starts at -- the distance the part stands at, or 0 where the canvas was pressed -- so only a number typed\n * is said.\n */\nexport function fastenDetailWordsOf(form: FastenForm, say: Say): string[] {\n return [\n ...(form.gapKept !== undefined\n ? [say('figure.text.fasten-summary-gap-worked-out')]\n : form.gapFrom === 'typed' && form.gap\n ? [say('figure.text.fasten-summary-gap', { mm: String(form.gap) })]\n : [])\n ]\n}\n\n/**\n * A part pressed on the canvas while the window is open (ADR-0140 stage 4): aimed at, on the face or the point pressed,\n * its middle where it was pressed -- the kernel's reading of the press (`figureFastenTargetAt`), the point and normal brought into that part's own\n * frame by the pose its body is drawn at (`at.id`, a row's copy too). The part itself, one hanging from it, or one with\n * nothing to fasten to is not aimed at; a press on a curve there is no fastening to aims at the part alone. Each says\n * why, by its words' key.\n */\n/* Put where the canvas was pressed: on the face or the surface there, with no gap (ADR-0140 stage 4). */\nconst PRESSED = { gap: 0, gapKept: undefined, gapFrom: 'pressed' as const }\n\nexport function aimFastenAt(\n revision: FigureRevision,\n part: string,\n form: FastenForm,\n at: { id: string; point?: readonly number[]; normal?: readonly number[] }\n): { form?: FastenForm; note?: 'aim-self' | 'aim-cannot' | 'target-would-loop' | 'aim-not-here'; part: string } {\n const target = ownerOf(at.id)\n const offered = fastenTargetsOf(revision, part).find(t => t.part === target)\n if (target === part) return { note: 'aim-self', part: target }\n if (!offered) return { note: 'aim-cannot', part: target }\n if (offered.loops) return { note: 'target-would-loop', part: target }\n const aimed = aimFasten(revision, part, form, { part: target })\n const pose = (revision.geometry as Array<{ id: string; pose?: { r: number[][]; t: number[] } }>).find(g => g.id === at.id)?.pose\n if (!pose || !at.point || !at.normal) return { form: aimed, part: target }\n /* Into the part's own frame: rᵀ (p − t), and the normal by rᵀ. */\n const own = (v: readonly number[], from: readonly number[] = [0, 0, 0]) => [0, 1, 2].map(c => [0, 1, 2].reduce((sum, i) => sum + pose.r[i]![c]! * (v[i]! - from[i]!), 0))\n const lands = figureFastenTargetAt(revision.asset, target, own(at.point, pose.t), own(at.normal), { ...revision.inputs })\n if ('face' in lands) {\n /* On the face where it was pressed, as a point of a curved surface is: its middle there. */\n const onFace = aimFasten(revision, part, { ...aimed, surface: undefined }, { targetFace: lands.face as FigureFace })\n const at = lands.at as Partial<Record<Axis, number>>\n return { form: { ...onFace, ...PRESSED, align: Object.fromEntries(Object.keys(at).map(a => [a, 'mm'])) as FastenForm['align'], alignMm: { ...at }, alignInput: {} }, part: target }\n }\n if ('surface' in lands) return { form: { ...aimed, ...PRESSED, toPlane: false, target, surface: lands.surface, align: {}, alignMm: {}, alignInput: {} }, part: target }\n return { form: aimed, note: 'aim-not-here', part: target }\n}\n"]}
1
+ {"version":3,"file":"fasten-form.js","sourceRoot":"","sources":["../../client/modeller/fasten-form.ts"],"names":[],"mappings":"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","sourcesContent":["import { FIGURE_FACES, figureFastenKeptGapOf, figureFastenTargetAt, figurePlaneFacingOf, figureSurfaceKeptPlaceOf } from '@hatiolab/figure-model'\nimport type { FigureAuthoringAction, FigureFace, FigureSurfacePlace } from '@hatiolab/figure-model'\n\nimport { faceViewOf, facesAsDrawnOf, type FaceView, type FastenMode, type FastenTarget } from './fasten-geometry.js'\nimport type { FastenChange } from './figure-fasten-drawing.js'\nimport {\n alignOf,\n alignAxesOf,\n alignRowsOf,\n canFasten,\n facesOf,\n fasteningOf,\n fastenGapOf,\n hangsFrom,\n heldBy,\n mountingPlaneOf,\n placeKeptOf,\n surfaceOf,\n type Alignment,\n type Axis\n} from './links.js'\nimport type { FigureRevision } from './revision.js'\nimport { standsWhereAdded } from './palette.js'\nimport { ownerOf } from './fields.js'\n\n/*\n * A fastening as it is chosen, before it is done: to what, which face, how, where across the face. The fastening window\n * (`figure-fasten-dialog.ts`) holds one and changes it as the author chooses; the attach command is worked out from it\n * only here, so the window, its preview and the panel's 「정렬 고치기」 send the same command for the same choice.\n */\n\nconst FACES = Object.keys(FIGURE_FACES) as FigureFace[]\n\nexport interface FastenForm {\n toPlane: boolean\n target: string\n targetFace: FigureFace\n /** How it meets the face: its near end on it, its far end on it (flush), or its middle (ADR-0140 3.11). */\n facing: FastenMode\n gap: number\n /** The record's gap when it is worked out (a length that follows something): kept until a number is typed. */\n gapKept: unknown\n /**\n * Where the gap came from (ADR-0140 stage 4, 「현재 상태로 붙이기」): `kept` -- the distance the part stands at, worked\n * out again whenever where or how it is fastened changes, so fastening does not move it; `typed` -- the author's\n * number, left as it is; `pressed` -- 0, the part put where the canvas was pressed.\n */\n gapFrom: 'kept' | 'typed' | 'pressed'\n align: Partial<Record<Axis, Alignment>>\n alignMm: Partial<Record<Axis, number>>\n alignInput: Partial<Record<Axis, string>>\n /** On a point of the target's curved surface instead of a face (ADR-0140 3.9): where, as the record says it. */\n surface?: FigureSurfacePlace\n}\n\nexport const freshFasten = (): FastenForm => ({\n toPlane: false,\n target: '',\n targetFace: 'top',\n facing: 'meet',\n gap: 0,\n gapKept: undefined,\n gapFrom: 'kept',\n align: {},\n alignMm: {},\n alignInput: {}\n})\n\n/** The part's own fastening as a form, or a fresh one: a window opens on what the part has (walk 1, 2026-09-26). */\nexport function fastenFormOf(revision: FigureRevision, part: string): FastenForm {\n const own = fasteningOf(revision, part)\n if (!own || own.atOrigin) {\n /* A part still where it was added was put nowhere by the author: fastened, it goes on the face, no gap to keep. */\n return addedUnplaced(revision, part) ? { ...freshFasten(), gapFrom: 'pressed' } : freshFasten()\n }\n /* A gap the record works out is the author's; a number is where the part stands, so aiming again keeps it there. */\n return { ...freshFasten(), ...own, gapFrom: own.gapKept !== undefined ? 'typed' : 'kept' } as FastenForm\n}\n\n/** A part fastened to nothing that still stands where the palette put it: the author has put it nowhere to keep. */\nfunction addedUnplaced(revision: FigureRevision, part: string): boolean {\n if (fasteningOf(revision, part)) return false\n const pose = (revision.geometry.find(g => (g as { id: string }).id === part) as { pose?: { r: number[][]; t: number[] } } | undefined)?.pose\n return standsWhereAdded(pose)\n}\n\n/**\n * The face a part just added starts on when aimed at `target`: the one asked, unless another part is fastened there\n * already -- then the first face of the target nothing is fastened to (review 2026-11-11: a thigh aimed at a pelvis\n * started on its top, where the body stands, and went inside the body until the bottom was chosen). A part the author\n * has placed keeps the face it stands by: a face holds many parts (rollers and a lid on one frame).\n */\nfunction freeFaceOf(revision: FigureRevision, part: string, target: string, asked: FigureFace): FigureFace {\n const on = (end: unknown) => end as { part?: string; face?: string }\n const joints = revision.asset.joints ?? []\n const taken = new Set(joints.filter(j => on(j.body0).part === target && on(j.body1).part !== part).map(j => on(j.body0).face))\n /* The face the target itself stands on its own parent by: a thigh hung under a pelvis touches it with its top. */\n let hungBy: FigureFace | undefined\n for (const j of joints)\n if (on(j.body1).part === target && on(j.body0).face && (j as { facing?: string }).facing !== 'flush') {\n hungBy = OPPOSITE[on(j.body0).face as FigureFace]\n taken.add(hungBy)\n }\n /*\n A tall part hung by its side -- an upper arm on a torso -- goes on downward: what is fastened to it starts under its\n bottom end, not on its top beside the shoulder (tutorial run 2026-11-12: a forearm started on the upper arm's top\n and its bottom had to be picked by hand).\n */\n if (hungBy && FIGURE_FACES[hungBy] !== 'y' && !taken.has('bottom') && tallOf(revision, target)) return 'bottom'\n if (!taken.has(asked)) return asked\n /* The face across from the one taken first: a body on the top, legs under the bottom. */\n const across = OPPOSITE[asked]\n const faces = facesOf(revision.asset, target)\n if (faces.includes(across) && !taken.has(across)) return across\n return (faces.find(face => !taken.has(face)) as FigureFace | undefined) ?? asked\n}\n\n/** Whether a part as drawn is at least half again as tall as it is wide and deep, read off its own faces. */\nfunction tallOf(revision: FigureRevision, part: string): boolean {\n const faces = (revision.geometry.find(g => (g as { id: string }).id === part) as { shape?: { faces?: Record<string, { at: number }> } } | undefined)?.shape?.faces\n const span = (lo: string, hi: string) => (faces?.[hi] && faces?.[lo] ? Math.abs(faces[hi]!.at - faces[lo]!.at) : undefined)\n const [x, y, z] = [span('left', 'right'), span('bottom', 'top'), span('back', 'front')]\n return x !== undefined && y !== undefined && z !== undefined && y >= 1.5 * Math.max(x, z)\n}\n\nconst OPPOSITE: Record<FigureFace, FigureFace> = { top: 'bottom', bottom: 'top', left: 'right', right: 'left', front: 'back', back: 'front' }\n\n/** What a part may be fastened to: every other part that can be, each said whether it would close a loop. */\nexport function fastenTargetsOf(revision: FigureRevision, part: string): Array<{ part: string; loops: boolean }> {\n const asset = revision.asset\n return (\n asset.appearance\n .map(look => look.target)\n .filter(one => one !== part && canFasten(asset, one))\n /* Not a part that hangs from this one: fastening a frame to its own roller would close a loop. */\n .map(one => ({ part: one, loops: hangsFrom(asset, one, part) }))\n )\n}\n\n/**\n * The point of a target's curved surface on the side the part stands on now (ADR-0140 3.9): the kernel's\n * (`figureSurfaceKeptPlaceOf`), or, the part standing on its axis, the surface's first point.\n */\nexport function surfaceKeptOf(revision: FigureRevision, part: string, target: string): FigureSurfacePlace | undefined {\n const surface = surfaceOf(revision.asset, target)\n if (!surface) return undefined\n return (\n figureSurfaceKeptPlaceOf(revision.asset, part, target, { ...revision.inputs }) ??\n (surface.form === 'around' ? { around: 0, along: 'centre' } : { toward: { x: 0, y: 1, z: 0 } })\n )\n}\n\n/**\n * A new aim: the plane, another part, another face of the same part, or a point of its curved surface. Where on the\n * face -- or the surface -- is filled in as where the part stands now, so fastening it keeps it there (`placeKeptOf`,\n * `surfaceKeptOf`); the author changes it from there. A part aimed at a sphere, or beside a cylinder's side within its\n * length, is aimed at the surface: it is fastened as it stands (ADR-0140 3.6).\n */\nexport function aimFasten(\n revision: FigureRevision,\n part: string,\n form: FastenForm,\n to: { plane: true } | { part: string } | { targetFace: FigureFace } | { surface: true }\n): FastenForm {\n if ('surface' in to) return { ...form, surface: surfaceKeptOf(revision, part, form.target), align: {}, alignMm: {}, alignInput: {} }\n if ('part' in to) {\n /* Beside its curved surface -- a sphere's anywhere, a cylinder's side within its length -- or with no face at all. */\n const beside = figureSurfaceKeptPlaceOf(revision.asset, part, to.part, { ...revision.inputs })\n const kept = beside ?? (!facesOf(revision.asset, to.part).length ? surfaceKeptOf(revision, part, to.part) : undefined)\n if (kept) return { ...form, toPlane: false, target: to.part, surface: kept, align: {}, alignMm: {}, alignInput: {} }\n }\n form = { ...form, surface: undefined }\n /* Aimed at the plane, it meets it toward the side the placement uses -- below a ceiling -- until the author says (ADR-0140 3.11). */\n const f: FastenForm =\n 'plane' in to\n ? { ...form, toPlane: true, target: '', facing: form.toPlane ? form.facing : (figurePlaneFacingOf(revision.asset) ?? form.facing) }\n : 'part' in to\n ? {\n ...form,\n toPlane: false,\n target: to.part,\n targetFace: to.part !== form.target && addedUnplaced(revision, part) ? freeFaceOf(revision, part, to.part, form.targetFace) : form.targetFace\n }\n : { ...form, targetFace: to.targetFace }\n const theirFaces = f.target ? facesOf(revision.asset, f.target) : FACES\n const targetFace = (theirFaces.includes(f.targetFace) ? f.targetFace : theirFaces[0]) as FigureFace\n const aim: FastenTarget | undefined = f.toPlane\n ? 'plane'\n : f.target\n ? { part: f.target, face: targetFace }\n : undefined\n /*\n * A part still where the palette put it has no place of the author's to keep: it goes to the face's centre (review\n * 2026-11-11: a shin added at the origin and aimed at a thigh 85 mm off it was put 85 mm off the thigh's centre; an\n * arm aimed at the body's side stood off the face, out of reach of the drawing).\n */\n const centred = { align: {}, alignMm: {}, alignInput: {} }\n return { ...f, ...(aim && !addedUnplaced(revision, part) ? placeKeptOf(revision, part, aim) : centred) }\n}\n\n/** A change the drawing asks: a face, a way, a gap or a place across the face. */\nexport function fastenChanged(\n revision: FigureRevision,\n part: string,\n form: FastenForm,\n change: FastenChange\n): FastenForm {\n const f = form\n if ('targetFace' in change) return keptGapOf(revision, part, aimFasten(revision, part, f, { targetFace: change.targetFace as FigureFace }))\n if ('onSurface' in change) return keptGapOf(revision, part, aimFasten(revision, part, f, { surface: true }))\n if ('surface' in change) return keptGapOf(revision, part, { ...f, surface: change.surface })\n if ('mode' in change) return keptGapOf(revision, part, { ...f, facing: change.mode })\n if ('gap' in change) return { ...f, gap: change.gap, gapKept: undefined, gapFrom: 'typed' }\n return {\n ...f,\n align: { ...f.align, [change.axis]: change.how },\n alignMm: change.how === 'mm' ? { ...f.alignMm, [change.axis]: change.mm ?? 0 } : f.alignMm\n }\n}\n\n/**\n * The form with the gap that keeps the part where it stands (ADR-0140 stage 4, user 2026-10-20 「현재 상태로 붙이기」):\n * figure-model's `figureFastenKeptGapOf` for what it is aimed at and how it meets it. A gap the author typed, or the 0 a\n * canvas press puts, is left as it is. Nothing aimed at yet, the form is as it was.\n */\nexport function keptGapOf(revision: FigureRevision, part: string, form: FastenForm): FastenForm {\n if (form.gapFrom !== 'kept') return form\n const asset = revision.asset\n const theirFaces = form.target ? facesOf(asset, form.target) : FACES\n const targetFace = (theirFaces.includes(form.targetFace) ? form.targetFace : theirFaces[0]) as FigureFace\n const planeWay = figurePlaneFacingOf(asset)\n const mode: FastenMode = form.toPlane ? (mountingPlaneOf(asset).facings.includes(form.facing) ? form.facing : (planeWay ?? 'meet')) : form.facing\n const to = form.toPlane\n ? ('plane' as const)\n : form.target && form.surface && surfaceOf(asset, form.target)\n ? { part: form.target, surface: form.surface }\n : form.target\n ? { part: form.target, face: targetFace }\n : undefined\n if (!to) return form\n return { ...form, gap: figureFastenKeptGapOf(asset, part, to, mode, { ...revision.inputs }), gapKept: undefined }\n}\n\n/** What a form comes to: the face aimed at, the way, the drawing of the face and the command. */\nexport interface FastenPlan {\n /** Nothing is aimed at until a part or the plane is chosen. */\n aim?: FastenTarget\n theirFaces: string[]\n targetFace: FigureFace\n mode: FastenMode\n view?: FaceView\n /** The axes across the face asked in rows: where the drawing cannot set the place. */\n alignRows: { axis: Axis; edges: boolean }[]\n /**\n * Every axis across the face, the drawing's too: the details ask each by a number as well (review 2026-11-11: a thigh\n * dragged to a pelvis's edge overshot by 47 mm, and dragged back by eye).\n */\n alignAxes?: { axis: Axis; edges: boolean }[]\n action?: FigureAuthoringAction\n /** The face the command would meet, lit on the canvas while it is tried. */\n face?: { part: string; face: string }\n /** On a point of the target's curved surface: which surface, about which axis, and where (ADR-0140 3.9). */\n surface?: { form: 'around' | 'toward'; axis: Axis; place: FigureSurfacePlace }\n /** The target's own face at each of the drawing's places, as the target is drawn (\\`facesAsDrawnOf\\`). */\n drawnFaces?: Record<FigureFace, FigureFace>\n}\n\nexport function fastenPlanOf(revision: FigureRevision, part: string, f: FastenForm): FastenPlan {\n const plan = fastenPlanWithout(revision, part, f)\n return f.target && !f.toPlane ? { ...plan, drawnFaces: facesAsDrawnOf(revision, f.target) } : plan\n}\n\nfunction fastenPlanWithout(revision: FigureRevision, part: string, f: FastenForm): FastenPlan {\n const asset = revision.asset\n const theirFaces = f.target ? facesOf(asset, f.target) : FACES\n const targetFace = (theirFaces.includes(f.targetFace) ? f.targetFace : theirFaces[0]) as FigureFace\n const aim: FastenTarget | undefined = f.toPlane\n ? 'plane'\n : f.target\n ? { part: f.target, face: targetFace }\n : undefined\n /* The plane takes a part standing on it or hanging below it, a wall only one standing out of it (ADR-0140 3.11). */\n const planeWay = figurePlaneFacingOf(asset)\n const mode: FastenMode = f.toPlane ? (mountingPlaneOf(asset).facings.includes(f.facing) ? f.facing : (planeWay ?? 'meet')) : f.facing\n const surface = !f.toPlane && f.target && f.surface ? surfaceOf(asset, f.target) : undefined\n if (surface) {\n /* On the surface: where is the surface's own words, so no alignment goes with it (ADR-0140 3.9). */\n const action = {\n kind: 'attach',\n part,\n to: { part: f.target, surface: f.surface },\n facing: mode,\n ...fastenGapOf(f),\n replace: !!heldBy(asset, part)\n } as FigureAuthoringAction\n return { theirFaces, targetFace, mode, alignRows: [], action, surface: { ...surface, place: f.surface! } }\n }\n if (!aim) return { theirFaces, targetFace, mode, alignRows: [] }\n const align = alignOf(asset, aim, f.align, f.alignMm, f.alignInput)\n const view = faceViewOf(revision, part, aim, mode)\n const action = {\n kind: 'attach',\n part,\n to: f.toPlane ? { plane: 'mounting-plane' } : { part: f.target, face: targetFace },\n /* On the plane the kernel takes the placement's way when none is said: only another way is said. */\n ...(f.toPlane ? (mode === planeWay ? {} : { facing: mode }) : { facing: mode }),\n ...fastenGapOf(f),\n ...(align ? { align } : {}),\n replace: !!heldBy(asset, part)\n } as FigureAuthoringAction\n return {\n aim,\n theirFaces,\n targetFace,\n mode,\n view,\n alignRows: alignRowsOf(asset, aim, view, f.alignInput),\n alignAxes: alignAxesOf(asset, aim),\n action,\n ...(f.toPlane ? {} : { face: { part: f.target, face: targetFace } })\n }\n}\n\ntype Say = (key: string, params?: Record<string, string>) => string\n\n/** 「bin의 윗면에 올려놓기」: what the fastening is, in one line -- the part is the one the window is open on, not named again. */\nexport function fastenSentenceOf(\n form: FastenForm,\n plan: FastenPlan,\n planeWord: string,\n say: Say\n): string {\n const where = plan.surface ? say('figure.label.surface-' + plan.surface.form) : say('figure.label.face-' + plan.targetFace)\n const to = form.toPlane ? planeWord : `${form.target}의 ${where}`\n return say(`figure.text.fasten-sentence-${plan.mode}`, { to })\n}\n\n/**\n * What the folded details hold that is not their default, said while folded; nothing for the default. The gap's default\n * is the one it starts at -- the distance the part stands at, or 0 where the canvas was pressed -- so only a number typed\n * is said.\n */\nexport function fastenDetailWordsOf(form: FastenForm, say: Say): string[] {\n return [\n ...(form.gapKept !== undefined\n ? [say('figure.text.fasten-summary-gap-worked-out')]\n : form.gapFrom === 'typed' && form.gap\n ? [say('figure.text.fasten-summary-gap', { mm: String(form.gap) })]\n : [])\n ]\n}\n\n/**\n * A part pressed on the canvas while the window is open (ADR-0140 stage 4): aimed at, on the face or the point pressed,\n * its middle where it was pressed -- the kernel's reading of the press (`figureFastenTargetAt`), the point and normal brought into that part's own\n * frame by the pose its body is drawn at (`at.id`, a row's copy too). The part itself, one hanging from it, or one with\n * nothing to fasten to is not aimed at; a press on a curve there is no fastening to aims at the part alone. Each says\n * why, by its words' key.\n */\n/* Put where the canvas was pressed: on the face or the surface there, with no gap (ADR-0140 stage 4). */\nconst PRESSED = { gap: 0, gapKept: undefined, gapFrom: 'pressed' as const }\n\nexport function aimFastenAt(\n revision: FigureRevision,\n part: string,\n form: FastenForm,\n at: { id: string; point?: readonly number[]; normal?: readonly number[] }\n): { form?: FastenForm; note?: 'aim-self' | 'aim-cannot' | 'target-would-loop' | 'aim-not-here'; part: string } {\n const target = ownerOf(at.id)\n const offered = fastenTargetsOf(revision, part).find(t => t.part === target)\n if (target === part) return { note: 'aim-self', part: target }\n if (!offered) return { note: 'aim-cannot', part: target }\n if (offered.loops) return { note: 'target-would-loop', part: target }\n const aimed = aimFasten(revision, part, form, { part: target })\n const pose = (revision.geometry as Array<{ id: string; pose?: { r: number[][]; t: number[] } }>).find(g => g.id === at.id)?.pose\n if (!pose || !at.point || !at.normal) return { form: aimed, part: target }\n /* Into the part's own frame: rᵀ (p − t), and the normal by rᵀ. */\n const own = (v: readonly number[], from: readonly number[] = [0, 0, 0]) => [0, 1, 2].map(c => [0, 1, 2].reduce((sum, i) => sum + pose.r[i]![c]! * (v[i]! - from[i]!), 0))\n const lands = figureFastenTargetAt(revision.asset, target, own(at.point, pose.t), own(at.normal), { ...revision.inputs })\n if ('face' in lands) {\n /* On the face where it was pressed, as a point of a curved surface is: its middle there. */\n const onFace = aimFasten(revision, part, { ...aimed, surface: undefined }, { targetFace: lands.face as FigureFace })\n const at = lands.at as Partial<Record<Axis, number>>\n return { form: { ...onFace, ...PRESSED, align: Object.fromEntries(Object.keys(at).map(a => [a, 'mm'])) as FastenForm['align'], alignMm: { ...at }, alignInput: {} }, part: target }\n }\n if ('surface' in lands) return { form: { ...aimed, ...PRESSED, toPlane: false, target, surface: lands.surface, align: {}, alignMm: {}, alignInput: {} }, part: target }\n return { form: aimed, note: 'aim-not-here', part: target }\n}\n"]}
@@ -1,12 +1,10 @@
1
1
  import { __decorate, __metadata } from "tslib";
2
2
  import { css, html, LitElement, nothing, svg } from 'lit';
3
3
  import { customElement, property, state } from 'lit/decorators.js';
4
- import { ref } from 'lit/directives/ref.js';
5
4
  import { i18next, localize } from '@operato/i18n';
6
5
  import { figureCavitySectionOf } from '@hatiolab/figure-model';
6
+ import { focusOnRender } from './focus-on-render.js';
7
7
  import { cavityRefusalWordsOf, cavityWorkingOf, END_FACE, endToggled, mm, SIDE_FACE, wallDragged } from './section-controls.js';
8
- /** A field opened by a press takes the keys at once. */
9
- const focusOnRender = () => ref(el => el && requestAnimationFrame(() => el.select()));
10
8
  /** How the section is laid on the screen, by the axis it is pushed along: across to the right, then down. */
11
9
  const SCREEN = { y: ['x', 'z'], x: ['z', 'y'], z: ['x', 'y'] };
12
10
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"figure-cavity-drawing.js","sourceRoot":"","sources":["../../client/modeller/figure-cavity-drawing.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing, svg } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { ref } from 'lit/directives/ref.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { figureCavitySectionOf } from '@hatiolab/figure-model'\nimport type { FigureAuthoringAction, FigureCavityRequest, FigureEvaluatedShape, FigureSection } from '@hatiolab/figure-model'\nimport { cavityRefusalWordsOf, cavityWorkingOf, END_FACE, endToggled, mm, SIDE_FACE, wallDragged } from './section-controls.js'\n\ntype Axis = 'x' | 'y' | 'z'\n\n/** A field opened by a press takes the keys at once. */\nconst focusOnRender = () => ref(el => el && requestAnimationFrame(() => (el as HTMLInputElement).select()))\ntype End = 'start' | 'end'\ntype Body = { id: string; shape: FigureEvaluatedShape }\n\n/** How the section is laid on the screen, by the axis it is pushed along: across to the right, then down. */\nconst SCREEN: Record<Axis, [Axis, Axis]> = { y: ['x', 'z'], x: ['z', 'y'], z: ['x', 'y'] }\n\n/**\n * 속 공간 그림 — the inside of a pushed part drawn, and edited by drawing (user 2026-10-01: 「이해와 편집이 직관적이지 않다」).\n *\n * Seen along the push, the section and its inside: a handle in the middle of each wall is dragged to its thickness,\n * every wall together unless 면마다 벽 is on. Cut along the push, the walls and the two ends: an end pressed opens or\n * closes it, a closed end's inner line is dragged to its thickness. While dragging, the figure behind shows what the\n * inside makes (`command-live`); letting go sends one `set-cavity`. What the kernel would refuse is drawn in the error\n * colour and said, by the kernel's own check, and is not sent.\n */\n@customElement('figure-cavity-drawing')\nexport class FigureCavityDrawing extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n display: grid;\n gap: 6px;\n }\n svg {\n width: 100%;\n display: block;\n touch-action: none;\n user-select: none;\n }\n svg text {\n font: inherit;\n }\n small[refusal] {\n color: var(--md-sys-color-error);\n }\n div[pane] {\n position: relative;\n }\n div[pane] input {\n position: absolute;\n width: 64px;\n transform: translate(-50%, -50%);\n font: inherit;\n }\n text[typed] {\n cursor: text;\n text-decoration: underline dotted;\n }\n `\n\n @property({ attribute: false }) body?: Body\n @property({ type: Boolean }) locked = false\n /** Walls one per side: a handle moves its own wall only. */\n @property({ type: Boolean }) perSide = false\n\n /** What is being dragged, and the inside it makes; undefined when nothing is. */\n @state() private working?: ReturnType<typeof cavityWorkingOf>\n @state() private refusal = ''\n private dragging: { kind: 'wall'; side: string } | { kind: 'end'; end: End } | null = null\n /** A number pressed to be typed: which, and where on its picture (percent of the picture's box). */\n @state() private typing?: ({ kind: 'wall'; side: string } | { kind: 'end'; end: End }) & { x: number; y: number; pane: 'top' | 'side'; value: number }\n private pressedAt = 0\n\n private get now() {\n return this.working ?? (this.body ? cavityWorkingOf(this.body.shape) : undefined)\n }\n\n private request(w: NonNullable<ReturnType<typeof cavityWorkingOf>>): FigureCavityRequest {\n return { wall: { ...w.wall }, start: w.start, end: w.end }\n }\n\n private action(w: NonNullable<ReturnType<typeof cavityWorkingOf>>): FigureAuthoringAction {\n return { kind: 'set-cavity', part: this.body!.id, cavity: this.request(w) }\n }\n\n /** What the kernel would refuse, in words; for one side's wall, the most that side can be with the opposite kept. */\n private judge(w: NonNullable<ReturnType<typeof cavityWorkingOf>>, side?: string): string {\n const words = cavityRefusalWordsOf(this.body!.shape, w, this.perSide, side)\n return words ? i18next.t(words.key, words.params) : ''\n }\n\n /** The working inside while dragging: drawn, judged, and previewed behind when the kernel would take it. */\n private hold(w: NonNullable<ReturnType<typeof cavityWorkingOf>>, side?: string) {\n this.working = w\n this.refusal = this.judge(w, side)\n this.emit('command-live', this.refusal ? null : this.action(w))\n }\n\n private release() {\n const w = this.working\n this.dragging = null\n this.working = undefined\n if (!w) return\n /* Refused: nothing is sent, and the reason stays said until the next drag -- letting go must not look like taking it. */\n if (this.refusal) {\n this.emit('command-live', null)\n return\n }\n this.emit('command', this.action(w))\n }\n\n private emit(name: 'command' | 'command-live', action: FigureAuthoringAction | null) {\n this.dispatchEvent(new CustomEvent(name, { detail: { action }, bubbles: true, composed: true }))\n }\n\n private point(ev: PointerEvent, el: SVGSVGElement) {\n const pt = el.createSVGPoint()\n pt.x = ev.clientX\n pt.y = ev.clientY\n return pt.matrixTransform(el.getScreenCTM()!.inverse())\n }\n\n render() {\n const e = this.body?.shape.extrusion\n const w = this.now\n if (!e || !w || (e.section.kind !== 'rectangle' && e.section.kind !== 'ellipse')) return nothing\n return html`<div pane>${this.top(e, w)}${this.typing?.pane === 'top' ? this.renderTyping() : nothing}</div>\n <div pane>${this.side(e, w)}${this.typing?.pane === 'side' ? this.renderTyping() : nothing}</div>\n ${this.refusal ? html`<small refusal role=\"alert\">${this.refusal}</small>` : nothing}`\n }\n\n /** Press a number, type it, Enter: the same one set-cavity a drag sends; Esc or leaving puts it back. */\n private type(ev: PointerEvent, what: { kind: 'wall'; side: string } | { kind: 'end'; end: End }, pane: 'top' | 'side', value: number) {\n if (this.locked) return\n ev.stopPropagation()\n const svgEl = (ev.target as Element).closest('svg')!\n const box = svgEl.getBoundingClientRect()\n this.refusal = ''\n this.typing = { ...what, pane, value, x: ((ev.clientX - box.left) / box.width) * 100, y: ((ev.clientY - box.top) / box.height) * 100 }\n }\n\n private renderTyping() {\n const t = this.typing!\n return html`<input type=\"number\" step=\"1\" min=\"1\" .value=${String(t.value)} style=${`left:${t.x}%;top:${t.y}%`}\n aria-label=${t.kind === 'wall' ? i18next.t('figure.label.section-wall') : i18next.t('figure.label.face-' + END_FACE(this.body!.shape.extrusion!.axis, t.end))}\n @keydown=${(ev: KeyboardEvent) => {\n ev.stopPropagation()\n if (ev.key === 'Escape') this.typing = undefined\n if (ev.key !== 'Enter') return\n const value = Number((ev.target as HTMLInputElement).value)\n this.typing = undefined\n if (!(Number.isFinite(value) && value > 0)) return\n const now = this.now!\n const next = t.kind === 'wall' ? { ...now, wall: wallDragged(now.wall, t.side, value, this.perSide) } : { ...now, [t.end]: { closed: Math.round(value) } }\n this.refusal = this.judge(next, t.kind === 'wall' ? t.side : undefined)\n if (!this.refusal) this.emit('command', this.action(next))\n }}\n @blur=${() => (this.typing = undefined)}\n ${focusOnRender()} />`\n }\n\n /** Seen along the push: the section, its inside and a handle on each wall. */\n private top(e: NonNullable<FigureEvaluatedShape['extrusion']>, w: NonNullable<ReturnType<typeof cavityWorkingOf>>) {\n const [h, v] = SCREEN[e.axis]\n const s = e.section\n const across = (a: Axis) => (s.kind === 'rectangle' ? s.size[a]! : 2 * (s as { radius: Record<string, number> }).radius[a]!)\n const W = 300,\n H = 170,\n pad = 26\n /* Wider room left and right: a wall's number stands outside the section there. */\n const k = Math.min((W - 2 * (pad + 10)) / across(h), (H - 2 * pad) / across(v))\n const ox = W / 2,\n oy = H / 2\n const inside = figureCavitySectionOf(s as FigureSection, e.axis, w.wall)\n const bad = !!this.refusal || !('section' in inside)\n const shape = (sec: FigureSection, c: Partial<Record<Axis, number>>, attrs: string) => {\n const cx = ox + (c[h] ?? 0) * k,\n cy = oy + (c[v] ?? 0) * k\n if (sec.kind === 'ellipse') return svg`<ellipse cx=${cx} cy=${cy} rx=${sec.radius[h]! * k} ry=${sec.radius[v]! * k} style=${attrs} />`\n const r = sec as { size: Record<string, number>; corner?: Record<string, number> }\n return svg`<rect x=${cx - (r.size[h]! * k) / 2} y=${cy - (r.size[v]! * k) / 2} width=${r.size[h]! * k} height=${r.size[v]! * k}\n rx=${(r.corner?.[h] ?? 0) * k} ry=${(r.corner?.[v] ?? 0) * k} style=${attrs} />`\n }\n const half = { [h]: (across(h) * k) / 2, [v]: (across(v) * k) / 2 } as Record<Axis, number>\n /* Each wall's handle sits on the inside's edge, half way along it; the value is the wall's own. */\n const handles = [`${h}-`, `${h}+`, `${v}-`, `${v}+`].map(side => {\n const a = side[0] as Axis,\n low = side[1] === '-'\n const sign = low ? -1 : 1\n const edge = sign * (half[a] - w.wall[side]! * k)\n /* The two handles across a narrow inside would stand on each other: then each steps aside, the low one first. */\n const room = 2 * half[a] - (w.wall[`${a}-`]! + w.wall[`${a}+`]!) * k\n const aside = room < 16 ? sign * 9 : 0\n const x = a === h ? ox + edge : ox + aside,\n y = a === v ? oy + edge : oy + aside\n /*\n The number stands just past the section's outer edge on its own side, so the opposite wall's never meets it\n however thin the walls or shallow the section (2026-10-02: at 70 mm deep the two walls' numbers lay on each other).\n */\n const tx = a === h ? ox + sign * (half[a] + 5) : ox,\n ty = a === v ? oy + sign * (half[a] + (low ? 5 : 13)) : oy + 4\n return svg`<g wall=${side} style=${`cursor:${a === h ? 'ew-resize' : 'ns-resize'}`}\n @pointerdown=${(ev: PointerEvent) => this.grab(ev, { kind: 'wall', side })}>\n <rect x=${x - 6} y=${y - 6} width=\"12\" height=\"12\" rx=\"2\" style=\"fill:var(--md-sys-color-surface);stroke:var(--md-sys-color-primary);stroke-width:1.5\" />\n <text typed x=${tx} y=${ty} font-size=\"11\" text-anchor=${a === h ? (low ? 'end' : 'start') : 'middle'} style=\"fill:var(--md-sys-color-on-surface)\"\n @pointerdown=${(ev: PointerEvent) => this.type(ev, { kind: 'wall', side }, 'top', w.wall[side]!)}>${mm(w.wall[side]!)}</text>\n <title>${i18next.t('figure.label.face-' + SIDE_FACE[side])} ${i18next.t('figure.label.section-wall')}</title>\n </g>`\n })\n return svg`<svg viewBox=${`0 0 ${W} ${H}`} role=\"img\" aria-label=${i18next.t('figure.label.section-cavity-top')}\n @pointermove=${(ev: PointerEvent) => this.drag(ev, e, k, ox, oy, half)}\n @pointerup=${() => this.release()} @pointercancel=${() => this.release()}>\n ${shape(s as FigureSection, {}, 'fill:var(--md-sys-color-primary-container);stroke:var(--md-sys-color-primary);stroke-width:1.5')}\n ${'section' in inside\n ? shape(inside.section, inside.centre, `fill:var(--md-sys-color-surface);stroke:${bad ? 'var(--md-sys-color-error)' : 'var(--md-sys-color-primary)'};stroke-width:1.2;stroke-dasharray:4 3`)\n : nothing}\n ${this.locked ? nothing : handles}\n </svg>`\n }\n\n /** Cut along the push: the walls across the first plane axis, and the two ends -- pressed to open or close. */\n private side(e: NonNullable<FigureEvaluatedShape['extrusion']>, w: NonNullable<ReturnType<typeof cavityWorkingOf>>) {\n const [h] = SCREEN[e.axis]\n const s = e.section\n const width = s.kind === 'rectangle' ? s.size[h]! : 2 * (s as { radius: Record<string, number> }).radius[h]!\n const length = e.end - e.start\n const W = 300,\n H = 170,\n padX = 40,\n padY = 26\n const k = Math.min((W - 2 * padX) / width, (H - 2 * padY) / length)\n const x0 = W / 2 - (width * k) / 2,\n x1 = W / 2 + (width * k) / 2,\n yTop = H / 2 - (length * k) / 2,\n yBot = H / 2 + (length * k) / 2\n const wl = w.wall[`${h}-`]! * k,\n wr = w.wall[`${h}+`]! * k\n const thick = (end: End) => (w[end] === 'open' ? 0 : (w[end] as { closed: number }).closed * k)\n /* The push's start is drawn at the bottom: a tote stands on its floor. */\n const floor = thick('start'),\n lid = thick('end')\n const fill = 'fill:var(--md-sys-color-primary-container);stroke:var(--md-sys-color-primary);stroke-width:1.2'\n const endZone = (end: End, y: number, t: number) => {\n const open = w[end] === 'open'\n const words = open\n ? i18next.t('figure.label.section-end-open')\n : `${i18next.t('figure.label.section-end-closed')} ${mm((w[end] as { closed: number }).closed)}`\n const label = `${i18next.t('figure.label.face-' + END_FACE(e.axis, end))}: ${words}`\n const inner = end === 'start' ? y - t : y + t\n return svg`<g end=${end} style=${`cursor:${open ? 'pointer' : 'ns-resize'}`}\n @pointerdown=${(ev: PointerEvent) => this.grab(ev, { kind: 'end', end })}>\n <rect x=${x0 + wl} y=${Math.min(y, inner) - 8} width=${x1 - x0 - wl - wr} height=${Math.abs(t) + 16} style=\"fill:transparent\" />\n ${open ? svg`<line x1=${x0 + wl} y1=${y} x2=${x1 - wr} y2=${y} style=\"stroke:var(--md-sys-color-outline);stroke-dasharray:3 3\" />` : nothing}\n <text ?typed=${!open} x=${W / 2} y=${end === 'start' ? yBot + 16 : yTop - 8} font-size=\"11\" text-anchor=\"middle\" style=\"fill:var(--md-sys-color-primary)\"\n @pointerdown=${(ev: PointerEvent) => !open && this.type(ev, { kind: 'end', end }, 'side', (w[end] as { closed: number }).closed)}>${label}</text>\n <title>${label}</title>\n </g>`\n }\n return svg`<svg viewBox=${`0 0 ${W} ${H + 8}`} role=\"img\" aria-label=${i18next.t('figure.label.section-cavity-side')}\n @pointermove=${(ev: PointerEvent) => this.dragEnd(ev, k, yTop, yBot)}\n @pointerup=${(ev: PointerEvent) => this.releaseEnd(ev)} @pointercancel=${() => this.release()}>\n <rect x=${x0} y=${yTop} width=${wl} height=${yBot - yTop} style=${fill} />\n <rect x=${x1 - wr} y=${yTop} width=${wr} height=${yBot - yTop} style=${fill} />\n ${floor ? svg`<rect x=${x0 + wl} y=${yBot - floor} width=${x1 - x0 - wl - wr} height=${floor} style=${fill} />` : nothing}\n ${lid ? svg`<rect x=${x0 + wl} y=${yTop} width=${x1 - x0 - wl - wr} height=${lid} style=${fill} />` : nothing}\n ${this.locked ? nothing : [endZone('start', yBot, floor), endZone('end', yTop, lid)]}\n </svg>`\n }\n\n private grab(ev: PointerEvent, what: NonNullable<FigureCavityDrawing['dragging']>) {\n if (this.locked) return\n ev.stopPropagation()\n ;(ev.currentTarget as Element).closest('svg')!.setPointerCapture(ev.pointerId)\n this.dragging = what\n this.pressedAt = ev.clientY\n this.refusal = ''\n }\n\n private drag(ev: PointerEvent, e: NonNullable<FigureEvaluatedShape['extrusion']>, k: number, ox: number, oy: number, half: Record<Axis, number>) {\n const d = this.dragging\n if (d?.kind !== 'wall') return\n const [h] = SCREEN[e.axis]\n const p = this.point(ev, ev.currentTarget as SVGSVGElement)\n const a = d.side[0] as Axis,\n low = d.side[1] === '-'\n const at = a === h ? p.x - ox : p.y - oy\n const value = (half[a] - (low ? -at : at)) / k\n this.hold({ ...this.now!, wall: wallDragged(this.now!.wall, d.side, value, this.perSide) }, d.side)\n }\n\n private dragEnd(ev: PointerEvent, k: number, yTop: number, yBot: number) {\n const d = this.dragging\n if (d?.kind !== 'end' || this.now![d.end] === 'open') return\n if (Math.abs(ev.clientY - this.pressedAt) < 3 && !this.working) return\n const p = this.point(ev, ev.currentTarget as SVGSVGElement)\n const t = d.end === 'start' ? (yBot - p.y) / k : (p.y - yTop) / k\n this.hold({ ...this.now!, [d.end]: { closed: Math.max(1, Math.round(t)) } })\n }\n\n /** A press on an end that did not move is a toggle; a drag was a thickness. */\n private releaseEnd(ev: PointerEvent) {\n const d = this.dragging\n if (d?.kind === 'end' && !this.working && Math.abs(ev.clientY - this.pressedAt) < 3) {\n this.dragging = null\n const next = { ...this.now!, [d.end]: endToggled(this.body!.shape, this.now![d.end]) }\n this.refusal = this.judge(next)\n if (!this.refusal) this.emit('command', this.action(next))\n return\n }\n this.release()\n }\n}\n\n"]}
1
+ {"version":3,"file":"figure-cavity-drawing.js","sourceRoot":"","sources":["../../client/modeller/figure-cavity-drawing.ts"],"names":[],"mappings":"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","sourcesContent":["import { css, html, LitElement, nothing, svg } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { i18next, localize } from '@operato/i18n'\nimport { figureCavitySectionOf } from '@hatiolab/figure-model'\nimport type { FigureAuthoringAction, FigureCavityRequest, FigureEvaluatedShape, FigureSection } from '@hatiolab/figure-model'\nimport { focusOnRender } from './focus-on-render.js'\nimport { cavityRefusalWordsOf, cavityWorkingOf, END_FACE, endToggled, mm, SIDE_FACE, wallDragged } from './section-controls.js'\n\ntype Axis = 'x' | 'y' | 'z'\n\ntype End = 'start' | 'end'\ntype Body = { id: string; shape: FigureEvaluatedShape }\n\n/** How the section is laid on the screen, by the axis it is pushed along: across to the right, then down. */\nconst SCREEN: Record<Axis, [Axis, Axis]> = { y: ['x', 'z'], x: ['z', 'y'], z: ['x', 'y'] }\n\n/**\n * 속 공간 그림 — the inside of a pushed part drawn, and edited by drawing (user 2026-10-01: 「이해와 편집이 직관적이지 않다」).\n *\n * Seen along the push, the section and its inside: a handle in the middle of each wall is dragged to its thickness,\n * every wall together unless 면마다 벽 is on. Cut along the push, the walls and the two ends: an end pressed opens or\n * closes it, a closed end's inner line is dragged to its thickness. While dragging, the figure behind shows what the\n * inside makes (`command-live`); letting go sends one `set-cavity`. What the kernel would refuse is drawn in the error\n * colour and said, by the kernel's own check, and is not sent.\n */\n@customElement('figure-cavity-drawing')\nexport class FigureCavityDrawing extends localize(i18next)(LitElement) {\n static styles = css`\n :host {\n display: grid;\n gap: 6px;\n }\n svg {\n width: 100%;\n display: block;\n touch-action: none;\n user-select: none;\n }\n svg text {\n font: inherit;\n }\n small[refusal] {\n color: var(--md-sys-color-error);\n }\n div[pane] {\n position: relative;\n }\n div[pane] input {\n position: absolute;\n width: 64px;\n transform: translate(-50%, -50%);\n font: inherit;\n }\n text[typed] {\n cursor: text;\n text-decoration: underline dotted;\n }\n `\n\n @property({ attribute: false }) body?: Body\n @property({ type: Boolean }) locked = false\n /** Walls one per side: a handle moves its own wall only. */\n @property({ type: Boolean }) perSide = false\n\n /** What is being dragged, and the inside it makes; undefined when nothing is. */\n @state() private working?: ReturnType<typeof cavityWorkingOf>\n @state() private refusal = ''\n private dragging: { kind: 'wall'; side: string } | { kind: 'end'; end: End } | null = null\n /** A number pressed to be typed: which, and where on its picture (percent of the picture's box). */\n @state() private typing?: ({ kind: 'wall'; side: string } | { kind: 'end'; end: End }) & { x: number; y: number; pane: 'top' | 'side'; value: number }\n private pressedAt = 0\n\n private get now() {\n return this.working ?? (this.body ? cavityWorkingOf(this.body.shape) : undefined)\n }\n\n private request(w: NonNullable<ReturnType<typeof cavityWorkingOf>>): FigureCavityRequest {\n return { wall: { ...w.wall }, start: w.start, end: w.end }\n }\n\n private action(w: NonNullable<ReturnType<typeof cavityWorkingOf>>): FigureAuthoringAction {\n return { kind: 'set-cavity', part: this.body!.id, cavity: this.request(w) }\n }\n\n /** What the kernel would refuse, in words; for one side's wall, the most that side can be with the opposite kept. */\n private judge(w: NonNullable<ReturnType<typeof cavityWorkingOf>>, side?: string): string {\n const words = cavityRefusalWordsOf(this.body!.shape, w, this.perSide, side)\n return words ? i18next.t(words.key, words.params) : ''\n }\n\n /** The working inside while dragging: drawn, judged, and previewed behind when the kernel would take it. */\n private hold(w: NonNullable<ReturnType<typeof cavityWorkingOf>>, side?: string) {\n this.working = w\n this.refusal = this.judge(w, side)\n this.emit('command-live', this.refusal ? null : this.action(w))\n }\n\n private release() {\n const w = this.working\n this.dragging = null\n this.working = undefined\n if (!w) return\n /* Refused: nothing is sent, and the reason stays said until the next drag -- letting go must not look like taking it. */\n if (this.refusal) {\n this.emit('command-live', null)\n return\n }\n this.emit('command', this.action(w))\n }\n\n private emit(name: 'command' | 'command-live', action: FigureAuthoringAction | null) {\n this.dispatchEvent(new CustomEvent(name, { detail: { action }, bubbles: true, composed: true }))\n }\n\n private point(ev: PointerEvent, el: SVGSVGElement) {\n const pt = el.createSVGPoint()\n pt.x = ev.clientX\n pt.y = ev.clientY\n return pt.matrixTransform(el.getScreenCTM()!.inverse())\n }\n\n render() {\n const e = this.body?.shape.extrusion\n const w = this.now\n if (!e || !w || (e.section.kind !== 'rectangle' && e.section.kind !== 'ellipse')) return nothing\n return html`<div pane>${this.top(e, w)}${this.typing?.pane === 'top' ? this.renderTyping() : nothing}</div>\n <div pane>${this.side(e, w)}${this.typing?.pane === 'side' ? this.renderTyping() : nothing}</div>\n ${this.refusal ? html`<small refusal role=\"alert\">${this.refusal}</small>` : nothing}`\n }\n\n /** Press a number, type it, Enter: the same one set-cavity a drag sends; Esc or leaving puts it back. */\n private type(ev: PointerEvent, what: { kind: 'wall'; side: string } | { kind: 'end'; end: End }, pane: 'top' | 'side', value: number) {\n if (this.locked) return\n ev.stopPropagation()\n const svgEl = (ev.target as Element).closest('svg')!\n const box = svgEl.getBoundingClientRect()\n this.refusal = ''\n this.typing = { ...what, pane, value, x: ((ev.clientX - box.left) / box.width) * 100, y: ((ev.clientY - box.top) / box.height) * 100 }\n }\n\n private renderTyping() {\n const t = this.typing!\n return html`<input type=\"number\" step=\"1\" min=\"1\" .value=${String(t.value)} style=${`left:${t.x}%;top:${t.y}%`}\n aria-label=${t.kind === 'wall' ? i18next.t('figure.label.section-wall') : i18next.t('figure.label.face-' + END_FACE(this.body!.shape.extrusion!.axis, t.end))}\n @keydown=${(ev: KeyboardEvent) => {\n ev.stopPropagation()\n if (ev.key === 'Escape') this.typing = undefined\n if (ev.key !== 'Enter') return\n const value = Number((ev.target as HTMLInputElement).value)\n this.typing = undefined\n if (!(Number.isFinite(value) && value > 0)) return\n const now = this.now!\n const next = t.kind === 'wall' ? { ...now, wall: wallDragged(now.wall, t.side, value, this.perSide) } : { ...now, [t.end]: { closed: Math.round(value) } }\n this.refusal = this.judge(next, t.kind === 'wall' ? t.side : undefined)\n if (!this.refusal) this.emit('command', this.action(next))\n }}\n @blur=${() => (this.typing = undefined)}\n ${focusOnRender()} />`\n }\n\n /** Seen along the push: the section, its inside and a handle on each wall. */\n private top(e: NonNullable<FigureEvaluatedShape['extrusion']>, w: NonNullable<ReturnType<typeof cavityWorkingOf>>) {\n const [h, v] = SCREEN[e.axis]\n const s = e.section\n const across = (a: Axis) => (s.kind === 'rectangle' ? s.size[a]! : 2 * (s as { radius: Record<string, number> }).radius[a]!)\n const W = 300,\n H = 170,\n pad = 26\n /* Wider room left and right: a wall's number stands outside the section there. */\n const k = Math.min((W - 2 * (pad + 10)) / across(h), (H - 2 * pad) / across(v))\n const ox = W / 2,\n oy = H / 2\n const inside = figureCavitySectionOf(s as FigureSection, e.axis, w.wall)\n const bad = !!this.refusal || !('section' in inside)\n const shape = (sec: FigureSection, c: Partial<Record<Axis, number>>, attrs: string) => {\n const cx = ox + (c[h] ?? 0) * k,\n cy = oy + (c[v] ?? 0) * k\n if (sec.kind === 'ellipse') return svg`<ellipse cx=${cx} cy=${cy} rx=${sec.radius[h]! * k} ry=${sec.radius[v]! * k} style=${attrs} />`\n const r = sec as { size: Record<string, number>; corner?: Record<string, number> }\n return svg`<rect x=${cx - (r.size[h]! * k) / 2} y=${cy - (r.size[v]! * k) / 2} width=${r.size[h]! * k} height=${r.size[v]! * k}\n rx=${(r.corner?.[h] ?? 0) * k} ry=${(r.corner?.[v] ?? 0) * k} style=${attrs} />`\n }\n const half = { [h]: (across(h) * k) / 2, [v]: (across(v) * k) / 2 } as Record<Axis, number>\n /* Each wall's handle sits on the inside's edge, half way along it; the value is the wall's own. */\n const handles = [`${h}-`, `${h}+`, `${v}-`, `${v}+`].map(side => {\n const a = side[0] as Axis,\n low = side[1] === '-'\n const sign = low ? -1 : 1\n const edge = sign * (half[a] - w.wall[side]! * k)\n /* The two handles across a narrow inside would stand on each other: then each steps aside, the low one first. */\n const room = 2 * half[a] - (w.wall[`${a}-`]! + w.wall[`${a}+`]!) * k\n const aside = room < 16 ? sign * 9 : 0\n const x = a === h ? ox + edge : ox + aside,\n y = a === v ? oy + edge : oy + aside\n /*\n The number stands just past the section's outer edge on its own side, so the opposite wall's never meets it\n however thin the walls or shallow the section (2026-10-02: at 70 mm deep the two walls' numbers lay on each other).\n */\n const tx = a === h ? ox + sign * (half[a] + 5) : ox,\n ty = a === v ? oy + sign * (half[a] + (low ? 5 : 13)) : oy + 4\n return svg`<g wall=${side} style=${`cursor:${a === h ? 'ew-resize' : 'ns-resize'}`}\n @pointerdown=${(ev: PointerEvent) => this.grab(ev, { kind: 'wall', side })}>\n <rect x=${x - 6} y=${y - 6} width=\"12\" height=\"12\" rx=\"2\" style=\"fill:var(--md-sys-color-surface);stroke:var(--md-sys-color-primary);stroke-width:1.5\" />\n <text typed x=${tx} y=${ty} font-size=\"11\" text-anchor=${a === h ? (low ? 'end' : 'start') : 'middle'} style=\"fill:var(--md-sys-color-on-surface)\"\n @pointerdown=${(ev: PointerEvent) => this.type(ev, { kind: 'wall', side }, 'top', w.wall[side]!)}>${mm(w.wall[side]!)}</text>\n <title>${i18next.t('figure.label.face-' + SIDE_FACE[side])} ${i18next.t('figure.label.section-wall')}</title>\n </g>`\n })\n return svg`<svg viewBox=${`0 0 ${W} ${H}`} role=\"img\" aria-label=${i18next.t('figure.label.section-cavity-top')}\n @pointermove=${(ev: PointerEvent) => this.drag(ev, e, k, ox, oy, half)}\n @pointerup=${() => this.release()} @pointercancel=${() => this.release()}>\n ${shape(s as FigureSection, {}, 'fill:var(--md-sys-color-primary-container);stroke:var(--md-sys-color-primary);stroke-width:1.5')}\n ${'section' in inside\n ? shape(inside.section, inside.centre, `fill:var(--md-sys-color-surface);stroke:${bad ? 'var(--md-sys-color-error)' : 'var(--md-sys-color-primary)'};stroke-width:1.2;stroke-dasharray:4 3`)\n : nothing}\n ${this.locked ? nothing : handles}\n </svg>`\n }\n\n /** Cut along the push: the walls across the first plane axis, and the two ends -- pressed to open or close. */\n private side(e: NonNullable<FigureEvaluatedShape['extrusion']>, w: NonNullable<ReturnType<typeof cavityWorkingOf>>) {\n const [h] = SCREEN[e.axis]\n const s = e.section\n const width = s.kind === 'rectangle' ? s.size[h]! : 2 * (s as { radius: Record<string, number> }).radius[h]!\n const length = e.end - e.start\n const W = 300,\n H = 170,\n padX = 40,\n padY = 26\n const k = Math.min((W - 2 * padX) / width, (H - 2 * padY) / length)\n const x0 = W / 2 - (width * k) / 2,\n x1 = W / 2 + (width * k) / 2,\n yTop = H / 2 - (length * k) / 2,\n yBot = H / 2 + (length * k) / 2\n const wl = w.wall[`${h}-`]! * k,\n wr = w.wall[`${h}+`]! * k\n const thick = (end: End) => (w[end] === 'open' ? 0 : (w[end] as { closed: number }).closed * k)\n /* The push's start is drawn at the bottom: a tote stands on its floor. */\n const floor = thick('start'),\n lid = thick('end')\n const fill = 'fill:var(--md-sys-color-primary-container);stroke:var(--md-sys-color-primary);stroke-width:1.2'\n const endZone = (end: End, y: number, t: number) => {\n const open = w[end] === 'open'\n const words = open\n ? i18next.t('figure.label.section-end-open')\n : `${i18next.t('figure.label.section-end-closed')} ${mm((w[end] as { closed: number }).closed)}`\n const label = `${i18next.t('figure.label.face-' + END_FACE(e.axis, end))}: ${words}`\n const inner = end === 'start' ? y - t : y + t\n return svg`<g end=${end} style=${`cursor:${open ? 'pointer' : 'ns-resize'}`}\n @pointerdown=${(ev: PointerEvent) => this.grab(ev, { kind: 'end', end })}>\n <rect x=${x0 + wl} y=${Math.min(y, inner) - 8} width=${x1 - x0 - wl - wr} height=${Math.abs(t) + 16} style=\"fill:transparent\" />\n ${open ? svg`<line x1=${x0 + wl} y1=${y} x2=${x1 - wr} y2=${y} style=\"stroke:var(--md-sys-color-outline);stroke-dasharray:3 3\" />` : nothing}\n <text ?typed=${!open} x=${W / 2} y=${end === 'start' ? yBot + 16 : yTop - 8} font-size=\"11\" text-anchor=\"middle\" style=\"fill:var(--md-sys-color-primary)\"\n @pointerdown=${(ev: PointerEvent) => !open && this.type(ev, { kind: 'end', end }, 'side', (w[end] as { closed: number }).closed)}>${label}</text>\n <title>${label}</title>\n </g>`\n }\n return svg`<svg viewBox=${`0 0 ${W} ${H + 8}`} role=\"img\" aria-label=${i18next.t('figure.label.section-cavity-side')}\n @pointermove=${(ev: PointerEvent) => this.dragEnd(ev, k, yTop, yBot)}\n @pointerup=${(ev: PointerEvent) => this.releaseEnd(ev)} @pointercancel=${() => this.release()}>\n <rect x=${x0} y=${yTop} width=${wl} height=${yBot - yTop} style=${fill} />\n <rect x=${x1 - wr} y=${yTop} width=${wr} height=${yBot - yTop} style=${fill} />\n ${floor ? svg`<rect x=${x0 + wl} y=${yBot - floor} width=${x1 - x0 - wl - wr} height=${floor} style=${fill} />` : nothing}\n ${lid ? svg`<rect x=${x0 + wl} y=${yTop} width=${x1 - x0 - wl - wr} height=${lid} style=${fill} />` : nothing}\n ${this.locked ? nothing : [endZone('start', yBot, floor), endZone('end', yTop, lid)]}\n </svg>`\n }\n\n private grab(ev: PointerEvent, what: NonNullable<FigureCavityDrawing['dragging']>) {\n if (this.locked) return\n ev.stopPropagation()\n ;(ev.currentTarget as Element).closest('svg')!.setPointerCapture(ev.pointerId)\n this.dragging = what\n this.pressedAt = ev.clientY\n this.refusal = ''\n }\n\n private drag(ev: PointerEvent, e: NonNullable<FigureEvaluatedShape['extrusion']>, k: number, ox: number, oy: number, half: Record<Axis, number>) {\n const d = this.dragging\n if (d?.kind !== 'wall') return\n const [h] = SCREEN[e.axis]\n const p = this.point(ev, ev.currentTarget as SVGSVGElement)\n const a = d.side[0] as Axis,\n low = d.side[1] === '-'\n const at = a === h ? p.x - ox : p.y - oy\n const value = (half[a] - (low ? -at : at)) / k\n this.hold({ ...this.now!, wall: wallDragged(this.now!.wall, d.side, value, this.perSide) }, d.side)\n }\n\n private dragEnd(ev: PointerEvent, k: number, yTop: number, yBot: number) {\n const d = this.dragging\n if (d?.kind !== 'end' || this.now![d.end] === 'open') return\n if (Math.abs(ev.clientY - this.pressedAt) < 3 && !this.working) return\n const p = this.point(ev, ev.currentTarget as SVGSVGElement)\n const t = d.end === 'start' ? (yBot - p.y) / k : (p.y - yTop) / k\n this.hold({ ...this.now!, [d.end]: { closed: Math.max(1, Math.round(t)) } })\n }\n\n /** A press on an end that did not move is a toggle; a drag was a thickness. */\n private releaseEnd(ev: PointerEvent) {\n const d = this.dragging\n if (d?.kind === 'end' && !this.working && Math.abs(ev.clientY - this.pressedAt) < 3) {\n this.dragging = null\n const next = { ...this.now!, [d.end]: endToggled(this.body!.shape, this.now![d.end]) }\n this.refusal = this.judge(next)\n if (!this.refusal) this.emit('command', this.action(next))\n return\n }\n this.release()\n }\n}\n\n"]}
@@ -25,6 +25,8 @@ export declare class FigureClips extends FigureClips_base {
25
25
  locked: boolean;
26
26
  /** Where each clip is scrubbed to, in seconds. */
27
27
  private at;
28
+ /** The clip the pose bar keys: the one last scrubbed. */
29
+ private active;
28
30
  private adding;
29
31
  private grouping;
30
32
  /** The track whose copy is being set up: onto which control, how many seconds later. */
@@ -34,6 +36,11 @@ export declare class FigureClips extends FigureClips_base {
34
36
  protected willUpdate(changed: PropertyValues): void;
35
37
  render(): import("lit-html").TemplateResult<1> | typeof nothing;
36
38
  private renderClip;
39
+ /**
40
+ * The clip being keyed -- the one last scrubbed or chosen here -- with its moment and 「현재 자세 기록」, right under the
41
+ * controls: type the controls, then record, without scrolling to the clip.
42
+ */
43
+ private renderPoseBar;
37
44
  /** 「이 자세 기억하기」: every control moved since the clip's pose was last shown or kept, as keys at this moment, one step. */
38
45
  private renderRemember;
39
46
  private renderTrack;
@@ -49,6 +56,8 @@ export declare class FigureClips extends FigureClips_base {
49
56
  */
50
57
  private renderGroups;
51
58
  private renderGroup;
59
+ /** A clip renamed: the pose bar, its moment and its pose stay with it under the new name. */
60
+ private rename;
52
61
  /** Show the clip's pose at a moment: one batch of input changes, not saved as the default. */
53
62
  /** Show the clip's pose at a moment. While the bar is dragged the pose is live (drawn, not recorded); the release
54
63
  * applies it as one batch of input changes. */