All skills
hyperb1iss avatar

/rig-setup

@18d3bf6

Set up a Hypercolor spatial layout and scene for a PC build from scratch: research the case's real dimensions, inventory the connected controllers and devices, interview the owner about what hangs on each port and where it sits, generate the attachment bindings, layout, and scene with the bundled generator, then dial the result in on the lit hardware until every fan, strip, strimer, LCD, and RAM stick animates in the right place and direction. Use this whenever someone wants their case, rig, PC, or build "mapped", "laid out", "set up", "onboarded", or "auto-configured" in Hypercolor, asks why a device animates backwards or upside down, wants to add a new controller or case to an existing layout, or mentions a case model (O11D, Hyte Y70, NZXT H9, Lancool, Torrent), a hub (Nollie, Uni Hub, iCUE LINK, L-Connect), or Strimer cables together with layout or positioning. Also use it when a device is missing from Hypercolor: "unsupported device", "device not found", "not detected", "nothing drives my X", anything about OpenRGB (install it, bridge a device through it, "OpenRGB sees it but Hypercolor doesn't"), or a request to "request support" for hardware. The coverage phase decides native driver, OpenRGB bridge, or a prefilled support request per device. Works with the REST API, the MCP tools, and the `hypercolor` CLI; it never needs the source tree.

  • 13 files
  • 161.7 KB
  • Updated 3 weeks ago
  • GitHub

Use this Skill: https://skilld.dev/gh/hyperb1iss/hypercolor/rig-setup

This session only. Nothing lands on disk.

referencesrig-spec.md

≈2.4k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Rig spec format

A rig spec is one person's build: which controller slot drives what, where each thing sits on the case, and the wiring facts (chain order, LED direction) that only the hardware can tell you. It references a case spec by id and is the file you edit during the dial-in loop. references/rigs/o11d-evo-rgb-reversed-example.json is a complete worked example (three controllers, four LCDs, two AIO rings, DRAM, strips, strimers).

Top level

{
  "schema": "hypercolor-rig-spec/1",
  "name": "My Case Layout",             // layout AND scene name (idempotency key)
  "case": "lian-li-o11d-evo-rgb",        // must match the case spec id
  "view": "reversed",                    // or "standard"
  "canvas": { "width": 640, "height": 630 },   // match the case aspect
  "description": "...",
  "effect_id": "<effect uuid>",          // optional: first scene layer, Color Wave by default
  "custom_templates": [ ... ],           // optional: simple strips the catalog lacks
  "controllers": { ... },
  "raw_zones": [ ... ],
  "bridge_rows": [ ... ],                // optional: strimers through an OpenRGB-bridged hub
  "bridge": { "zone_sizes": { ... } },   // optional: hub zone sizes apply pushes into config
  "verified": [ ... ], "unverified": [ ... ]   // free text, keep them honest
}

references/rigs/o11d-evo-rgb-reversed-bridge-example.json is an older test snapshot with the Nollie, DRAM, and motherboard driven through the OpenRGB bridge. Its Corsair rings and radiator ordering predate the native example's geometry corrections.

Controllers and bindings

"controllers": {
  "hub": {
    "device": "<daemon device uuid>",
    "layout_device_id": "<layout_device_id from GET /devices/{id}>",
    "bindings": [
      { "slot": "channel-3", "template": "lian-li-sl-infinity-fan", "instances": 3,
        "place": "top", "chain": "rear_to_front", "rotate": 3.14159 }
    ]
  }
}

Each binding is one PUT /devices/{id}/attachments entry plus placement. Fields:

field meaning
slot, template, instances, led_offset the attachment binding itself; several bindings may share a slot with different led_offset (two strips on one channel)
place a case-spec mount name, or motherboard for a full-board part like a backplate
chain how instances map onto a row/column: rear_to_front (default) or front_to_rear for rows, top_to_bottom (default) or bottom_to_top for columns
index pin one instance to one mount position explicitly (single-fan slots on a column)
board {u, v, w, hgt, rot} board-frame rectangle instead of a mount
anchor + offset + size_mm + rot board feature by name, nudged by {du, dv} mm
case {d, h, w, hgt, rot} raw case-frame rectangle
rotate extra rotation (radians) applied after placement; the whole-zone flip
mirror reverse LED travel along the zone's long axis (ring winding, strip direction, matrix columns)
mirror_y reverse the cross axis (matrix rows, vertical strips)
led_start_override force the zone's LED window start; 0 means "relative to the segment", the robust choice for strimer slots
label name fragment for the generated zone

Board-frame placements (board, anchor, motherboard) flip with the board in a reversed view; rot is specified in the board frame and the generator adds π. Mount placements take their rotation from the case spec; use rotate to flip a template whose natural orientation disagrees with the mount.

Raw zones

Devices without an attachment profile (LCDs, AIO rings, RAM, onboard accents) are placed directly from their segment:

{ "layout_device_id": "corsair:1b1c:0c4e:...", "segment": "Display", "name": "Pump LCD",
  "kind": "display", "px": [480, 480], "circular": true, "size_mm": [55, 55], "anchor": "cpu_socket" }

