@operato/scene-storage 10.0.0-beta.32 → 10.0.0-beta.34

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 (89) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/crane-3d.d.ts +14 -0
  3. package/dist/crane-3d.js +238 -0
  4. package/dist/crane-3d.js.map +1 -0
  5. package/dist/crane.d.ts +157 -0
  6. package/dist/crane.js +440 -0
  7. package/dist/crane.js.map +1 -0
  8. package/dist/index.d.ts +13 -6
  9. package/dist/index.js +9 -4
  10. package/dist/index.js.map +1 -1
  11. package/dist/mobile-storage-rack.d.ts +17 -0
  12. package/dist/mobile-storage-rack.js +55 -0
  13. package/dist/mobile-storage-rack.js.map +1 -0
  14. package/dist/rack-column.d.ts +35 -0
  15. package/dist/rack-column.js +258 -0
  16. package/dist/rack-column.js.map +1 -0
  17. package/dist/rack-grid-3d.d.ts +13 -0
  18. package/dist/rack-grid-3d.js +94 -0
  19. package/dist/rack-grid-3d.js.map +1 -0
  20. package/dist/rack-grid-cell.d.ts +341 -0
  21. package/dist/rack-grid-cell.js +321 -0
  22. package/dist/rack-grid-cell.js.map +1 -0
  23. package/dist/rack-grid-helpers.d.ts +28 -0
  24. package/dist/rack-grid-helpers.js +71 -0
  25. package/dist/rack-grid-helpers.js.map +1 -0
  26. package/dist/rack-grid-location.d.ts +37 -0
  27. package/dist/rack-grid-location.js +227 -0
  28. package/dist/rack-grid-location.js.map +1 -0
  29. package/dist/rack-grid.d.ts +80 -0
  30. package/dist/rack-grid.js +829 -0
  31. package/dist/rack-grid.js.map +1 -0
  32. package/dist/stock.d.ts +78 -0
  33. package/dist/stock.js +333 -0
  34. package/dist/stock.js.map +1 -0
  35. package/dist/{rack-cell-3d.d.ts → storage-cell-3d.d.ts} +1 -1
  36. package/dist/{rack-cell-3d.js → storage-cell-3d.js} +3 -3
  37. package/dist/storage-cell-3d.js.map +1 -0
  38. package/dist/{rack-cell.d.ts → storage-cell.d.ts} +12 -6
  39. package/dist/{rack-cell.js → storage-cell.js} +9 -9
  40. package/dist/storage-cell.js.map +1 -0
  41. package/dist/{asrs-rack-3d.d.ts → storage-rack-3d.d.ts} +1 -1
  42. package/dist/{asrs-rack-3d.js → storage-rack-3d.js} +4 -4
  43. package/dist/storage-rack-3d.js.map +1 -0
  44. package/dist/{asrs-rack.d.ts → storage-rack.d.ts} +22 -16
  45. package/dist/{asrs-rack.js → storage-rack.js} +32 -26
  46. package/dist/storage-rack.js.map +1 -0
  47. package/dist/templates/index.d.ts +60 -0
  48. package/dist/templates/index.js +59 -17
  49. package/dist/templates/index.js.map +1 -1
  50. package/package.json +3 -3
  51. package/src/crane-3d.ts +273 -0
  52. package/src/crane.ts +538 -0
  53. package/src/index.ts +13 -6
  54. package/src/mobile-storage-rack.ts +56 -0
  55. package/src/rack-column.ts +340 -0
  56. package/src/rack-grid-3d.ts +128 -0
  57. package/src/rack-grid-cell.ts +404 -0
  58. package/src/rack-grid-helpers.ts +77 -0
  59. package/src/rack-grid-location.ts +286 -0
  60. package/src/rack-grid.ts +994 -0
  61. package/src/stock.ts +426 -0
  62. package/src/{rack-cell-3d.ts → storage-cell-3d.ts} +2 -2
  63. package/src/{rack-cell.ts → storage-cell.ts} +19 -13
  64. package/src/{asrs-rack-3d.ts → storage-rack-3d.ts} +3 -3
  65. package/src/{asrs-rack.ts → storage-rack.ts} +31 -25
  66. package/src/templates/index.ts +59 -17
  67. package/test/test-rack-grid-crane.ts +212 -0
  68. package/test/test-rack-grid.ts +77 -0
  69. package/test/{test-asrs-crane.ts → test-storage-rack-crane.ts} +8 -8
  70. package/translations/en.json +55 -7
  71. package/translations/ja.json +52 -4
  72. package/translations/ko.json +52 -4
  73. package/translations/ms.json +55 -7
  74. package/translations/zh.json +52 -4
  75. package/tsconfig.tsbuildinfo +1 -1
  76. package/dist/asrs-crane-3d.d.ts +0 -17
  77. package/dist/asrs-crane-3d.js +0 -181
  78. package/dist/asrs-crane-3d.js.map +0 -1
  79. package/dist/asrs-crane.d.ts +0 -98
  80. package/dist/asrs-crane.js +0 -216
  81. package/dist/asrs-crane.js.map +0 -1
  82. package/dist/asrs-rack-3d.js.map +0 -1
  83. package/dist/asrs-rack.js.map +0 -1
  84. package/dist/rack-cell-3d.js.map +0 -1
  85. package/dist/rack-cell.js.map +0 -1
  86. package/src/asrs-crane-3d.ts +0 -211
  87. package/src/asrs-crane.ts +0 -275
  88. /package/icons/{asrs-crane.png → crane.png} +0 -0
  89. /package/icons/{asrs-rack.png → storage-rack.png} +0 -0
