@operato/scene-transport 10.0.0-beta.22 → 10.0.0-beta.25

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 (63) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/agv-3d.js +29 -6
  3. package/dist/agv-3d.js.map +1 -1
  4. package/dist/agv.d.ts +35 -2
  5. package/dist/agv.js +64 -3
  6. package/dist/agv.js.map +1 -1
  7. package/dist/forklift-3d-layout.d.ts +37 -0
  8. package/dist/forklift-3d-layout.js +74 -0
  9. package/dist/forklift-3d-layout.js.map +1 -0
  10. package/dist/forklift-3d.d.ts +14 -1
  11. package/dist/forklift-3d.js +155 -137
  12. package/dist/forklift-3d.js.map +1 -1
  13. package/dist/forklift.d.ts +94 -13
  14. package/dist/forklift.js +204 -36
  15. package/dist/forklift.js.map +1 -1
  16. package/dist/generic-transport-3d.d.ts +22 -0
  17. package/dist/generic-transport-3d.js +84 -0
  18. package/dist/generic-transport-3d.js.map +1 -0
  19. package/dist/generic-transport-types.d.ts +60 -0
  20. package/dist/generic-transport-types.js +8 -0
  21. package/dist/generic-transport-types.js.map +1 -0
  22. package/dist/generic-transport.d.ts +49 -0
  23. package/dist/generic-transport.js +193 -0
  24. package/dist/generic-transport.js.map +1 -0
  25. package/dist/index.d.ts +3 -0
  26. package/dist/index.js +4 -0
  27. package/dist/index.js.map +1 -1
  28. package/dist/templates/index.d.ts +39 -0
  29. package/dist/templates/index.js +29 -8
  30. package/dist/templates/index.js.map +1 -1
  31. package/dist/tugger-3d.js +5 -1
  32. package/dist/tugger-3d.js.map +1 -1
  33. package/dist/tugger.d.ts +27 -2
  34. package/dist/tugger.js +50 -3
  35. package/dist/tugger.js.map +1 -1
  36. package/dist/worker-3d.js +6 -1
  37. package/dist/worker-3d.js.map +1 -1
  38. package/dist/worker.d.ts +24 -2
  39. package/dist/worker.js +47 -3
  40. package/dist/worker.js.map +1 -1
  41. package/package.json +9 -4
  42. package/src/agv-3d.ts +30 -6
  43. package/src/agv.ts +81 -2
  44. package/src/forklift-3d-layout.ts +92 -0
  45. package/src/forklift-3d.ts +158 -146
  46. package/src/forklift.ts +235 -35
  47. package/src/generic-transport-3d.ts +89 -0
  48. package/src/generic-transport-types.ts +57 -0
  49. package/src/generic-transport.ts +235 -0
  50. package/src/index.ts +11 -0
  51. package/src/templates/index.ts +30 -8
  52. package/src/tugger-3d.ts +5 -1
  53. package/src/tugger.ts +65 -2
  54. package/src/worker-3d.ts +6 -1
  55. package/src/worker.ts +62 -2
  56. package/test/test-forklift-3d-direction.ts +339 -0
  57. package/translations/en.json +3 -1
  58. package/translations/ja.json +3 -1
  59. package/translations/ko.json +3 -1
  60. package/translations/ms.json +3 -1
  61. package/translations/zh.json +3 -1
  62. package/tsconfig.json +2 -1
  63. package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,35 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [10.0.0-beta.25](https://github.com/things-scene/operato-scene/compare/v10.0.0-beta.24...v10.0.0-beta.25) (2026-05-03)
7
+
8
+ **Note:** Version bump only for package @operato/scene-transport
9
+
10
+
11
+
12
+
13
+
14
+ ## [10.0.0-beta.24](https://github.com/things-scene/operato-scene/compare/v10.0.0-beta.23...v10.0.0-beta.24) (2026-05-02)
15
+
16
+
17
+ ### :rocket: New Features
18
+
19
+ * **transport:** Forklift/GenericTransport adopt Mover (pick/place API) ([770da57](https://github.com/things-scene/operato-scene/commit/770da573cab5724a422d6700f9d11e2b772a7849))
20
+ * **transport:** GenericTransport (GLB-based) + transportable Forklift ([d3e360b](https://github.com/things-scene/operato-scene/commit/d3e360b9c20f696a984f2914bd5fbec7a2d3b868))
21
+
22
+
23
+ ### :bug: Bug Fix
24
+
25
+ * **scene:** Container → ContainerAbstract for 3D-only components ([89bdea7](https://github.com/things-scene/operato-scene/commit/89bdea73b37247601932b92692ea5d5e7780976c))
26
+ * **transport:** use effectiveDepth in 3D builds + AGV state-overlay z-fight margins ([1f5e884](https://github.com/things-scene/operato-scene/commit/1f5e884862335d9c3169f7bb856a50939ecf200b))
27
+
28
+
29
+ ### :mega: Other
30
+
31
+ * tune default template sizes for board overview ([582232a](https://github.com/things-scene/operato-scene/commit/582232ae078631e13754ba2e06320e211c3a1de1))
32
+
33
+
34
+
6
35
  ## [10.0.0-beta.22](https://github.com/things-scene/operato-scene/compare/v10.0.0-beta.21...v10.0.0-beta.22) (2026-04-30)
7
36
 
8
37
 
package/dist/agv-3d.js CHANGED
@@ -33,7 +33,13 @@ const CHARGE_COPPER = 0xc77a00;
33
33
  export class Agv3D extends RealObjectGroup {
34
34
  build() {
35
35
  super.build();
36
- const { width, height, depth = 0 } = this.component.state;
36
+ const { width, height } = this.component.state;
37
+ // Resolve depth via the NaN-safe getter so a freshly-created AGV (template
38
+ // doesn't carry `depth`, Placeable.added writes it via setState which races
39
+ // with the first build cycle) renders with the Placeable archetype default
40
+ // instead of the destructure fallback. Hard-coded fallback was 0 → invisible
41
+ // first frame until the user toggled 3D mode and a fresh build read state.
42
+ const depth = this.effectiveDepth;
37
43
  const bodyColor = this.component.state.bodyColor || '#999';
38
44
  const emissiveColor = this.component.state.lampEmissive || '#222222';
39
45
  const status = this.component.state.status;
@@ -42,6 +48,14 @@ export class Agv3D extends RealObjectGroup {
42
48
  const deckH = depth * 0.05;
43
49
  const wheelR = chassisH * 0.30;
44
50
  const baseY = -depth / 2;
51
+ // Z-fight margin — pushes status-driven overlay meshes (LED strips, body
52
+ // color tint band) slightly proud of the chassis / deck surfaces they sit
53
+ // on. Without this, a coplanar overlay flickers against the body underneath
54
+ // because both surfaces resolve to the same depth-buffer slot, and the
55
+ // emissive overlay is exactly the part the user uses to read AGV state.
56
+ // Sized by AGV scale so it stays sub-perceptual on big AGVs and still
57
+ // beats z-buffer precision on small ones.
58
+ const zFightMargin = Math.max(0.5, Math.min(width, height) * 0.003);
45
59
  // ── Rounded chassis (volumetric — the Kiva AGV signature) ────────
46
60
  const chassisRadius = Math.min(width, height) * 0.10;
47
61
  const chassisGeo = new RoundedBoxGeometry(width * 0.95, chassisH, height * 0.95, 4, chassisRadius);
@@ -69,9 +83,12 @@ export class Agv3D extends RealObjectGroup {
69
83
  liftMesh.position.set(0, baseY + chassisH + deckH + liftH / 2, 0);
70
84
  liftMesh.castShadow = true;
71
85
  this.object3d.add(liftMesh);
72
- // Body color band on lift rim (status hint)
86
+ // Body color band on lift rim (status hint).
87
+ // Radius takes max(3% relative, zFightMargin absolute) so a small AGV
88
+ // doesn't collapse the gap below depth-buffer precision.
73
89
  const tintH = liftH * 0.3;
74
- const tintGeo = new THREE.CylinderGeometry(liftR * 1.03, liftR * 1.03, tintH, 24, 1, true);
90
+ const tintRadius = liftR + Math.max(liftR * 0.03, zFightMargin);
91
+ const tintGeo = new THREE.CylinderGeometry(tintRadius, tintRadius, tintH, 24, 1, true);
75
92
  const tintMesh = new THREE.Mesh(tintGeo, new THREE.MeshStandardMaterial({
76
93
  color: bodyColor,
77
94
  side: THREE.DoubleSide,
@@ -80,9 +97,15 @@ export class Agv3D extends RealObjectGroup {
80
97
  metalness: 0.1,
81
98
  roughness: 0.6
82
99
  }));
83
- tintMesh.position.set(0, baseY + chassisH + deckH + tintH / 2, 0);
100
+ // Lift slightly above deck so the bottom edge doesn't graze deck top.
101
+ tintMesh.position.set(0, baseY + chassisH + deckH + tintH / 2 + zFightMargin, 0);
84
102
  this.object3d.add(tintMesh);
85
103
  // ── LED strip (4 sides, rounded corners follow chassis bevel) ────
104
+ // Position so the strip's outer face sits *past* the chassis surface by
105
+ // zFightMargin — the original placement put it flush, which guaranteed
106
+ // a depth-buffer tie with the chassis side and visibly flickered exactly
107
+ // on the part used to read AGV status. Inner face stays inside the
108
+ // chassis (occluded), so the strip still reads as flush-mounted.
86
109
  const stripH = chassisH * 0.10;
87
110
  const stripT = Math.min(width, height) * 0.015;
88
111
  const stripY = baseY + chassisH * 0.55;
@@ -96,13 +119,13 @@ export class Agv3D extends RealObjectGroup {
96
119
  for (const zSign of [-1, 1]) {
97
120
  const stripGeo = new THREE.BoxGeometry(width * 0.85, stripH, stripT);
98
121
  const stripMesh = new THREE.Mesh(stripGeo, stripMaterial);
99
- stripMesh.position.set(0, stripY, zSign * (height * 0.475 - stripT / 2));
122
+ stripMesh.position.set(0, stripY, zSign * (height * 0.475 - stripT / 2 + zFightMargin));
100
123
  this.object3d.add(stripMesh);
101
124
  }
102
125
  for (const xSign of [-1, 1]) {
103
126
  const stripGeo = new THREE.BoxGeometry(stripT, stripH, height * 0.85);
104
127
  const stripMesh = new THREE.Mesh(stripGeo, stripMaterial);
105
- stripMesh.position.set(xSign * (width * 0.475 - stripT / 2), stripY, 0);
128
+ stripMesh.position.set(xSign * (width * 0.475 - stripT / 2 + zFightMargin), stripY, 0);
106
129
  this.object3d.add(stripMesh);
107
130
  }
108
131
  // ── Safety bumpers (front + rear) ────────────────────────────────
@@ -1 +1 @@
1
- {"version":3,"file":"agv-3d.js","sourceRoot":"","sources":["../src/agv-3d.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * Agv 3D — payload (Kiva-style) automated guided vehicle.\n *\n * LO-POLY but with **rounded volume** — the Kiva AGV's signature is a\n * pill-shaped, low-slung chassis with rounded corners, not a flat box.\n *\n * Structure:\n * - rounded-box chassis (volumetric, with bevels — the visual identity)\n * - top deck with raised lift pad at center (Kiva-style under-shelf lift)\n * - LED strip running around the perimeter\n * - safety bumpers (front + rear, hi-vis with black corners)\n * - LiDAR sensor: cylindrical body + transparent dome top\n * - 4 wheel covers (fender bumps integrated into chassis sides)\n * - charging contacts at rear\n * - corner indicator lamps on deck\n */\n\nimport * as THREE from 'three'\nimport * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js'\nimport { RoundedBoxGeometry } from 'three/examples/jsm/geometries/RoundedBoxGeometry.js'\nimport { RealObjectGroup } from '@hatiolab/things-scene'\n\nconst CHASSIS_COLOR_DARK = 0x444444\nconst DECK_COLOR = 0x666677\nconst LIFT_PAD_COLOR = 0x4a4a55\nconst TIRE_COLOR = 0x202020\nconst WHEEL_COVER_COLOR = 0x3a3a3a\nconst LIDAR_BODY = 0x222233\nconst LIDAR_DOME = 0x445566\nconst BUMPER_COLOR = 0xeeaa00\nconst BUMPER_BLACK = 0x111111\nconst CHARGE_COPPER = 0xc77a00\n\nexport class Agv3D extends RealObjectGroup {\n build() {\n super.build()\n\n const { width, height, depth = 0 } = this.component.state\n const bodyColor = (this.component.state.bodyColor as string) || '#999'\n const emissiveColor = (this.component.state.lampEmissive as string) || '#222222'\n const status = this.component.state.status\n const lampIntensity = status && status !== 'idle' ? 1.5 : 0.2\n\n const chassisH = depth * 0.85\n const deckH = depth * 0.05\n const wheelR = chassisH * 0.30\n const baseY = -depth / 2\n\n // ── Rounded chassis (volumetric — the Kiva AGV signature) ────────\n const chassisRadius = Math.min(width, height) * 0.10\n const chassisGeo = new RoundedBoxGeometry(width * 0.95, chassisH, height * 0.95, 4, chassisRadius)\n const chassisMesh = new THREE.Mesh(\n chassisGeo,\n new THREE.MeshStandardMaterial({\n color: CHASSIS_COLOR_DARK,\n metalness: 0.4,\n roughness: 0.5\n })\n )\n chassisMesh.position.set(0, baseY + chassisH / 2, 0)\n chassisMesh.castShadow = true\n chassisMesh.receiveShadow = true\n this.object3d.add(chassisMesh)\n\n // ── Top deck (rounded slab) ───────────────────────────────────────\n const deckGeo = new RoundedBoxGeometry(width * 0.95, deckH, height * 0.95, 2, chassisRadius * 0.5)\n const deckMesh = new THREE.Mesh(\n deckGeo,\n new THREE.MeshStandardMaterial({ color: DECK_COLOR, metalness: 0.5, roughness: 0.4 })\n )\n deckMesh.position.set(0, baseY + chassisH + deckH / 2, 0)\n deckMesh.castShadow = true\n deckMesh.receiveShadow = true\n this.object3d.add(deckMesh)\n\n // ── Lift mechanism (round pad — Kiva-style under-shelf lift) ─────\n const liftR = Math.min(width, height) * 0.30\n const liftH = deckH * 1.5\n const liftGeo = new THREE.CylinderGeometry(liftR, liftR * 1.05, liftH, 24)\n const liftMesh = new THREE.Mesh(\n liftGeo,\n new THREE.MeshStandardMaterial({ color: LIFT_PAD_COLOR, metalness: 0.6, roughness: 0.35 })\n )\n liftMesh.position.set(0, baseY + chassisH + deckH + liftH / 2, 0)\n liftMesh.castShadow = true\n this.object3d.add(liftMesh)\n\n // Body color band on lift rim (status hint)\n const tintH = liftH * 0.3\n const tintGeo = new THREE.CylinderGeometry(liftR * 1.03, liftR * 1.03, tintH, 24, 1, true)\n const tintMesh = new THREE.Mesh(\n tintGeo,\n new THREE.MeshStandardMaterial({\n color: bodyColor,\n side: THREE.DoubleSide,\n transparent: true,\n opacity: 0.7,\n metalness: 0.1,\n roughness: 0.6\n })\n )\n tintMesh.position.set(0, baseY + chassisH + deckH + tintH / 2, 0)\n this.object3d.add(tintMesh)\n\n // ── LED strip (4 sides, rounded corners follow chassis bevel) ────\n const stripH = chassisH * 0.10\n const stripT = Math.min(width, height) * 0.015\n const stripY = baseY + chassisH * 0.55\n const stripMaterial = new THREE.MeshStandardMaterial({\n color: emissiveColor,\n emissive: emissiveColor,\n emissiveIntensity: lampIntensity,\n metalness: 0.1,\n roughness: 0.4\n })\n for (const zSign of [-1, 1]) {\n const stripGeo = new THREE.BoxGeometry(width * 0.85, stripH, stripT)\n const stripMesh = new THREE.Mesh(stripGeo, stripMaterial)\n stripMesh.position.set(0, stripY, zSign * (height * 0.475 - stripT / 2))\n this.object3d.add(stripMesh)\n }\n for (const xSign of [-1, 1]) {\n const stripGeo = new THREE.BoxGeometry(stripT, stripH, height * 0.85)\n const stripMesh = new THREE.Mesh(stripGeo, stripMaterial)\n stripMesh.position.set(xSign * (width * 0.475 - stripT / 2), stripY, 0)\n this.object3d.add(stripMesh)\n }\n\n // ── Safety bumpers (front + rear) ────────────────────────────────\n const bumperH = chassisH * 0.18\n const bumperT = Math.min(width, height) * 0.025\n const bumperY = baseY + bumperH / 2 + wheelR * 0.5\n const bumperMaterial = new THREE.MeshStandardMaterial({\n color: BUMPER_COLOR,\n metalness: 0.1,\n roughness: 0.6\n })\n const bumperBlackMaterial = new THREE.MeshStandardMaterial({\n color: BUMPER_BLACK,\n metalness: 0.2,\n roughness: 0.7\n })\n for (const zSign of [-1, 1]) {\n const yellow = new RoundedBoxGeometry(width * 0.7, bumperH, bumperT, 2, bumperT * 0.4)\n const yMesh = new THREE.Mesh(yellow, bumperMaterial)\n yMesh.position.set(0, bumperY, zSign * (height * 0.475 + bumperT / 2))\n this.object3d.add(yMesh)\n for (const xSign of [-1, 1]) {\n const black = new RoundedBoxGeometry(width * 0.13, bumperH, bumperT, 2, bumperT * 0.4)\n const bMesh = new THREE.Mesh(black, bumperBlackMaterial)\n bMesh.position.set(xSign * (width * 0.7 / 2 + width * 0.065), bumperY, zSign * (height * 0.475 + bumperT / 2))\n this.object3d.add(bMesh)\n }\n }\n\n // ── LiDAR sensor (cylinder body + transparent dome) ──────────────\n const lidarR = Math.min(width, height) * 0.10\n const lidarBodyH = lidarR * 0.7\n const lidarBodyGeo = new THREE.CylinderGeometry(lidarR, lidarR * 1.1, lidarBodyH, 16)\n const lidarBodyMesh = new THREE.Mesh(\n lidarBodyGeo,\n new THREE.MeshStandardMaterial({ color: LIDAR_BODY, metalness: 0.6, roughness: 0.4 })\n )\n lidarBodyMesh.position.set(0, baseY + chassisH + lidarBodyH / 2, height * 0.35)\n lidarBodyMesh.castShadow = true\n this.object3d.add(lidarBodyMesh)\n\n const domeGeo = new THREE.SphereGeometry(lidarR * 0.95, 24, 16, 0, Math.PI * 2, 0, Math.PI / 2)\n const domeMesh = new THREE.Mesh(\n domeGeo,\n new THREE.MeshStandardMaterial({\n color: LIDAR_DOME,\n metalness: 0.3,\n roughness: 0.2,\n transparent: true,\n opacity: 0.8\n })\n )\n domeMesh.position.set(0, baseY + chassisH + lidarBodyH, height * 0.35)\n this.object3d.add(domeMesh)\n\n // Status hint on LiDAR top\n const hintR = lidarR * 0.25\n const hintMesh = new THREE.Mesh(\n new THREE.SphereGeometry(hintR, 24, 8),\n new THREE.MeshStandardMaterial({\n color: emissiveColor,\n emissive: emissiveColor,\n emissiveIntensity: lampIntensity,\n roughness: 0.3\n })\n )\n hintMesh.position.set(0, baseY + chassisH + lidarBodyH + lidarR * 0.85, height * 0.35)\n this.object3d.add(hintMesh)\n\n // ── Wheels with covers ───────────────────────────────────────────\n const wheelW = width * 0.07\n const tireMaterial = new THREE.MeshStandardMaterial({ color: TIRE_COLOR, roughness: 0.95 })\n const coverMaterial = new THREE.MeshStandardMaterial({\n color: WHEEL_COVER_COLOR,\n metalness: 0.5,\n roughness: 0.6\n })\n\n const tireGeos: THREE.BufferGeometry[] = []\n for (const xSign of [-1, 1]) {\n for (const zSign of [-1, 1]) {\n const tire = new THREE.CylinderGeometry(wheelR, wheelR, wheelW, 24)\n tire.rotateZ(Math.PI / 2)\n tire.translate(xSign * width * 0.42, baseY + wheelR, zSign * height * 0.32)\n tireGeos.push(tire)\n // Rounded fender cover\n const cover = new RoundedBoxGeometry(wheelW * 1.5, wheelR * 1.4, wheelR * 1.6, 2, wheelR * 0.25)\n cover.translate(xSign * (width * 0.42 + wheelW * 0.4), baseY + wheelR * 1.2, zSign * height * 0.32)\n const coverMesh = new THREE.Mesh(cover, coverMaterial)\n coverMesh.castShadow = true\n this.object3d.add(coverMesh)\n }\n }\n const tireMesh = new THREE.Mesh(BufferGeometryUtils.mergeGeometries(tireGeos), tireMaterial)\n tireMesh.castShadow = true\n this.object3d.add(tireMesh)\n\n // ── Charging contacts (rear) ─────────────────────────────────────\n const chargeMaterial = new THREE.MeshStandardMaterial({\n color: CHARGE_COPPER,\n metalness: 0.9,\n roughness: 0.2\n })\n const chargeT = wheelR * 0.15\n const chargeH = wheelR * 0.6\n const chargeW = width * 0.08\n for (const xSign of [-1, 1]) {\n const chargeGeo = new RoundedBoxGeometry(chargeW, chargeH, chargeT, 1, chargeT * 0.3)\n const chargeMesh = new THREE.Mesh(chargeGeo, chargeMaterial)\n chargeMesh.position.set(xSign * width * 0.10, baseY + chargeH / 2 + wheelR * 0.2, -height * 0.475 - chargeT / 2)\n this.object3d.add(chargeMesh)\n }\n\n // ── Corner indicator lamps ───────────────────────────────────────\n const cornerR = Math.min(width, height) * 0.022\n for (const xSign of [-1, 1]) {\n for (const zSign of [-1, 1]) {\n const cornerMesh = new THREE.Mesh(\n new THREE.SphereGeometry(cornerR, 24, 6),\n new THREE.MeshStandardMaterial({\n color: emissiveColor,\n emissive: emissiveColor,\n emissiveIntensity: lampIntensity * 0.6,\n roughness: 0.3\n })\n )\n cornerMesh.position.set(\n xSign * (width * 0.42),\n baseY + chassisH + deckH + cornerR * 0.6,\n zSign * (height * 0.42)\n )\n this.object3d.add(cornerMesh)\n }\n }\n }\n\n updateDimension() {}\n\n onchange(after: Record<string, unknown>, before: Record<string, unknown>) {\n if (\n 'status' in after ||\n 'bodyColor' in after ||\n 'lampEmissive' in after ||\n 'width' in after ||\n 'height' in after ||\n 'depth' in after\n ) {\n this.update()\n return\n }\n super.onchange(after, before)\n }\n\n updateAlpha() {}\n}\n"]}
1
+ {"version":3,"file":"agv-3d.js","sourceRoot":"","sources":["../src/agv-3d.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * Agv 3D — payload (Kiva-style) automated guided vehicle.\n *\n * LO-POLY but with **rounded volume** — the Kiva AGV's signature is a\n * pill-shaped, low-slung chassis with rounded corners, not a flat box.\n *\n * Structure:\n * - rounded-box chassis (volumetric, with bevels — the visual identity)\n * - top deck with raised lift pad at center (Kiva-style under-shelf lift)\n * - LED strip running around the perimeter\n * - safety bumpers (front + rear, hi-vis with black corners)\n * - LiDAR sensor: cylindrical body + transparent dome top\n * - 4 wheel covers (fender bumps integrated into chassis sides)\n * - charging contacts at rear\n * - corner indicator lamps on deck\n */\n\nimport * as THREE from 'three'\nimport * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js'\nimport { RoundedBoxGeometry } from 'three/examples/jsm/geometries/RoundedBoxGeometry.js'\nimport { RealObjectGroup } from '@hatiolab/things-scene'\n\nconst CHASSIS_COLOR_DARK = 0x444444\nconst DECK_COLOR = 0x666677\nconst LIFT_PAD_COLOR = 0x4a4a55\nconst TIRE_COLOR = 0x202020\nconst WHEEL_COVER_COLOR = 0x3a3a3a\nconst LIDAR_BODY = 0x222233\nconst LIDAR_DOME = 0x445566\nconst BUMPER_COLOR = 0xeeaa00\nconst BUMPER_BLACK = 0x111111\nconst CHARGE_COPPER = 0xc77a00\n\nexport class Agv3D extends RealObjectGroup {\n build() {\n super.build()\n\n const { width, height } = this.component.state\n // Resolve depth via the NaN-safe getter so a freshly-created AGV (template\n // doesn't carry `depth`, Placeable.added writes it via setState which races\n // with the first build cycle) renders with the Placeable archetype default\n // instead of the destructure fallback. Hard-coded fallback was 0 → invisible\n // first frame until the user toggled 3D mode and a fresh build read state.\n const depth = this.effectiveDepth\n const bodyColor = (this.component.state.bodyColor as string) || '#999'\n const emissiveColor = (this.component.state.lampEmissive as string) || '#222222'\n const status = this.component.state.status\n const lampIntensity = status && status !== 'idle' ? 1.5 : 0.2\n\n const chassisH = depth * 0.85\n const deckH = depth * 0.05\n const wheelR = chassisH * 0.30\n const baseY = -depth / 2\n\n // Z-fight margin — pushes status-driven overlay meshes (LED strips, body\n // color tint band) slightly proud of the chassis / deck surfaces they sit\n // on. Without this, a coplanar overlay flickers against the body underneath\n // because both surfaces resolve to the same depth-buffer slot, and the\n // emissive overlay is exactly the part the user uses to read AGV state.\n // Sized by AGV scale so it stays sub-perceptual on big AGVs and still\n // beats z-buffer precision on small ones.\n const zFightMargin = Math.max(0.5, Math.min(width, height) * 0.003)\n\n // ── Rounded chassis (volumetric — the Kiva AGV signature) ────────\n const chassisRadius = Math.min(width, height) * 0.10\n const chassisGeo = new RoundedBoxGeometry(width * 0.95, chassisH, height * 0.95, 4, chassisRadius)\n const chassisMesh = new THREE.Mesh(\n chassisGeo,\n new THREE.MeshStandardMaterial({\n color: CHASSIS_COLOR_DARK,\n metalness: 0.4,\n roughness: 0.5\n })\n )\n chassisMesh.position.set(0, baseY + chassisH / 2, 0)\n chassisMesh.castShadow = true\n chassisMesh.receiveShadow = true\n this.object3d.add(chassisMesh)\n\n // ── Top deck (rounded slab) ───────────────────────────────────────\n const deckGeo = new RoundedBoxGeometry(width * 0.95, deckH, height * 0.95, 2, chassisRadius * 0.5)\n const deckMesh = new THREE.Mesh(\n deckGeo,\n new THREE.MeshStandardMaterial({ color: DECK_COLOR, metalness: 0.5, roughness: 0.4 })\n )\n deckMesh.position.set(0, baseY + chassisH + deckH / 2, 0)\n deckMesh.castShadow = true\n deckMesh.receiveShadow = true\n this.object3d.add(deckMesh)\n\n // ── Lift mechanism (round pad — Kiva-style under-shelf lift) ─────\n const liftR = Math.min(width, height) * 0.30\n const liftH = deckH * 1.5\n const liftGeo = new THREE.CylinderGeometry(liftR, liftR * 1.05, liftH, 24)\n const liftMesh = new THREE.Mesh(\n liftGeo,\n new THREE.MeshStandardMaterial({ color: LIFT_PAD_COLOR, metalness: 0.6, roughness: 0.35 })\n )\n liftMesh.position.set(0, baseY + chassisH + deckH + liftH / 2, 0)\n liftMesh.castShadow = true\n this.object3d.add(liftMesh)\n\n // Body color band on lift rim (status hint).\n // Radius takes max(3% relative, zFightMargin absolute) so a small AGV\n // doesn't collapse the gap below depth-buffer precision.\n const tintH = liftH * 0.3\n const tintRadius = liftR + Math.max(liftR * 0.03, zFightMargin)\n const tintGeo = new THREE.CylinderGeometry(tintRadius, tintRadius, tintH, 24, 1, true)\n const tintMesh = new THREE.Mesh(\n tintGeo,\n new THREE.MeshStandardMaterial({\n color: bodyColor,\n side: THREE.DoubleSide,\n transparent: true,\n opacity: 0.7,\n metalness: 0.1,\n roughness: 0.6\n })\n )\n // Lift slightly above deck so the bottom edge doesn't graze deck top.\n tintMesh.position.set(0, baseY + chassisH + deckH + tintH / 2 + zFightMargin, 0)\n this.object3d.add(tintMesh)\n\n // ── LED strip (4 sides, rounded corners follow chassis bevel) ────\n // Position so the strip's outer face sits *past* the chassis surface by\n // zFightMargin — the original placement put it flush, which guaranteed\n // a depth-buffer tie with the chassis side and visibly flickered exactly\n // on the part used to read AGV status. Inner face stays inside the\n // chassis (occluded), so the strip still reads as flush-mounted.\n const stripH = chassisH * 0.10\n const stripT = Math.min(width, height) * 0.015\n const stripY = baseY + chassisH * 0.55\n const stripMaterial = new THREE.MeshStandardMaterial({\n color: emissiveColor,\n emissive: emissiveColor,\n emissiveIntensity: lampIntensity,\n metalness: 0.1,\n roughness: 0.4\n })\n for (const zSign of [-1, 1]) {\n const stripGeo = new THREE.BoxGeometry(width * 0.85, stripH, stripT)\n const stripMesh = new THREE.Mesh(stripGeo, stripMaterial)\n stripMesh.position.set(0, stripY, zSign * (height * 0.475 - stripT / 2 + zFightMargin))\n this.object3d.add(stripMesh)\n }\n for (const xSign of [-1, 1]) {\n const stripGeo = new THREE.BoxGeometry(stripT, stripH, height * 0.85)\n const stripMesh = new THREE.Mesh(stripGeo, stripMaterial)\n stripMesh.position.set(xSign * (width * 0.475 - stripT / 2 + zFightMargin), stripY, 0)\n this.object3d.add(stripMesh)\n }\n\n // ── Safety bumpers (front + rear) ────────────────────────────────\n const bumperH = chassisH * 0.18\n const bumperT = Math.min(width, height) * 0.025\n const bumperY = baseY + bumperH / 2 + wheelR * 0.5\n const bumperMaterial = new THREE.MeshStandardMaterial({\n color: BUMPER_COLOR,\n metalness: 0.1,\n roughness: 0.6\n })\n const bumperBlackMaterial = new THREE.MeshStandardMaterial({\n color: BUMPER_BLACK,\n metalness: 0.2,\n roughness: 0.7\n })\n for (const zSign of [-1, 1]) {\n const yellow = new RoundedBoxGeometry(width * 0.7, bumperH, bumperT, 2, bumperT * 0.4)\n const yMesh = new THREE.Mesh(yellow, bumperMaterial)\n yMesh.position.set(0, bumperY, zSign * (height * 0.475 + bumperT / 2))\n this.object3d.add(yMesh)\n for (const xSign of [-1, 1]) {\n const black = new RoundedBoxGeometry(width * 0.13, bumperH, bumperT, 2, bumperT * 0.4)\n const bMesh = new THREE.Mesh(black, bumperBlackMaterial)\n bMesh.position.set(xSign * (width * 0.7 / 2 + width * 0.065), bumperY, zSign * (height * 0.475 + bumperT / 2))\n this.object3d.add(bMesh)\n }\n }\n\n // ── LiDAR sensor (cylinder body + transparent dome) ──────────────\n const lidarR = Math.min(width, height) * 0.10\n const lidarBodyH = lidarR * 0.7\n const lidarBodyGeo = new THREE.CylinderGeometry(lidarR, lidarR * 1.1, lidarBodyH, 16)\n const lidarBodyMesh = new THREE.Mesh(\n lidarBodyGeo,\n new THREE.MeshStandardMaterial({ color: LIDAR_BODY, metalness: 0.6, roughness: 0.4 })\n )\n lidarBodyMesh.position.set(0, baseY + chassisH + lidarBodyH / 2, height * 0.35)\n lidarBodyMesh.castShadow = true\n this.object3d.add(lidarBodyMesh)\n\n const domeGeo = new THREE.SphereGeometry(lidarR * 0.95, 24, 16, 0, Math.PI * 2, 0, Math.PI / 2)\n const domeMesh = new THREE.Mesh(\n domeGeo,\n new THREE.MeshStandardMaterial({\n color: LIDAR_DOME,\n metalness: 0.3,\n roughness: 0.2,\n transparent: true,\n opacity: 0.8\n })\n )\n domeMesh.position.set(0, baseY + chassisH + lidarBodyH, height * 0.35)\n this.object3d.add(domeMesh)\n\n // Status hint on LiDAR top\n const hintR = lidarR * 0.25\n const hintMesh = new THREE.Mesh(\n new THREE.SphereGeometry(hintR, 24, 8),\n new THREE.MeshStandardMaterial({\n color: emissiveColor,\n emissive: emissiveColor,\n emissiveIntensity: lampIntensity,\n roughness: 0.3\n })\n )\n hintMesh.position.set(0, baseY + chassisH + lidarBodyH + lidarR * 0.85, height * 0.35)\n this.object3d.add(hintMesh)\n\n // ── Wheels with covers ───────────────────────────────────────────\n const wheelW = width * 0.07\n const tireMaterial = new THREE.MeshStandardMaterial({ color: TIRE_COLOR, roughness: 0.95 })\n const coverMaterial = new THREE.MeshStandardMaterial({\n color: WHEEL_COVER_COLOR,\n metalness: 0.5,\n roughness: 0.6\n })\n\n const tireGeos: THREE.BufferGeometry[] = []\n for (const xSign of [-1, 1]) {\n for (const zSign of [-1, 1]) {\n const tire = new THREE.CylinderGeometry(wheelR, wheelR, wheelW, 24)\n tire.rotateZ(Math.PI / 2)\n tire.translate(xSign * width * 0.42, baseY + wheelR, zSign * height * 0.32)\n tireGeos.push(tire)\n // Rounded fender cover\n const cover = new RoundedBoxGeometry(wheelW * 1.5, wheelR * 1.4, wheelR * 1.6, 2, wheelR * 0.25)\n cover.translate(xSign * (width * 0.42 + wheelW * 0.4), baseY + wheelR * 1.2, zSign * height * 0.32)\n const coverMesh = new THREE.Mesh(cover, coverMaterial)\n coverMesh.castShadow = true\n this.object3d.add(coverMesh)\n }\n }\n const tireMesh = new THREE.Mesh(BufferGeometryUtils.mergeGeometries(tireGeos), tireMaterial)\n tireMesh.castShadow = true\n this.object3d.add(tireMesh)\n\n // ── Charging contacts (rear) ─────────────────────────────────────\n const chargeMaterial = new THREE.MeshStandardMaterial({\n color: CHARGE_COPPER,\n metalness: 0.9,\n roughness: 0.2\n })\n const chargeT = wheelR * 0.15\n const chargeH = wheelR * 0.6\n const chargeW = width * 0.08\n for (const xSign of [-1, 1]) {\n const chargeGeo = new RoundedBoxGeometry(chargeW, chargeH, chargeT, 1, chargeT * 0.3)\n const chargeMesh = new THREE.Mesh(chargeGeo, chargeMaterial)\n chargeMesh.position.set(xSign * width * 0.10, baseY + chargeH / 2 + wheelR * 0.2, -height * 0.475 - chargeT / 2)\n this.object3d.add(chargeMesh)\n }\n\n // ── Corner indicator lamps ───────────────────────────────────────\n const cornerR = Math.min(width, height) * 0.022\n for (const xSign of [-1, 1]) {\n for (const zSign of [-1, 1]) {\n const cornerMesh = new THREE.Mesh(\n new THREE.SphereGeometry(cornerR, 24, 6),\n new THREE.MeshStandardMaterial({\n color: emissiveColor,\n emissive: emissiveColor,\n emissiveIntensity: lampIntensity * 0.6,\n roughness: 0.3\n })\n )\n cornerMesh.position.set(\n xSign * (width * 0.42),\n baseY + chassisH + deckH + cornerR * 0.6,\n zSign * (height * 0.42)\n )\n this.object3d.add(cornerMesh)\n }\n }\n }\n\n updateDimension() {}\n\n onchange(after: Record<string, unknown>, before: Record<string, unknown>) {\n if (\n 'status' in after ||\n 'bodyColor' in after ||\n 'lampEmissive' in after ||\n 'width' in after ||\n 'height' in after ||\n 'depth' in after\n ) {\n this.update()\n return\n }\n super.onchange(after, before)\n }\n\n updateAlpha() {}\n}\n"]}
package/dist/agv.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Component, ComponentNature, RealObject } from '@hatiolab/things-scene';
2
- import { type Alignment, type Heights, type LegendBinding, type PlacementArchetype } from '@operato/scene-base';
2
+ import { type Alignment, type CarrierAttachPoint, type Heights, type LegendBinding, type MoveOptions, type PlacementArchetype } from '@operato/scene-base';
3
3
  /**
4
4
  * Agv status — common to both payload and towing AGVs (kept narrow on purpose).
5
5
  *
@@ -14,7 +14,16 @@ import { type Alignment, type Heights, type LegendBinding, type PlacementArchety
14
14
  * invite drift.
15
15
  */
16
16
  export type AgvStatus = 'idle' | 'moving' | 'charging' | 'error';
17
- declare const Base: typeof Component;
17
+ declare const Base: typeof Component & {
18
+ new (...args: any[]): Component & {
19
+ isCarrierHolder: boolean;
20
+ isMover: boolean;
21
+ attachPointFor(carrier: Component): CarrierAttachPoint | undefined;
22
+ pick(carrier: Component, options?: MoveOptions): Promise<void>;
23
+ place(carrier: Component, holder: Component, options?: MoveOptions): Promise<void>;
24
+ pickAndPlace(carrier: Component, holder: Component, options?: MoveOptions): Promise<void>;
25
+ };
26
+ };
18
27
  /**
19
28
  * Agv — payload (unit-load) automated guided vehicle. The Kiva-style flat-deck
20
29
  * AGV that drives under or carries cargo to/from operation surfaces.
@@ -39,10 +48,34 @@ export default class Agv extends Base {
39
48
  static placement: PlacementArchetype;
40
49
  static align: Alignment;
41
50
  static defaultDepth: (h: Heights) => number;
51
+ /**
52
+ * Heading yaw offset (rad). things-scene's vehicle convention is
53
+ * `vehicle forward = component-local -Z` (= "rotation=0 → toward canvas
54
+ * top edge"); the framework default `Math.PI / 2` aligns with that.
55
+ * Stated explicitly so the model's forward axis is documented at the
56
+ * class level rather than relying silently on the framework default.
57
+ */
58
+ static yawOffset: number;
42
59
  get nature(): ComponentNature;
43
60
  get anchors(): never[];
44
61
  /** Accept logistics packages (placement='operation') as deck cargo. */
45
62
  containable(component: Component): boolean;
63
+ /**
64
+ * AGV attach point — flat top deck. Cargo lands on the deck surface
65
+ * (top of the AGV envelope, which is `+depth/2` in component-local Y).
66
+ * Multiple cargo items stack vertically by their own depth.
67
+ *
68
+ * `attach` is the AGV's `_realObject.object3d` directly — there is no
69
+ * inner sub-frame the way Forklift has a fork-tip frame, because the
70
+ * deck moves rigidly with the chassis. Cargo Y reflects the cargoDepth
71
+ * × slot index stack offset.
72
+ */
73
+ attachPointFor(carrier: Component): CarrierAttachPoint | undefined;
74
+ /**
75
+ * Stack slot = the carrier's index among siblings. Stable because
76
+ * children order is preserved; no persisted state needed.
77
+ */
78
+ private _slotIndexOf;
46
79
  /**
47
80
  * 2D — render() sets up the rounded chassis path; the framework fills it
48
81
  * with `fillStyle` (= bodyColor from Legendable) and strokes with
package/dist/agv.js CHANGED
@@ -2,8 +2,8 @@ import { __decorate } from "tslib";
2
2
  /*
3
3
  * Copyright © HatioLab Inc. All rights reserved.
4
4
  */
5
- import { Container, sceneComponent } from '@hatiolab/things-scene';
6
- import { Legendable, Placeable } from '@operato/scene-base';
5
+ import { ContainerAbstract, sceneComponent } from '@hatiolab/things-scene';
6
+ import { CarrierHolder, FloorBound, Legendable, Mover, Placeable } from '@operato/scene-base';
7
7
  import { Agv3D } from './agv-3d.js';
8
8
  /**
9
9
  * Body color — neutral industrial gray base, slightly modulated by status.
@@ -52,11 +52,28 @@ const NATURE = {
52
52
  label: 'battery',
53
53
  name: 'battery',
54
54
  placeholder: '0..1'
55
+ },
56
+ {
57
+ // AGV travel speed in scene units / second. Used by Mover.moveTo
58
+ // to derive motion duration. Tune per board scale; forklift convention.
59
+ type: 'number',
60
+ label: 'speed',
61
+ name: 'speed',
62
+ placeholder: 'units/sec'
55
63
  }
56
64
  ],
57
65
  help: 'scene/component/agv'
58
66
  };
59
- const Base = Legendable(Placeable(Container));
67
+ // Composition: ContainerAbstract → Placeable → Legendable → CarrierHolder → Mover → FloorBound.
68
+ // Same chain as Forklift — the AGV is a wheeled, payload-carrying vehicle
69
+ // with the same pick/place semantics; differences (deck-stack instead of
70
+ // fork-mount) are encoded in `attachPointFor`. FloorBound is outermost so
71
+ // its rotation guard sees state changes last.
72
+ //
73
+ // `ContainerAbstract` (not `Container`) — Container = MixinHTMLElement(ContainerAbstract),
74
+ // which forces `isHTMLElement(): true` and trips the 3D pipeline's
75
+ // addObject DOM-skip gate. AGV lives only in the 3D scene graph; no DOM.
76
+ const Base = FloorBound(Mover(CarrierHolder(Legendable(Placeable(ContainerAbstract)))));
60
77
  /**
61
78
  * Agv — payload (unit-load) automated guided vehicle. The Kiva-style flat-deck
62
79
  * AGV that drives under or carries cargo to/from operation surfaces.
@@ -84,6 +101,14 @@ let Agv = class Agv extends Base {
84
101
  static placement = 'floor';
85
102
  static align = 'bottom';
86
103
  static defaultDepth = (h) => h.operation - h.floor;
104
+ /**
105
+ * Heading yaw offset (rad). things-scene's vehicle convention is
106
+ * `vehicle forward = component-local -Z` (= "rotation=0 → toward canvas
107
+ * top edge"); the framework default `Math.PI / 2` aligns with that.
108
+ * Stated explicitly so the model's forward axis is documented at the
109
+ * class level rather than relying silently on the framework default.
110
+ */
111
+ static yawOffset = Math.PI / 2;
87
112
  get nature() {
88
113
  return NATURE;
89
114
  }
@@ -97,6 +122,42 @@ let Agv = class Agv extends Base {
97
122
  return true;
98
123
  return component.isDescendible(this);
99
124
  }
125
+ /**
126
+ * AGV attach point — flat top deck. Cargo lands on the deck surface
127
+ * (top of the AGV envelope, which is `+depth/2` in component-local Y).
128
+ * Multiple cargo items stack vertically by their own depth.
129
+ *
130
+ * `attach` is the AGV's `_realObject.object3d` directly — there is no
131
+ * inner sub-frame the way Forklift has a fork-tip frame, because the
132
+ * deck moves rigidly with the chassis. Cargo Y reflects the cargoDepth
133
+ * × slot index stack offset.
134
+ */
135
+ attachPointFor(carrier) {
136
+ const ro = this._realObject;
137
+ if (!ro?.object3d)
138
+ return undefined;
139
+ const depth = this.state.depth ?? 0;
140
+ const slotIdx = this._slotIndexOf(carrier);
141
+ const cargoDepth = carrier.state.depth ?? 100;
142
+ const deckY = depth / 2;
143
+ return {
144
+ attach: ro.object3d,
145
+ localPosition: {
146
+ x: 0,
147
+ y: deckY + slotIdx * cargoDepth,
148
+ z: 0
149
+ }
150
+ };
151
+ }
152
+ /**
153
+ * Stack slot = the carrier's index among siblings. Stable because
154
+ * children order is preserved; no persisted state needed.
155
+ */
156
+ _slotIndexOf(carrier) {
157
+ const children = this.children ?? [];
158
+ const idx = children.indexOf(carrier);
159
+ return idx < 0 ? children.length : idx;
160
+ }
100
161
  /**
101
162
  * 2D — render() sets up the rounded chassis path; the framework fills it
102
163
  * with `fillStyle` (= bodyColor from Legendable) and strokes with
package/dist/agv.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"agv.js","sourceRoot":"","sources":["../src/agv.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\nimport { Component, ComponentNature, Container, RealObject, sceneComponent } from '@hatiolab/things-scene'\nimport {\n Legendable,\n Placeable,\n type Alignment,\n type Heights,\n type LegendBinding,\n type PlacementArchetype\n} from '@operato/scene-base'\n\nimport { Agv3D } from './agv-3d.js'\n\n/**\n * Agv status — common to both payload and towing AGVs (kept narrow on purpose).\n *\n * - `idle` — parked, awaiting task\n * - `moving` — driving along a path / executing transport\n * - `charging` — at a charging dock / battery station\n * - `error` — fault / blocked / e-stop\n *\n * Loaded-vs-empty distinction is *not* in the status enum because for a\n * Kiva-style payload AGV it's already obvious from the children (cargo\n * components) parented to it — duplicating that as a status flag would\n * invite drift.\n */\nexport type AgvStatus = 'idle' | 'moving' | 'charging' | 'error'\n\n/**\n * Body color — neutral industrial gray base, slightly modulated by status.\n * AGVs typically have status-color LED strips rather than full body color\n * change; the body legend stays subtle so the LED strip + lamp do the\n * communicating.\n */\nconst BODY_LEGEND = {\n idle: '#999',\n moving: '#aaa',\n charging: '#aaa',\n error: '#c66',\n default: '#999'\n}\n\n/**\n * LED strip emissive — the dominant status indicator for AGVs (typically a\n * color-band running around the chassis perimeter).\n */\nconst LAMP_EMISSIVE_LEGEND = {\n idle: '#222222',\n moving: '#44ff44', // green (operating)\n charging: '#ffaa00', // amber (charging)\n error: '#ff3333', // red\n default: '#222222'\n}\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n {\n type: 'select',\n label: 'status',\n name: 'status',\n property: {\n options: [\n { display: 'Idle', value: 'idle' },\n { display: 'Moving', value: 'moving' },\n { display: 'Charging', value: 'charging' },\n { display: 'Error', value: 'error' }\n ]\n }\n },\n {\n type: 'number',\n label: 'battery',\n name: 'battery',\n placeholder: '0..1'\n }\n ],\n help: 'scene/component/agv'\n}\n\nconst Base = Legendable(Placeable(Container)) as unknown as typeof Component\n\n/**\n * Agv — payload (unit-load) automated guided vehicle. The Kiva-style flat-deck\n * AGV that drives under or carries cargo to/from operation surfaces.\n *\n * **Container-based for cargo containment.** A payload Agv has a flat top\n * deck whose surface is at the scene's operation height. Boxes, parcels,\n * loaded pallets (anything with `placement: 'operation'`) can be added as\n * children — when they are, their natural archetype-derived zPos puts them\n * exactly on the AGV's deck (since AGV depth = operation - floor).\n *\n * For the towing variant (no cargo deck, pulls trailers behind), see Tugger.\n */\n@sceneComponent('agv')\nexport default class Agv extends Base {\n static legends: Record<string, LegendBinding> = {\n bodyColor: { from: 'status', legend: BODY_LEGEND },\n lampEmissive: { from: 'status', legend: LAMP_EMISSIVE_LEGEND }\n }\n\n /**\n * AGV sits on its wheels — `floor` archetype. Default depth = operation,\n * so the top deck lands at the scene's operation height. This is the\n * design point of payload AGVs: the deck height matches conveyor belt\n * height, equipment ports, and forklift fork height — cargo transfers\n * across all of them at the same level.\n */\n static placement: PlacementArchetype = 'floor'\n static align: Alignment = 'bottom'\n static defaultDepth = (h: Heights) => h.operation - h.floor\n\n get nature() {\n return NATURE\n }\n\n get anchors() {\n return []\n }\n\n /** Accept logistics packages (placement='operation') as deck cargo. */\n containable(component: Component) {\n const archetype = (component.constructor as any).placement\n if (archetype === 'operation') return true\n return component.isDescendible(this as any)\n }\n\n /**\n * 2D — render() sets up the rounded chassis path; the framework fills it\n * with `fillStyle` (= bodyColor from Legendable) and strokes with\n * `strokeStyle`. Additional top-down details (bumpers, LiDAR, lift pad,\n * direction triangle) are drawn in `postrender()`.\n */\n render(ctx: CanvasRenderingContext2D) {\n const { width, height, left, top } = this.state\n const radius = Math.min(width, height) * 0.12\n ctx.beginPath()\n ctx.roundRect(left, top, width, height, radius)\n }\n\n /** Top-view accent details — bumpers, lift pad, LiDAR, direction triangle. */\n postrender(ctx: CanvasRenderingContext2D) {\n super.postrender?.(ctx)\n\n const { width, height, left, top } = this.state\n const cx = left + width / 2\n const cy = top + height / 2\n const accentColor = (this.state.lampEmissive as string) || '#44ff44'\n\n ctx.save()\n\n // Hi-vis bumper strips (front + rear)\n const bumperT = Math.min(width, height) * 0.06\n ctx.fillStyle = '#eeaa00'\n ctx.fillRect(left + width * 0.15, top, width * 0.7, bumperT)\n ctx.fillRect(left + width * 0.15, top + height - bumperT, width * 0.7, bumperT)\n ctx.fillStyle = '#111'\n ctx.fillRect(left + width * 0.02, top, width * 0.13, bumperT)\n ctx.fillRect(left + width * 0.85, top, width * 0.13, bumperT)\n ctx.fillRect(left + width * 0.02, top + height - bumperT, width * 0.13, bumperT)\n ctx.fillRect(left + width * 0.85, top + height - bumperT, width * 0.13, bumperT)\n\n // Lift pad (center circle — Kiva-style under-shelf lift)\n const padR = Math.min(width, height) * 0.22\n ctx.fillStyle = '#4a4a55'\n ctx.strokeStyle = '#222'\n ctx.lineWidth = 1\n ctx.beginPath()\n ctx.ellipse(cx, cy, padR, padR, 0, 0, Math.PI * 2)\n ctx.fill()\n ctx.stroke()\n\n // LiDAR sensor (small filled circle near front)\n const lidarR = Math.min(width, height) * 0.07\n ctx.fillStyle = '#222233'\n ctx.beginPath()\n ctx.ellipse(cx, top + height * 0.20, lidarR, lidarR, 0, 0, Math.PI * 2)\n ctx.fill()\n ctx.stroke()\n // Status hint on LiDAR\n ctx.fillStyle = accentColor\n ctx.beginPath()\n ctx.ellipse(cx, top + height * 0.20, lidarR * 0.4, lidarR * 0.4, 0, 0, Math.PI * 2)\n ctx.fill()\n\n // Direction-of-travel triangle\n ctx.fillStyle = accentColor\n ctx.strokeStyle = '#111'\n ctx.beginPath()\n ctx.moveTo(cx, top + height * 0.06)\n ctx.lineTo(cx - width * 0.06, top + height * 0.13)\n ctx.lineTo(cx + width * 0.06, top + height * 0.13)\n ctx.closePath()\n ctx.fill()\n ctx.stroke()\n\n ctx.restore()\n }\n\n buildRealObject(): RealObject | undefined {\n return new Agv3D(this as any)\n }\n}\n"]}
1
+ {"version":3,"file":"agv.js","sourceRoot":"","sources":["../src/agv.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\nimport { Component, ComponentNature, ContainerAbstract, RealObject, sceneComponent } from '@hatiolab/things-scene'\nimport {\n CarrierHolder,\n FloorBound,\n Legendable,\n Mover,\n Placeable,\n type Alignment,\n type CarrierAttachPoint,\n type Heights,\n type LegendBinding,\n type MoveOptions,\n type PlacementArchetype\n} from '@operato/scene-base'\n\nimport { Agv3D } from './agv-3d.js'\n\n/**\n * Agv status — common to both payload and towing AGVs (kept narrow on purpose).\n *\n * - `idle` — parked, awaiting task\n * - `moving` — driving along a path / executing transport\n * - `charging` — at a charging dock / battery station\n * - `error` — fault / blocked / e-stop\n *\n * Loaded-vs-empty distinction is *not* in the status enum because for a\n * Kiva-style payload AGV it's already obvious from the children (cargo\n * components) parented to it — duplicating that as a status flag would\n * invite drift.\n */\nexport type AgvStatus = 'idle' | 'moving' | 'charging' | 'error'\n\n/**\n * Body color — neutral industrial gray base, slightly modulated by status.\n * AGVs typically have status-color LED strips rather than full body color\n * change; the body legend stays subtle so the LED strip + lamp do the\n * communicating.\n */\nconst BODY_LEGEND = {\n idle: '#999',\n moving: '#aaa',\n charging: '#aaa',\n error: '#c66',\n default: '#999'\n}\n\n/**\n * LED strip emissive — the dominant status indicator for AGVs (typically a\n * color-band running around the chassis perimeter).\n */\nconst LAMP_EMISSIVE_LEGEND = {\n idle: '#222222',\n moving: '#44ff44', // green (operating)\n charging: '#ffaa00', // amber (charging)\n error: '#ff3333', // red\n default: '#222222'\n}\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n {\n type: 'select',\n label: 'status',\n name: 'status',\n property: {\n options: [\n { display: 'Idle', value: 'idle' },\n { display: 'Moving', value: 'moving' },\n { display: 'Charging', value: 'charging' },\n { display: 'Error', value: 'error' }\n ]\n }\n },\n {\n type: 'number',\n label: 'battery',\n name: 'battery',\n placeholder: '0..1'\n },\n {\n // AGV travel speed in scene units / second. Used by Mover.moveTo\n // to derive motion duration. Tune per board scale; forklift convention.\n type: 'number',\n label: 'speed',\n name: 'speed',\n placeholder: 'units/sec'\n }\n ],\n help: 'scene/component/agv'\n}\n\n// Composition: ContainerAbstract → Placeable → Legendable → CarrierHolder → Mover → FloorBound.\n// Same chain as Forklift — the AGV is a wheeled, payload-carrying vehicle\n// with the same pick/place semantics; differences (deck-stack instead of\n// fork-mount) are encoded in `attachPointFor`. FloorBound is outermost so\n// its rotation guard sees state changes last.\n//\n// `ContainerAbstract` (not `Container`) — Container = MixinHTMLElement(ContainerAbstract),\n// which forces `isHTMLElement(): true` and trips the 3D pipeline's\n// addObject DOM-skip gate. AGV lives only in the 3D scene graph; no DOM.\nconst Base = FloorBound(Mover(CarrierHolder(Legendable(Placeable(ContainerAbstract))))) as unknown as typeof Component & {\n new (...args: any[]): Component & {\n isCarrierHolder: boolean\n isMover: boolean\n attachPointFor(carrier: Component): CarrierAttachPoint | undefined\n pick(carrier: Component, options?: MoveOptions): Promise<void>\n place(carrier: Component, holder: Component, options?: MoveOptions): Promise<void>\n pickAndPlace(carrier: Component, holder: Component, options?: MoveOptions): Promise<void>\n }\n}\n\n/**\n * Agv — payload (unit-load) automated guided vehicle. The Kiva-style flat-deck\n * AGV that drives under or carries cargo to/from operation surfaces.\n *\n * **Container-based for cargo containment.** A payload Agv has a flat top\n * deck whose surface is at the scene's operation height. Boxes, parcels,\n * loaded pallets (anything with `placement: 'operation'`) can be added as\n * children — when they are, their natural archetype-derived zPos puts them\n * exactly on the AGV's deck (since AGV depth = operation - floor).\n *\n * For the towing variant (no cargo deck, pulls trailers behind), see Tugger.\n */\n@sceneComponent('agv')\nexport default class Agv extends Base {\n static legends: Record<string, LegendBinding> = {\n bodyColor: { from: 'status', legend: BODY_LEGEND },\n lampEmissive: { from: 'status', legend: LAMP_EMISSIVE_LEGEND }\n }\n\n /**\n * AGV sits on its wheels — `floor` archetype. Default depth = operation,\n * so the top deck lands at the scene's operation height. This is the\n * design point of payload AGVs: the deck height matches conveyor belt\n * height, equipment ports, and forklift fork height — cargo transfers\n * across all of them at the same level.\n */\n static placement: PlacementArchetype = 'floor'\n static align: Alignment = 'bottom'\n static defaultDepth = (h: Heights) => h.operation - h.floor\n\n /**\n * Heading yaw offset (rad). things-scene's vehicle convention is\n * `vehicle forward = component-local -Z` (= \"rotation=0 → toward canvas\n * top edge\"); the framework default `Math.PI / 2` aligns with that.\n * Stated explicitly so the model's forward axis is documented at the\n * class level rather than relying silently on the framework default.\n */\n static yawOffset = Math.PI / 2\n\n get nature() {\n return NATURE\n }\n\n get anchors() {\n return []\n }\n\n /** Accept logistics packages (placement='operation') as deck cargo. */\n containable(component: Component) {\n const archetype = (component.constructor as any).placement\n if (archetype === 'operation') return true\n return component.isDescendible(this as any)\n }\n\n /**\n * AGV attach point — flat top deck. Cargo lands on the deck surface\n * (top of the AGV envelope, which is `+depth/2` in component-local Y).\n * Multiple cargo items stack vertically by their own depth.\n *\n * `attach` is the AGV's `_realObject.object3d` directly — there is no\n * inner sub-frame the way Forklift has a fork-tip frame, because the\n * deck moves rigidly with the chassis. Cargo Y reflects the cargoDepth\n * × slot index stack offset.\n */\n attachPointFor(carrier: Component): CarrierAttachPoint | undefined {\n const ro = (this as any)._realObject as { object3d?: any } | undefined\n if (!ro?.object3d) return undefined\n\n const depth = (this.state.depth as number) ?? 0\n const slotIdx = this._slotIndexOf(carrier)\n const cargoDepth = (carrier.state as any).depth ?? 100\n const deckY = depth / 2\n\n return {\n attach: ro.object3d,\n localPosition: {\n x: 0,\n y: deckY + slotIdx * cargoDepth,\n z: 0\n }\n }\n }\n\n /**\n * Stack slot = the carrier's index among siblings. Stable because\n * children order is preserved; no persisted state needed.\n */\n private _slotIndexOf(carrier: Component): number {\n const children = ((this as any).children as Component[] | undefined) ?? []\n const idx = children.indexOf(carrier)\n return idx < 0 ? children.length : idx\n }\n\n /**\n * 2D — render() sets up the rounded chassis path; the framework fills it\n * with `fillStyle` (= bodyColor from Legendable) and strokes with\n * `strokeStyle`. Additional top-down details (bumpers, LiDAR, lift pad,\n * direction triangle) are drawn in `postrender()`.\n */\n render(ctx: CanvasRenderingContext2D) {\n const { width, height, left, top } = this.state\n const radius = Math.min(width, height) * 0.12\n ctx.beginPath()\n ctx.roundRect(left, top, width, height, radius)\n }\n\n /** Top-view accent details — bumpers, lift pad, LiDAR, direction triangle. */\n postrender(ctx: CanvasRenderingContext2D) {\n super.postrender?.(ctx)\n\n const { width, height, left, top } = this.state\n const cx = left + width / 2\n const cy = top + height / 2\n const accentColor = (this.state.lampEmissive as string) || '#44ff44'\n\n ctx.save()\n\n // Hi-vis bumper strips (front + rear)\n const bumperT = Math.min(width, height) * 0.06\n ctx.fillStyle = '#eeaa00'\n ctx.fillRect(left + width * 0.15, top, width * 0.7, bumperT)\n ctx.fillRect(left + width * 0.15, top + height - bumperT, width * 0.7, bumperT)\n ctx.fillStyle = '#111'\n ctx.fillRect(left + width * 0.02, top, width * 0.13, bumperT)\n ctx.fillRect(left + width * 0.85, top, width * 0.13, bumperT)\n ctx.fillRect(left + width * 0.02, top + height - bumperT, width * 0.13, bumperT)\n ctx.fillRect(left + width * 0.85, top + height - bumperT, width * 0.13, bumperT)\n\n // Lift pad (center circle — Kiva-style under-shelf lift)\n const padR = Math.min(width, height) * 0.22\n ctx.fillStyle = '#4a4a55'\n ctx.strokeStyle = '#222'\n ctx.lineWidth = 1\n ctx.beginPath()\n ctx.ellipse(cx, cy, padR, padR, 0, 0, Math.PI * 2)\n ctx.fill()\n ctx.stroke()\n\n // LiDAR sensor (small filled circle near front)\n const lidarR = Math.min(width, height) * 0.07\n ctx.fillStyle = '#222233'\n ctx.beginPath()\n ctx.ellipse(cx, top + height * 0.20, lidarR, lidarR, 0, 0, Math.PI * 2)\n ctx.fill()\n ctx.stroke()\n // Status hint on LiDAR\n ctx.fillStyle = accentColor\n ctx.beginPath()\n ctx.ellipse(cx, top + height * 0.20, lidarR * 0.4, lidarR * 0.4, 0, 0, Math.PI * 2)\n ctx.fill()\n\n // Direction-of-travel triangle\n ctx.fillStyle = accentColor\n ctx.strokeStyle = '#111'\n ctx.beginPath()\n ctx.moveTo(cx, top + height * 0.06)\n ctx.lineTo(cx - width * 0.06, top + height * 0.13)\n ctx.lineTo(cx + width * 0.06, top + height * 0.13)\n ctx.closePath()\n ctx.fill()\n ctx.stroke()\n\n ctx.restore()\n }\n\n buildRealObject(): RealObject | undefined {\n return new Agv3D(this as any)\n }\n}\n"]}
@@ -0,0 +1,37 @@
1
+ export interface ForkliftLayoutState {
2
+ width?: number;
3
+ height?: number;
4
+ depth?: number;
5
+ forkHeight?: number;
6
+ }
7
+ /**
8
+ * Local-frame top-of-fork-tip surface — where cargo center sits when
9
+ * attached. Forks point along **-Z** (vehicle forward), so z is negative.
10
+ */
11
+ export declare function cargoMountLocal(state: ForkliftLayoutState): {
12
+ x: number;
13
+ y: number;
14
+ z: number;
15
+ width: number;
16
+ depth: number;
17
+ };
18
+ /**
19
+ * Mast mounting Z (forward edge of chassis, in -Z direction).
20
+ */
21
+ export declare function mastZ(state: ForkliftLayoutState): number;
22
+ /**
23
+ * Counterweight Z (back of vehicle, in +Z direction).
24
+ */
25
+ export declare function counterweightZ(state: ForkliftLayoutState): number;
26
+ /**
27
+ * Fork blade tip Z (heel + blade length in -Z direction).
28
+ */
29
+ export declare function forkTipZ(state: ForkliftLayoutState): number;
30
+ /**
31
+ * Front (drive) wheel Z.
32
+ */
33
+ export declare function frontWheelZ(state: ForkliftLayoutState): number;
34
+ /**
35
+ * Rear (caster) wheel Z.
36
+ */
37
+ export declare function rearWheelZ(state: ForkliftLayoutState): number;
@@ -0,0 +1,74 @@
1
+ /*
2
+ * Copyright © HatioLab Inc. All rights reserved.
3
+ *
4
+ * Pure geometry helpers extracted from `forklift-3d.ts` so the model's
5
+ * coordinate convention (-Z forward) can be unit-tested without pulling
6
+ * in `@hatiolab/things-scene` (its bundled module hides RealObjectGroup
7
+ * behind a single-bundle minify and won't load standalone in node).
8
+ *
9
+ * Each helper takes a plain `state` object — never the live component —
10
+ * and returns world-frame mesh positions. The forklift-3d.ts build() uses
11
+ * the same helpers so any drift between authoring and tests fails loud.
12
+ */
13
+ /**
14
+ * Local-frame top-of-fork-tip surface — where cargo center sits when
15
+ * attached. Forks point along **-Z** (vehicle forward), so z is negative.
16
+ */
17
+ export function cargoMountLocal(state) {
18
+ const width = state.width ?? 100;
19
+ const height = state.height ?? 200;
20
+ const depth = state.depth ?? 200;
21
+ const raw = state.forkHeight ?? 0;
22
+ const forkHeight = Math.max(0, Math.min(raw, depth * 0.85));
23
+ const wheelR = depth * 0.07;
24
+ const forkH = depth * 0.018;
25
+ const forkLen = height * 0.42;
26
+ const y = -depth / 2 + wheelR + forkHeight + forkH;
27
+ const z = -(height * 0.42 + forkLen / 2); // forks tip in -Z
28
+ return { x: 0, y, z, width: width * 0.4, depth: forkLen };
29
+ }
30
+ /**
31
+ * Mast mounting Z (forward edge of chassis, in -Z direction).
32
+ */
33
+ export function mastZ(state) {
34
+ const height = state.height ?? 200;
35
+ const mastRailD = height * 0.03;
36
+ const chassisLen = height * 0.62;
37
+ return -(chassisLen / 2 + mastRailD);
38
+ }
39
+ /**
40
+ * Counterweight Z (back of vehicle, in +Z direction).
41
+ */
42
+ export function counterweightZ(state) {
43
+ const height = state.height ?? 200;
44
+ const cwD = height * 0.28;
45
+ const chassisLen = height * 0.62;
46
+ const zBack = -chassisLen * 0.5;
47
+ return -zBack + cwD * 0.5; // matches forklift-3d.ts cwZ formula
48
+ }
49
+ /**
50
+ * Fork blade tip Z (heel + blade length in -Z direction).
51
+ */
52
+ export function forkTipZ(state) {
53
+ const height = state.height ?? 200;
54
+ const mastRailD = height * 0.03;
55
+ const carriageD = mastRailD * 0.7;
56
+ const forkLen = height * 0.42;
57
+ // heel z = mastZ - mastRailD - carriageD; blade tip extends -forkLen further.
58
+ return mastZ(state) - mastRailD - carriageD - forkLen;
59
+ }
60
+ /**
61
+ * Front (drive) wheel Z.
62
+ */
63
+ export function frontWheelZ(state) {
64
+ const height = state.height ?? 200;
65
+ return -height * 0.30;
66
+ }
67
+ /**
68
+ * Rear (caster) wheel Z.
69
+ */
70
+ export function rearWheelZ(state) {
71
+ const height = state.height ?? 200;
72
+ return height * 0.32;
73
+ }
74
+ //# sourceMappingURL=forklift-3d-layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"forklift-3d-layout.js","sourceRoot":"","sources":["../src/forklift-3d-layout.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AASH;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,KAA0B;IAOxD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,GAAG,CAAA;IAChC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,GAAG,CAAA;IAClC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,IAAI,GAAG,CAAA;IAChC,MAAM,GAAG,GAAG,KAAK,CAAC,UAAU,IAAI,CAAC,CAAA;IACjC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,GAAG,IAAI,CAAC,CAAC,CAAA;IAC3D,MAAM,MAAM,GAAG,KAAK,GAAG,IAAI,CAAA;IAC3B,MAAM,KAAK,GAAG,KAAK,GAAG,KAAK,CAAA;IAC3B,MAAM,OAAO,GAAG,MAAM,GAAG,IAAI,CAAA;IAC7B,MAAM,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,GAAG,MAAM,GAAG,UAAU,GAAG,KAAK,CAAA;IAClD,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,IAAI,GAAG,OAAO,GAAG,CAAC,CAAC,CAAA,CAAC,kBAAkB;IAC3D,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,GAAG,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,CAAA;AAC3D,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,KAAK,CAAC,KAA0B;IAC9C,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,GAAG,CAAA;IAClC,MAAM,SAAS,GAAG,MAAM,GAAG,IAAI,CAAA;IAC/B,MAAM,UAAU,GAAG,MAAM,GAAG,IAAI,CAAA;IAChC,OAAO,CAAC,CAAC,UAAU,GAAG,CAAC,GAAG,SAAS,CAAC,CAAA;AACtC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,KAA0B;IACvD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,GAAG,CAAA;IAClC,MAAM,GAAG,GAAG,MAAM,GAAG,IAAI,CAAA;IACzB,MAAM,UAAU,GAAG,MAAM,GAAG,IAAI,CAAA;IAChC,MAAM,KAAK,GAAG,CAAC,UAAU,GAAG,GAAG,CAAA;IAC/B,OAAO,CAAC,KAAK,GAAG,GAAG,GAAG,GAAG,CAAA,CAAC,qCAAqC;AACjE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,KAA0B;IACjD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,GAAG,CAAA;IAClC,MAAM,SAAS,GAAG,MAAM,GAAG,IAAI,CAAA;IAC/B,MAAM,SAAS,GAAG,SAAS,GAAG,GAAG,CAAA;IACjC,MAAM,OAAO,GAAG,MAAM,GAAG,IAAI,CAAA;IAC7B,8EAA8E;IAC9E,OAAO,KAAK,CAAC,KAAK,CAAC,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAA;AACvD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,KAA0B;IACpD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,GAAG,CAAA;IAClC,OAAO,CAAC,MAAM,GAAG,IAAI,CAAA;AACvB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,UAAU,CAAC,KAA0B;IACnD,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,IAAI,GAAG,CAAA;IAClC,OAAO,MAAM,GAAG,IAAI,CAAA;AACtB,CAAC","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * Pure geometry helpers extracted from `forklift-3d.ts` so the model's\n * coordinate convention (-Z forward) can be unit-tested without pulling\n * in `@hatiolab/things-scene` (its bundled module hides RealObjectGroup\n * behind a single-bundle minify and won't load standalone in node).\n *\n * Each helper takes a plain `state` object — never the live component —\n * and returns world-frame mesh positions. The forklift-3d.ts build() uses\n * the same helpers so any drift between authoring and tests fails loud.\n */\n\nexport interface ForkliftLayoutState {\n width?: number\n height?: number\n depth?: number\n forkHeight?: number\n}\n\n/**\n * Local-frame top-of-fork-tip surface — where cargo center sits when\n * attached. Forks point along **-Z** (vehicle forward), so z is negative.\n */\nexport function cargoMountLocal(state: ForkliftLayoutState): {\n x: number\n y: number\n z: number\n width: number\n depth: number\n} {\n const width = state.width ?? 100\n const height = state.height ?? 200\n const depth = state.depth ?? 200\n const raw = state.forkHeight ?? 0\n const forkHeight = Math.max(0, Math.min(raw, depth * 0.85))\n const wheelR = depth * 0.07\n const forkH = depth * 0.018\n const forkLen = height * 0.42\n const y = -depth / 2 + wheelR + forkHeight + forkH\n const z = -(height * 0.42 + forkLen / 2) // forks tip in -Z\n return { x: 0, y, z, width: width * 0.4, depth: forkLen }\n}\n\n/**\n * Mast mounting Z (forward edge of chassis, in -Z direction).\n */\nexport function mastZ(state: ForkliftLayoutState): number {\n const height = state.height ?? 200\n const mastRailD = height * 0.03\n const chassisLen = height * 0.62\n return -(chassisLen / 2 + mastRailD)\n}\n\n/**\n * Counterweight Z (back of vehicle, in +Z direction).\n */\nexport function counterweightZ(state: ForkliftLayoutState): number {\n const height = state.height ?? 200\n const cwD = height * 0.28\n const chassisLen = height * 0.62\n const zBack = -chassisLen * 0.5\n return -zBack + cwD * 0.5 // matches forklift-3d.ts cwZ formula\n}\n\n/**\n * Fork blade tip Z (heel + blade length in -Z direction).\n */\nexport function forkTipZ(state: ForkliftLayoutState): number {\n const height = state.height ?? 200\n const mastRailD = height * 0.03\n const carriageD = mastRailD * 0.7\n const forkLen = height * 0.42\n // heel z = mastZ - mastRailD - carriageD; blade tip extends -forkLen further.\n return mastZ(state) - mastRailD - carriageD - forkLen\n}\n\n/**\n * Front (drive) wheel Z.\n */\nexport function frontWheelZ(state: ForkliftLayoutState): number {\n const height = state.height ?? 200\n return -height * 0.30\n}\n\n/**\n * Rear (caster) wheel Z.\n */\nexport function rearWheelZ(state: ForkliftLayoutState): number {\n const height = state.height ?? 200\n return height * 0.32\n}\n"]}
@@ -1,6 +1,19 @@
1
+ import * as THREE from 'three';
1
2
  import { RealObjectGroup } from '@hatiolab/things-scene';
2
3
  export declare class Forklift3D extends RealObjectGroup {
3
- /** Local-frame position of the fork-tip top surface — where cargo sits. */
4
+ /**
5
+ * Inner group that holds the actual mesh tree. Rotated π around Y so
6
+ * the procedural model (drawn with forks pointing along component-local
7
+ * +Z) aligns with things-scene's vehicle convention of -Z forward.
8
+ *
9
+ * Carriers attach onto this group (not `object3d`) so they inherit the
10
+ * same rotation as the visible mesh — `cargoMount` coordinates remain
11
+ * authored in the model's natural +Z-forward frame and the wrapper
12
+ * transforms them to match the visible forks.
13
+ */
14
+ private _modelGroup?;
15
+ get modelGroup(): THREE.Group | undefined;
16
+ /** Local-frame (-Z forward) fork-tip top surface — where cargo sits. */
4
17
  get cargoMount(): {
5
18
  x: number;
6
19
  y: number;