kind is one of display (matrix sized to the panel, lcd-display preset), ring (count, optional start_angle, direction), vstrip / hstrip (count, optional direction), custom (explicit LED positions), or point. segment must be the device segment name exactly as GET /devices/{id} reports it. mirror, mirror_y, and rot work here too.

Custom zones require a positive integer count and exactly that many positions ({"x": 0.0, "y": 1.0}), in device LED order. Each coordinate must be a finite number in [0, 1]. Use circular: true for a ring-shaped footprint; the default footprint is rectangular. The generator preserves position order and applies mirror and mirror_y before the placement rotation. Raw-zone rot is the final canvas rotation in radians, including for board anchors; it does not inherit the board flip. Keep the map's source URL with the rig when using measured coordinates.

Bridged hubs

A hub reached through the OpenRGB bridge has the layout id openrgb:<host>:<port>:<identity> (openrgb:127-0-0-1:6742:serial:0994fa72ab3cae43; the fingerprint used for config keys is a different string, see below) and one generic slot per zone (channel-1, channel-atx-1, ...) with cumulative led_start. Fan and strip bindings work as on the native hub, so a controllers entry only needs the new device uuid and layout id.

Strimers are the exception. Through the bridge each strimer row is its own zone (six 20-LED "Channel ATX n", four or six 27-LED "Channel GPU n"), and a 120-LED strimer template cannot bind to a 20-LED zone, so the rows are placed as raw strips by a bridge_rows block that the generator expands into N raw_zones entries:

"bridge_rows": [
  { "layout_device_id": "openrgb:127-0-0-1:6742:serial:0994fa72ab3cae43",
    "name": "24-pin strimer row",
    "segments": ["Channel ATX 1", "Channel ATX 2", "Channel ATX 3", "Channel ATX 4", "Channel ATX 5", "Channel ATX 6"],
    "kind": "hstrip", "count": 20,
    "anchor": "atx24_header", "offset": { "du": 45, "dv": -18.75 }, "pitch_mm": 7.5,
    "size_mm": [90, 7], "rot": 3.14159 }
]
field meaning
segments the zone names in row order, exactly as GET /devices/{id} reports them; row i gets segments[i] and the name "<name> <i+1>" (or names[i])
kind, count hstrip or vstrip, LEDs per row (a list when rows differ)
anchor + offset, or board where row 1 sits, same meaning as for bindings
pitch_mm spacing between rows, applied along stack
stack dv or du; defaults to the row's cross axis (dv for a horizontal row, du when rot makes it vertical)
size_mm, rot, direction, mirror, mirror_y per-row geometry and flags, shared by every row

The dial-in flags read the same way as for a strimer matrix, one level up: the whole block upside down is a reversed segments list (mirror_y on a matrix); every row running the wrong way along the cable is direction or mirror (columns).

Bridge zone sizes

Hubs arrive through the bridge with every zone at 0 LEDs, and OpenRGB does not persist the sizes you set. bridge.zone_sizes is fingerprint → zone name → LED count, the same shape as drivers.openrgb.zone_sizes in the daemon config; gen_layout.py apply merges it into that key (--skip-zone-sizes to opt out) so a reinstall or a server restart restores the hub. The key is the full fingerprint string as the driver mints it, the same form controller_fps uses: bridge:openrgb:<host>:<port>:serial:<SERIAL> with the serial in the case OpenRGB reports (upper for the Nollie), or ...:location:<path> for devices without a serial. It is not the layout id: GET /devices/{id} carries it as bridge.fingerprint, hypercolor devices info <id> prints it on daemons that ship the coverage routes, and the bridge matches the key case-insensitively:

"bridge": { "zone_sizes": { "bridge:openrgb:127.0.0.1:6742:serial:0994FA72AB3CAE43": { "Channel 1": 20, "Channel 2": 60, "Channel ATX 1": 20 } } }

apply prefers the bridge.fingerprint the daemon reports for the matching controller over the spelling in the rig, so a key written as the device's layout id (openrgb:127-0-0-1:6742:serial:...) is also resolved when the device is on the daemon; the rig's own string is the fallback.

plan warns when a zone the layout targets is still at 0 LEDs on the daemon, because frames into an unsized zone succeed and light nothing.

Which flag fixes what

When the user reports what they see, translate it before touching the file:

observation cause flag
a sweep hits fan 3 before fan 1 chain order chain
each fan animates the wrong way but the row order is right template winding rotate: π on edge-on templates, mirror on rings
a matrix (strimer) shows the sweep on the wrong strip first rows reversed mirror_y
a matrix runs the sweep the wrong way along the cable columns reversed mirror
a vertical thing is upside down length reversed rotate: π (matrices) or mirror (strips)
a ring spins the wrong way winding mirror

A 180° rotation reverses both axes of a matrix. If the user says "still wrong" after a π rotation, the real fix was a single axis; revert and use mirror or mirror_y.

Generator regression checks

From the repository root, run uv run python -m unittest discover -s skills/rig-setup/tests -v. The tests check generated geometry and SVG placement; they do not establish physical fan identity or confirm the pending Corsair mount rotation.

Source: SKILL.md on GitHub

No third-party reports yet.

Signed by skilld at 18d3bf6. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub yesterday.

Activeupdated 3 weeks ago

README badge

README badge for hyperb1iss/hypercolor/rig-setup