@things-factory/figure-ui 10.1.154 → 10.1.155

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 (110) hide show
  1. package/client/modeller/canvas.ts +1 -1
  2. package/client/modeller/editor.ts +2 -2
  3. package/client/modeller/figure-capability-panel.ts +6 -24
  4. package/client/modeller/figure-carrier.ts +1 -1
  5. package/client/modeller/figure-clips.ts +1 -1
  6. package/client/modeller/figure-controls.ts +2 -2
  7. package/client/modeller/figure-face-mapping.ts +1 -1
  8. package/client/modeller/figure-links.ts +3 -2
  9. package/client/modeller/figure-material-panel.ts +1 -1
  10. package/client/modeller/figure-preview.ts +2 -2
  11. package/client/modeller/figure-properties.ts +1 -1
  12. package/client/modeller/figure-section-editor.ts +1 -1
  13. package/client/modeller/figure-section-panel.ts +1 -1
  14. package/client/modeller/figure-settings.ts +2 -2
  15. package/client/modeller/figure-verdict.ts +1 -1
  16. package/client/pages/figure-list-page.ts +7 -1
  17. package/client/viewparts/figure-detail-dock.ts +90 -41
  18. package/client/viewparts/figure-thumb.ts +2 -22
  19. package/dist-client/modeller/canvas.d.ts +1 -1
  20. package/dist-client/modeller/canvas.js +1 -1
  21. package/dist-client/modeller/canvas.js.map +1 -1
  22. package/dist-client/modeller/editor.js +2 -2
  23. package/dist-client/modeller/editor.js.map +1 -1
  24. package/dist-client/modeller/figure-capability-panel.d.ts +0 -3
  25. package/dist-client/modeller/figure-capability-panel.js +5 -18
  26. package/dist-client/modeller/figure-capability-panel.js.map +1 -1
  27. package/dist-client/modeller/figure-carrier.js +1 -1
  28. package/dist-client/modeller/figure-carrier.js.map +1 -1
  29. package/dist-client/modeller/figure-clips.js +1 -1
  30. package/dist-client/modeller/figure-clips.js.map +1 -1
  31. package/dist-client/modeller/figure-controls.js +2 -2
  32. package/dist-client/modeller/figure-controls.js.map +1 -1
  33. package/dist-client/modeller/figure-face-mapping.js +1 -1
  34. package/dist-client/modeller/figure-face-mapping.js.map +1 -1
  35. package/dist-client/modeller/figure-links.js +3 -2
  36. package/dist-client/modeller/figure-links.js.map +1 -1
  37. package/dist-client/modeller/figure-material-panel.js +1 -1
  38. package/dist-client/modeller/figure-material-panel.js.map +1 -1
  39. package/dist-client/modeller/figure-preview.d.ts +1 -1
  40. package/dist-client/modeller/figure-preview.js +2 -2
  41. package/dist-client/modeller/figure-preview.js.map +1 -1
  42. package/dist-client/modeller/figure-properties.js +1 -1
  43. package/dist-client/modeller/figure-properties.js.map +1 -1
  44. package/dist-client/modeller/figure-section-editor.js +1 -1
  45. package/dist-client/modeller/figure-section-editor.js.map +1 -1
  46. package/dist-client/modeller/figure-section-panel.js +1 -1
  47. package/dist-client/modeller/figure-section-panel.js.map +1 -1
  48. package/dist-client/modeller/figure-settings.d.ts +1 -1
  49. package/dist-client/modeller/figure-settings.js +1 -1
  50. package/dist-client/modeller/figure-settings.js.map +1 -1
  51. package/dist-client/modeller/figure-verdict.js +1 -1
  52. package/dist-client/modeller/figure-verdict.js.map +1 -1
  53. package/dist-client/pages/figure-list-page.d.ts +1 -0
  54. package/dist-client/pages/figure-list-page.js +11 -1
  55. package/dist-client/pages/figure-list-page.js.map +1 -1
  56. package/dist-client/tsconfig.tsbuildinfo +1 -1
  57. package/dist-client/viewparts/figure-detail-dock.d.ts +10 -1
  58. package/dist-client/viewparts/figure-detail-dock.js +93 -41
  59. package/dist-client/viewparts/figure-detail-dock.js.map +1 -1
  60. package/dist-client/viewparts/figure-thumb.d.ts +1 -0
  61. package/dist-client/viewparts/figure-thumb.js +2 -22
  62. package/dist-client/viewparts/figure-thumb.js.map +1 -1
  63. package/package.json +5 -4
  64. package/test/browser/detail-page.js +10 -2
  65. package/test/browser/product-page.check.mjs +1 -1
  66. package/test/browser/screen-page.js +1 -1
  67. package/test/browser/serve-detail.mjs +7 -2
  68. package/test/figure-controls-keys.test.ts +19 -0
  69. package/test/i18n-prefix-guard.test.ts +4 -1
  70. package/test/layout.test.ts +4 -3
  71. package/test/links.test.ts +5 -4
  72. package/test/properties.test.ts +2 -1
  73. package/test/refusals.test.ts +2 -1
  74. package/test/theme.test.ts +1 -1
  75. package/test/verdict.test.ts +2 -1
  76. package/test/words.ts +20 -0
  77. package/translations/en.json +2 -33
  78. package/translations/es.json +2 -33
  79. package/translations/ja.json +2 -33
  80. package/translations/ko.json +2 -33
  81. package/translations/ms.json +2 -33
  82. package/translations/zh.json +2 -33
  83. package/client/modeller/controls.ts +0 -54
  84. package/client/modeller/figure-view.ts +0 -151
  85. package/client/modeller/preview-model.ts +0 -89
  86. package/client/modeller/side-panel-styles.ts +0 -374
  87. package/client/viewparts/detail-motion.ts +0 -11
  88. package/client/viewparts/figure-asset-viewer.ts +0 -177
  89. package/dist-client/modeller/controls.d.ts +0 -28
  90. package/dist-client/modeller/controls.js +0 -28
  91. package/dist-client/modeller/controls.js.map +0 -1
  92. package/dist-client/modeller/figure-view.d.ts +0 -117
  93. package/dist-client/modeller/figure-view.js +0 -78
  94. package/dist-client/modeller/figure-view.js.map +0 -1
  95. package/dist-client/modeller/preview-model.d.ts +0 -54
  96. package/dist-client/modeller/preview-model.js +0 -79
  97. package/dist-client/modeller/preview-model.js.map +0 -1
  98. package/dist-client/modeller/side-panel-styles.d.ts +0 -27
  99. package/dist-client/modeller/side-panel-styles.js +0 -374
  100. package/dist-client/modeller/side-panel-styles.js.map +0 -1
  101. package/dist-client/viewparts/detail-motion.d.ts +0 -6
  102. package/dist-client/viewparts/detail-motion.js +0 -9
  103. package/dist-client/viewparts/detail-motion.js.map +0 -1
  104. package/dist-client/viewparts/figure-asset-viewer.d.ts +0 -31
  105. package/dist-client/viewparts/figure-asset-viewer.js +0 -198
  106. package/dist-client/viewparts/figure-asset-viewer.js.map +0 -1
  107. package/test/controls.test.ts +0 -60
  108. package/test/detail-motion.test.ts +0 -26
  109. package/test/preview.test.ts +0 -53
  110. package/test/view.test.ts +0 -13