@@ -1,13 +1,20 @@
1
1
  /*
2
- * things-scene catalog templates for the storage domain — pallet/box/parcel
3
- * variants, ASRS rack/crane, ASRS aisle composite, and the virtual `spot` placement marker.
2
+ * things-scene catalog templates for the storage domain.
3
+ *
4
+ * Components:
5
+ * - pallet / box / parcel — carriers
6
+ * - rack — multi-level storage shelf (bays × levels)
7
+ * - rack-table — bulk layout (rows × columns × shelves) helper
8
+ * - crane — stacker picker (Mover + CarrierHolder + ContainerCapacity)
9
+ * - mobile-rack — Mover(Rack), an AGV-mounted / cart-mounted moving rack
10
+ * - spot — virtual placement marker
4
11
  */
5
12
  import spot from './spot.js';
6
13
  const pallet = new URL('../../icons/pallet.png', import.meta.url).href;
7
14
  const box = new URL('../../icons/box.png', import.meta.url).href;
8
15
  const parcel = new URL('../../icons/parcel.png', import.meta.url).href;
9
- const asrsRack = new URL('../../icons/asrs-rack.png', import.meta.url).href;
10
- const asrsCrane = new URL('../../icons/asrs-crane.png', import.meta.url).href;
16
+ const rack = new URL('../../icons/storage-rack.png', import.meta.url).href;
17
+ const crane = new URL('../../icons/crane.png', import.meta.url).href;
11
18
  export default [
12
19
  {
13
20
  type: 'pallet',
@@ -79,12 +86,12 @@ export default [
79
86
  }
80
87
  },
81
88
  {
82
- type: 'asrs-rack',
83
- description: 'AS/RS storage rack (multi-level)',
89
+ type: 'storage-rack',
90
+ description: 'storage rack multi-level shelves',
84
91
  group: 'storage',
85
- icon: asrsRack,
92
+ icon: rack,
86
93
  model: {
87
- type: 'asrs-rack',
94
+ type: 'storage-rack',
88
95
  top: 300,
89
96
  left: 100,
90
97
  width: 800,
@@ -94,12 +101,32 @@ export default [
94
101
  }
95
102
  },
96
103
  {
97
- type: 'asrs-crane',
98
- description: 'AS/RS stacker crane',
104
+ type: 'rack-grid',
105
+ description: 'rack table — N×M rack layout + auto location IDs',
99
106
  group: 'storage',
100
- icon: asrsCrane,
107
+ icon: rack,
101
108
  model: {
102
- type: 'asrs-crane',
109
+ type: 'rack-grid',
110
+ top: 100,
111
+ left: 100,
112
+ width: 1200,
113
+ height: 600,
114
+ rows: 2,
115
+ columns: 4,
116
+ shelves: 4,
117
+ zone: 'A',
118
+ locPattern: '{z}{s}-{u}-{sh}',
119
+ sectionDigits: 2,
120
+ unitDigits: 2
121
+ }
122
+ },
123
+ {
124
+ type: 'crane',
125
+ description: 'stacker crane — picker actor',
126
+ group: 'storage',
127
+ icon: crane,
128
+ model: {
129
+ type: 'crane',
103
130
  top: 550,
104
131
  left: 400,
105
132
  width: 100,
@@ -108,11 +135,26 @@ export default [
108
135
  carriageHeight: 100
109
136
  }
110
137
  },
138
+ {
139
+ type: 'mobile-storage-rack',
140
+ description: 'mobile rack — Mover(Rack), AGV/cart-mounted',
141
+ group: 'storage',
142
+ icon: rack,
143
+ model: {
144
+ type: 'mobile-storage-rack',
145
+ top: 300,
146
+ left: 100,
147
+ width: 400,
148
+ height: 200,
149
+ levels: 3,
150
+ bays: 3
151
+ }
152
+ },
111
153
  {
112
154
  type: 'group',
113
- description: 'AS/RS aisle — 4-level rack pair + stacker crane',
155
+ description: 'storage aisle — rack pair + crane',
114
156
  group: 'storage',
115
- icon: asrsRack,
157
+ icon: rack,
116
158
  model: {
117
159
  type: 'group',
118
160
  top: 100,
@@ -121,7 +163,7 @@ export default [
121
163
  height: 220,
122
164
  components: [
123
165
  {
124
- type: 'asrs-rack',
166
+ type: 'storage-rack',
125
167
  top: 100,
126
168
  left: 100,
127
169
  width: 800,
@@ -130,7 +172,7 @@ export default [
130
172
  bays: 8
131
173
  },
132
174
  {
133
- type: 'asrs-crane',
175
+ type: 'crane',
134
176
  top: 140,
135
177
  left: 420,
136
178
  width: 60,
@@ -139,7 +181,7 @@ export default [
139
181
  carriageHeight: 0
140
182
  },
141
183
  {
142
- type: 'asrs-rack',
184
+ type: 'storage-rack',
143
185
  top: 320,
144
186
  left: 100,
145
187
  width: 800,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * things-scene catalog templates for the storage domain pallet/box/parcel\n * variants, ASRS rack/crane, ASRS aisle composite, and the virtual `spot` placement marker.\n */\nimport spot from './spot.js'\nconst pallet = new URL('../../icons/pallet.png', import.meta.url).href\nconst box = new URL('../../icons/box.png', import.meta.url).href\nconst parcel = new URL('../../icons/parcel.png', import.meta.url).href\nconst asrsRack = new URL('../../icons/asrs-rack.png', import.meta.url).href\nconst asrsCrane = new URL('../../icons/asrs-crane.png', import.meta.url).href\n\nexport default [\n {\n type: 'pallet',\n description: 'wood pallet (EUR / EPAL)',\n group: 'storage',\n icon: pallet,\n model: {\n type: 'pallet',\n top: 100,\n left: 100,\n width: 80,\n height: 80,\n material: 'wood'\n }\n },\n {\n type: 'pallet',\n description: 'plastic pallet',\n group: 'storage',\n icon: pallet,\n model: {\n type: 'pallet',\n top: 100,\n left: 250,\n width: 80,\n height: 80,\n material: 'plastic'\n }\n },\n {\n type: 'box',\n description: 'wood crate',\n group: 'storage',\n icon: box,\n model: {\n type: 'box',\n top: 100,\n left: 400,\n width: 80,\n height: 80,\n material: 'wood'\n }\n },\n {\n type: 'box',\n description: 'plastic tote',\n group: 'storage',\n icon: box,\n model: {\n type: 'box',\n top: 100,\n left: 520,\n width: 80,\n height: 80,\n material: 'plastic'\n }\n },\n {\n type: 'parcel',\n description: 'cardboard parcel',\n group: 'storage',\n icon: parcel,\n model: {\n type: 'parcel',\n top: 100,\n left: 640,\n width: 60,\n height: 80\n }\n },\n {\n type: 'asrs-rack',\n description: 'AS/RS storage rack (multi-level)',\n group: 'storage',\n icon: asrsRack,\n model: {\n type: 'asrs-rack',\n top: 300,\n left: 100,\n width: 800,\n height: 200,\n levels: 4,\n bays: 5\n }\n },\n {\n type: 'asrs-crane',\n description: 'AS/RS stacker crane',\n group: 'storage',\n icon: asrsCrane,\n model: {\n type: 'asrs-crane',\n top: 550,\n left: 400,\n width: 100,\n height: 200,\n status: 'idle',\n carriageHeight: 100\n }\n },\n {\n type: 'group',\n description: 'AS/RS aisle4-level rack pair + stacker crane',\n group: 'storage',\n icon: asrsRack,\n model: {\n type: 'group',\n top: 100,\n left: 100,\n width: 840,\n height: 220,\n components: [\n {\n type: 'asrs-rack',\n top: 100,\n left: 100,\n width: 800,\n height: 80,\n levels: 4,\n bays: 8\n },\n {\n type: 'asrs-crane',\n top: 140,\n left: 420,\n width: 60,\n height: 220,\n status: 'idle',\n carriageHeight: 0\n },\n {\n type: 'asrs-rack',\n top: 320,\n left: 100,\n width: 800,\n height: 80,\n levels: 4,\n bays: 8\n }\n ]\n }\n },\n spot\n]\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/templates/index.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * things-scene catalog templates for the storage domain.\n *\n * Components:\n * - pallet / box / parcel — carriers\n * - rack multi-level storage shelf (bays × levels)\n * - rack-table — bulk layout (rows × columns × shelves) helper\n * - crane stacker picker (Mover + CarrierHolder + ContainerCapacity)\n * - mobile-rack — Mover(Rack), an AGV-mounted / cart-mounted moving rack\n * - spot — virtual placement marker\n */\nimport spot from './spot.js'\nconst pallet = new URL('../../icons/pallet.png', import.meta.url).href\nconst box = new URL('../../icons/box.png', import.meta.url).href\nconst parcel = new URL('../../icons/parcel.png', import.meta.url).href\nconst rack = new URL('../../icons/storage-rack.png', import.meta.url).href\nconst crane = new URL('../../icons/crane.png', import.meta.url).href\n\nexport default [\n {\n type: 'pallet',\n description: 'wood pallet (EUR / EPAL)',\n group: 'storage',\n icon: pallet,\n model: {\n type: 'pallet',\n top: 100,\n left: 100,\n width: 80,\n height: 80,\n material: 'wood'\n }\n },\n {\n type: 'pallet',\n description: 'plastic pallet',\n group: 'storage',\n icon: pallet,\n model: {\n type: 'pallet',\n top: 100,\n left: 250,\n width: 80,\n height: 80,\n material: 'plastic'\n }\n },\n {\n type: 'box',\n description: 'wood crate',\n group: 'storage',\n icon: box,\n model: {\n type: 'box',\n top: 100,\n left: 400,\n width: 80,\n height: 80,\n material: 'wood'\n }\n },\n {\n type: 'box',\n description: 'plastic tote',\n group: 'storage',\n icon: box,\n model: {\n type: 'box',\n top: 100,\n left: 520,\n width: 80,\n height: 80,\n material: 'plastic'\n }\n },\n {\n type: 'parcel',\n description: 'cardboard parcel',\n group: 'storage',\n icon: parcel,\n model: {\n type: 'parcel',\n top: 100,\n left: 640,\n width: 60,\n height: 80\n }\n },\n {\n type: 'storage-rack',\n description: 'storage rack multi-level shelves',\n group: 'storage',\n icon: rack,\n model: {\n type: 'storage-rack',\n top: 300,\n left: 100,\n width: 800,\n height: 200,\n levels: 4,\n bays: 5\n }\n },\n {\n type: 'rack-grid',\n description: 'rack table — N×M rack layout + auto location IDs',\n group: 'storage',\n icon: rack,\n model: {\n type: 'rack-grid',\n top: 100,\n left: 100,\n width: 1200,\n height: 600,\n rows: 2,\n columns: 4,\n shelves: 4,\n zone: 'A',\n locPattern: '{z}{s}-{u}-{sh}',\n sectionDigits: 2,\n unitDigits: 2\n }\n },\n {\n type: 'crane',\n description: 'stacker crane — picker actor',\n group: 'storage',\n icon: crane,\n model: {\n type: 'crane',\n top: 550,\n left: 400,\n width: 100,\n height: 200,\n status: 'idle',\n carriageHeight: 100\n }\n },\n {\n type: 'mobile-storage-rack',\n description: 'mobile rackMover(Rack), AGV/cart-mounted',\n group: 'storage',\n icon: rack,\n model: {\n type: 'mobile-storage-rack',\n top: 300,\n left: 100,\n width: 400,\n height: 200,\n levels: 3,\n bays: 3\n }\n },\n {\n type: 'group',\n description: 'storage aisle — rack pair + crane',\n group: 'storage',\n icon: rack,\n model: {\n type: 'group',\n top: 100,\n left: 100,\n width: 840,\n height: 220,\n components: [\n {\n type: 'storage-rack',\n top: 100,\n left: 100,\n width: 800,\n height: 80,\n levels: 4,\n bays: 8\n },\n {\n type: 'crane',\n top: 140,\n left: 420,\n width: 60,\n height: 220,\n status: 'idle',\n carriageHeight: 0\n },\n {\n type: 'storage-rack',\n top: 320,\n left: 100,\n width: 800,\n height: 80,\n levels: 4,\n bays: 8\n }\n ]\n }\n },\n spot\n]\n"]}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@operato/scene-storage",
3
3
  "description": "Storage-domain components for things-scene (smart factory / logistics) — pallet, box, parcel; AS/RS and shelves planned.",
4
4
  "author": "heartyoh",
5
- "version": "10.0.0-beta.32",
5
+ "version": "10.0.0-beta.34",
6
6
  "type": "module",
7
7
  "main": "dist/index.js",
8
8
  "module": "dist/index.js",
@@ -26,7 +26,7 @@
26
26
  },
27
27
  "dependencies": {
28
28
  "@hatiolab/things-scene": "^10.0.0-beta.1",
29
- "@operato/scene-base": "^10.0.0-beta.32",
29
+ "@operato/scene-base": "^10.0.0-beta.33",
30
30
  "three": "^0.183.0"
31
31
  },
32
32
  "devDependencies": {
@@ -45,5 +45,5 @@
45
45
  "typescript": "^5.0.4"
46
46
  },
47
47
  "prettier": "@hatiolab/prettier-config",
48
- "gitHead": "9c9fec2b993ccda805cdd53fe11e15fb4b71254e"
48
+ "gitHead": "07e3c36c043a6225ea2686dee96357a605f0812f"
49
49
  }
@@ -0,0 +1,273 @@
1
+ /*
2
+ * Copyright © HatioLab Inc. All rights reserved.
3
+ *
4
+ * Crane 3D — heavy-duty pallet AS/RS stacker crane (twin-mast).
5
+ *
6
+ * Axis convention (things-scene 3D):
7
+ * +X = aisle 진행 방향 (Crane 좌우 이동, *옆으로 길게* 축)
8
+ * +Y = 수직 (Crane 키, carriage 상하 이동)
9
+ * +Z = aisle 폭 방향 (Rack cell 쪽 / fork 신축 방향)
10
+ *
11
+ * **스케일 룰**:
12
+ * - 모든 가로(X,Z) dimension 과 Y 두께 → 2D footprint (state.width, state.height) 비례
13
+ * - Mast Y 길이만 → state.depth 사용 (수직 키)
14
+ * - Y 두께는 절대 depth (크레인 키) 에 비례 안 함 → 키워도 뭉치 안 두꺼워짐
15
+ * - mm/cm/scene-unit 무관 — 사용자의 footprint 스케일에 자동 맞춤
16
+ *
17
+ * 부품:
18
+ * [Ceiling rail]
19
+ * [Top guide trolley] — 천장 rail 위
20
+ * [Top frame] — 두 mast 상부 연결
21
+ * [Mast L][Mast R] — twin yellow column (X 축으로 떨어져 있음)
22
+ * [Carriage] — 두 mast 사이 가로 frame (carriageHeight 로 상하)
23
+ * └── [Two forks] — carriage 에서 ±Z 신축 (forkExtension)
24
+ * [Base trolley] — 바닥 motor housing (X 길게)
25
+ * └── [Cabinet] — base 한쪽 red 컨트롤박스
26
+ * └── [Status lamp]
27
+ * [Floor rail]
28
+ *
29
+ * Actuators (state):
30
+ * carriageHeight, forkExtension (±), forkLift
31
+ */
32
+
33
+ import * as THREE from 'three'
34
+ import { RealObjectGroup } from '@hatiolab/things-scene'
35
+
36
+ const MAST_COLOR = 0xff7a00 // mast — orange
37
+ const TROLLEY_COLOR = 0x3a4048 // base / top — dark charcoal
38
+ const CARRIAGE_COLOR = 0xffcc00 // carriage (shuttle) — yellow
39
+ const CONTROLLER_COLOR = 0xc63333 // cabinet — red
40
+ const FORK_COLOR = 0xffcc00 // fork — yellow (same as carriage)
41
+ const RAIL_COLOR = 0x1a1f24 // rail — dark steel
42
+ const LAMP_OFF = 0x222222
43
+
44
+ export class Crane3D extends RealObjectGroup {
45
+ private _forkGroup?: THREE.Group
46
+ private _forkTopY: number = 0
47
+ private _bladeMidZ: number = 0
48
+
49
+ build() {
50
+ super.build()
51
+
52
+ this._forkGroup = undefined
53
+ this._forkTopY = 0
54
+ this._bladeMidZ = 0
55
+
56
+ const { width, height, depth } = this.component.state
57
+ const emissiveColor = (this.component.state.lampEmissive as string) || '#222222'
58
+ const status = this.component.state.status
59
+ const lampOn = status && status !== 'idle'
60
+
61
+ // Actuators
62
+ const D = numOr(depth, Math.max(width, height) * 4)
63
+ const carriageRaw = numOr((this.component.state as any).carriageHeight, D * 0.4)
64
+ const carriageHeight = Math.max(0, Math.min(carriageRaw, D * 0.85))
65
+
66
+ const forkLength = numOr((this.component.state as any).forkLength, height * 0.6)
67
+ const forkExtensionRaw = numOr((this.component.state as any).forkExtension, 0)
68
+ const forkExtension = Math.max(-forkLength, Math.min(forkLength, forkExtensionRaw))
69
+ const forkLift = numOr((this.component.state as any).forkLift, 0)
70
+
71
+ // ── Axis convention (FIXED): ─────────────────────────────────────
72
+ // Rail = X (state.left = 2D X = 3D X). Crane 좌우 이동.
73
+ // Fork = Z (2D Y = 3D Z). Fork 앞뒤 신축.
74
+ // 사용자: "포크는 앞뒤로, 크레인 본체는 좌우로."
75
+ // width = rail-direction 풋프린트 (좁음)
76
+ // height = cross-aisle (fork 방향) 풋프린트 (깊음, fork 가 cell 까지 닿는 거리)
77
+ const S = Math.min(width, height)
78
+ const railH = S * 0.04
79
+ const baseH = S * 0.18
80
+ const topFrameH = S * 0.1
81
+ const topGuideH = S * 0.1
82
+ const carriageH = S * 0.12
83
+ const mastW = width * 0.1 // mast X 단면 (along rail)
84
+ const mastD = height * 0.25 // mast Z 단면 (cross-rail)
85
+ const mastSpacing = width * 0.7 // 두 mast X 간격
86
+ const bladeW = S * 0.1
87
+ const bladeH = S * 0.05
88
+ const bladeL = forkLength
89
+ const bladeSpacing = mastSpacing * 0.45
90
+ const carriageW = mastSpacing - mastW * 0.2
91
+ const carriageZ = height * 0.55
92
+ const cabW = S * 0.4
93
+ const cabH = S * 0.4
94
+ const cabD = S * 0.3
95
+
96
+ const baseY = -D / 2
97
+ const mastH = Math.max(D - railH * 2 - baseH - topFrameH - topGuideH, S * 0.5)
98
+
99
+ // ── Materials ─────────────────────────────────────────────────────
100
+ const mastMat = new THREE.MeshStandardMaterial({ color: MAST_COLOR, metalness: 0.3, roughness: 0.5 })
101
+ const trolleyMat = new THREE.MeshStandardMaterial({ color: TROLLEY_COLOR, metalness: 0.6, roughness: 0.5 })
102
+ const carriageMat = new THREE.MeshStandardMaterial({ color: CARRIAGE_COLOR, metalness: 0.85, roughness: 0.35 })
103
+ const cabinetMat = new THREE.MeshStandardMaterial({ color: CONTROLLER_COLOR, metalness: 0.2, roughness: 0.6 })
104
+ const forkMat = new THREE.MeshStandardMaterial({ color: FORK_COLOR, metalness: 0.85, roughness: 0.3 })
105
+ const railMat = new THREE.MeshStandardMaterial({ color: RAIL_COLOR, metalness: 0.9, roughness: 0.3 })
106
+
107
+ // ── Floor rail ────────────────────────────────────────────────────
108
+ {
109
+ const geo = new THREE.BoxGeometry(width * 1.1, railH, height * 0.35)
110
+ const mesh = new THREE.Mesh(geo, railMat)
111
+ mesh.position.set(0, baseY + railH / 2, 0)
112
+ mesh.receiveShadow = true
113
+ this.object3d.add(mesh)
114
+ }
115
+
116
+ // ── Base trolley ──────────────────────────────────────────────────
117
+ const baseTrolleyY = baseY + railH + baseH / 2
118
+ {
119
+ const geo = new THREE.BoxGeometry(width * 0.95, baseH, height * 0.7)
120
+ const mesh = new THREE.Mesh(geo, trolleyMat)
121
+ mesh.position.set(0, baseTrolleyY, 0)
122
+ mesh.castShadow = true
123
+ mesh.receiveShadow = true
124
+ this.object3d.add(mesh)
125
+ }
126
+
127
+ // ── Control cabinet on one side of base ───────────────────────────
128
+ {
129
+ const geo = new THREE.BoxGeometry(cabW, cabH, cabD)
130
+ const cab = new THREE.Mesh(geo, cabinetMat)
131
+ cab.position.set(
132
+ -width * 0.4 + cabW / 2,
133
+ baseTrolleyY + baseH / 2 + cabH / 2,
134
+ -height * 0.25 + cabD / 2
135
+ )
136
+ cab.castShadow = true
137
+ this.object3d.add(cab)
138
+ }
139
+
140
+ // ── Status lamp ───────────────────────────────────────────────────
141
+ {
142
+ const lampR = S * 0.04
143
+ const lampH = S * 0.1
144
+ const lampMat = new THREE.MeshStandardMaterial({
145
+ color: lampOn ? emissiveColor : LAMP_OFF,
146
+ emissive: lampOn ? emissiveColor : LAMP_OFF,
147
+ emissiveIntensity: lampOn ? 1.5 : 0.2,
148
+ metalness: 0,
149
+ roughness: 0.3
150
+ })
151
+ const geo = new THREE.CylinderGeometry(lampR, lampR * 0.8, lampH, 12)
152
+ const lamp = new THREE.Mesh(geo, lampMat)
153
+ lamp.position.set(width * 0.4, baseTrolleyY + baseH / 2 + lampH / 2, 0)
154
+ this.object3d.add(lamp)
155
+ }
156
+
157
+ // ── Twin masts ────────────────────────────────────────────────────
158
+ const mastY = baseTrolleyY + baseH / 2 + mastH / 2
159
+ for (const xOff of [-mastSpacing / 2, +mastSpacing / 2]) {
160
+ const geo = new THREE.BoxGeometry(mastW, mastH, mastD)
161
+ const mesh = new THREE.Mesh(geo, mastMat)
162
+ mesh.position.set(xOff, mastY, 0)
163
+ mesh.castShadow = true
164
+ mesh.receiveShadow = true
165
+ this.object3d.add(mesh)
166
+ }
167
+
168
+ // ── Carriage (between masts) ──────────────────────────────────────
169
+ const carriageY = baseTrolleyY + baseH / 2 + carriageHeight + carriageH / 2
170
+ {
171
+ const geo = new THREE.BoxGeometry(carriageW, carriageH, carriageZ)
172
+ const mesh = new THREE.Mesh(geo, carriageMat)
173
+ mesh.position.set(0, carriageY, 0)
174
+ mesh.castShadow = true
175
+ mesh.receiveShadow = true
176
+ this.object3d.add(mesh)
177
+ }
178
+
179
+ // ── Two-prong forks (telescopic ±Z) ───────────────────────────────
180
+ // forkExtension 부호: + = +Z, - = -Z. forkExtension=0 일 때 blade 중심이 carriage 안쪽
181
+ // (= retracted, blade tip 이 carriage 앞면 근처).
182
+ const forkSign = forkExtension >= 0 ? 1 : -1
183
+ const forkBaseZ = forkSign * (carriageZ / 2 - bladeL / 2 + Math.abs(forkExtension))
184
+ const forkY = carriageY + forkLift - bladeH / 2
185
+ {
186
+ const group = new THREE.Group()
187
+ group.position.set(0, forkY, forkBaseZ)
188
+ // forkSign 으로 blade tip 방향 설정
189
+ group.rotation.y = forkSign < 0 ? Math.PI : 0
190
+
191
+ for (const xOff of [-bladeSpacing / 2, +bladeSpacing / 2]) {
192
+ const geo = new THREE.BoxGeometry(bladeW, bladeH, bladeL)
193
+ const mesh = new THREE.Mesh(geo, forkMat)
194
+ mesh.position.set(xOff, 0, 0)
195
+ mesh.castShadow = true
196
+ mesh.receiveShadow = true
197
+ group.add(mesh)
198
+ }
199
+
200
+ this.object3d.add(group)
201
+ this._forkGroup = group
202
+ this._forkTopY = bladeH / 2
203
+ this._bladeMidZ = 0
204
+ }
205
+
206
+ // ── Top frame (connects mast tops) ────────────────────────────────
207
+ const topFrameY = mastY + mastH / 2 + topFrameH / 2
208
+ {
209
+ const geo = new THREE.BoxGeometry(mastSpacing + mastW, topFrameH, height * 0.35)
210
+ const mesh = new THREE.Mesh(geo, trolleyMat)
211
+ mesh.position.set(0, topFrameY, 0)
212
+ mesh.castShadow = true
213
+ this.object3d.add(mesh)
214
+ }
215
+
216
+ // ── Top guide trolley ─────────────────────────────────────────────
217
+ const topGuideY = topFrameY + topFrameH / 2 + topGuideH / 2
218
+ {
219
+ const geo = new THREE.BoxGeometry(mastSpacing + mastW * 2, topGuideH, height * 0.3)
220
+ const mesh = new THREE.Mesh(geo, trolleyMat)
221
+ mesh.position.set(0, topGuideY, 0)
222
+ mesh.castShadow = true
223
+ this.object3d.add(mesh)
224
+ }
225
+
226
+ // ── Ceiling rail ──────────────────────────────────────────────────
227
+ {
228
+ const geo = new THREE.BoxGeometry(width * 1.1, railH, height * 0.3)
229
+ const mesh = new THREE.Mesh(geo, railMat)
230
+ mesh.position.set(0, topGuideY + topGuideH / 2 + railH / 2, 0)
231
+ this.object3d.add(mesh)
232
+ }
233
+ }
234
+
235
+ getCarriageFrame(): THREE.Object3D | undefined {
236
+ return this._forkGroup ?? this.object3d
237
+ }
238
+
239
+ get platformTopY(): number {
240
+ return this._forkTopY
241
+ }
242
+
243
+ get bladeMidZ(): number {
244
+ return this._bladeMidZ
245
+ }
246
+
247
+ updateDimension() {}
248
+
249
+ onchange(after: Record<string, unknown>, before: Record<string, unknown>) {
250
+ if (
251
+ 'width' in after ||
252
+ 'height' in after ||
253
+ 'depth' in after ||
254
+ 'carriageHeight' in after ||
255
+ 'forkLength' in after ||
256
+ 'forkExtension' in after ||
257
+ 'forkLift' in after ||
258
+ 'status' in after ||
259
+ 'bodyColor' in after ||
260
+ 'lampEmissive' in after
261
+ ) {
262
+ this.update()
263
+ return
264
+ }
265
+ super.onchange(after, before)
266
+ }
267
+
268
+ updateAlpha() {}
269
+ }
270
+
271
+ function numOr(v: unknown, dflt: number): number {
272
+ return typeof v === 'number' && Number.isFinite(v) ? v : dflt
273
+ }