UniteLabs
Concepts

Deck

The coordinate frame and resource tree that place labware in 3D space, and the layout files that make a deck reproducible across runs.

The deck is the spatial model every liquid-handling command resolves against. When you call aspirate(plate["A1"]), the SDK needs to know where well A1 sits in 3D space — and it knows because the plate is placed in a carrier site, which is placed in a carrier, which is placed on the deck at a known track. The deck is the root of that resource tree, and the origin of the coordinate frame.

Coordinate system

The deck is a 3-dimensional space with x, y, z coordinates in millimeters:

  • x: left → right (track direction)
  • y: front → back (depth)
  • z: bottom → top (height)

When standing in front of the device, the origin is in the bottom-left corner at the front. Depending on the device, the origin can be below the physical deck surface and beyond the marked tracks — device-specific details are documented in each device guide.

Every resource has two locations:

PropertyWhat it returns
resource.locationPosition relative to parent (None if not placed)
resource.absolute_locationAbsolute position from the deck origin

The absolute location is computed by walking the resource tree and summing each parent's offset.

The resource tree

Labware on a deck is always a tree. The deck is the root; carriers are children of the deck; carrier sites hold plates; plates hold wells. Children inherit position from their parent:

Deck
└── Carrier (track 15)
    └── CarrierSite [slot 0]
        └── Plate "wellplate"
            ├── Well A1
            ├── Well A2
            └── ...

When you call lh.deck.find(identifier="wellplate"), the SDK walks this tree to find the plate by its identifier. Positions are always stored relative to the parent; the absolute location is computed by summing up the chain.

This structure is what makes the labware model composable. Swap a carrier at track 7 for a different one, and every well inside it gets a new absolute location automatically. Save the tree to a file and reload it verbatim in the next run.

Deck bounds

Decks have dimensions constrained by the physical handler. The default bounds prevent placing a carrier outside the reachable area, but some workflows legitimately need to override this — for instance, placing a tip carrier below the minimum track so it is only reachable by the CO-RE96 head and not individual channels. Bounds can be relaxed per deck (deck.configure(min_track=None, max_track=None)), but positions outside the standard area may not be reachable by every module.

Layout as data

A deck layout is data. Once built, it can be serialized to JSON and reloaded in any future run — no need to reconstruct it from scratch each time. The JSON captures every carrier, every position, and every nested piece of labware, including identifiers and state.

The deck JSON file is intended to be committed alongside the workflow script that uses it:

  • It becomes a full audit trail of which physical layout was used for each experiment.
  • Deck changes produce reviewable diffs.
  • The workflow and its deck travel together when deployed or shared.

For the conventions on when to use the JSON form vs. a Python-script form of a deck, see Save/Load a Deck.

Where to go next