@@ -1,28 +0,0 @@
1
- export function controlsOf(asset, values = {}) {
2
- return asset.document.model.inputs
3
- .filter(input => input.role === 'state')
4
- .map(input => {
5
- const policy = asset.stateInputs?.[input.id];
6
- const start = asset.stateDefaults[input.id] ?? input.min;
7
- return {
8
- id: input.id,
9
- label: policy?.label ?? input.id,
10
- named: !!policy?.label,
11
- unit: input.unit,
12
- min: input.min,
13
- max: input.max,
14
- value: values[input.id] ?? start,
15
- start,
16
- sweep: policy?.sweep ?? 0,
17
- step: input.unit === 'deg' ? 1 : (input.max - input.min) / 100
18
- };
19
- });
20
- }
21
- /** Whether the pose being looked at differs from the default pose -- only then is there a pose to keep. */
22
- export const poseDiffers = (controls) => controls.some(c => c.value !== c.start);
23
- /** The current pose as the defaults: one `set-state-defaults` edit. */
24
- export const poseAsDefault = (controls) => ({
25
- kind: 'set-state-defaults',
26
- values: Object.fromEntries(controls.map(c => [c.id, c.value]))
27
- });
28
- //# sourceMappingURL=controls.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"controls.js","sourceRoot":"","sources":["../../client/modeller/controls.ts"],"names":[],"mappings":"AAyBA,MAAM,UAAU,UAAU,CAAC,KAAkB,EAAE,SAAiC,EAAE;IAChF,OAAO,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM;SAC/B,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC;SACvC,GAAG,CAAC,KAAK,CAAC,EAAE;QACX,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;QAC5C,MAAM,KAAK,GAAG,KAAK,CAAC,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,KAAK,CAAC,GAAG,CAAA;QACxD,OAAO;YACL,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,KAAK,CAAC,EAAE;YAChC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,KAAK;YACtB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,KAAK;YAChC,KAAK;YACL,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;YACzB,IAAI,EAAE,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,GAAG;SAC/D,CAAA;IACH,CAAC,CAAC,CAAA;AACN,CAAC;AAED,2GAA2G;AAC3G,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,QAA4B,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK,CAAC,CAAA;AAEpG,uEAAuE;AACvE,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,QAA4B,EAAE,EAAE,CAAC,CAAC;IAC9D,IAAI,EAAE,oBAA6B;IACnC,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;CAC/D,CAAC,CAAA","sourcesContent":["import type { FigureAsset } from '@hatiolab/figure-model'\n\n/*\n * The figure's controls -- its state inputs: the values a board or a connector sets to pose\n * the figure (a lift height, a joint angle, a gripper opening). Kept apart from the element so the reading is tested\n * without a browser.\n */\nexport interface Control {\n id: string\n /** The name a person reads, or the id when none is given. */\n label: string\n named: boolean\n unit: string\n min: number\n max: number\n /** Where it stands in the editor now -- the pose being looked at, not yet the default. */\n value: number\n /** Where it starts when the figure is placed: the default pose. */\n start: number\n /** Seconds to travel the whole range, 0 when it moves at once. */\n sweep: number\n /** A slider step: one degree for an angle, else a hundredth of the range. */\n step: number\n}\n\nexport function controlsOf(asset: FigureAsset, values: Record<string, number> = {}): Control[] {\n return asset.document.model.inputs\n .filter(input => input.role === 'state')\n .map(input => {\n const policy = asset.stateInputs?.[input.id]\n const start = asset.stateDefaults[input.id] ?? input.min\n return {\n id: input.id,\n label: policy?.label ?? input.id,\n named: !!policy?.label,\n unit: input.unit,\n min: input.min,\n max: input.max,\n value: values[input.id] ?? start,\n start,\n sweep: policy?.sweep ?? 0,\n step: input.unit === 'deg' ? 1 : (input.max - input.min) / 100\n }\n })\n}\n\n/** Whether the pose being looked at differs from the default pose -- only then is there a pose to keep. */\nexport const poseDiffers = (controls: readonly Control[]) => controls.some(c => c.value !== c.start)\n\n/** The current pose as the defaults: one `set-state-defaults` edit. */\nexport const poseAsDefault = (controls: readonly Control[]) => ({\n kind: 'set-state-defaults' as const,\n values: Object.fromEntries(controls.map(c => [c.id, c.value]))\n})\n"]}
@@ -1,117 +0,0 @@
1
- /**
2
- * 저작 화면의 **보기 설정**.
3
- *
4
- * ## 저장되지 않는다
5
- *
6
- * 이것은 자산이 아니라 **작업대**다. 조명을 밝게 하고 바닥을 켠 것은 그 사람이 지금
7
- * 보기 편한 상태일 뿐, 그 자산의 성질이 아니다. 그래서 자산에 안 들어가고, 보는 사람의
8
- * 브라우저에 남는다.
9
- *
10
- * 다른 사람이 같은 자산을 열면 자기 설정으로 본다. 그것이 맞다.
11
- *
12
- * ## 씬이 아는 이름을 그대로 쓴다
13
- *
14
- * 여기 이름은 전부 `model-layer` 의 상태 이름이다. 옮겨 적는 표를 두지 않는다 — 표를
15
- * 두면 씬이 새 설정을 받아도 이쪽이 모른다.
16
- *
17
- * 값이 바뀌면 씬이 스스로 반영한다(`three-capability` 의 `onchange`). 다만 `grid` 는
18
- * 한동안 3D 를 세울 때만 읽혔다 — things-scene 10.1.5 에서 고쳤다.
19
- */
20
- export interface ViewSettings {
21
- /**
22
- * 어떤 도면에 놓인 것으로 보나 — 씬 전체의 좌표 모드.
23
- *
24
- * **도형의 `placement` 와 다른 것이다.** 도형의 것은 「이 종류는 바닥에 서나, 천장에
25
- * 매달리나」이고, 이것은 「지금 보고 있는 도면이 어느 쪽을 기준으로 재나」다. 바닥
26
- * 기준 도면에 천정 기반 OHT 를 놓으면 도면은 안 뒤집히고 OHT 가 천장 높이에 매달린다.
27
- *
28
- * 한동안 도형의 `placement` 를 이 자리에 흘려 넣었다. 모델러에 도형이 하나뿐이라
29
- * 그럴듯해 보였지만, 그러면 도형의 성질이 씬 전체를 뒤집는다 — 도면에서는 성립할 수가
30
- * 없고(도면에는 도형이 여럿이다), 저작 중에는 배치를 고를 때마다 저작자가 적어 둔
31
- * 높이가 전부 다른 숫자로 보였다.
32
- *
33
- * 씬의 낱말 그대로다: `floor` 바닥 기준 · `space` 중심 기준(바닥 없음) · `inverted`
34
- * 천장 기준. **미리보기에만 먹인다** — 편집 캔버스의 `zPos` 는 저작자가 직접 적는
35
- * 숫자라 그 뜻이 보기 설정에 따라 바뀌면 안 된다.
36
- */
37
- placement: 'floor' | 'space' | 'inverted';
38
- /**
39
- * 천장 높이 (mm). 천정 기반 도형을 미리보기에서 어디에 매달 것인가.
40
- *
41
- * 도형은 제가 놓일 방의 높이를 모른다. 도면은 알지만 미리보기에는 도면이 없으므로,
42
- * 저작자가 가정할 값을 여기서 정한다.
43
- */
44
- ceilingHeight: number;
45
- /** 좌표 바탕(축 가이드). 원점과 눈금을 보인다. */
46
- grid: boolean;
47
- /** 축 이름표(X · Y · Z). 눈금만 두고 글자를 끌 수 있다. */
48
- gridLabels: boolean;
49
- /** 판의 바닥면. 좌표 바탕과 겹치므로 기본은 끈다. */
50
- floor: boolean;
51
- /** Environment — 반사(IBL). 금속 재질이 무엇을 비출지 정한다. */
52
- environment: EnvironmentName;
53
- /** Sky Color — 배경색. */
54
- skyColor: string;
55
- /** Key Light Intensity. */
56
- dirLightIntensity: number;
57
- /** Key Light — Follow Camera. 끄면 그림자 방향이 고정된다. */
58
- dirLightFollowCamera: boolean;
59
- /** Key Light — Cast Shadow. */
60
- dirShadowEnabled: boolean;
61
- /** Hemisphere Light Intensity — 그늘진 면을 들어올린다. */
62
- hemiIntensity: number;
63
- }
64
- /**
65
- * 환경 프리셋 — **`scene-manager` 의 `SkyPreset` 과 같은 여덟이다.**
66
- *
67
- * 한동안 다섯만 적었다. 씬은 여덟을 다 받는데 이쪽이 셋을 몰라서 고를 수 없었다.
68
- * operato-board 의 3D 씬 속성 패널도 같은 여덟을 보인다.
69
- */
70
- export declare const ENVIRONMENTS: readonly ["studio", "warehouse", "factory", "office", "home", "sunny", "cloudy", "rainy"];
71
- export type EnvironmentName = (typeof ENVIRONMENTS)[number];
72
- /**
73
- * 씬에 그대로 넣는 보기 설정 — **좌표 기준과 천장 높이는 빼고.**
74
- *
75
- * 나머지는 전부 `model-layer` 의 상태 이름이라 그대로 넣으면 씬이 알아서 반응한다.
76
- * 그런데 `placement` 는 편집 캔버스에 들어가면 안 되고(거기는 늘 상자 기준이다),
77
- * `ceilingHeight` 는 씬이 모르는 이름이다.
78
- *
79
- * **rest spread 로 넘기지 않으려고 이 함수가 있다.** 캔버스가 한동안
80
- * `const { grid, ..., ...light } = view` 로 나머지를 통째로 넘겼는데, 그러면 설정을
81
- * 하나 더할 때마다 그것이 두 화면에 **말없이** 실린다. 새로 더한 좌표 기준이 바로
82
- * 그 길로 캔버스에 들어갈 뻔했다.
83
- */
84
- export declare function sceneLook(view: ViewSettings): Record<string, unknown>;
85
- /**
86
- * 씬의 좌표 기준 — **씬의 낱말 그대로 셋이다.**
87
- *
88
- * 형식의 `floor` · `center` · `ceiling` 과 짝이 맞지만 철자가 다르다. 옮겨 적는 표를 두지
89
- * 않는 것이 이 파일의 규칙이므로 씬 쪽을 쓴다. 화면에는 둘 다 보인다 — 「천장 기준
90
- * (inverted)」.
91
- */
92
- export declare const SCENE_REFERENCES: readonly ["floor", "space", "inverted"];
93
- /** 배경색 기본값. 회색이라 부품 색이 제 색으로 보인다. */
94
- export declare const WORKBENCH = "#7c7c7c";
95
- /**
96
- * 처음 값.
97
- *
98
- * **지금 저작 화면이 실제로 쓰던 값 그대로다.** 설정을 만들면서 화면이 달라지면
99
- * 무엇이 설정 때문이고 무엇이 원래 그랬는지 갈리지 않는다.
100
- */
101
- export declare const DEFAULT_VIEW: ViewSettings;
102
- /**
103
- * How tall the preview board is: enough room for the tallest instance where the figure actually stands.
104
- *
105
- * A floor or center figure stands on the floor, so the tallest instance is the whole height. Only a
106
- * ceiling figure needs the room up to the ceiling. The board used to reach the ceiling for every figure,
107
- * which made a 920 tall AGV preview 4400 tall.
108
- *
109
- * This is an envelope, not a placement rule: where each instance goes is still the scene's
110
- * (`FigureRealObject.effectiveZPos`), and the camera fits what the scene drew.
111
- */
112
- export declare function previewBoardDepth(figure: {
113
- placement?: 'floor' | 'ceiling' | 'center' | 'wall';
114
- base: {
115
- y: number;
116
- };
117
- }, ceilingHeight: number, factor: number): number;
@@ -1,78 +0,0 @@
1
- /**
2
- * 환경 프리셋 — **`scene-manager` 의 `SkyPreset` 과 같은 여덟이다.**
3
- *
4
- * 한동안 다섯만 적었다. 씬은 여덟을 다 받는데 이쪽이 셋을 몰라서 고를 수 없었다.
5
- * operato-board 의 3D 씬 속성 패널도 같은 여덟을 보인다.
6
- */
7
- export const ENVIRONMENTS = [
8
- 'studio',
9
- 'warehouse',
10
- 'factory',
11
- 'office',
12
- 'home',
13
- 'sunny',
14
- 'cloudy',
15
- 'rainy'
16
- ];
17
- /**
18
- * 씬에 그대로 넣는 보기 설정 — **좌표 기준과 천장 높이는 빼고.**
19
- *
20
- * 나머지는 전부 `model-layer` 의 상태 이름이라 그대로 넣으면 씬이 알아서 반응한다.
21
- * 그런데 `placement` 는 편집 캔버스에 들어가면 안 되고(거기는 늘 상자 기준이다),
22
- * `ceilingHeight` 는 씬이 모르는 이름이다.
23
- *
24
- * **rest spread 로 넘기지 않으려고 이 함수가 있다.** 캔버스가 한동안
25
- * `const { grid, ..., ...light } = view` 로 나머지를 통째로 넘겼는데, 그러면 설정을
26
- * 하나 더할 때마다 그것이 두 화면에 **말없이** 실린다. 새로 더한 좌표 기준이 바로
27
- * 그 길로 캔버스에 들어갈 뻔했다.
28
- */
29
- export function sceneLook(view) {
30
- const { placement, ceilingHeight, ...look } = view;
31
- return look;
32
- }
33
- /**
34
- * 씬의 좌표 기준 — **씬의 낱말 그대로 셋이다.**
35
- *
36
- * 형식의 `floor` · `center` · `ceiling` 과 짝이 맞지만 철자가 다르다. 옮겨 적는 표를 두지
37
- * 않는 것이 이 파일의 규칙이므로 씬 쪽을 쓴다. 화면에는 둘 다 보인다 — 「천장 기준
38
- * (inverted)」.
39
- */
40
- export const SCENE_REFERENCES = ['floor', 'space', 'inverted'];
41
- /** 배경색 기본값. 회색이라 부품 색이 제 색으로 보인다. */
42
- export const WORKBENCH = '#7c7c7c';
43
- /**
44
- * 처음 값.
45
- *
46
- * **지금 저작 화면이 실제로 쓰던 값 그대로다.** 설정을 만들면서 화면이 달라지면
47
- * 무엇이 설정 때문이고 무엇이 원래 그랬는지 갈리지 않는다.
48
- */
49
- export const DEFAULT_VIEW = {
50
- placement: 'floor',
51
- /* 공장 천장의 흔한 높이. 반도체 fab 의 OHT 레일이 대체로 이 언저리다. */
52
- ceilingHeight: 4000,
53
- grid: true,
54
- gridLabels: true,
55
- floor: false,
56
- environment: 'studio',
57
- skyColor: WORKBENCH,
58
- dirLightIntensity: 2.0,
59
- dirLightFollowCamera: true,
60
- dirShadowEnabled: true,
61
- hemiIntensity: 4.0
62
- };
63
- /**
64
- * How tall the preview board is: enough room for the tallest instance where the figure actually stands.
65
- *
66
- * A floor or center figure stands on the floor, so the tallest instance is the whole height. Only a
67
- * ceiling figure needs the room up to the ceiling. The board used to reach the ceiling for every figure,
68
- * which made a 920 tall AGV preview 4400 tall.
69
- *
70
- * This is an envelope, not a placement rule: where each instance goes is still the scene's
71
- * (`FigureRealObject.effectiveZPos`), and the camera fits what the scene drew.
72
- */
73
- export function previewBoardDepth(figure, ceilingHeight, factor) {
74
- const tallest = figure.base.y * factor;
75
- const reach = figure.placement === 'ceiling' ? Math.max(ceilingHeight, tallest) : tallest;
76
- return Math.round(reach * 1.1);
77
- }
78
- //# sourceMappingURL=figure-view.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"figure-view.js","sourceRoot":"","sources":["../../client/modeller/figure-view.ts"],"names":[],"mappings":"AAgEA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,QAAQ;IACR,WAAW;IACX,SAAS;IACT,QAAQ;IACR,MAAM;IACN,OAAO;IACP,QAAQ;IACR,OAAO;CACC,CAAA;AAGV;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,SAAS,CAAC,IAAkB;IAC1C,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAA;IAClD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,UAAU,CAAU,CAAA;AAEvE,qCAAqC;AACrC,MAAM,CAAC,MAAM,SAAS,GAAG,SAAS,CAAA;AAElC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAiB;IACxC,SAAS,EAAE,OAAO;IAClB,iDAAiD;IACjD,aAAa,EAAE,IAAI;IACnB,IAAI,EAAE,IAAI;IACV,UAAU,EAAE,IAAI;IAChB,KAAK,EAAE,KAAK;IACZ,WAAW,EAAE,QAAQ;IACrB,QAAQ,EAAE,SAAS;IACnB,iBAAiB,EAAE,GAAG;IACtB,oBAAoB,EAAE,IAAI;IAC1B,gBAAgB,EAAE,IAAI;IACtB,aAAa,EAAE,GAAG;CACnB,CAAA;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAC/B,MAAoF,EACpF,aAAqB,EACrB,MAAc;IAEd,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,MAAM,CAAA;IACtC,MAAM,KAAK,GAAG,MAAM,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAA;IACzF,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,GAAG,CAAC,CAAA;AAChC,CAAC","sourcesContent":["/**\n * 저작 화면의 **보기 설정**.\n *\n * ## 저장되지 않는다\n *\n * 이것은 자산이 아니라 **작업대**다. 조명을 밝게 하고 바닥을 켠 것은 그 사람이 지금\n * 보기 편한 상태일 뿐, 그 자산의 성질이 아니다. 그래서 자산에 안 들어가고, 보는 사람의\n * 브라우저에 남는다.\n *\n * 다른 사람이 같은 자산을 열면 자기 설정으로 본다. 그것이 맞다.\n *\n * ## 씬이 아는 이름을 그대로 쓴다\n *\n * 여기 이름은 전부 `model-layer` 의 상태 이름이다. 옮겨 적는 표를 두지 않는다 — 표를\n * 두면 씬이 새 설정을 받아도 이쪽이 모른다.\n *\n * 값이 바뀌면 씬이 스스로 반영한다(`three-capability` 의 `onchange`). 다만 `grid` 는\n * 한동안 3D 를 세울 때만 읽혔다 — things-scene 10.1.5 에서 고쳤다.\n */\nexport interface ViewSettings {\n /**\n * 어떤 도면에 놓인 것으로 보나 — 씬 전체의 좌표 모드.\n *\n * **도형의 `placement` 와 다른 것이다.** 도형의 것은 「이 종류는 바닥에 서나, 천장에\n * 매달리나」이고, 이것은 「지금 보고 있는 도면이 어느 쪽을 기준으로 재나」다. 바닥\n * 기준 도면에 천정 기반 OHT 를 놓으면 도면은 안 뒤집히고 OHT 가 천장 높이에 매달린다.\n *\n * 한동안 도형의 `placement` 를 이 자리에 흘려 넣었다. 모델러에 도형이 하나뿐이라\n * 그럴듯해 보였지만, 그러면 도형의 성질이 씬 전체를 뒤집는다 — 도면에서는 성립할 수가\n * 없고(도면에는 도형이 여럿이다), 저작 중에는 배치를 고를 때마다 저작자가 적어 둔\n * 높이가 전부 다른 숫자로 보였다.\n *\n * 씬의 낱말 그대로다: `floor` 바닥 기준 · `space` 중심 기준(바닥 없음) · `inverted`\n * 천장 기준. **미리보기에만 먹인다** — 편집 캔버스의 `zPos` 는 저작자가 직접 적는\n * 숫자라 그 뜻이 보기 설정에 따라 바뀌면 안 된다.\n */\n placement: 'floor' | 'space' | 'inverted'\n /**\n * 천장 높이 (mm). 천정 기반 도형을 미리보기에서 어디에 매달 것인가.\n *\n * 도형은 제가 놓일 방의 높이를 모른다. 도면은 알지만 미리보기에는 도면이 없으므로,\n * 저작자가 가정할 값을 여기서 정한다.\n */\n ceilingHeight: number\n /** 좌표 바탕(축 가이드). 원점과 눈금을 보인다. */\n grid: boolean\n /** 축 이름표(X · Y · Z). 눈금만 두고 글자를 끌 수 있다. */\n gridLabels: boolean\n /** 판의 바닥면. 좌표 바탕과 겹치므로 기본은 끈다. */\n floor: boolean\n /** Environment — 반사(IBL). 금속 재질이 무엇을 비출지 정한다. */\n environment: EnvironmentName\n /** Sky Color — 배경색. */\n skyColor: string\n /** Key Light Intensity. */\n dirLightIntensity: number\n /** Key Light — Follow Camera. 끄면 그림자 방향이 고정된다. */\n dirLightFollowCamera: boolean\n /** Key Light — Cast Shadow. */\n dirShadowEnabled: boolean\n /** Hemisphere Light Intensity — 그늘진 면을 들어올린다. */\n hemiIntensity: number\n}\n\n/**\n * 환경 프리셋 — **`scene-manager` 의 `SkyPreset` 과 같은 여덟이다.**\n *\n * 한동안 다섯만 적었다. 씬은 여덟을 다 받는데 이쪽이 셋을 몰라서 고를 수 없었다.\n * operato-board 의 3D 씬 속성 패널도 같은 여덟을 보인다.\n */\nexport const ENVIRONMENTS = [\n 'studio',\n 'warehouse',\n 'factory',\n 'office',\n 'home',\n 'sunny',\n 'cloudy',\n 'rainy'\n] as const\nexport type EnvironmentName = (typeof ENVIRONMENTS)[number]\n\n/**\n * 씬에 그대로 넣는 보기 설정 — **좌표 기준과 천장 높이는 빼고.**\n *\n * 나머지는 전부 `model-layer` 의 상태 이름이라 그대로 넣으면 씬이 알아서 반응한다.\n * 그런데 `placement` 는 편집 캔버스에 들어가면 안 되고(거기는 늘 상자 기준이다),\n * `ceilingHeight` 는 씬이 모르는 이름이다.\n *\n * **rest spread 로 넘기지 않으려고 이 함수가 있다.** 캔버스가 한동안\n * `const { grid, ..., ...light } = view` 로 나머지를 통째로 넘겼는데, 그러면 설정을\n * 하나 더할 때마다 그것이 두 화면에 **말없이** 실린다. 새로 더한 좌표 기준이 바로\n * 그 길로 캔버스에 들어갈 뻔했다.\n */\nexport function sceneLook(view: ViewSettings): Record<string, unknown> {\n const { placement, ceilingHeight, ...look } = view\n return look\n}\n\n/**\n * 씬의 좌표 기준 — **씬의 낱말 그대로 셋이다.**\n *\n * 형식의 `floor` · `center` · `ceiling` 과 짝이 맞지만 철자가 다르다. 옮겨 적는 표를 두지\n * 않는 것이 이 파일의 규칙이므로 씬 쪽을 쓴다. 화면에는 둘 다 보인다 — 「천장 기준\n * (inverted)」.\n */\nexport const SCENE_REFERENCES = ['floor', 'space', 'inverted'] as const\n\n/** 배경색 기본값. 회색이라 부품 색이 제 색으로 보인다. */\nexport const WORKBENCH = '#7c7c7c'\n\n/**\n * 처음 값.\n *\n * **지금 저작 화면이 실제로 쓰던 값 그대로다.** 설정을 만들면서 화면이 달라지면\n * 무엇이 설정 때문이고 무엇이 원래 그랬는지 갈리지 않는다.\n */\nexport const DEFAULT_VIEW: ViewSettings = {\n placement: 'floor',\n /* 공장 천장의 흔한 높이. 반도체 fab 의 OHT 레일이 대체로 이 언저리다. */\n ceilingHeight: 4000,\n grid: true,\n gridLabels: true,\n floor: false,\n environment: 'studio',\n skyColor: WORKBENCH,\n dirLightIntensity: 2.0,\n dirLightFollowCamera: true,\n dirShadowEnabled: true,\n hemiIntensity: 4.0\n}\n\n/**\n * How tall the preview board is: enough room for the tallest instance where the figure actually stands.\n *\n * A floor or center figure stands on the floor, so the tallest instance is the whole height. Only a\n * ceiling figure needs the room up to the ceiling. The board used to reach the ceiling for every figure,\n * which made a 920 tall AGV preview 4400 tall.\n *\n * This is an envelope, not a placement rule: where each instance goes is still the scene's\n * (`FigureRealObject.effectiveZPos`), and the camera fits what the scene drew.\n */\nexport function previewBoardDepth(\n figure: { placement?: 'floor' | 'ceiling' | 'center' | 'wall'; base: { y: number } },\n ceilingHeight: number,\n factor: number\n): number {\n const tallest = figure.base.y * factor\n const reach = figure.placement === 'ceiling' ? Math.max(ceilingHeight, tallest) : tallest\n return Math.round(reach * 1.1)\n}\n"]}
@@ -1,54 +0,0 @@
1
- import type { FigureAsset } from '@hatiolab/figure-model';
2
- export declare const PREVIEW_FACTOR = 2;
3
- /** The type the preview registers the figure under: this figure's own, never a real type a board uses. */
4
- export declare function previewTypeOf(context: string): string;
5
- export declare const PREVIEW_WAYS: readonly {
6
- name: string;
7
- axes: readonly ('x' | 'y' | 'z')[];
8
- }[];
9
- /** The size the figure was made at: its instance size when it declares one, else the room its bodies take. */
10
- export declare function authoredSizeOf(asset: FigureAsset): {
11
- x: number;
12
- y: number;
13
- z: number;
14
- };
15
- /** The eight instances: where each stands on the board and how large, in the scene's words. */
16
- export declare function previewInstances(type: string, size: {
17
- x: number;
18
- y: number;
19
- z: number;
20
- }): {
21
- components: {
22
- type: string;
23
- id: string;
24
- left: number;
25
- top: number;
26
- width: number;
27
- height: number;
28
- depth: number;
29
- }[];
30
- board: {
31
- width: number;
32
- height: number;
33
- };
34
- };
35
- /**
36
- * Where a variant asks a size the figure does not declare, the size it is drawn at instead -- as the board draws it
37
- * (things-scene clamps each axis to the declared range; chief architect's ruling 2026-09-25). Per variant, empty when
38
- * it is drawn as asked. A figure that follows its height only is drawn at its one width in the wider variants, and
39
- * the preview says so rather than drawing them as though they grew.
40
- */
41
- export declare function previewClampsOf(asset: FigureAsset, size: {
42
- x: number;
43
- y: number;
44
- z: number;
45
- }): Record<string, Array<{
46
- axis: 'x' | 'y' | 'z';
47
- asked: number;
48
- used: number;
49
- }>>;
50
- /**
51
- * The part the preview's size help speaks of: the one picked in the help, else the one chosen in the editor, else the
52
- * first that has a size rule. A choice that is not among the parts (removed, or a part with no rule) is passed over.
53
- */
54
- export declare function setupPartOf(picked: string, chosen: string, targets: string[]): string;
@@ -1,79 +0,0 @@
1
- import { compileFigureAsset, figureOccupiedBoxesOf, figureWritersOf, FIGURE_INSTANCE_SIZE_INPUTS } from '@hatiolab/figure-model';
2
- /* The preview's arithmetic, apart from the element so it is tested without a browser (see figure-preview.ts). */
3
- export const PREVIEW_FACTOR = 2;
4
- /** The type the preview registers the figure under: this figure's own, never a real type a board uses. */
5
- export function previewTypeOf(context) {
6
- return `figure-preview-${context || 'new'}`;
7
- }
8
- export const PREVIEW_WAYS = [
9
- { name: 'base', axes: [] },
10
- { name: 'x', axes: ['x'] },
11
- { name: 'y', axes: ['y'] },
12
- { name: 'z', axes: ['z'] },
13
- { name: 'x·y', axes: ['x', 'y'] },
14
- { name: 'x·z', axes: ['x', 'z'] },
15
- { name: 'y·z', axes: ['y', 'z'] },
16
- { name: 'x·y·z', axes: ['x', 'y', 'z'] }
17
- ];
18
- /** The size the figure was made at: its instance size when it declares one, else the room its bodies take. */
19
- export function authoredSizeOf(asset) {
20
- const d = asset.designInputs;
21
- const declared = ['x', 'y', 'z'].map(axis => d[FIGURE_INSTANCE_SIZE_INPUTS[axis]]);
22
- if (declared.every(v => typeof v === 'number' && v > 0))
23
- return { x: declared[0], y: declared[1], z: declared[2] };
24
- /* No declared size: the room its bodies take up, so the instance is placed at the size it draws. */
25
- const boxes = figureOccupiedBoxesOf(compileFigureAsset(asset).evaluate().geometry, figureWritersOf(asset));
26
- const span = (axis) => boxes.length ? Math.max(...boxes.map(b => b.centre[axis] + b.extent[axis] / 2)) - Math.min(...boxes.map(b => b.centre[axis] - b.extent[axis] / 2)) : 0;
27
- return { x: Math.max(1, Math.round(span('x'))), y: Math.max(1, Math.round(span('y'))), z: Math.max(1, Math.round(span('z'))) };
28
- }
29
- /** The eight instances: where each stands on the board and how large, in the scene's words. */
30
- export function previewInstances(type, size) {
31
- const COLUMNS = 4;
32
- const cell = { x: size.x * PREVIEW_FACTOR * 1.25, z: size.z * PREVIEW_FACTOR * 1.25 };
33
- const components = PREVIEW_WAYS.map((way, at) => {
34
- const grow = (axis) => (way.axes.includes(axis) ? PREVIEW_FACTOR : 1);
35
- const width = Math.round(size.x * grow('x'));
36
- const height = Math.round(size.z * grow('z'));
37
- const column = at % COLUMNS;
38
- const row = Math.floor(at / COLUMNS);
39
- return {
40
- type,
41
- id: `at-${way.name}`,
42
- left: Math.round(column * cell.x + (cell.x - width) / 2),
43
- top: Math.round(row * cell.z + (cell.z - height) / 2),
44
- width,
45
- height,
46
- /* Always written: without it the height is taken as the plan's mean and "grow y only" would not grow it. */
47
- depth: Math.round(size.y * grow('y'))
48
- };
49
- });
50
- return { components, board: { width: Math.round(cell.x * COLUMNS), height: Math.round(cell.z * Math.ceil(PREVIEW_WAYS.length / COLUMNS)) } };
51
- }
52
- /**
53
- * Where a variant asks a size the figure does not declare, the size it is drawn at instead -- as the board draws it
54
- * (things-scene clamps each axis to the declared range; chief architect's ruling 2026-09-25). Per variant, empty when
55
- * it is drawn as asked. A figure that follows its height only is drawn at its one width in the wider variants, and
56
- * the preview says so rather than drawing them as though they grew.
57
- */
58
- export function previewClampsOf(asset, size) {
59
- const inputs = asset.document.model.inputs;
60
- return Object.fromEntries(PREVIEW_WAYS.map(way => [
61
- way.name,
62
- ['x', 'y', 'z'].flatMap(axis => {
63
- const input = inputs.find(i => i.id === FIGURE_INSTANCE_SIZE_INPUTS[axis]);
64
- if (!input)
65
- return [];
66
- const asked = Math.round(size[axis] * (way.axes.includes(axis) ? PREVIEW_FACTOR : 1));
67
- const used = Math.round(Math.min(Math.max(asked, input.min ?? -Infinity), input.max ?? Infinity));
68
- return used === asked ? [] : [{ axis, asked, used }];
69
- })
70
- ]));
71
- }
72
- /**
73
- * The part the preview's size help speaks of: the one picked in the help, else the one chosen in the editor, else the
74
- * first that has a size rule. A choice that is not among the parts (removed, or a part with no rule) is passed over.
75
- */
76
- export function setupPartOf(picked, chosen, targets) {
77
- return [picked, chosen].find(id => !!id && targets.includes(id)) ?? targets[0] ?? '';
78
- }
79
- //# sourceMappingURL=preview-model.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"preview-model.js","sourceRoot":"","sources":["../../client/modeller/preview-model.ts"],"names":[],"mappings":"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","sourcesContent":["import { compileFigureAsset, figureOccupiedBoxesOf, figureWritersOf, FIGURE_INSTANCE_SIZE_INPUTS } from '@hatiolab/figure-model'\nimport type { FigureAsset } from '@hatiolab/figure-model'\n\n/* The preview's arithmetic, apart from the element so it is tested without a browser (see figure-preview.ts). */\n\nexport const PREVIEW_FACTOR = 2\n\n/** The type the preview registers the figure under: this figure's own, never a real type a board uses. */\nexport function previewTypeOf(context: string): string {\n return `figure-preview-${context || 'new'}`\n}\n\nexport const PREVIEW_WAYS: readonly { name: string; axes: readonly ('x' | 'y' | 'z')[] }[] = [\n { name: 'base', axes: [] },\n { name: 'x', axes: ['x'] },\n { name: 'y', axes: ['y'] },\n { name: 'z', axes: ['z'] },\n { name: 'x·y', axes: ['x', 'y'] },\n { name: 'x·z', axes: ['x', 'z'] },\n { name: 'y·z', axes: ['y', 'z'] },\n { name: 'x·y·z', axes: ['x', 'y', 'z'] }\n]\n\n/** The size the figure was made at: its instance size when it declares one, else the room its bodies take. */\nexport function authoredSizeOf(asset: FigureAsset): { x: number; y: number; z: number } {\n const d = asset.designInputs\n const declared = (['x', 'y', 'z'] as const).map(axis => d[FIGURE_INSTANCE_SIZE_INPUTS[axis]])\n if (declared.every(v => typeof v === 'number' && v > 0)) return { x: declared[0]!, y: declared[1]!, z: declared[2]! }\n /* No declared size: the room its bodies take up, so the instance is placed at the size it draws. */\n const boxes = figureOccupiedBoxesOf(compileFigureAsset(asset).evaluate().geometry, figureWritersOf(asset))\n const span = (axis: 'x' | 'y' | 'z') =>\n boxes.length ? Math.max(...boxes.map(b => b.centre[axis] + b.extent[axis] / 2)) - Math.min(...boxes.map(b => b.centre[axis] - b.extent[axis] / 2)) : 0\n return { x: Math.max(1, Math.round(span('x'))), y: Math.max(1, Math.round(span('y'))), z: Math.max(1, Math.round(span('z'))) }\n}\n\n/** The eight instances: where each stands on the board and how large, in the scene's words. */\nexport function previewInstances(type: string, size: { x: number; y: number; z: number }) {\n const COLUMNS = 4\n const cell = { x: size.x * PREVIEW_FACTOR * 1.25, z: size.z * PREVIEW_FACTOR * 1.25 }\n const components = PREVIEW_WAYS.map((way, at) => {\n const grow = (axis: 'x' | 'y' | 'z') => (way.axes.includes(axis) ? PREVIEW_FACTOR : 1)\n const width = Math.round(size.x * grow('x'))\n const height = Math.round(size.z * grow('z'))\n const column = at % COLUMNS\n const row = Math.floor(at / COLUMNS)\n return {\n type,\n id: `at-${way.name}`,\n left: Math.round(column * cell.x + (cell.x - width) / 2),\n top: Math.round(row * cell.z + (cell.z - height) / 2),\n width,\n height,\n /* Always written: without it the height is taken as the plan's mean and \"grow y only\" would not grow it. */\n depth: Math.round(size.y * grow('y'))\n }\n })\n return { components, board: { width: Math.round(cell.x * COLUMNS), height: Math.round(cell.z * Math.ceil(PREVIEW_WAYS.length / COLUMNS)) } }\n}\n\n\n/**\n * Where a variant asks a size the figure does not declare, the size it is drawn at instead -- as the board draws it\n * (things-scene clamps each axis to the declared range; chief architect's ruling 2026-09-25). Per variant, empty when\n * it is drawn as asked. A figure that follows its height only is drawn at its one width in the wider variants, and\n * the preview says so rather than drawing them as though they grew.\n */\nexport function previewClampsOf(asset: FigureAsset, size: { x: number; y: number; z: number }): Record<string, Array<{ axis: 'x' | 'y' | 'z'; asked: number; used: number }>> {\n const inputs = asset.document.model.inputs\n return Object.fromEntries(\n PREVIEW_WAYS.map(way => [\n way.name,\n (['x', 'y', 'z'] as const).flatMap(axis => {\n const input = inputs.find(i => i.id === FIGURE_INSTANCE_SIZE_INPUTS[axis])\n if (!input) return []\n const asked = Math.round(size[axis] * (way.axes.includes(axis) ? PREVIEW_FACTOR : 1))\n const used = Math.round(Math.min(Math.max(asked, input.min ?? -Infinity), input.max ?? Infinity))\n return used === asked ? [] : [{ axis, asked, used }]\n })\n ])\n )\n}\n\n/**\n * The part the preview's size help speaks of: the one picked in the help, else the one chosen in the editor, else the\n * first that has a size rule. A choice that is not among the parts (removed, or a part with no rule) is passed over.\n */\nexport function setupPartOf(picked: string, chosen: string, targets: string[]): string {\n return [picked, chosen].find(id => !!id && targets.includes(id)) ?? targets[0] ?? ''\n}\n"]}
@@ -1,27 +0,0 @@
1
- /**
2
- * The side panel's one look, for every element that draws in the modeller's side.
3
- *
4
- * The side is drawn by several elements (the type field, the figure's properties, a part's values, fastening, places,
5
- * motion, material, controls, clips, the environment) and each had styled its own fields: three label styles and
6
- * three field heights in one column (user, 2026-09-24: "why are the styles and layout all different?"). They share
7
- * this sheet now and keep only what is theirs.
8
- *
9
- * The vocabulary:
10
- * section one titled group; the side is a stack of them
11
- * h3 a group's title
12
- *
13
- * Three sizes and two weights (user 2026-10-01, the panel checked for balance: eight sizes, and titles smaller than
14
- * what they titled): a title at the body token and semibold, everything else at the small token, and a hint at the
15
- * micro one. Sections are 16 px above their title and 12 px below their last line.
16
- * div[inline-field] a short label and its one field on one line
17
- * div[field] a label above a full-width field
18
- * div[form] short labels beside their fields, the fields starting on one line
19
- * div[vector-row] a title, then X · Y · Z in one row of cells with the axis inside (`div[triple]` of
20
- * `div[cell]`) -- three values read together, as vector tools lay them out
21
- * div[pair] two controls side by side
22
- * label[toggle] a checkbox and its words
23
- * p[hint] · small the quiet line under a field
24
- * button[act] an action under the fields it acts on
25
- * [scrub] a label dragged sideways to scrub its field
26
- */
27
- export declare const SidePanelStyles: import("lit").CSSResult;