@operato/scene-storage 10.0.0-beta.33 → 10.0.0-beta.35

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 +23 -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 +163 -0
  6. package/dist/crane.js +459 -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 +2 -2
  51. package/src/crane-3d.ts +273 -0
  52. package/src/crane.ts +555 -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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-cell-3d.js","sourceRoot":"","sources":["../src/storage-cell-3d.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * RackCell 3D — invisible anchor group positioned at the cell's location\n * within the parent rack's 3D coordinate space.\n *\n * RackCell has no geometry of its own. Its sole 3D purpose is to provide\n * an Object3D that carriers can be attached to (via Three.js `.attach()`),\n * placed at the exact cell position within the rack. The position is derived\n * from the parent Rack's CellMap (by cellId), not from 2D state fields —\n * rack cells occupy 3D levels that have no 2D analogue.\n *\n * updateTransform() override: things-scene's standard updateTransform\n * reads `component.center` (2D) and flattens it to 3D. For rack cells this\n * is wrong — we need the 3D cell position (bay x, level y, row z) from the\n * parent rack. So we override and read it directly from the CellMap.\n */\n\nimport * as THREE from 'three'\nimport { RealObjectGroup } from '@hatiolab/things-scene'\n\nexport class StorageCell3D extends RealObjectGroup {\n build() {\n super.build()\n this._repositionFromCellMap()\n }\n\n updateDimension() {\n // intentional no-op — size comes from the cell definition, not state\n }\n\n updateTransform() {\n this._repositionFromCellMap()\n }\n\n updateAlpha() {\n // invisible — no materials to update\n }\n\n /**\n * Position this group at the cell's localPosition within the rack's 3D space.\n *\n * CellMap.grid() places cell origins at:\n * x = b * bayWidth, y = l * levelHeight, z = r * rowDepth\n * (starting from 0,0,0 at the rack's bottom-left-front corner).\n *\n * The rack's object3d is centered: X spans [-width/2, +width/2],\n * Y spans [-depth/2, +depth/2], Z spans [-height/2, +height/2].\n *\n * So the cell centre in rack-local 3D space:\n * x3d = cellPos.x + bayWidth/2 - width/2\n * y3d = cellPos.y + levelHeight/2 - rackDepth/2\n * z3d = cellPos.z + rowDepth/2 - rackHeight/2\n */\n _repositionFromCellMap() {\n const rack = (this.component as any).parent\n if (!rack?.cellMap) return\n\n const cellId = this.component.state.cellId as string | undefined\n if (!cellId) return\n\n const cell = rack.cellMap.findById(cellId)\n if (!cell) return\n\n const rs = rack.state as any\n const rackWidth = (rs?.width as number) || 1000\n const rackDepth = (rs?.depth as number) || 3000 // Y dimension (floor→ceiling)\n const rackHeight = (rs?.height as number) || 600 // Z dimension (front→back, 2D height)\n const bays = Math.max(1, Math.floor(rs?.bays || 5))\n const levels = Math.max(1, Math.floor(rs?.levels || 4))\n const rows = 1\n\n const bayWidth = rackWidth / bays\n const levelHeight = rackDepth / levels\n const rowDepth = rackHeight / rows\n\n const x3d = cell.localPosition.x + bayWidth / 2 - rackWidth / 2\n const y3d = cell.localPosition.y + levelHeight / 2 - rackDepth / 2\n const z3d = cell.localPosition.z + rowDepth / 2 - rackHeight / 2\n\n this.object3d.position.set(x3d, y3d, z3d)\n\n // Optionally visualise cells in debug mode (outline box, very faint)\n if (process.env.NODE_ENV !== 'production' && (rack.state as any)?.debugCells) {\n this._addDebugBox(bayWidth, levelHeight, rowDepth)\n }\n }\n\n private _debugBox?: THREE.LineSegments\n\n private _addDebugBox(w: number, h: number, d: number) {\n if (this._debugBox) return\n const geo = new THREE.BoxGeometry(w * 0.98, h * 0.98, d * 0.98)\n const edges = new THREE.EdgesGeometry(geo)\n this._debugBox = new THREE.LineSegments(\n edges,\n new THREE.LineBasicMaterial({ color: 0x00ff88, transparent: true, opacity: 0.2 })\n )\n this.object3d.add(this._debugBox)\n }\n}\n"]}
@@ -7,16 +7,22 @@ import { type AttachFrame } from '@operato/scene-base';
7
7
  * - multi: small stack (up to 4, e.g. a multi-deep tray)
8
8
  * - bulk: unlimited (e.g. a floor area measured in slots)
9
9
  */
10
- export type RackCellType = 'single' | 'multi' | 'bulk';
10
+ export type StorageCellType = 'single' | 'multi' | 'bulk';
11
11
  /** RackCell 컴포넌트 state */
12
- export interface RackCellState extends State {
12
+ export interface StorageCellState extends State {
13
13
  cellId?: string;
14
- cellType?: RackCellType;
14
+ cellType?: StorageCellType;
15
+ /**
16
+ * 자동 할당된 location ID — RackTable.assignLocations() 가 set. 외부 시스템
17
+ * (WMS, picker 명령 등) 이 cell 을 지칭하는 사람-친화 ID. RackTable 없이
18
+ * 단독으로 Rack 을 사용할 땐 unset.
19
+ */
20
+ locationId?: string;
15
21
  material3d?: Material3D;
16
22
  }
17
23
  declare const RackCell_base: any;
18
24
  /**
19
- * RackCell — single-slot storage cell inside an AsrsRack.
25
+ * RackCell — single-slot storage cell inside an Rack.
20
26
  *
21
27
  * Mixin chain: CarrierHolder(ContainerAbstract)
22
28
  * - CarrierHolder: publishes attachPointFor(), gates containable() to Carriables
@@ -27,9 +33,9 @@ declare const RackCell_base: any;
27
33
  * 2D→3D coordinate mapping which cannot express 3D levels.
28
34
  */
29
35
  export default class RackCell extends RackCell_base {
30
- state: RackCellState;
36
+ state: StorageCellState;
31
37
  get cellId(): string;
32
- get cellType(): RackCellType;
38
+ get cellType(): StorageCellType;
33
39
  /** Maximum carrier count for this cell based on cellType. */
34
40
  get capacity(): number;
35
41
  get nature(): ComponentNature;
@@ -1,13 +1,13 @@
1
1
  /*
2
2
  * Copyright © HatioLab Inc. All rights reserved.
3
3
  *
4
- * RackCell — a single storage slot within an AsrsRack.
4
+ * RackCell — a single storage slot within an Rack.
5
5
  *
6
6
  * A RackCell is a virtual component: it occupies a specific (bay, row, level)
7
7
  * coordinate within the parent rack and acts as a CarrierHolder for one carrier
8
8
  * (or several, depending on `cellType`).
9
9
  *
10
- * The crane (AsrsCrane) navigates toward a RackCell as its `place()` destination —
10
+ * The crane (or any picker) navigates toward a RackCell as its `place()` destination —
11
11
  * because the rack cell is a discrete component, Mover.moveTo() can target it
12
12
  * directly and arrive at exactly the right bay × level position.
13
13
  *
@@ -16,7 +16,7 @@
16
16
  * positioned within the rack's coordinate space (RackCell3D handles
17
17
  * this via updateTransform override).
18
18
  *
19
- * Lifecycle: AsrsRack._buildCells() instantiates RackCell children.
19
+ * Lifecycle: Rack._buildCells() instantiates RackCell children.
20
20
  * Do not create RackCell components manually — they are managed by the rack.
21
21
  *
22
22
  * Domain aliases:
@@ -26,7 +26,7 @@
26
26
  import { __decorate } from "tslib";
27
27
  import { ContainerAbstract, TRANSFER_SLOT_KEY, sceneComponent } from '@hatiolab/things-scene';
28
28
  import { CarrierHolder } from '@operato/scene-base';
29
- import { RackCell3D } from './rack-cell-3d.js';
29
+ import { StorageCell3D } from './storage-cell-3d.js';
30
30
  const NATURE = {
31
31
  mutable: false,
32
32
  resizable: false,
@@ -51,10 +51,10 @@ const NATURE = {
51
51
  }
52
52
  }
53
53
  ],
54
- help: 'scene/component/rack-cell'
54
+ help: 'scene/component/storage-cell'
55
55
  };
56
56
  /**
57
- * RackCell — single-slot storage cell inside an AsrsRack.
57
+ * RackCell — single-slot storage cell inside an Rack.
58
58
  *
59
59
  * Mixin chain: CarrierHolder(ContainerAbstract)
60
60
  * - CarrierHolder: publishes attachPointFor(), gates containable() to Carriables
@@ -178,11 +178,11 @@ let RackCell = class RackCell extends CarrierHolder(ContainerAbstract) {
178
178
  }
179
179
  // ── 3D ───────────────────────────────────────────────────────────────────
180
180
  buildRealObject() {
181
- return new RackCell3D(this);
181
+ return new StorageCell3D(this);
182
182
  }
183
183
  };
184
184
  RackCell = __decorate([
185
- sceneComponent('rack-cell')
185
+ sceneComponent('storage-cell')
186
186
  ], RackCell);
187
187
  export default RackCell;
188
188
  function resolveCarrierDepth(c) {
@@ -194,4 +194,4 @@ function resolveCarrierDepth(c) {
194
194
  function numOr(v, dflt) {
195
195
  return typeof v === 'number' && Number.isFinite(v) ? v : dflt;
196
196
  }
197
- //# sourceMappingURL=rack-cell.js.map
197
+ //# sourceMappingURL=storage-cell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-cell.js","sourceRoot":"","sources":["../src/storage-cell.ts"],"names":[],"mappings":"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","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * RackCell — a single storage slot within an Rack.\n *\n * A RackCell is a virtual component: it occupies a specific (bay, row, level)\n * coordinate within the parent rack and acts as a CarrierHolder for one carrier\n * (or several, depending on `cellType`).\n *\n * The crane (or any picker) navigates toward a RackCell as its `place()` destination —\n * because the rack cell is a discrete component, Mover.moveTo() can target it\n * directly and arrive at exactly the right bay × level position.\n *\n * Visual: invisible in 2D (no visible 2D footprint — rack cells don't make\n * sense as 2D top-down boxes). In 3D, each cell is an invisible Group\n * positioned within the rack's coordinate space (RackCell3D handles\n * this via updateTransform override).\n *\n * Lifecycle: Rack._buildCells() instantiates RackCell children.\n * Do not create RackCell components manually — they are managed by the rack.\n *\n * Domain aliases:\n * cell.store(carrier) ← cell.receive(carrier)\n * cell.retrieve(carrier, target) ← cell.dispatch(carrier, target)\n */\n\nimport {\n Component,\n ComponentNature,\n ContainerAbstract,\n RealObject,\n TRANSFER_SLOT_KEY,\n sceneComponent\n} from '@hatiolab/things-scene'\nimport type { State, Material3D } from '@hatiolab/things-scene'\nimport { CarrierHolder, type AttachFrame } from '@operato/scene-base'\n\nimport { StorageCell3D } from './storage-cell-3d.js'\n\n/**\n * How many carriers a cell can hold simultaneously.\n * - single: exactly 1 (typical pallet bay)\n * - multi: small stack (up to 4, e.g. a multi-deep tray)\n * - bulk: unlimited (e.g. a floor area measured in slots)\n */\nexport type StorageCellType = 'single' | 'multi' | 'bulk'\n\n/** RackCell 컴포넌트 state */\nexport interface StorageCellState extends State {\n // ── 식별 ──\n cellId?: string\n cellType?: StorageCellType\n /**\n * 자동 할당된 location ID — RackTable.assignLocations() 가 set. 외부 시스템\n * (WMS, picker 명령 등) 이 cell 을 지칭하는 사람-친화 ID. RackTable 없이\n * 단독으로 Rack 을 사용할 땐 unset.\n */\n locationId?: string\n\n // ── 3D 재질 ──\n material3d?: Material3D\n}\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: false,\n rotatable: false,\n properties: [\n {\n type: 'string',\n label: 'cell-id',\n name: 'cellId',\n placeholder: 'e.g. 0-0-0'\n },\n {\n type: 'select',\n label: 'cell-type',\n name: 'cellType',\n property: {\n options: [\n { display: 'Single', value: 'single' },\n { display: 'Multi', value: 'multi' },\n { display: 'Bulk', value: 'bulk' }\n ]\n }\n }\n ],\n help: 'scene/component/storage-cell'\n}\n\n/**\n * RackCell — single-slot storage cell inside an Rack.\n *\n * Mixin chain: CarrierHolder(ContainerAbstract)\n * - CarrierHolder: publishes attachPointFor(), gates containable() to Carriables\n * - ContainerAbstract: manages child carrier components\n *\n * No Placeable mixin — RackCell3D self-positions from the parent rack's\n * CellMap (via updateTransform override), bypassing things-scene's standard\n * 2D→3D coordinate mapping which cannot express 3D levels.\n */\n@sceneComponent('storage-cell')\nexport default class RackCell extends CarrierHolder(ContainerAbstract) {\n declare state: StorageCellState\n\n // ── Identification ────────────────────────────────────────────────────────\n\n get cellId(): string {\n return this.state.cellId ?? ''\n }\n\n get cellType(): StorageCellType {\n return this.state.cellType ?? 'single'\n }\n\n /** Maximum carrier count for this cell based on cellType. */\n get capacity(): number {\n switch (this.cellType) {\n case 'single': return 1\n case 'multi': return 4\n case 'bulk': return Infinity\n }\n }\n\n // ── Interface ─────────────────────────────────────────────────────────────\n\n get nature(): ComponentNature {\n return NATURE\n }\n\n get anchors(): [] {\n return []\n }\n\n // ── Transfer protocol ─────────────────────────────────────────────────────\n\n /** True when fewer carriers are currently held than capacity. */\n canReceive(_component?: any): boolean {\n const occupied = (this.components as Component[] | undefined)?.length ?? 0\n return occupied < this.capacity\n }\n\n /**\n * Accept a carrier into this cell.\n * Sets TRANSFER_SLOT_KEY = cellId on the carrier, then reparents.\n * Fires 'transfer-received' so monitors can react.\n */\n async receive(carrier: any, options: any = {}): Promise<void> {\n if (!this.canReceive(carrier)) {\n this.trigger('transfer-rejected', {\n type: 'transfer-rejected',\n component: carrier,\n container: this,\n reason: 'no-slot'\n })\n return\n }\n carrier[TRANSFER_SLOT_KEY] = this.cellId\n this.reparent(carrier, options)\n this.trigger('transfer-received', {\n type: 'transfer-received',\n component: carrier,\n container: this,\n slotId: this.cellId\n })\n }\n\n /**\n * Release a carrier from this cell to `target`.\n * Delegates to `target.receive()` if available, otherwise `target.reparent()`.\n */\n async dispatch(carrier: any, target: any, options: any = {}): Promise<void> {\n if (target?.canReceive && !target.canReceive(carrier)) {\n this.trigger('transfer-rejected', {\n type: 'transfer-rejected',\n component: carrier,\n container: this,\n reason: 'target-full'\n })\n return\n }\n delete carrier[TRANSFER_SLOT_KEY]\n if (typeof target?.receive === 'function') {\n await target.receive(carrier, options)\n } else {\n ;(target as any).reparent?.(carrier, options)\n }\n this.trigger('transfer-dispatched', {\n type: 'transfer-dispatched',\n component: carrier,\n container: this,\n target\n })\n }\n\n // ── Domain aliases ────────────────────────────────────────────────────────\n\n /** Alias for receive() — semantic sugar for the storage domain. */\n store(carrier: any, options?: any): Promise<void> {\n return this.receive(carrier, options)\n }\n\n /** Alias for dispatch() — semantic sugar for the storage domain. */\n retrieve(carrier: any, target: any, options?: any): Promise<void> {\n return this.dispatch(carrier, target, options)\n }\n\n // ── 3D attach frame ───────────────────────────────────────────────────────\n\n /**\n * Return the 3D attach frame for carriers placed in this cell.\n * Carriers are lifted by their own halfDepth so the bottom face\n * rests at the cell's Y-center (which is levelHeight/2 above the beam).\n */\n attachPointFor(carrier: Component): AttachFrame | null {\n const root = this._realObject?.object3d\n if (!root) return null\n const carrierDepth = resolveCarrierDepth(carrier)\n return {\n attach: root,\n localPosition: { x: 0, y: carrierDepth / 2, z: 0 }\n }\n }\n\n // ── 2D rendering ──────────────────────────────────────────────────────────\n\n /** RackCell has no 2D visual — the rack draws its own structure. */\n render(_ctx: CanvasRenderingContext2D) {\n // intentional no-op\n }\n\n // ── 3D ───────────────────────────────────────────────────────────────────\n\n buildRealObject(): RealObject | undefined {\n return new StorageCell3D(this)\n }\n}\n\nfunction resolveCarrierDepth(c: Component): number {\n const eff = (c as any)._realObject?.effectiveDepth\n if (typeof eff === 'number' && Number.isFinite(eff)) return eff\n return numOr((c as any)?.state?.depth, 0)\n}\n\nfunction numOr(v: unknown, dflt: number): number {\n return typeof v === 'number' && Number.isFinite(v) ? v : dflt\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { RealObjectGroup } from '@hatiolab/things-scene';
2
- export declare class AsrsRack3D extends RealObjectGroup {
2
+ export declare class StorageRack3D extends RealObjectGroup {
3
3
  build(): void;
4
4
  updateDimension(): void;
5
5
  onchange(after: Record<string, unknown>, before: Record<string, unknown>): void;
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * Copyright © HatioLab Inc. All rights reserved.
3
3
  *
4
- * AsrsRack 3D — multi-level high-bay storage rack.
4
+ * Rack 3D — multi-level storage shelf system.
5
5
  *
6
6
  * LO-POLY but visually unambiguous as a rack. The signature parts:
7
7
  *
@@ -13,7 +13,7 @@
13
13
  * this is a load-bearing storage rack, not just a generic frame)
14
14
  *
15
15
  * No floor / ceiling panels — the rack is open by design (cells are accessed
16
- * by the stacker crane from the front/aisle side).
16
+ * by a picker from the front side).
17
17
  *
18
18
  * Cargo (pallets, boxes) added as children render at their own z position.
19
19
  * The rack itself is purely structural geometry.
@@ -24,7 +24,7 @@ import { RealObjectGroup } from '@hatiolab/things-scene';
24
24
  const POST_COLOR = 0x6a7080;
25
25
  const BEAM_COLOR = 0x556070;
26
26
  const BRACE_COLOR = 0x556070;
27
- export class AsrsRack3D extends RealObjectGroup {
27
+ export class StorageRack3D extends RealObjectGroup {
28
28
  build() {
29
29
  super.build();
30
30
  const { width, height, depth = 3000 } = this.component.state;
@@ -126,4 +126,4 @@ export class AsrsRack3D extends RealObjectGroup {
126
126
  }
127
127
  updateAlpha() { }
128
128
  }
129
- //# sourceMappingURL=asrs-rack-3d.js.map
129
+ //# sourceMappingURL=storage-rack-3d.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-rack-3d.js","sourceRoot":"","sources":["../src/storage-rack-3d.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAA;AAC9B,OAAO,KAAK,mBAAmB,MAAM,iDAAiD,CAAA;AACtF,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAExD,MAAM,UAAU,GAAG,QAAQ,CAAA;AAC3B,MAAM,UAAU,GAAG,QAAQ,CAAA;AAC3B,MAAM,WAAW,GAAG,QAAQ,CAAA;AAE5B,MAAM,OAAO,aAAc,SAAQ,eAAe;IAChD,KAAK;QACH,KAAK,CAAC,KAAK,EAAE,CAAA;QAEb,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAA;QAC5D,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,MAAiB,IAAI,CAAC,CAAC,CAAC,CAAA;QACpF,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAe,IAAI,CAAC,CAAC,CAAC,CAAA;QAEhF,MAAM,KAAK,GAAG,CAAC,KAAK,GAAG,CAAC,CAAA;QACxB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,EAAE,MAAM,CAAC,GAAG,IAAI,CAAA;QACnD,MAAM,KAAK,GAAG,KAAK,GAAG,KAAK,CAAA;QAC3B,MAAM,MAAM,GAAG,KAAK,GAAG,GAAG,CAAA;QAE1B,MAAM,YAAY,GAAG,IAAI,KAAK,CAAC,oBAAoB,CAAC;YAClD,KAAK,EAAE,UAAU;YACjB,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;SACf,CAAC,CAAA;QACF,MAAM,YAAY,GAAG,IAAI,KAAK,CAAC,oBAAoB,CAAC;YAClD,KAAK,EAAE,UAAU;YACjB,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;SACf,CAAC,CAAA;QACF,MAAM,aAAa,GAAG,IAAI,KAAK,CAAC,oBAAoB,CAAC;YACnD,KAAK,EAAE,WAAW;YAClB,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;SACf,CAAC,CAAA;QAEF,oEAAoE;QACpE,yEAAyE;QACzE,MAAM,QAAQ,GAA2B,EAAE,CAAA;QAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,GAAG,CAAA;YAC5B,MAAM,CAAC,GAAG,KAAK,GAAG,KAAK,CAAA;YACvB,qBAAqB;YACrB,KAAK,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBAC5B,MAAM,IAAI,GAAG,IAAI,KAAK,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAA;gBACvD,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAA;gBACtD,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACrB,CAAC;QACH,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC,CAAA;QAC5F,QAAQ,CAAC,UAAU,GAAG,IAAI,CAAA;QAC1B,QAAQ,CAAC,aAAa,GAAG,IAAI,CAAA;QAC7B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QAE3B,oEAAoE;QACpE,mEAAmE;QACnE,MAAM,QAAQ,GAA2B,EAAE,CAAA;QAC3C,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,IAAI,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC;YACpC,MAAM,KAAK,GAAG,EAAE,GAAG,MAAM,CAAA;YACzB,MAAM,CAAC,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YAEpE,KAAK,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;gBAC5B,MAAM,IAAI,GAAG,IAAI,KAAK,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,CAAA;gBACvD,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAA;gBACtD,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACrB,CAAC;QACH,CAAC;QACD,MAAM,QAAQ,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,YAAY,CAAC,CAAA;QAC5F,QAAQ,CAAC,UAAU,GAAG,IAAI,CAAA;QAC1B,QAAQ,CAAC,aAAa,GAAG,IAAI,CAAA;QAC7B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;QAE3B,oEAAoE;QACpE,kEAAkE;QAClE,0DAA0D;QAC1D,MAAM,SAAS,GAA2B,EAAE,CAAA;QAC5C,MAAM,KAAK,GAAG,KAAK,GAAG,IAAI,CAAA;QAC1B,MAAM,KAAK,GAAG,KAAK,GAAG,MAAM,CAAA;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC,CAAA;QACzD,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;QAC3C,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,GAAG,KAAK,GAAG,GAAG,CAAA;QAEtC,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;YACpC,0DAA0D;YAC1D,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC;gBAAE,SAAQ;YAE3B,MAAM,WAAW,GAAG,CAAC,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,KAAK,CAAA;YAElD,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC;gBACnC,MAAM,WAAW,GAAG,KAAK,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,GAAG,KAAK,CAAA;gBAE9C,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;oBAC3B,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;oBAC7D,KAAK,CAAC,OAAO,CAAC,IAAI,GAAG,UAAU,CAAC,CAAA;oBAChC,KAAK,CAAC,SAAS,CAAC,WAAW,EAAE,WAAW,EAAE,KAAK,CAAC,CAAA;oBAChD,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;gBACvB,CAAC;YACH,CAAC;QACH,CAAC;QACD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,SAAS,GAAG,IAAI,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,eAAe,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC,CAAA;YAC/F,SAAS,CAAC,UAAU,GAAG,IAAI,CAAA;YAC3B,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;QAC9B,CAAC;IACH,CAAC;IAED,eAAe,KAAI,CAAC;IAEpB,QAAQ,CAAC,KAA8B,EAAE,MAA+B;QACtE,IACE,QAAQ,IAAI,KAAK;YACjB,MAAM,IAAI,KAAK;YACf,OAAO,IAAI,KAAK;YAChB,QAAQ,IAAI,KAAK;YACjB,OAAO,IAAI,KAAK,EAChB,CAAC;YACD,IAAI,CAAC,MAAM,EAAE,CAAA;YACb,OAAM;QACR,CAAC;QACD,KAAK,CAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;IAC/B,CAAC;IAED,WAAW,KAAI,CAAC;CACjB","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n *\n * Rack 3D — multi-level storage shelf system.\n *\n * LO-POLY but visually unambiguous as a rack. The signature parts:\n *\n * - 4 corner uprights (vertical posts running floor → top)\n * - intermediate uprights between bays (one between each adjacent bay pair)\n * - horizontal beams at each level on both front and back faces (defining\n * the cell decks)\n * - diagonal cross-bracing on the back face (the \"X\" pattern that says\n * this is a load-bearing storage rack, not just a generic frame)\n *\n * No floor / ceiling panels — the rack is open by design (cells are accessed\n * by a picker from the front side).\n *\n * Cargo (pallets, boxes) added as children render at their own z position.\n * The rack itself is purely structural geometry.\n */\n\nimport * as THREE from 'three'\nimport * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js'\nimport { RealObjectGroup } from '@hatiolab/things-scene'\n\nconst POST_COLOR = 0x6a7080\nconst BEAM_COLOR = 0x556070\nconst BRACE_COLOR = 0x556070\n\nexport class StorageRack3D extends RealObjectGroup {\n build() {\n super.build()\n\n const { width, height, depth = 3000 } = this.component.state\n const levels = Math.max(1, Math.floor((this.component.state.levels as number) || 4))\n const bays = Math.max(1, Math.floor((this.component.state.bays as number) || 5))\n\n const baseY = -depth / 2\n const postW = Math.min(width / bays, height) * 0.06\n const beamH = depth * 0.025\n const braceT = postW * 0.6\n\n const postMaterial = new THREE.MeshStandardMaterial({\n color: POST_COLOR,\n metalness: 0.7,\n roughness: 0.4\n })\n const beamMaterial = new THREE.MeshStandardMaterial({\n color: BEAM_COLOR,\n metalness: 0.7,\n roughness: 0.4\n })\n const braceMaterial = new THREE.MeshStandardMaterial({\n color: BRACE_COLOR,\n metalness: 0.7,\n roughness: 0.4\n })\n\n // ── Uprights (vertical posts at every bay boundary) ──────────────\n // bays + 1 vertical positions; for each, one front post + one back post.\n const postGeos: THREE.BufferGeometry[] = []\n for (let i = 0; i <= bays; i++) {\n const xFrac = i / bays - 0.5\n const x = xFrac * width\n // Front + back posts\n for (const zSign of [-1, 1]) {\n const post = new THREE.BoxGeometry(postW, depth, postW)\n post.translate(x, 0, zSign * (height / 2 - postW / 2))\n postGeos.push(post)\n }\n }\n const postMesh = new THREE.Mesh(BufferGeometryUtils.mergeGeometries(postGeos), postMaterial)\n postMesh.castShadow = true\n postMesh.receiveShadow = true\n this.object3d.add(postMesh)\n\n // ── Horizontal beams (front + back faces at each level) ──────────\n // levels + 1 vertical positions (level 0 = ground, level N = top).\n const beamGeos: THREE.BufferGeometry[] = []\n for (let lv = 0; lv <= levels; lv++) {\n const yFrac = lv / levels\n const y = baseY + yFrac * depth - beamH / 2 + (lv === 0 ? beamH : 0)\n\n for (const zSign of [-1, 1]) {\n const beam = new THREE.BoxGeometry(width, beamH, beamH)\n beam.translate(0, y, zSign * (height / 2 - beamH / 2))\n beamGeos.push(beam)\n }\n }\n const beamMesh = new THREE.Mesh(BufferGeometryUtils.mergeGeometries(beamGeos), beamMaterial)\n beamMesh.castShadow = true\n beamMesh.receiveShadow = true\n this.object3d.add(beamMesh)\n\n // ── Diagonal cross-bracing on the back face (the \"X\" pattern) ────\n // Two diagonals per level — \"/\" and \"\\\" — making an X across each\n // bay-tall cell. Visual signature of a load-bearing rack.\n const braceGeos: THREE.BufferGeometry[] = []\n const cellW = width / bays\n const cellH = depth / levels\n const braceLen = Math.sqrt(cellW * cellW + cellH * cellH)\n const braceAngle = Math.atan2(cellH, cellW)\n const backZ = height / 2 - postW * 0.6\n\n for (let bay = 0; bay < bays; bay++) {\n // Brace only every other bay to keep things visually open\n if (bay % 2 !== 0) continue\n\n const cellCenterX = (bay - bays / 2 + 0.5) * cellW\n\n for (let lv = 0; lv < levels; lv++) {\n const cellCenterY = baseY + (lv + 0.5) * cellH\n\n for (const sign of [-1, 1]) {\n const brace = new THREE.BoxGeometry(braceLen, braceT, braceT)\n brace.rotateZ(sign * braceAngle)\n brace.translate(cellCenterX, cellCenterY, backZ)\n braceGeos.push(brace)\n }\n }\n }\n if (braceGeos.length > 0) {\n const braceMesh = new THREE.Mesh(BufferGeometryUtils.mergeGeometries(braceGeos), braceMaterial)\n braceMesh.castShadow = true\n this.object3d.add(braceMesh)\n }\n }\n\n updateDimension() {}\n\n onchange(after: Record<string, unknown>, before: Record<string, unknown>) {\n if (\n 'levels' in after ||\n 'bays' 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,33 +1,39 @@
1
1
  import { Component, ComponentNature, RealObject } from '@hatiolab/things-scene';
2
2
  import type { State, Material3D } from '@hatiolab/things-scene';
3
3
  import { CellMap, type AttachFrame, type Alignment, type Heights, type PlacementArchetype } from '@operato/scene-base';
4
- /** AsrsRack 컴포넌트 state */
5
- export interface AsrsRackState extends State {
4
+ /** Rack 컴포넌트 state */
5
+ export interface StorageRackState extends State {
6
6
  bays?: number;
7
7
  levels?: number;
8
8
  debugCells?: boolean;
9
9
  material3d?: Material3D;
10
10
  }
11
- declare const AsrsRack_base: any;
11
+ declare const Rack_base: any;
12
12
  /**
13
- * AsrsRack — a multi-level high-bay storage rack, the structural backbone of
14
- * an AS/RS (Automated Storage / Retrieval System).
13
+ * Rack — a multi-level storage shelf system. A *Storage* whose role is to hold
14
+ * carriers in a (bay × level) grid of cells.
15
15
  *
16
16
  * `levels` × `bays` cells form a vertical grid. Each cell holds one logistics
17
- * package (Pallet / Box / Parcel). A pair of AsrsRacks separated by an aisle
18
- * (where an AsrsCrane runs) is the typical AS/RS configuration.
17
+ * package (Pallet / Box / Parcel). A picker (Crane / Forklift / robot arm)
18
+ * accesses individual cells via Phase G/H Pickable contract — the picker is
19
+ * Rack-agnostic, knowing only how to interact with a cell.
19
20
  *
20
- * **Monitoring mode** (default): pallets/boxes are direct children of the rack,
21
- * placed by the WCS data binding. No RackCell children are created.
21
+ * **Monitoring mode** (default): carriers are direct children of the rack,
22
+ * placed by external data binding. No RackCell children are created.
22
23
  *
23
24
  * **Simulation mode**: call `rack._buildCells()` after placing the rack on the
24
- * scene. This creates RackCell children at the correct 3D positions. The
25
- * AsrsCrane then navigates to individual RackCells for pick-and-place.
25
+ * scene. This creates RackCell children at the correct 3D positions. A picker
26
+ * (Crane / Forklift / ...) then navigates to individual RackCells for
27
+ * pick-and-place.
26
28
  *
27
29
  * **Placement**: `floor` archetype, full ceiling depth by default.
30
+ *
31
+ * **Mobility**: this Rack is stationary. A `MobileRack = Mover(Rack)` mixin
32
+ * extension can be added later for AGV-mounted or cart-mounted variants —
33
+ * the cell topology and pickable contract stay the same.
28
34
  */
29
- export default class AsrsRack extends AsrsRack_base {
30
- state: AsrsRackState;
35
+ export default class Rack extends Rack_base {
36
+ state: StorageRackState;
31
37
  static placement: PlacementArchetype;
32
38
  static align: Alignment;
33
39
  static defaultDepth: (h: Heights) => number;
@@ -48,7 +54,7 @@ export default class AsrsRack extends AsrsRack_base {
48
54
  * Create RackCell child components for each cell in the CellMap.
49
55
  *
50
56
  * Called explicitly to enter simulation mode — monitoring-mode racks
51
- * never call this (pallets are direct children, no explicit cells).
57
+ * never call this (carriers are direct children, no explicit cells).
52
58
  *
53
59
  * Idempotent: removes existing rack-cell children first.
54
60
  */
@@ -64,7 +70,7 @@ export default class AsrsRack extends AsrsRack_base {
64
70
  containable(component: Component): boolean;
65
71
  /**
66
72
  * Attach frame for carriers that are DIRECT children of the rack
67
- * (monitoring mode, where pallets go directly into the rack without
73
+ * (monitoring mode, where carriers go directly into the rack without
68
74
  * explicit RackCell components).
69
75
  *
70
76
  * In simulation mode, carriers become children of their RackCell,
@@ -75,7 +81,7 @@ export default class AsrsRack extends AsrsRack_base {
75
81
  attachPointFor(_carrier: Component): AttachFrame | null;
76
82
  /**
77
83
  * 2D — top-down rectangle showing the rack footprint, with subdivisions
78
- * suggesting the bay layout (lines parallel to the aisle).
84
+ * suggesting the bay layout.
79
85
  */
80
86
  render(ctx: CanvasRenderingContext2D): void;
81
87
  get fillStyle(): string;
@@ -4,7 +4,7 @@ import { __decorate } from "tslib";
4
4
  */
5
5
  import { Component, ContainerAbstract, sceneComponent } from '@hatiolab/things-scene';
6
6
  import { CellContainer, CellMap, CarrierHolder, Placeable } from '@operato/scene-base';
7
- import { AsrsRack3D } from './asrs-rack-3d.js';
7
+ import { StorageRack3D } from './storage-rack-3d.js';
8
8
  const NATURE = {
9
9
  mutable: false,
10
10
  resizable: true,
@@ -23,11 +23,11 @@ const NATURE = {
23
23
  placeholder: '# of horizontal bays (default 5)'
24
24
  }
25
25
  ],
26
- help: 'scene/component/asrs-rack'
26
+ help: 'scene/component/rack'
27
27
  };
28
28
  // `ContainerAbstract` (not `Container`) — Container = MixinHTMLElement(ContainerAbstract),
29
29
  // which forces `isHTMLElement(): true` and trips the 3D pipeline's
30
- // addObject DOM-skip gate. ASRS rack lives only in the 3D scene graph.
30
+ // addObject DOM-skip gate. Rack lives only in the 3D scene graph.
31
31
  //
32
32
  // Mixin chain: CellContainer → CarrierHolder → Placeable → ContainerAbstract
33
33
  // CellContainer: cell topology (cellMap, cell(), findAvailableCell(), occupiedCellIds())
@@ -35,23 +35,29 @@ const NATURE = {
35
35
  // Placeable: floor-archetype positioning
36
36
  // ContainerAbstract: child component management
37
37
  /**
38
- * AsrsRack — a multi-level high-bay storage rack, the structural backbone of
39
- * an AS/RS (Automated Storage / Retrieval System).
38
+ * Rack — a multi-level storage shelf system. A *Storage* whose role is to hold
39
+ * carriers in a (bay × level) grid of cells.
40
40
  *
41
41
  * `levels` × `bays` cells form a vertical grid. Each cell holds one logistics
42
- * package (Pallet / Box / Parcel). A pair of AsrsRacks separated by an aisle
43
- * (where an AsrsCrane runs) is the typical AS/RS configuration.
42
+ * package (Pallet / Box / Parcel). A picker (Crane / Forklift / robot arm)
43
+ * accesses individual cells via Phase G/H Pickable contract — the picker is
44
+ * Rack-agnostic, knowing only how to interact with a cell.
44
45
  *
45
- * **Monitoring mode** (default): pallets/boxes are direct children of the rack,
46
- * placed by the WCS data binding. No RackCell children are created.
46
+ * **Monitoring mode** (default): carriers are direct children of the rack,
47
+ * placed by external data binding. No RackCell children are created.
47
48
  *
48
49
  * **Simulation mode**: call `rack._buildCells()` after placing the rack on the
49
- * scene. This creates RackCell children at the correct 3D positions. The
50
- * AsrsCrane then navigates to individual RackCells for pick-and-place.
50
+ * scene. This creates RackCell children at the correct 3D positions. A picker
51
+ * (Crane / Forklift / ...) then navigates to individual RackCells for
52
+ * pick-and-place.
51
53
  *
52
54
  * **Placement**: `floor` archetype, full ceiling depth by default.
55
+ *
56
+ * **Mobility**: this Rack is stationary. A `MobileRack = Mover(Rack)` mixin
57
+ * extension can be added later for AGV-mounted or cart-mounted variants —
58
+ * the cell topology and pickable contract stay the same.
53
59
  */
54
- let AsrsRack = class AsrsRack extends CellContainer(CarrierHolder(Placeable(ContainerAbstract))) {
60
+ let Rack = class Rack extends CellContainer(CarrierHolder(Placeable(ContainerAbstract))) {
55
61
  static placement = 'floor';
56
62
  static align = 'bottom';
57
63
  static defaultDepth = (h) => h.ceiling - h.floor;
@@ -91,7 +97,7 @@ let AsrsRack = class AsrsRack extends CellContainer(CarrierHolder(Placeable(Cont
91
97
  * Create RackCell child components for each cell in the CellMap.
92
98
  *
93
99
  * Called explicitly to enter simulation mode — monitoring-mode racks
94
- * never call this (pallets are direct children, no explicit cells).
100
+ * never call this (carriers are direct children, no explicit cells).
95
101
  *
96
102
  * Idempotent: removes existing rack-cell children first.
97
103
  */
@@ -99,20 +105,20 @@ let AsrsRack = class AsrsRack extends CellContainer(CarrierHolder(Placeable(Cont
99
105
  // Remove existing rack-cell children
100
106
  const existing = this.components ?? [];
101
107
  for (const child of [...existing]) {
102
- if (child.state?.type === 'rack-cell') {
108
+ if (child.state?.type === 'storage-cell') {
103
109
  this.removeComponent(child);
104
110
  }
105
111
  }
106
112
  // Create a RackCell for each cell in the map
107
- const RackCellClass = Component.register('rack-cell');
113
+ const RackCellClass = Component.register('storage-cell');
108
114
  if (!RackCellClass) {
109
- console.warn('AsrsRack._buildCells: rack-cell type not registered. Import rack-cell.ts first.');
115
+ console.warn('Rack._buildCells: rack-cell type not registered. Import rack-cell.ts first.');
110
116
  return;
111
117
  }
112
118
  const context = this._app;
113
119
  for (const cell of this.cellMap.cells) {
114
120
  const model = {
115
- type: 'rack-cell',
121
+ type: 'storage-cell',
116
122
  cellId: cell.id,
117
123
  width: cell.size.width,
118
124
  height: cell.size.depth, // 2D height = 3D Z depth
@@ -132,7 +138,7 @@ let AsrsRack = class AsrsRack extends CellContainer(CarrierHolder(Placeable(Cont
132
138
  * - Everything else (sensors, labels, etc. can be siblings of the rack, not children).
133
139
  */
134
140
  containable(component) {
135
- if (component.state?.type === 'rack-cell')
141
+ if (component.state?.type === 'storage-cell')
136
142
  return true;
137
143
  const archetype = component.constructor.placement;
138
144
  if (archetype === 'operation')
@@ -142,7 +148,7 @@ let AsrsRack = class AsrsRack extends CellContainer(CarrierHolder(Placeable(Cont
142
148
  // ── CarrierHolder — attach frame for direct carrier children ─────────────
143
149
  /**
144
150
  * Attach frame for carriers that are DIRECT children of the rack
145
- * (monitoring mode, where pallets go directly into the rack without
151
+ * (monitoring mode, where carriers go directly into the rack without
146
152
  * explicit RackCell components).
147
153
  *
148
154
  * In simulation mode, carriers become children of their RackCell,
@@ -159,7 +165,7 @@ let AsrsRack = class AsrsRack extends CellContainer(CarrierHolder(Placeable(Cont
159
165
  // ── 2D rendering ─────────────────────────────────────────────────────────
160
166
  /**
161
167
  * 2D — top-down rectangle showing the rack footprint, with subdivisions
162
- * suggesting the bay layout (lines parallel to the aisle).
168
+ * suggesting the bay layout.
163
169
  */
164
170
  render(ctx) {
165
171
  const { width, height, left, top } = this.state;
@@ -179,11 +185,11 @@ let AsrsRack = class AsrsRack extends CellContainer(CarrierHolder(Placeable(Cont
179
185
  }
180
186
  // ── 3D ───────────────────────────────────────────────────────────────────
181
187
  buildRealObject() {
182
- return new AsrsRack3D(this);
188
+ return new StorageRack3D(this);
183
189
  }
184
190
  };
185
- AsrsRack = __decorate([
186
- sceneComponent('asrs-rack')
187
- ], AsrsRack);
188
- export default AsrsRack;
189
- //# sourceMappingURL=asrs-rack.js.map
191
+ Rack = __decorate([
192
+ sceneComponent('storage-rack')
193
+ ], Rack);
194
+ export default Rack;
195
+ //# sourceMappingURL=storage-rack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage-rack.js","sourceRoot":"","sources":["../src/storage-rack.ts"],"names":[],"mappings":";AAAA;;GAEG;AACH,OAAO,EAAE,SAAS,EAAmB,iBAAiB,EAAc,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAElH,OAAO,EACL,aAAa,EACb,OAAO,EACP,aAAa,EACb,SAAS,EAKV,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AAepD,MAAM,MAAM,GAAoB;IAC9B,OAAO,EAAE,KAAK;IACd,SAAS,EAAE,IAAI;IACf,SAAS,EAAE,IAAI;IACf,UAAU,EAAE;QACV;YACE,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,QAAQ;YACf,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,kCAAkC;SAChD;QACD;YACE,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,MAAM;YACb,IAAI,EAAE,MAAM;YACZ,WAAW,EAAE,kCAAkC;SAChD;KACF;IACD,IAAI,EAAE,sBAAsB;CAC7B,CAAA;AAED,2FAA2F;AAC3F,mEAAmE;AACnE,kEAAkE;AAClE,EAAE;AACF,6EAA6E;AAC7E,2FAA2F;AAC3F,gFAAgF;AAChF,+CAA+C;AAC/C,kDAAkD;AAClD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEY,IAAM,IAAI,GAAV,MAAM,IAAK,SAAQ,aAAa,CAAC,aAAa,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAG1F,MAAM,CAAC,SAAS,GAAuB,OAAO,CAAA;IAC9C,MAAM,CAAC,KAAK,GAAc,QAAQ,CAAA;IAClC,MAAM,CAAC,YAAY,GAAG,CAAC,CAAU,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,KAAK,CAAA;IAEzD,IAAI,MAAM;QACR,OAAO,MAAM,CAAA;IACf,CAAC;IAED,IAAI,OAAO;QACT,OAAO,EAAE,CAAA;IACX,CAAC;IAED,6EAA6E;IAE7E;;;;;;;;;OASG;IACH,IAAI,OAAO;QACT,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAE,IAAI,CAAC,KAAK,CAAC,IAAe,IAAI,CAAC,CAAC,CAAC,CAAA;QACtE,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAE,IAAI,CAAC,KAAK,CAAC,MAAiB,IAAI,CAAC,CAAC,CAAC,CAAA;QAC1E,MAAM,KAAK,GAAI,IAAI,CAAC,KAAK,CAAC,KAAgB,IAAI,IAAI,CAAA;QAClD,MAAM,SAAS,GAAI,IAAI,CAAC,KAAK,CAAC,KAAgB,IAAI,IAAI,CAAA,CAAG,mBAAmB;QAC5E,MAAM,UAAU,GAAI,IAAI,CAAC,KAAK,CAAC,MAAiB,IAAI,GAAG,CAAA,CAAE,gBAAgB;QAEzE,OAAO,OAAO,CAAC,IAAI,CAAC;YAClB,IAAI;YACJ,IAAI,EAAE,CAAC;YACP,MAAM;YACN,QAAQ,EAAE,KAAK,GAAG,IAAI;YACtB,QAAQ,EAAE,UAAU;YACpB,WAAW,EAAE,SAAS,GAAG,MAAM;SAChC,CAAC,CAAA;IACJ,CAAC;IAED;;;;;;;OAOG;IACH,WAAW;QACT,qCAAqC;QACrC,MAAM,QAAQ,GAAI,IAAI,CAAC,UAAsC,IAAI,EAAE,CAAA;QACnE,KAAK,MAAM,KAAK,IAAI,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC;YAClC,IAAK,KAAa,CAAC,KAAK,EAAE,IAAI,KAAK,cAAc,EAAE,CAAC;gBAClD,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAA;YAC7B,CAAC;QACH,CAAC;QAED,6CAA6C;QAC7C,MAAM,aAAa,GAAI,SAAiB,CAAC,QAAQ,CAAC,cAAc,CAAoD,CAAA;QACpH,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,OAAO,CAAC,IAAI,CAAC,6EAA6E,CAAC,CAAA;YAC3F,OAAM;QACR,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAA;QACzB,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACtC,MAAM,KAAK,GAAG;gBACZ,IAAI,EAAE,cAAc;gBACpB,MAAM,EAAE,IAAI,CAAC,EAAE;gBACf,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK;gBACtB,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,EAAG,yBAAyB;gBACnD,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAG,sBAAsB;aACjD,CAAA;YACD,MAAM,QAAQ,GAAG,IAAI,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;YAClD,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAA;QAC7B,CAAC;IACH,CAAC;IAED,6EAA6E;IAE7E;;;;;;;OAOG;IACH,WAAW,CAAC,SAAoB;QAC9B,IAAK,SAAiB,CAAC,KAAK,EAAE,IAAI,KAAK,cAAc;YAAE,OAAO,IAAI,CAAA;QAClE,MAAM,SAAS,GAAI,SAAS,CAAC,WAAmB,CAAC,SAAS,CAAA;QAC1D,IAAI,SAAS,KAAK,WAAW;YAAE,OAAO,IAAI,CAAA;QAC1C,OAAO,SAAS,CAAC,aAAa,CAAC,IAAI,CAAC,CAAA;IACtC,CAAC;IAED,4EAA4E;IAE5E;;;;;;;;;OASG;IACH,cAAc,CAAC,QAAmB;QAChC,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAA;QACvC,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAA;QACtB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAA;IACzB,CAAC;IAED,4EAA4E;IAE5E;;;OAGG;IACH,MAAM,CAAC,GAA6B;QAClC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAA;QAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAE,IAAI,CAAC,KAAK,CAAC,IAAe,IAAI,CAAC,CAAC,CAAC,CAAA;QAEtE,GAAG,CAAC,SAAS,EAAE,CAAA;QACf,kBAAkB;QAClB,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,CAAC,CAAA;QAClC,oCAAoC;QACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9B,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,IAAI,CAAA;YACnC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;YAClB,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,GAAG,MAAM,CAAC,CAAA;QAC7B,CAAC;IACH,CAAC;IAED,IAAI,SAAS;QACX,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,4EAA4E;IAE5E,eAAe;QACb,OAAO,IAAI,aAAa,CAAC,IAAI,CAAC,CAAA;IAChC,CAAC;;AAlJkB,IAAI;IADxB,cAAc,CAAC,cAAc,CAAC;GACV,IAAI,CAmJxB;eAnJoB,IAAI","sourcesContent":["/*\n * Copyright © HatioLab Inc. All rights reserved.\n */\nimport { Component, ComponentNature, ContainerAbstract, RealObject, sceneComponent } from '@hatiolab/things-scene'\nimport type { State, Material3D } from '@hatiolab/things-scene'\nimport {\n CellContainer,\n CellMap,\n CarrierHolder,\n Placeable,\n type AttachFrame,\n type Alignment,\n type Heights,\n type PlacementArchetype\n} from '@operato/scene-base'\n\nimport { StorageRack3D } from './storage-rack-3d.js'\n\n/** Rack 컴포넌트 state */\nexport interface StorageRackState extends State {\n // ── 토폴로지 ──\n bays?: number\n levels?: number\n\n // ── 디버그 ──\n debugCells?: boolean\n\n // ── 3D 재질 ──\n material3d?: Material3D\n}\n\nconst NATURE: ComponentNature = {\n mutable: false,\n resizable: true,\n rotatable: true,\n properties: [\n {\n type: 'number',\n label: 'levels',\n name: 'levels',\n placeholder: '# of vertical levels (default 4)'\n },\n {\n type: 'number',\n label: 'bays',\n name: 'bays',\n placeholder: '# of horizontal bays (default 5)'\n }\n ],\n help: 'scene/component/rack'\n}\n\n// `ContainerAbstract` (not `Container`) — Container = MixinHTMLElement(ContainerAbstract),\n// which forces `isHTMLElement(): true` and trips the 3D pipeline's\n// addObject DOM-skip gate. Rack lives only in the 3D scene graph.\n//\n// Mixin chain: CellContainer → CarrierHolder → Placeable → ContainerAbstract\n// CellContainer: cell topology (cellMap, cell(), findAvailableCell(), occupiedCellIds())\n// CarrierHolder: 3D attach-point protocol (attachPointFor, containable gates)\n// Placeable: floor-archetype positioning\n// ContainerAbstract: child component management\n/**\n * Rack — a multi-level storage shelf system. A *Storage* whose role is to hold\n * carriers in a (bay × level) grid of cells.\n *\n * `levels` × `bays` cells form a vertical grid. Each cell holds one logistics\n * package (Pallet / Box / Parcel). A picker (Crane / Forklift / robot arm)\n * accesses individual cells via Phase G/H Pickable contract — the picker is\n * Rack-agnostic, knowing only how to interact with a cell.\n *\n * **Monitoring mode** (default): carriers are direct children of the rack,\n * placed by external data binding. No RackCell children are created.\n *\n * **Simulation mode**: call `rack._buildCells()` after placing the rack on the\n * scene. This creates RackCell children at the correct 3D positions. A picker\n * (Crane / Forklift / ...) then navigates to individual RackCells for\n * pick-and-place.\n *\n * **Placement**: `floor` archetype, full ceiling depth by default.\n *\n * **Mobility**: this Rack is stationary. A `MobileRack = Mover(Rack)` mixin\n * extension can be added later for AGV-mounted or cart-mounted variants —\n * the cell topology and pickable contract stay the same.\n */\n@sceneComponent('storage-rack')\nexport default class Rack extends CellContainer(CarrierHolder(Placeable(ContainerAbstract))) {\n declare state: StorageRackState\n\n static placement: PlacementArchetype = 'floor'\n static align: Alignment = 'bottom'\n static defaultDepth = (h: Heights) => h.ceiling - h.floor\n\n get nature() {\n return NATURE\n }\n\n get anchors() {\n return []\n }\n\n // ── CellContainer ─────────────────────────────────────────────────────────\n\n /**\n * Derive the cell topology from the rack's current dimensions and bay/level\n * counts. The CellMap is rebuilt fresh each time (state changes trigger\n * re-reads via things-scene's invalidation pipeline).\n *\n * Coordinate convention (matches things-scene 3D):\n * X = bay axis (left → right)\n * Y = level axis (floor → ceiling, the rack's `depth` state property)\n * Z = row axis (front → back, the rack's `height` state property)\n */\n get cellMap(): CellMap {\n const bays = Math.max(1, Math.floor((this.state.bays as number) || 5))\n const levels = Math.max(1, Math.floor((this.state.levels as number) || 4))\n const width = (this.state.width as number) || 1000\n const rackDepth = (this.state.depth as number) || 3000 // Y: floor→ceiling\n const rackHeight = (this.state.height as number) || 600 // Z: front→back\n\n return CellMap.grid({\n bays,\n rows: 1,\n levels,\n bayWidth: width / bays,\n rowDepth: rackHeight,\n levelHeight: rackDepth / levels\n })\n }\n\n /**\n * Create RackCell child components for each cell in the CellMap.\n *\n * Called explicitly to enter simulation mode — monitoring-mode racks\n * never call this (carriers are direct children, no explicit cells).\n *\n * Idempotent: removes existing rack-cell children first.\n */\n _buildCells(): void {\n // Remove existing rack-cell children\n const existing = (this.components as Component[] | undefined) ?? []\n for (const child of [...existing]) {\n if ((child as any).state?.type === 'storage-cell') {\n this.removeComponent(child)\n }\n }\n\n // Create a RackCell for each cell in the map\n const RackCellClass = (Component as any).register('storage-cell') as (new (...args: any[]) => Component) | undefined\n if (!RackCellClass) {\n console.warn('Rack._buildCells: rack-cell type not registered. Import rack-cell.ts first.')\n return\n }\n\n const context = this._app\n for (const cell of this.cellMap.cells) {\n const model = {\n type: 'storage-cell',\n cellId: cell.id,\n width: cell.size.width,\n height: cell.size.depth, // 2D height = 3D Z depth\n depth: cell.size.height // 3D Y = level height\n }\n const rackCell = new RackCellClass(model, context)\n this.addComponent(rackCell)\n }\n }\n\n // ── Container gates ───────────────────────────────────────────────────────\n\n /**\n * Allow:\n * - Carriable components (pallets, boxes, parcels) — direct children in monitoring mode.\n * - RackCell — created by _buildCells() in simulation mode.\n *\n * Block:\n * - Everything else (sensors, labels, etc. can be siblings of the rack, not children).\n */\n containable(component: Component): boolean {\n if ((component as any).state?.type === 'storage-cell') return true\n const archetype = (component.constructor as any).placement\n if (archetype === 'operation') return true\n return component.isDescendible(this)\n }\n\n // ── CarrierHolder — attach frame for direct carrier children ─────────────\n\n /**\n * Attach frame for carriers that are DIRECT children of the rack\n * (monitoring mode, where carriers go directly into the rack without\n * explicit RackCell components).\n *\n * In simulation mode, carriers become children of their RackCell,\n * and each RackCell provides its own attachPointFor(). So this method\n * is only invoked on direct-child carriers in monitoring mode — it\n * returns the rack's own object3d as the attach frame (default behavior).\n */\n attachPointFor(_carrier: Component): AttachFrame | null {\n const root = this._realObject?.object3d\n if (!root) return null\n return { attach: root }\n }\n\n // ── 2D rendering ─────────────────────────────────────────────────────────\n\n /**\n * 2D — top-down rectangle showing the rack footprint, with subdivisions\n * suggesting the bay layout.\n */\n render(ctx: CanvasRenderingContext2D) {\n const { width, height, left, top } = this.state\n const bays = Math.max(1, Math.floor((this.state.bays as number) || 5))\n\n ctx.beginPath()\n // Outer rectangle\n ctx.rect(left, top, width, height)\n // Bay subdivisions (vertical lines)\n for (let i = 1; i < bays; i++) {\n const x = left + (width * i) / bays\n ctx.moveTo(x, top)\n ctx.lineTo(x, top + height)\n }\n }\n\n get fillStyle() {\n return '#a0a0a8'\n }\n\n // ── 3D ───────────────────────────────────────────────────────────────────\n\n buildRealObject(): RealObject | undefined {\n return new StorageRack3D(this)\n }\n}\n"]}
@@ -34,6 +34,13 @@ declare const _default: ({
34
34
  material: string;
35
35
  levels?: undefined;
36
36
  bays?: undefined;
37
+ rows?: undefined;
38
+ columns?: undefined;
39
+ shelves?: undefined;
40
+ zone?: undefined;
41
+ locPattern?: undefined;
42
+ sectionDigits?: undefined;
43
+ unitDigits?: undefined;
37
44
  status?: undefined;
38
45
  carriageHeight?: undefined;
39
46
  components?: undefined;
@@ -52,6 +59,13 @@ declare const _default: ({
52
59
  material?: undefined;
53
60
  levels?: undefined;
54
61
  bays?: undefined;
62
+ rows?: undefined;
63
+ columns?: undefined;
64
+ shelves?: undefined;
65
+ zone?: undefined;
66
+ locPattern?: undefined;
67
+ sectionDigits?: undefined;
68
+ unitDigits?: undefined;
55
69
  status?: undefined;
56
70
  carriageHeight?: undefined;
57
71
  components?: undefined;
@@ -70,6 +84,38 @@ declare const _default: ({
70
84
  levels: number;
71
85
  bays: number;
72
86
  material?: undefined;
87
+ rows?: undefined;
88
+ columns?: undefined;
89
+ shelves?: undefined;
90
+ zone?: undefined;
91
+ locPattern?: undefined;
92
+ sectionDigits?: undefined;
93
+ unitDigits?: undefined;
94
+ status?: undefined;
95
+ carriageHeight?: undefined;
96
+ components?: undefined;
97
+ };
98
+ } | {
99
+ type: string;
100
+ description: string;
101
+ group: string;
102
+ icon: string;
103
+ model: {
104
+ type: string;
105
+ top: number;
106
+ left: number;
107
+ width: number;
108
+ height: number;
109
+ rows: number;
110
+ columns: number;
111
+ shelves: number;
112
+ zone: string;
113
+ locPattern: string;
114
+ sectionDigits: number;
115
+ unitDigits: number;
116
+ material?: undefined;
117
+ levels?: undefined;
118
+ bays?: undefined;
73
119
  status?: undefined;
74
120
  carriageHeight?: undefined;
75
121
  components?: undefined;
@@ -90,6 +136,13 @@ declare const _default: ({
90
136
  material?: undefined;
91
137
  levels?: undefined;
92
138
  bays?: undefined;
139
+ rows?: undefined;
140
+ columns?: undefined;
141
+ shelves?: undefined;
142
+ zone?: undefined;
143
+ locPattern?: undefined;
144
+ sectionDigits?: undefined;
145
+ unitDigits?: undefined;
93
146
  components?: undefined;
94
147
  };
95
148
  } | {
@@ -127,6 +180,13 @@ declare const _default: ({
127
180
  material?: undefined;
128
181
  levels?: undefined;
129
182
  bays?: undefined;
183
+ rows?: undefined;
184
+ columns?: undefined;
185
+ shelves?: undefined;
186
+ zone?: undefined;
187
+ locPattern?: undefined;
188
+ sectionDigits?: undefined;
189
+ unitDigits?: undefined;
130
190
  status?: undefined;
131
191
  carriageHeight?: undefined;
132
192
  };