Skip to content

Add support for 3D printed rack-mount solutions, including internal multi-splits. #372

@dirtyformal

Description

@dirtyformal

Summary

Support 3D printed rack-mount enclosures (OpenRack, RackMod, etc.) that contain multiple devices in defined bays/slots.

Problem

Users have 3D printed rack enclosures with internal bays:

3D printed enclosure example

Each enclosure is a single rack unit with multiple internal "bays" for mini PCs, SBCs, etc. Current workaround is text annotations, which isn't ideal.

Solution: Container Devices with Slots

Container devices define their internal slot layout. Child devices are placed into specific slots.

┌─────────────────────────────────┐
│ U6  ┌───────────────┬──────────┐│
│     │ Bay 1 (70%)   │Bay 2(30%)││  ← Container with custom slot widths
│ U5  │[Beelink EQR6] │  [Vent]  ││  ← Children in slots
│     └───────────────┴──────────┘│
└─────────────────────────────────┘

Data Model

// Container DeviceType
interface DeviceType {
  // Defines slots for child devices
  slots?: Array<{
    id: string;             // "bay-1", "bay-2"
    width_fraction: number; // 0.7, 0.3 (must sum to 1.0)
    label?: string;         // "Left Bay", "Vent"
  }>;
}

// Child PlacedDevice
interface PlacedDevice {
  container_id?: string;  // ID of parent PlacedDevice
  slot_id?: string;       // Which slot ("bay-1")
}

Example: 1U Enclosure with 70/30 Split

// DeviceType for the enclosure
{
  slug: "openrack-1u-2bay",
  manufacturer: "Custom",
  model: "OpenRack 1U",
  u_height: 1,
  category: "accessory",
  slots: [
    { id: "bay-1", width_fraction: 0.7, label: "Main Bay" },
    { id: "bay-2", width_fraction: 0.3, label: "Vent/Small" }
  ]
}

// PlacedDevice for child in bay 1
{
  id: "device-123",
  device_type: "beelink-eqr6",
  position: 5,
  container_id: "enclosure-456",  // References parent
  slot_id: "bay-1"
}

Implementation

Depends on: #146 (half-width foundation)

  1. Schema: Add slots to DeviceType, container_id + slot_id to PlacedDevice
  2. Rendering: Draw slot dividers, render children within slot bounds
  3. Placement UX: Click slot to place device, or drag into slot
  4. Collision: Children don't collide with rack - only with other children in same container
  5. Slot editor: UI to define slot count and width fractions

Slot Editor UX

Simple approach for defining slots:

  1. Select number of bays: 2, 3, or 4 (buttons)
  2. Default to equal widths
  3. "Customize widths" expands sliders for each bay
  4. Widths must sum to 100%
┌─────────────────────────────┐
│ Number of bays: [2] [3] [4] │
│                             │
│ ☑ Customize widths          │
│   Bay 1: [====70%====]      │
│   Bay 2: [==30%==]          │
│                             │
│ Preview:                    │
│ ┌──────────────┬───────┐    │
│ │    Bay 1     │ Bay 2 │    │
│ └──────────────┴───────┘    │
└─────────────────────────────┘

Acceptance Criteria

  • slots array on DeviceType schema (id, width_fraction, label)
  • container_id and slot_id on PlacedDevice schema
  • Container renders with visible slot dividers
  • Children render inside their assigned slot
  • Slot editor UI for defining bay layout
  • Variable width fractions (e.g., 70/30, 50/50, 33/33/34)
  • Generic "Custom 1U Enclosure" and "Custom 2U Enclosure" device types
  • Clicking empty slot opens device placement
  • Save/load preserves container relationships

Constraints

  • No nested containers: A container cannot be placed inside another container
  • Children don't collide with rack: Only with siblings in same container
  • Orphan handling: If container deleted, children are also removed

Files to Modify

  • src/lib/types/index.ts - slots on DeviceType, container fields on PlacedDevice
  • src/lib/schemas/index.ts - Zod schemas with slot validation
  • src/lib/components/RackDevice.svelte - Container rendering with slots
  • src/lib/components/SlotEditor.svelte - New component for slot configuration
  • src/lib/stores/layout.svelte.ts - Container placement logic
  • src/lib/utils/collision.ts - Container-aware collision

Original request from @username - thank you for the detailed feature request and images!

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions