<!-- Markdown copy of https://freshavlabs.com/docs/lamina-lighting-control/ -->

PLUGIN MANUAL / v1.2.5

# Lamina Lighting Control

sACN (E1.31) architectural lighting control from the Q-SYS Core: presets with crossfade, a console-style command pad, live-input arbitration, and a fire-alarm egress path.

## Introduction

Lamina Lighting Control runs architectural lighting from the Q-SYS Core. It sends and receives sACN (E1.31), stores the presets in the design, and exposes every channel, trigger and fade time as a control pin. A wall button, a UCI, the scheduler and room-combine logic all recall the same look through the same path. Lamina Faders, a free companion plugin in the same download, adds an assignable fader bank.

Presets on the Core

Up to 15 presets plus an Off look and an Emergency look, with a global or per-preset crossfade.

Command Pad

Console-style channel entry: digits, THRU, AND, AT, FULL, OUT, ENTER, CLEAR and RELEASE.

sACN In and Out

512 output channels and 512 input monitor channels, every one a pin, with priority arbitration on the input.

Lamina Faders

Up to 32 faders across up to 24 banks, linked to the controller automatically.

## Requirements

| Component      | Requirement                                                                                                                                                            |
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Q-SYS Designer | Tested with Q-SYS Designer 10.4                                                                                                                                        |
| Q-SYS Core     | Any Q-SYS Core processor. Verified on a Core Nano                                                                                                                      |
| Network        | A Core interface on the same Layer 2 segment as the fixtures and consoles. See [Network and sACN Setup](https://freshavlabs.com/docs/lamina-lighting-control/#network) |
| License        | One activation code per Core. See [Licensing](https://freshavlabs.com/docs/lamina-lighting-control/#licensing)                                                         |

Lamina Faders needs the controller's Script Access set to All, see [Lamina Faders](https://freshavlabs.com/docs/lamina-lighting-control/#faders-overview).

## Installation

The Lamina pack contains two plugin files:

| File                   | Purpose                         | License  |
| ---------------------- | ------------------------------- | -------- |
| `Lamina.qplugx`        | The lighting controller         | Licensed |
| `Lamina_Faders.qplugx` | Assignable fader bank companion | Free     |

Step 1. Copy the plugin files

Copy each `.qplugx` file into `Documents\QSC\Q-Sys Designer\Plugins\`. A subfolder works; Designer scans the folder recursively. Double-clicking a file also installs it, into the Plugins folder itself. The plugin appears in Schematic Elements under Plugins, Fresh AV Labs.

Step 2. Add it to the design

Drag the plugin from Schematic Elements into the design.

Updating

Every release uses the same filename. Copy the new file over the old one. When you open the design, Designer offers the newer version, and the plugin's settings survive the update.

Before you update the plugin or change the design, export the presets. See [Preset Backup](https://freshavlabs.com/docs/lamina-lighting-control/#preset-backup).

## Quick Start

Step 1. Add the controller

Add Lamina Lighting Control to the design. Select the block and set `Preset Count` to the number of looks the room needs. Leave `Channel Count` at 512 unless the rig uses fewer channels, see [Plugin Properties](https://freshavlabs.com/docs/lamina-lighting-control/#properties). The Control page shows one row per preset.

Step 2. Push the design

Push the design to the Core. The LICENSE box counts down, or reads `ACTIVATED`, and the status bar reads `OK`. Without a code the plugin runs a 10-minute demo, see [Licensing](https://freshavlabs.com/docs/lamina-lighting-control/#licensing).

Step 3. Point the output at the fixtures

On the sACN I/O page, set `Universe Out` to the fixtures' universe. In `Out Interface`, pick the Core interface that faces the lighting network. Leave `Dest IP` blank. The status bar stays at `OK`. If it names the interface instead, see [Network and sACN Setup](https://freshavlabs.com/docs/lamina-lighting-control/#network).

Step 4. Build a look

On the Control page, press `1` `THRU` `8` `AT` `FULL` `ENTER`. Channels 1 to 8 go to full on the fixtures, and `WB Summary` reads `8/512 active, peak 255`.

Step 5. Save the look into a preset

Turn on `Save Enable`, then press `Preset Save 1`. `Save Enable` turns itself off and the save buttons grey again.

Step 6. Recall it

Press `Preset Trigger 1`. `Preset Active 1` lights and the room crossfades to the look over `Fade Time`.

Step 7. Add Lamina Faders

Set the controller's Script Access to All, add Lamina Faders, and push the design. Its `Linked` LED lights and its status bar reads `OK`. With more than one controller in the design, pick one in `Lamina Component`. See [Lamina Faders](https://freshavlabs.com/docs/lamina-lighting-control/#faders-overview).

The most common support call: `Join Multicast` is off on a new instance, so no multicast input arrives. See [Network and sACN Setup](https://freshavlabs.com/docs/lamina-lighting-control/#network).

## Plugin Properties

Properties are set in Designer with the block selected. The plugin reads them when the design starts and holds them while it runs, so changing one is a re-deploy. Settings an operator changes live are controls instead: `Per-Preset Fades` on the Control page, `Bank Select` on the DMX monitor, and the whole sACN configuration. The Settings page echoes the eight controller settings read-only, under SETTINGS (edit in Properties panel).

### Activation codes

| Property                 | Range / Choices | Default | Description                                                                                                                                                                                         |
| ------------------------ | --------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Activation_Code`        | Text            | *blank* | The activation code for this Core's Locking ID. Leave blank to run the demo. See [Licensing](https://freshavlabs.com/docs/lamina-lighting-control/#licensing).                                      |
| `Activation_Code_Backup` | Text            | *blank* | The code for the other Core of a redundant pair. Leave blank on a single Core.                                                                                                                      |
| `Show_Locking_ID`        | No / Yes        | No      | When Yes, shows the Core's Locking ID in the plugin header and gives its pin the `License~Locking ID` name. See [Control Pins](https://freshavlabs.com/docs/lamina-lighting-control/#control-pins). |

### Controller

| Property            | Range / Choices                 | Default       | Description                                                                                                                                                                                                                                                        |
| ------------------- | ------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `Channel Count`     | 1 - 512                         | 512           | Lamina's active width. The plugin transmits, fades and mirrors to the `Ch` pins only up to this channel, and the command pad clamps ranges to it. A lower count stops driving every fixture above it. Monitor cells past it render blank.                          |
| `Display Unit`      | Percent / Decimal               | Decimal       | How the command pad reads a bare level after `AT`. Decimal takes 0 to 255. Percent takes 0 to 100 and scales it. The DMX monitor and the `Ch` pins stay 0 to 255 either way.                                                                                       |
| `Protocol`          | sACN                            | sACN          | The only value. Lamina speaks sACN (E1.31) and nothing else.                                                                                                                                                                                                       |
| `Passthrough`       | On / Off                        | On            | On: Live is a selectable source and, while it is active, the working buffer follows the input. Off: `Live Trigger` is disabled and the input can only monitor. See [Live Input and Arbitration](https://freshavlabs.com/docs/lamina-lighting-control/#live-input). |
| `Power-on Preset`   | Off, P1 - P15                   | Off           | The look recalled when the design starts. A choice above `Preset Count` recalls Off and logs a warning.                                                                                                                                                            |
| `Preset Count`      | 1 - 15                          | 4             | How many savable presets the panel shows. The Off and Emergency looks are separate and not counted. Recall and save pins above the count exist but do nothing, see [Control Pins](https://freshavlabs.com/docs/lamina-lighting-control/#control-pins).             |
| `Fire Alarm Enable` | On / Off                        | Off           | Arms the egress path. While Off, `Fire Trigger` does nothing. See [Emergency and Fire Alarm](https://freshavlabs.com/docs/lamina-lighting-control/#emergency).                                                                                                     |
| `Fire Contact`      | Normally Open / Normally Closed | Normally Open | Which state of `Fire Trigger` means alarm. Normally Open alarms when the trigger goes high. Normally Closed alarms when it goes low, so a cut loop or a dead contact reads as an alarm.                                                                            |

### Debug

| Property      | Range / Choices    | Default  | Description                                                                     |
| ------------- | ------------------ | -------- | ------------------------------------------------------------------------------- |
| `Debug_Level` | Standard / Verbose | Standard | Log verbosity in the plugin's debug window. Verbose adds high-frequency output. |

## Network and sACN Setup

sACN configuration lives on the sACN I/O page as controls rather than Properties, so it is reachable from a UCI and can be changed on a running design. Input and output are configured separately: each has its own enable, universe, and interface.

### Port and Layer 2 segment

Lamina sends and receives sACN on UDP port 5568, so allow that port in any ACL on the lighting segment.

sACN traffic must share a Layer 2 segment with the Core

Fixtures, consoles, and the Core have to sit on the same Layer 2 network. Routed traffic to port 5568 does not reach the Core's receiver, and neither does unicast from off-segment. Plan the lighting VLAN so the Core has an interface on it, and pick that interface explicitly in `Out Interface` rather than leaving the choice to routing.

### Output universe and destination

The destination address is not something you normally type. With `Dest IP` blank, Lamina multicasts to the group address that E1.31 derives from the universe number: `239.255.<hi>.<lo>`, where `<hi>` is the universe divided by 256 and `<lo>` is the remainder. Universe 1 is therefore `239.255.0.1`, and universe 300 is `239.255.1.44`. Put a valid address in `Dest IP` and Lamina unicasts every frame to that address instead, ignoring the group.

| Control        | Range        | Notes                                                                                                                                                                                                                                                                                   |
| -------------- | ------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Universe Out` | 1 to 63999   | The universe Lamina transmits. Sets the multicast group when `Dest IP` is blank.                                                                                                                                                                                                        |
| `Dest IP`      | Text (blank) | Blank multicasts to the `Universe Out` group. A dotted-quad IPv4 address unicasts to that address, and spaces in it are ignored. Anything else halts output, and `Status` reads `Fault - Dest IP '<value>' is not a valid address - output halted`. Correct the value to resume output. |
| `Out Priority` | 0 to 200     | The priority Lamina stamps on its own frames. Seeds at 100.                                                                                                                                                                                                                             |
| `FPS`          | 5 to 30      | Transmit rate. Seeds at 15, and is clamped to the range - the crossfade engine runs on this same cadence.                                                                                                                                                                               |

### Input universe and multicast

| Control          | Range                    | Notes                                                                                                                                                                                                                                                                                                                                                 |
| ---------------- | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Universe In`    | 1 to 63999               | The universe Lamina receives. Independent of `Universe Out` - they are two separate controls, and pointing them at the same universe is a choice, not a default.                                                                                                                                                                                      |
| `Join Multicast` | `Off` / `On` (**`Off`**) | Joins the `Universe In` group so a multicast source can be received. Ships off, and nothing seeds it on - a fresh instance receives no multicast input until you turn it on. With it off the socket still opens on port 5568, but no group is joined and `In Interface` places no join - changing `In Interface` still re-opens the receiver, though. |
| `Min Priority`   | 0 to 200                 | The floor for accepting an incoming stream. Seeds at 100. Anything below it is ignored. 200 is the E1.31 ceiling, and the receiver rejects packets claiming more.                                                                                                                                                                                     |

### Choosing the input interface

`Out Interface` and `In Interface` each list `Auto` plus every network interface on the Core. `Auto` means something different on each side.

The input side reads the interface for one purpose: to place the multicast join. With `Join Multicast` off there is no join, so nothing on the receive path reads the interface, and the socket opens on port 5568 either way. The control is not inert, though. Changing `In Interface` re-opens the receiver whatever `Join Multicast` says. That clears the tracked source, blanks `Rx Source`, and restarts the kick timer, exactly as changing `Universe In` does. With `Join Multicast` on, `Auto` joins the universe's group on every real interface, skipping loopback and any interface without an address. Whichever interface carries the stream is covered.

An automatic re-open has the same consequences as a manual one

The interface watch re-opens the receiver on its own, with every consequence of changing `In Interface` by hand. That includes re-arming a kick that has already fired, so it can fire a second time. Nobody has to touch the plugin for this to happen.

What can trigger it depends on `In Interface`. Named, only that interface's address matters. On `Auto` the receiver joins on every usable interface, so a DHCP lease renewing on an interface that has nothing to do with lighting is enough. If you rely on `Kick`, name the interface. With `Join Multicast` off there is no join to re-place, and the watch never re-opens the receiver at all.

### Choosing the output interface

Output cannot cover every interface the way the input join does, because a frame leaves on exactly one interface. `Auto` pins egress to the first usable interface the Core reports, which on a multi-homed Core is not always the one facing the fixtures. A unicast `Dest IP` is the exception: there `Auto` is fine, because routing picks the interface by destination.

On a single-homed Core none of this matters. On anything else, name the interface that faces the lighting network.

### When a named interface fails

Naming an interface is a hard commitment, and it fails closed

Picking a specific interface tells Lamina that lighting traffic belongs on that network and nowhere else, so it will never quietly fall back to another one. If the named interface has no usable IP - down, no lease, or renamed out from under the design - output halts and the plugin raises a fault rather than bleeding lighting multicast onto a subnet you deliberately excluded. The input side fails closed on the same condition, in the one place the interface is used: the multicast join is skipped. The socket still opens on port 5568, but with no group joined the stream is not delivered, so a `Join Multicast` input goes silent. The two sides announce it differently: output raises a `Status` fault naming the interface, while input only writes a warning to the debug log - so on the input side watch `Input Present` and `Rx Source`, not `Status`.

Recovery is automatic when the interface comes back. Lamina checks the Core's interface list once a second, and when the list changes and the new one holds for about three seconds, it re-opens whichever socket's binding moved. `Refresh` in the header is still the path when the list has *not* changed - a join that failed for some other reason.

## Licensing

The plugin reads `Activation_Code` and `Activation_Code_Backup` when the design starts.

Three license states

1. **Blank.** The plugin runs a 10-minute demo with every function. The LICENSE box counts down. Restart the design to start another demo.
2. **Valid code.** The LICENSE box reads `ACTIVATED`. There is no time limit.
3. **Wrong code.** The plugin runs the same demo and the LICENSE box reads `DEMO (invalid code): M:SS remaining`, so a mistyped code is visible. Correct or clear the code before the demo ends.

### What demo expiry stops

The licensed product is the sACN output. At expiry the plugin sends three stream-terminate packets, stops transmitting, and greys out `Out Enable`. `Out Enable` still reads on; the license is what holds the output down. Preset, Off and Live recall, saving, the command pad and `Import Apply` grey out, and a recall or save from a pin is refused. The working buffer keeps fading, the DMX monitor and its output cells keep working, the input keeps arriving, and Lamina Faders still moves the buffer. Nothing it moves is transmitted. The alarm path is not exempt, see [Emergency and Fire Alarm](https://freshavlabs.com/docs/lamina-lighting-control/#emergency).

### Activate

Step 1. Read the Core's Locking ID

Set `Show_Locking_ID` to Yes and push the design. The Locking ID appears in the LOCKING ID box. Core Manager also shows it under Licensing, for any Core, with no design change. The Designer emulator reports `EMULATOR` or `*100000000000000`. The plugin marks it as not a Core ID. No code can be made for it.

Step 2. Get a code for that Locking ID

Buy or request an activation code at [freshavlabs.com](https://freshavlabs.com), quoting the Locking ID exactly.

Step 3. Enter the code and push the design

Paste the code into `Activation_Code` and push the design. The LICENSE box reads `ACTIVATED`. The plugin compares only the digits of the code, so punctuation and spaces do not matter. A code entered on a running design applies at the next design start.

Redundant Core pairs

Each Core has its own Locking ID and needs its own code. Put the primary Core's code in `Activation_Code` and the backup Core's code in `Activation_Code_Backup`. Read the backup Core's Locking ID from its own Core Manager; no failover is needed. Either code matching the running Core licenses the plugin, so a failover stays licensed.

### License status

Q-SYS prefixes the LICENSE box text with its own status word, so the box reads `OK - ACTIVATED` or `Compromised - DEMO: 9:59 remaining`.

| Status                              | Color  | Meaning                                                                           |
| ----------------------------------- | ------ | --------------------------------------------------------------------------------- |
| ACTIVATED                           | Green  | A code validated against this Core. No time limit.                                |
| DEMO: M:SS remaining                | Yellow | No code entered. Counting down.                                                   |
| DEMO (invalid code): M:SS remaining | Yellow | A code was entered and did not validate against this Core's Locking ID.           |
| DEMO EXPIRED - Activation Required  | Red    | The demo ran out. "What demo expiry stops" above says what the plugin still does. |

At expiry the plugin's `Status` control also reads `Fault - License required - demo expired`, so a Status Combiner sees the fault.

Codes are bound to one Core

An activation code works only on the Core whose Locking ID it was made for. It cannot move to another Core.

## The Plugin Panel

The block opens on three pages, chosen from the tab strip Designer draws above the panel. The split is by job rather than by feature: what an operator touches is on Control, what the network needs is on sACN I/O, and what you set once is on Settings.

With one exception, nothing on the panel is panel-only: every control is also a pin, see [Control Pins](https://freshavlabs.com/docs/lamina-lighting-control/#control-pins). The exception is the DMX monitor's cells, which carry no pins of their own. Those values reach the schematic through the `Ch` and `In Ch` pins instead. The reverse case is `Fire Trigger`, a pin with no widget, see [Emergency and Fire Alarm](https://freshavlabs.com/docs/lamina-lighting-control/#emergency).

| Page         | Holds                                                                                                 | Covered in                                                                                                                                                                              |
| ------------ | ----------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Control**  | The preset rows, the Live/Off selectors, the save arm, the active-state readout, and the command pad. | [Presets and Looks](https://freshavlabs.com/docs/lamina-lighting-control/#presets), [Command Pad](https://freshavlabs.com/docs/lamina-lighting-control/#command-pad)                    |
| **sACN I/O** | Input and output configuration, and the DMX monitor.                                                  | [Network and sACN Setup](https://freshavlabs.com/docs/lamina-lighting-control/#network), [Live Input and Arbitration](https://freshavlabs.com/docs/lamina-lighting-control/#live-input) |
| **Settings** | Preset backup, the emergency look, and a read-only echo of the Properties.                            | [Preset Backup](https://freshavlabs.com/docs/lamina-lighting-control/#preset-backup), [Emergency and Fire Alarm](https://freshavlabs.com/docs/lamina-lighting-control/#emergency)       |

### Shared chrome

The header and the status bar render on all three pages, so the license state and the fault line are never a page away. The header carries the plugin name and version, the LICENSE readout, a LOCKING ID readout when `Show_Locking_ID` is `Yes`, and `Refresh`. Directly beneath it, the full-width `Status` bar is the plugin's connection and fault line - it is the same `Status` pin a Status Combiner reads. When more than one condition is active, the bar shows the most serious: an alarm, then halted output, then a rejected import. A value written to `Status` from outside the plugin, over QRC for example, is overwritten at once and logged as a warning.

`Refresh` re-opens both sockets, transmit and receive. Lamina already re-opens them by itself when the Core's interface list changes, so an interface coming back needs no button. Use `Refresh` for the case that is not a list change - a join that failed for some other reason. See [Network and sACN Setup](https://freshavlabs.com/docs/lamina-lighting-control/#network).

### The DMX monitor

The monitor sits at the bottom of the sACN I/O page: 64 cells in 16 columns, each stacking the channel number, the live input value, and the output value. The input row is read-only. The output row is editable - type a number into a cell and that channel goes there, which is the panel's direct-to-channel path alongside the command pad.

64 cells is a view, not a limit. `Bank Select` with the `<` and `>` buttons pages it across the universe in blocks of 64, and the number of banks tracks `Channel Count` - eight at the default 512, one at 64. Cells past `Channel Count` render blank. The real per-channel surface is the `Ch` and `In Ch` pins, which are 512 wide regardless of what the monitor is showing.

## Presets and Looks

A preset is a stored 512-channel look. `Preset Count` decides how many savable presets the panel shows, see [Plugin Properties](https://freshavlabs.com/docs/lamina-lighting-control/#properties).

Two more looks exist alongside those and are not counted in `Preset Count`:

* **Off** - its own stored look, recalled by `Off Trigger` and saved by `Preset Off Save`. It seeds to all channels at zero, but it is a preset like any other: save a dim house look into it and `Off` becomes that.
* **Emergency** - the egress look, seeded to all channels full. See [Emergency and Fire Alarm](https://freshavlabs.com/docs/lamina-lighting-control/#emergency).

### Recalling

`Preset Trigger 1..N`, `Off Trigger`, and `Live Trigger` select the active source. Exactly one is active at a time, and `Preset Active`, `Off Active`, and `Live Active` light to say which. `State Readout` names it in text: the preset's `Preset Name` if it has one, otherwise `Preset N`, or `Off`, `Live`, or `EMERGENCY`.

Recall is gated, and every gate fails silently by design rather than throwing:

| Gate                    | Effect                                                                                                                                                                                    |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Disable Wall Triggers` | Blocks every recall - presets, Off, and Live. The panel legend reads PRESET LOCKOUT. Saving is not affected.                                                                              |
| License                 | Recall is a licensed operation. An expired demo drops it. See [Licensing](https://freshavlabs.com/docs/lamina-lighting-control/#licensing).                                               |
| `Preset Count`          | `Preset Trigger 9` does nothing when `Preset Count` is 4. The check is in the handler, not just the panel, so a pin or an external API call is bounded the same way the UI is.            |
| An active alarm         | While the fire-alarm egress is active, nothing but the emergency look can take the room. See [Emergency and Fire Alarm](https://freshavlabs.com/docs/lamina-lighting-control/#emergency). |
| `Passthrough`           | Gates `Live Trigger` only. With it off, Live cannot become the active source. See [Live Input and Arbitration](https://freshavlabs.com/docs/lamina-lighting-control/#live-input).         |

### Fading

A recall crossfades over `Fade Time`, which seeds at 2 seconds. Setting it to 0 does not snap - a zero or unset `Fade Time` reads as the 2-second default.

To snap, or to give one look its own timing, turn on `Per-Preset Fades`. It is a live toggle on the Control page rather than a Property, so it can move on a running design. With it on, each preset's own `Preset Fade` is taken literally, and 0 there genuinely snaps. With it off, the per-preset fields grey out and every recall uses the global `Fade Time`.

A fade is a committed transition

Editing a preset's stored values in the middle of a recall into that preset does not bend the fade in flight. The target look is read once when the recall starts; the edit lands on the next recall.

### Saving

Saving is armed, not immediate. The sequence is arm, save, and it disarms itself:

Step 1. Build the look

Set the channels from the DMX monitor's output cells or the command pad. The fixtures follow the working buffer live, so what you see is what will be stored.

Step 2. Arm

Turn on `Save Enable` (legend ARM SAVE). The save buttons stay greyed until you do.

Step 3. Choose what to capture

`Capture Source` is `Current Output` by default, which stores the working buffer. Set it to `Live Input` to store the incoming sACN universe instead - see [Live Input and Arbitration](https://freshavlabs.com/docs/lamina-lighting-control/#live-input).

Step 4. Save

Press `Preset Save N`, `Preset Off Save`, or `Emergency Save`. `Save Enable` turns itself back off immediately and the buttons re-grey, so one arm buys exactly one save.

Saving is licensed and is blocked outright during an alarm. Unlike recall, it ignores `Disable Wall Triggers`.

### On startup

`Power-on Preset` recalls a look when the design starts. It is a Property and its list always offers `P1` through `P15` regardless of `Preset Count`, so a selection above the count would point at a slot the panel never shows. It does not: the plugin recalls `Off` instead and logs a warning, which means lowering `Preset Count` cannot boot the room to a blank look.

## Command Pad

The command pad on the Control page is a console-style channel editor. The grammar is one sentence - channels, then a level:

```
1 THRU 8 AND 20 AT FULL ENTER
```

`AT` is mandatory: it is what separates the channel list from the level, and a command without it is rejected. Channels are single numbers, `THRU` ranges, or both joined by `AND`. The level is `FULL`, `OUT`, or a number.

| Key            | Does                                                                                                                                                                 |
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `0` to `9`     | Build up a number. It becomes a token when you press any other key.                                                                                                  |
| `THRU`         | Makes the two numbers around it an inclusive range. The range is clamped to `Channel Count` before it is expanded, so `1 THRU 9999` is bounded rather than enormous. |
| `AND`          | Joins channels or ranges. Renders as `+` on the command line.                                                                                                        |
| `AT`           | Separates channels from the level. **Required.** Renders as `@`.                                                                                                     |
| `FULL` / `OUT` | Level 255 and level 0.                                                                                                                                               |
| `ENTER`        | Parses the line and writes it into the working buffer.                                                                                                               |
| `CLEAR`        | **Backspace, not clear-all.** One press deletes one digit, or one whole token when no digits are pending. Press it repeatedly to walk the line back.                 |
| `RELEASE`      | Throws away manual edits and snaps the working buffer back to the active source's look.                                                                              |

A bare number as the level is read through `Display Unit`: 0 to 255 on `Decimal`, 0 to 100 on `Percent`. See [Plugin Properties](https://freshavlabs.com/docs/lamina-lighting-control/#properties).

### The two readouts

`Command Line` echoes the line as you build it, in console shorthand: `1 THRU 8 + 20 @ FULL`. A successful `ENTER` clears it. A rejected one leaves an `ERR:` code in its place.

| Readout         | Meaning                                           |
| --------------- | ------------------------------------------------- |
| `ERR: no_at`    | No `AT` in the line - there is no level to apply. |
| `ERR: chan`     | Something in the channel list is not a number.    |
| `ERR: thru`     | A `THRU` without a valid number after it.         |
| `ERR: sep`      | Two channel terms with no `AND` between them.     |
| `ERR: no_level` | The line ends at `AT`.                            |
| `ERR: level`    | The level is neither `FULL`, `OUT`, nor a number. |

`WB Summary` reports the working buffer as a whole - `8/512 active, peak 255`: how many channels are non-zero out of `Channel Count`, and the highest value among them. It is a sanity check for "is anything actually on", which is otherwise a long scroll through the monitor.

The pad edits, it does not select

`ENTER` writes into the working buffer on top of whatever source is active, and it does not change the active source. The preset stays lit and `State Readout` adds `(modified)` to say the room no longer matches it. `RELEASE`, or any recall, drops the overlay. That is what makes the pad safe to use for building a look before a save.

## Live Input and Arbitration

Lamina can receive an sACN universe as well as send one. The input is always a monitor: incoming values land on the `In Ch` pins and the DMX monitor's input row whether or not they are allowed to drive the room. Whether they drive it is what `Passthrough` decides.

With `Passthrough` on, `Live` is a selectable source like any preset - `Live Trigger` makes it active, and while it is active the working buffer follows the incoming frames. With `Passthrough` off, `Live Trigger` is disabled, the input can never reach the output, and the monitor keeps working. `Passthrough` is a Property, so that choice is a re-deploy.

Configuration lives on the sACN I/O page: `In Enable`, `Universe In`, `Min Priority`, the two source filters, and `Join Multicast`. The controls and the interface rules are covered in [Network and sACN Setup](https://freshavlabs.com/docs/lamina-lighting-control/#network).

### Which source wins

Lamina tracks exactly one source at a time, keyed by the CID each sACN source puts in its packets rather than by its address.

* **First to arrive acquires.** When nothing is tracked - at startup, after a reopen, or after a loss - the first packet that passes the filters becomes the tracked source.
* **Strictly higher priority preempts.** A source claiming a higher priority than the tracked one takes over immediately.
* **Equal priority is ignored.** A second source at the same priority as the one already tracked does not interleave and does not take over. The first one holds until it stops.
* **Lower priority is ignored** while a source is tracked.

Equal priority does not mean last one wins

Two consoles left at the same priority is not a coin flip that resolves per packet - it is first-come, and the loser is inert until the winner goes quiet for 2.5 seconds. If a second console appears dead, check whether the first is still transmitting before checking anything else. To make a source authoritative on purpose, give it a strictly higher priority rather than an equal one.

`Min Priority` is the floor for being considered at all: a stream below it is dropped before arbitration. `Filter Source IP` and `Filter Source Name` narrow the field further, by address and by the name the source puts in its packets.

Lamina also ignores its own output. The transmitter and the receiver are one plugin, and multicast loops back, so without that filter an instance transmitting and receiving on the same universe would acquire itself as its input.

### The Rx Source readout

`Rx Source` (pin `Input~Source`) names the tracked source. It has three states.

| State   | Readout                                     | When                                                                                                 |
| ------- | ------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| Tracked | `Console A @ 192.168.10.20 · pri 100`       | A source is being tracked. One that sends a blank source name degrades to `192.168.10.20 · pri 100`. |
| Lost    | `LOST: Console A @ 192.168.10.20 · pri 100` | The tracked source went silent or terminated. The identity persists as a breadcrumb.                 |
| Idle    | `—`                                         | Nothing is tracked: `In Enable` is off, or the receiver was just reopened.                           |

The priority shown is the tracked source's current priority, and it follows that source - consoles lower their priority when releasing a cue, and the readout moves with it.

Idle does not mean healthy

The idle character is written on `In Enable` off and on every reopen, including one where an explicitly-named `In Interface` had no usable IP and the multicast join was skipped. `Rx Source` cannot tell you which of those happened, and that particular failure raises no `Status` fault - it only writes a warning to the debug log. If the input is not arriving and the readout is idle, check the interface and the debug log rather than waiting for `Status` to say something. See [Network and sACN Setup](https://freshavlabs.com/docs/lamina-lighting-control/#network).

### When the source stops

Loss is silence: 2.5 seconds with no packet from the tracked source, per E1.31. It keys on packets arriving, not on values changing, because a compliant source transmits continuously - a console parked on a static look is sending the same frame over and over, and that is not a loss. An explicit stream-terminate from the tracked source declares the loss immediately rather than waiting out the timer.

On loss, `Input Present` goes false, `Rx Source` takes the `LOST:` prefix, and the tracked source is released so a new one can acquire. The output is not touched.

Hold is the design, everywhere

Lamina never zeroes the room because input went away. On loss, the last frame stays in the working buffer and the light stays up. The same is true of a reconfiguration: changing `Universe In` re-opens the receiver but does not clear the held values, so the monitor and the room can keep showing the old universe's look until a new source arrives. That stale reading is intended, not a bug. The only thing that clears the held values is turning `In Enable` off.

This is deliberate and it is the safe default for architectural lighting: a network hiccup should never drop a room to black. If you want silence to move the room, `Kick` is how you ask for it.

### Kick

`Kick` is the opt-in that turns silence into an action. Turn on `Kick Enable`, set `Kick Timeout` in seconds, and pick a `Kick Fallback`. `Kick Timeout` starts at 2 on a newly placed block. A block placed earlier keeps its stored value, and at 0 Kick never fires. `Kick Fallback` ships at `Off`. It only fires when Live is the active source - silence while a preset or Off is driving the room is not a reason to change anything, so Kick stays out of it.

| `Kick Fallback`           | On timeout                                                                                                  |
| ------------------------- | ----------------------------------------------------------------------------------------------------------- |
| `Off`                     | Recalls the Off look.                                                                                       |
| `Hold`                    | Takes no action. The live frame is already held, so the room stays exactly as it was at the moment of loss. |
| `P1` to `P<Preset Count>` | Recalls that preset.                                                                                        |

The list offers only presets that actually exist. If `Preset Count` is later lowered under a saved selection, the fallback recalls `Off` rather than an unseeded slot.

## Emergency and Fire Alarm

Lamina can take a contact closure from a fire-alarm system and drive the room to a stored egress look.

Read this before specifying the emergency path

**NOT a certified life-safety / emergency-lighting device.** The Fire Alarm / Emergency override is a convenience integration - it recalls an egress look on a fire-alarm contact - and is not a UL924-listed, code-required emergency lighting control unit, not a substitute for code-mandated emergency luminaires/inverters/transfer devices, and carries no life-safety certification. It runs on a single, non-redundant Lua thread and depends on the Core being powered, licensed, and functional. Specifying/installing it must not replace any AHJ-required emergency lighting system.

### Wiring and arming

Two Properties configure the path, `Fire Alarm Enable` and `Fire Contact`, see [Plugin Properties](https://freshavlabs.com/docs/lamina-lighting-control/#properties). Both are design-time, so there is no live toggle for arming or for polarity.

`Fire Trigger` is a toggle input pin with no panel widget. Wire it to whatever carries the alarm contact into the design - a Core GPIO, a contact-closure input, or any logic that resolves to a boolean.

Normally Closed is the supervised choice

`Normally Closed` alarms on low, which means a cut loop, a lost input, or a dead contact all read as an alarm. That is the point: the failure mode is a false alarm rather than a silent one. `Normally Open` cannot tell a healthy quiet contact from a severed one. Pick `Normally Closed` unless the alarm interface forces otherwise.

The contact is debounced for 50 milliseconds, so a bouncing relay produces one transition rather than a burst.

### What happens on alarm

The egress look snaps in - it does not crossfade. `Fade Time` and `Per-Preset Fades` are not consulted, because an evacuation is not a cue.

The panel then locks down. Preset recall, Live and Off, the save arm, the command pad keys, `Import Apply`, and the monitor's editable cells all go disabled, and the block is enforced in the handlers as well as in the panel - a pin or an external API call cannot move the room during an alarm either. `Emergency Active` lights, `State Readout` reads `EMERGENCY`, and `Status` goes to fault with `EMERGENCY - egress active` so a Status Combiner surfaces it. If output is halted during the alarm, `Status` reads `EMERGENCY - egress HALTED:` and the reason instead.

### The egress look

It lives in its own slot - it is not one of the 15, and `Preset Count` does not affect it. It seeds to every channel at full, which is the safe default for an egress look on an unconfigured install.

To author it, build the look, arm `Save Enable`, and press `Emergency Save` on the Settings page. It cannot be re-captured during an alarm, for the obvious reason.

### Coming back

When the contact clears, the alarm releases and Lamina restores what was running before, crossfading normally. There is one exception, and it matters if you drive the room from a console:

A dead Live source does not come back as Live

If the pre-alarm source was Live and the input is in a declared-loss state when the alarm clears, Lamina does not restore Live - it recalls the `Power-on Preset` instead. This is the one case where the room does not return to the source it was on, so if a console feeds the room, set `Power-on Preset` to something sensible rather than leaving it at `Off`.

### The license gates the alarm too

The licensed product is sACN output, and that is true during an alarm. A demo that expires mid-alarm stream-terminates and goes dark. This is deliberate: the license fault owns the output, and the alarm does not override it.

A backup code is mandatory on any fire-alarm-wired deployment

The emergency path is not license-exempt, and on a redundant pair it is only as good as the codes in the design. A failover drops the surviving Core into the 10-minute demo, and 10 minutes later the output stops - including during an alarm. Any deployment that wires `Fire Trigger` must have a valid code for every Core that can run the design: `Activation_Code` for one, `Activation_Code_Backup` for the other. See [Licensing](https://freshavlabs.com/docs/lamina-lighting-control/#licensing).

## Preset Backup

Presets live in the design, which means they travel with the design file and they are lost with it. Preset Backup is the way out: the PRESET BACKUP card on the Settings page turns every stored look into a block of plain text you can copy anywhere, and takes it back.

It is text, not a file format. Copy it into a ticket, a password manager, a commit, an email to yourself. Nothing beyond the plugin is needed at either end.

| Control        | Pin                    | Does                                               |
| -------------- | ---------------------- | -------------------------------------------------- |
| `Export`       | `Presets~Export`       | Read-only. Holds the current blob. Copy out of it. |
| `Import`       | `Presets~Import`       | Paste a blob in.                                   |
| `Import Apply` | `Presets~Import Apply` | Applies whatever is in `Import`.                   |

`Export` rebuilds after every save and after every successful import, so the stored levels in the box follow the presets. Names and fades get no rebuild of their own: they are read at rebuild time, so renaming a preset, changing a `Preset Fade`, or retyping `Emergency Name` leaves the box carrying the old text until the next save or import. Save or re-import before you copy the blob, or the backup goes out with the old name.

### What is in the blob

All 17 stored looks, always: `Off`, `P1` through `P15`, and the emergency look. `Preset Count` does not narrow it - a design showing 4 presets still exports all 15 preset slots, so lowering the count and exporting cannot quietly discard the looks above it.

The format is a version line, then one line per look, five pipe-separated fields each:

```
v1
P|0|0|Off|0,0,0,0, ...
P|1|3|House Warm|255,128,0, ...
E|0|0|Egress|255,255,255, ...
```

| Field  | Is                                                                   |
| ------ | -------------------------------------------------------------------- |
| tag    | `P` for a preset (slot `0` is `Off`), `E` for the emergency look.    |
| slot   | `0` to `15` for a `P` line; always `0` for the `E` line.             |
| fade   | The preset's `Preset Fade`. `Off` and the emergency look export `0`. |
| name   | The preset's `Preset Name`.                                          |
| values | 512 channel levels, comma-separated.                                 |

The value list is always 512 wide, whatever `Channel Count` is set to. That is deliberate: a backup taken on a design narrowed to 64 channels still carries the whole universe, so `Channel Count` can never truncate what you have stored.

The levels are the raw 0 to 255 values. `Display Unit` does not touch them.

### Why pipes

The delimiter is `|`, and the reason is worth knowing before you hand-assemble a blob: tabs do not survive the round trip. A blob copied out of `Export` and pasted back into `Import` passes through a Q-SYS text widget, which strips tabs on the way through. The parser then sees one field per line and rejects the import with `fieldcount`. That was confirmed on a Core rather than reasoned about. A pipe is a printable character in the same class as the value commas, and it comes through intact.

Tab-delimited blobs are still accepted on import, as a fallback for older backups. Preset names are sanitized on the way out - a pipe, tab, or line break in a name becomes a space - so a name can never split a line into the wrong number of fields.

### Round-tripping through a clipboard

The parser is deliberately forgiving about what a clipboard does to text. A blob copied on Windows comes back with CRLF line endings, which would leave the first line as `v1` plus a stray carriage return and fail the version check. So a leading byte-order mark is stripped, CRLF and lone CR are both normalized, and the version token is read case- and whitespace-insensitively: `V1` and `v1` pass as readily as `v1`.

### Importing

`Import Apply` validates the whole blob before it writes anything, so a malformed import cannot land half of itself and leave the design in a mixed state.

A rejection leaves every stored preset untouched, and `Status` reads `Fault - Import rejected: <reason>`:

| Reason       | Means                                                                          |
| ------------ | ------------------------------------------------------------------------------ |
| `version`    | The first line is not `v1`.                                                    |
| `fieldcount` | A line does not have five fields. This is the one a tab-mangled blob produces. |
| `valuecount` | A line's value list is not exactly 512 long.                                   |
| `tag`        | A tag other than `P` or `E`.                                                   |
| `slot`       | A slot that is not a whole number, or is outside its tag's range.              |
| `fade`       | A fade field that is neither blank nor a number.                               |

The reason stays on `Status` until an import succeeds or the script restarts. An alarm or halted output takes the bar while either is active, see [Shared chrome](https://freshavlabs.com/docs/lamina-lighting-control/#shared-chrome).

A successful apply clears the `Import` box - that empty box is the confirmation. A rejected one deliberately leaves your text in place so you can fix it and try again.

Two names that import differently

A blank `name` on a preset line clears that preset's name. A blank name on the `E` line does not clear `Emergency Name` - it is ignored and the existing name stays. So an import can blank a preset's name and cannot blank the emergency one; retype that on the Settings page instead - and save or re-import before you copy a fresh blob, or the retyped name will not be in it.

The `Off` line is the other asymmetry. It exports a name and a fade and it imports neither - only its values land. `Off` has no name or fade of its own to set.

Writing to the preset store is a licensed operation, the same as a save, so an expired demo blocks an import. `Import Apply` is also blocked outright during an alarm, in the handler as well as on the panel. See [Licensing](https://freshavlabs.com/docs/lamina-lighting-control/#licensing) and [Emergency and Fire Alarm](https://freshavlabs.com/docs/lamina-lighting-control/#emergency).

## Lamina Faders

Lamina Faders is the second plugin in the download: an assignable fader bank that drives and follows the controller's channels. It is free and carries no licensing of its own - no activation code, no demo timer, no license readout in its header. It is a separate block with its own pins, not a page of the controller.

A bank points at a start channel and the faders under it take the channels from there up. Moving one writes straight into the controller's working buffer - the same buffer the command pad and the monitor's output cells write into - so a fader move is a manual edit with no fade on it, and it marks the state modified exactly as a command pad `ENTER` does. See [Command Pad](https://freshavlabs.com/docs/lamina-lighting-control/#command-pad). An alarm is the exception: the controller refuses channel writes while it is in lockdown, so a fader move during an alarm never reaches the buffer. See [Emergency and Fire Alarm](https://freshavlabs.com/docs/lamina-lighting-control/#emergency). Traffic runs both ways: when a channel moves for any other reason - a preset recall, a command, live input - the fader tracks it.

Faders is free, but it drives a licensed controller. On an expired demo the faders move a buffer nobody is transmitting, see [Licensing](https://freshavlabs.com/docs/lamina-lighting-control/#licensing).

### Linking to a controller

There is no property to type a controller's name into. The link is discovery plus the `Lamina Component` selector, and that pair is the whole mechanism.

At startup Faders scans the design's components and keeps the ones whose type identifies them as a Lamina controller. That scan is why the controller's block needs Script Access set to All - without it the controller is invisible to the scan. Faders does not match itself, so extra fader banks in a design never confuse it.

What happens next depends on what the scan found:

| Scan result                              | What Faders does                                                                                                                                                                                                                                        |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Exactly one controller, nothing picked   | Selects it and links. The ordinary case, and it needs no configuration.                                                                                                                                                                                 |
| A pick the scan still finds              | Keeps it.                                                                                                                                                                                                                                               |
| A pick the scan no longer finds          | Ignores it and behaves as though nothing were picked. If one other controller is on the design it links to that one and rewrites the selector to match; if several are, you get `Multiple Lamina found` even though the selector still shows your pick. |
| More than one controller, nothing picked | Refuses to guess. `Status` goes to Compromised, the faders stay disabled, and you pick one from the `Lamina Component` selector. This is what the controller's Code Name is for.                                                                        |
| Nothing found                            | `Status` goes to Fault and the faders stay disabled.                                                                                                                                                                                                    |

Before accepting a component, Faders reads `Ch 1` and `Ch 512` from it. Both must answer, or it is rejected as not a Lamina.

`Refresh` re-runs that whole resolution, and so does touching the `Lamina Component` selector. Refresh is also the recovery path: if the link breaks while the design is running - the controller's block is renamed or removed out from under it - the next read or write fails, Faders drops to Fault, and Refresh re-establishes it.

### Status

The `Linked` LED lights when a controller is linked. `Status` carries the detail, and its reason text is what tells you which failure you have:

| `Status`     | Reason                                                              | Means                                                                                                                                                                   |
| ------------ | ------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Initializing | (none)                                                              | The startup window before the first scan. Faders defers its link work and staggers it per instance, so a design full of fader banks does not do all of it in one frame. |
| OK           | (none)                                                              | Linked.                                                                                                                                                                 |
| Compromised  | `Multiple Lamina found — pick one in the Lamina Component selector` | More than one controller, and no pick.                                                                                                                                  |
| Fault        | `No Lamina found — set the Lamina block's Script Access to All`     | The scan found nothing.                                                                                                                                                 |
| Fault        | `Lamina link lost — press Refresh`                                  | A read or write to the linked block failed while the design was running.                                                                                                |
| Fault        | `Lamina '<name>' not found`                                         | The picked component could not be opened.                                                                                                                               |
| Fault        | `'<name>' is not a Lamina (no Ch surface)`                          | The component opened but failed the `Ch 1` / `Ch 512` check.                                                                                                            |

## Fader Banks and Copy/Paste

Two Properties size the surface. Both are design-time, so changing either is a re-deploy.

| Property      | Range   | Ships at |
| ------------- | ------- | -------- |
| `Fader Count` | 2 to 32 | 12       |
| `Bank Count`  | 2 to 24 | 8        |

The floor on both is 2, not 1. At a count of 1 the parameterized controls collapse to scalars, which breaks the indexed pins and the layout, so the plugin clamps to 2 rather than offer a size it cannot render.

### How a bank maps to channels

A bank is a start channel plus the faders that follow it. The first fader drives that bank's `Bank Start`, the second the next channel up, and so on - fader `n` drives channel `Bank Start + n - 1`. Nothing wraps and nothing runs past the universe: a fader whose channel would land above 512 is disabled, and its readout and channel label go blank.

`Bank Start` is per bank, 1 to 512, and it is seeded once. On the instance's first run the banks are laid out contiguously - bank 1 at channel 1, bank 2 one `Fader Count` up, and so on, each clamped to 512.

The seed fires once, and Fader Count does not re-stride it

Those defaults are written on the first run and never again - the plugin keeps a hidden marker so it can never overwrite starts you have set. That means changing `Fader Count` later does not re-stride the banks. Go from 12 faders to 16 and every bank keeps its old 12-channel spacing while its faders now reach 16 wide, so the banks overlap: bank 2 still starts 12 channels up but bank 1 now runs 16 across. `AUTO DEPLOY` is the fix.

`AUTO DEPLOY` takes bank 1's current start and cascades it across every bank, stepping by `Fader Count` and clamping each to 512. It re-strides the set after a `Fader Count` change, and it re-bases the whole patch onto a different channel: put bank 1 where you want it and press it once.

### Selecting a bank

`Bank` is the canonical selector - the numeric SEL field on the panel. The SELECT row does the same job as a row of buttons, one per bank, with the active one lit. `Bank Up` and `Bank Down` are pins with no widget, for a wall plate or a UCI. All of them clamp at the ends; none of them wrap.

`Bank Name` names each bank, and `Bank Name Display` echoes the active one - editing the active bank's name updates the echo live rather than at the next bank switch. `Bank Active` is a per-bank output pin.

`Fader Label` names each fader, stored per bank, so every bank carries its own set. `Sync Fader Labels` changes that: on `Yes`, editing a label writes it to the same fader position on every bank, which is what you want when the banks are the same rig at different channel offsets. It ships `No`.

### Copy and paste a bank

Copy/Paste copies the look, not the patch

`Bank Start` is never written by a paste. Copy captures the fader values - the look - and paste applies them to the destination bank's own channels. Copy a bank patched at channel 1 and paste it onto a bank patched at channel 25 and you get the first bank's look on the second bank's fixtures. It is not a way to re-patch a bank; `Bank Start` and `AUTO DEPLOY` are.

`COPY` snapshots the current bank. `PASTE` writes the enabled scopes into whatever bank is current when you press it. Three scope toggles decide what travels:

| Scope  | Copies                                                  |
| ------ | ------------------------------------------------------- |
| `NAME` | The bank's `Bank Name`.                                 |
| `VAL`  | The fader values - the look. Needs a link at both ends. |
| `LBL`  | The per-fader labels.                                   |

All three start on. Turn one off and it stays off across restarts.

Values are the one scope that needs the controller: names and labels are Faders' own data, but values are read from and written to the linked controller's channels. Copy while unlinked and the clipboard holds name and labels only - and the echo says so, reading `Copied Bank 3 (name/labels only — not linked)`. Paste with `VAL` on and no values to paste and the values are skipped with a warning in the log while the other scopes still apply.

The clipboard is transient. It is empty at every load, and the echo is cleared at startup so it can never advertise a copy it no longer holds.

`Clipboard Text` sets that echo's prefix. It ships `Copied Bank`; clear it to blank and the echo is the bank number alone.

Only the faders actually mapped in the source bank are captured. A bank whose upper faders run past 512 has nothing stored against them, so a paste cannot drop a captured zero onto an unrelated channel.

## Binding Faders to a UCI

Every element of the fader strip is a pin, so a UCI, a touch panel, or another script drives the bank without the plugin's own panel being on screen anywhere.

| Pin               | Direction | Carries                                                       |
| ----------------- | --------- | ------------------------------------------------------------- |
| `Fader~Fader N`   | Both      | The fader's level, 0 to 255.                                  |
| `Fader~Label N`   | Both      | The fader's label text.                                       |
| `Fader~Readout N` | Output    | The formatted readout text.                                   |
| `Fader~Channel N` | Output    | `Ch <n>` for a mapped fader; blank when unlinked or past 512. |

### The 0 to 255 contract

`Fader` is an integer knob with a minimum of 0 and a maximum of 255. That is the range on the pin and it does not move. Bind a UCI fader to it and give the UCI control the same 0 to 255 range.

`Value Display` does not change that. It is readout text only: it decides whether `Fader Readout` reads `128` or `50%` and it touches nothing else. It ships `Percent`.

Read the Fader pin, not the readout

`Fader Readout` is display text. On `Percent` it is lossy - 256 levels collapse onto 101 percentages - and it carries a `%` character. A UCI that reads the readout instead of the `Fader` pin gets a string it has to parse and a value it cannot round-trip. Bind the `Fader` pin.

The two plugins do not mean the same thing by their unit setting

Faders' `Value Display` ships `Percent` and the controller's `Display Unit` ships `Decimal`, but they are not two halves of one display preference. `Value Display` formats a readout. `Display Unit` formats no level at all: it decides how a bare number typed at the command pad is read, and the controller's levels stay 0 to 255 on screen either way. Set `Display Unit` to `Percent` to match Faders and every level on screen is unchanged - only the echo in the Settings page's `SETTINGS` card moves - while every command pad entry is silently re-read: `@ 50` stops meaning level 50 and starts meaning 128. See [Command Pad](https://freshavlabs.com/docs/lamina-lighting-control/#command-pad) and [Plugin Properties](https://freshavlabs.com/docs/lamina-lighting-control/#properties).

### The readout lags the fader, deliberately

When a channel moves on the controller, the `Fader` pin follows it immediately. `Fader Readout` does not. The text is rebuilt by a roughly 10 Hz collector that runs only while something is waiting and stops itself once it has caught up. Formatting text allocates memory, and a 32-wide bank tracking a live console at full frame rate would do it 32 times a frame; the collector is what keeps that off the Core's script budget.

The visible effect is that the slider and the number under it can disagree for a fraction of a second during a fast move. That is the design, not a fault. A bank switch is the exception - it formats every readout immediately, so switching banks never leaves the previous bank's numbers on screen.

### Changing Fader Count later

`Fader Count` is a Property, so changing it means a re-deploy, and it re-dimensions the pins. Two things do not follow it:

* **`Bank Start` does not re-stride.** The starts were seeded on the first run and are yours from then on. Press `AUTO DEPLOY` to re-cascade them at the new width. See [Fader Banks and Copy/Paste](https://freshavlabs.com/docs/lamina-lighting-control/#faders-banks).
* **Stored labels can come back wrong.** Labels are stored per bank at a stride of the current `Fader Count`, so changing it re-indexes the whole store. Labels above bank 1 will not line up afterwards - expect blanks, or labels against the wrong fader. The plugin tolerates the mismatch rather than erroring on it; retype the affected ones.

### Disabled faders still have live pins

A fader is disabled when Faders is not linked, or when its channel would fall past 512. Disabling greys the widget on the panel - it does not detach the pin, and a bound UCI control can still drive it. The refusal to write lives in the handler instead: a fader with no link or no channel takes the value and does nothing with it. So a UCI bound to a bank wider than its patch is safe - it cannot write past the universe - but it also gets no feedback that the move went nowhere beyond the greyed fader and the blank `Fader~Channel` pin.

## Control Pins

Nearly everything on either plugin's panel is also a pin on its schematic block, so a UCI, a wall plate, the scheduler, or another script drives the same value through the same path. This section is the map.

Pin names read `Group~Name`. The text before the tilde is the heading Designer groups the pin under; the text after it is the pin itself. A control that exists more than once carries an index, and which side of the tilde it lands on varies: the faders put it on the name, as in `Fader~Fader 4`, while the presets put it on the group, as in `Preset 4~Recall`. The tables below give the exact form for each.

One rule shapes several entries in this section. A pin takes its `Group~Name` form from the panel layout, so a control the panel draws only conditionally has no such name while its condition is off. The pin still exists - it just appears in the pin list under its bare control name, with no tilde group at all. Whether it still *does* anything in that state depends on the control, so check the note where it applies. `Show_Locking_ID` and `Preset Count` both gate naming this way, and each is called out where it applies.

Some panel legends differ from their pin names: ARM SAVE is `Transport~Save Arm`, PRESET LOCKOUT is `Transport~Disable Wall`, SAVE OFF PRESET is `Off~Save`, LIVE and OFF are `Live~Recall` and `Off~Recall`, and the command pad's + and @ keys are `Command~Key AND` and `Command~Key AT`.

### Lamina Lighting Control: header and status

| Pin                             | Type    | Direction |
| ------------------------------- | ------- | --------- |
| `Connection~Status`             | Status  | Output    |
| `Connection~Refresh`            | Trigger | Input     |
| `License~Status`                | Status  | Output    |
| `License~Locking ID` (see note) | Text    | Output    |

`Show_Locking_ID` ships as `No`, and it gates the layout entry rather than just the panel widget. So on a default design there is no LOCKING ID readout drawn *and* the pin has no tilde group: look for it under its bare name, `LicenseLockingID`. Set `Show_Locking_ID` to `Yes` and the readout appears and the pin becomes `License~Locking ID`. It reports the same Locking ID either way. See [Licensing](https://freshavlabs.com/docs/lamina-lighting-control/#licensing).

### Channels

| Pin                      | Type  | Direction | Range    |
| ------------------------ | ----- | --------- | -------- |
| `Ch 1` to `Ch 512`       | Value | Both      | 0 to 255 |
| `In Ch 1` to `In Ch 512` | Value | Output    | 0 to 255 |

These are the per-channel integration surface. They carry no tilde group - they appear in the pin list under their bare names rather than beneath a heading, so look for `Ch 1` rather than for a Channels heading. `Ch` is the working buffer. `In Ch` mirrors the received universe and is output-only. Both are 512 pins wide regardless of `Channel Count` - the pin list never shrinks - but the engine only mirrors the first `Channel Count` of them. At `Channel Count` 64, `In Ch 65` to `In Ch 512` still exist and sit at 0. See [The Plugin Panel](https://freshavlabs.com/docs/lamina-lighting-control/#panel-overview).

### Preset pins

Here `N` runs from 1 to `Preset Count`. These grouped names exist only for the slots the panel actually draws; read the note below for the ones above that.

| Pin               | Type    | Direction | Range     |
| ----------------- | ------- | --------- | --------- |
| `Preset N~Recall` | Trigger | Input     |           |
| `Preset N~Active` | LED     | Output    |           |
| `Preset N~Name`   | Text    | Both      |           |
| `Preset N~Fade`   | Value   | Both      | 0 to 60 s |
| `Preset N~Save`   | Trigger | Input     |           |

All five preset controls are declared at the full 15 slots regardless of `Preset Count`, so the pin surface does not shrink when the panel draws fewer rows. What changes is both the naming and what those pins do. `Preset Count` gates the layout, so on a default design of 4 it is only slots 1 to 4 that get the grouped form above. Slots 5 to 15 exist with no tilde group: they are `Preset Trigger 5`, `Preset Active 5`, `Preset Name 5`, `Preset Fade 5`, and `Preset Save 5`, on up to 15. Note that the bare name for a recall is `Preset Trigger`, not `Preset Recall`.

Above the count, those pins do not all behave like the drawn ones, and the difference matters if you are wiring to them:

* **`Preset Trigger` and `Preset Save` are gated.** On a default design of 4, firing `Preset Trigger 7` recalls nothing and saving to `Preset Save 7` stores nothing. This is deliberate: it stops a pin, a UCI, or an external script from reaching a slot the panel does not draw. If you have wired a wall plate to a recall above your `Preset Count` and nothing happens, this is why - raise the count.
* **`Preset Name` and `Preset Fade` still hold what you write** and still round-trip through Export, but nothing recalls them while the count sits below their slot.
* **`Preset Active` stays dark**, because nothing can make a slot above the count the active source.

Raise `Preset Count` and each newly drawn slot takes its `Preset N~` form and starts responding. See [Presets and Looks](https://freshavlabs.com/docs/lamina-lighting-control/#presets).

### Live, Off, and transport

| Pin                          | Type    | Direction | Range     |
| ---------------------------- | ------- | --------- | --------- |
| `Live~Recall`                | Trigger | Input     |           |
| `Live~Active`                | LED     | Output    |           |
| `Off~Recall`                 | Trigger | Input     |           |
| `Off~Active`                 | LED     | Output    |           |
| `Off~Save`                   | Trigger | Input     |           |
| `Transport~Save Arm`         | Toggle  | Both      |           |
| `Transport~Capture Source`   | Text    | Both      |           |
| `Transport~Disable Wall`     | Toggle  | Both      |           |
| `Transport~Fade Time`        | Value   | Both      | 0 to 60 s |
| `Transport~Per-Preset Fades` | Toggle  | Both      |           |
| `Transport~State`            | Text    | Output    |           |

`Transport~Save Arm` and `Transport~Capture Source` are one control each, drawn on both the Control page and the Settings page. See [The Plugin Panel](https://freshavlabs.com/docs/lamina-lighting-control/#panel-overview).

### Command pad pins

| Pin                                                | Type    | Direction |
| -------------------------------------------------- | ------- | --------- |
| `Command~Key 0` to `Command~Key 9`                 | Trigger | Input     |
| `Command~Key THRU` / `AND` / `AT` / `FULL` / `OUT` | Trigger | Input     |
| `Command~Key RELEASE` / `CLEAR` / `ENTER`          | Trigger | Input     |
| `Command~Line`                                     | Text    | Output    |
| `Command~WB Summary`                               | Text    | Output    |

See [Command Pad](https://freshavlabs.com/docs/lamina-lighting-control/#command-pad).

### sACN input

| Pin                    | Type   | Direction | Range      |
| ---------------------- | ------ | --------- | ---------- |
| `Input~Enable`         | Toggle | Both      |            |
| `Input~Universe`       | Value  | Both      | 1 to 63999 |
| `Input~Interface`      | Text   | Both      |            |
| `Input~Join Multicast` | Toggle | Both      |            |
| `Input~Filter IP`      | Text   | Both      |            |
| `Input~Filter Name`    | Text   | Both      |            |
| `Input~Min Priority`   | Value  | Both      | 0 to 200   |
| `Input~Kick Enable`    | Toggle | Both      |            |
| `Input~Kick Timeout`   | Value  | Both      | 0 to 600 s |
| `Input~Kick Fallback`  | Text   | Both      |            |
| `Input~Present`        | LED    | Output    |            |
| `Input~Source`         | Text   | Output    |            |

`Input~Source` is the `Rx Source` readout, and its three states are covered in [Live Input and Arbitration](https://freshavlabs.com/docs/lamina-lighting-control/#live-input).

### sACN output

| Pin                | Type   | Direction | Range      |
| ------------------ | ------ | --------- | ---------- |
| `Output~Enable`    | Toggle | Both      |            |
| `Output~Universe`  | Value  | Both      | 1 to 63999 |
| `Output~Priority`  | Value  | Both      | 0 to 200   |
| `Output~Interface` | Text   | Both      |            |
| `Output~Dest IP`   | Text   | Both      |            |
| `Output~FPS`       | Value  | Both      | 5 to 30    |

### DMX monitor

| Pin                 | Type    | Direction | Range  |
| ------------------- | ------- | --------- | ------ |
| `Monitor~Bank`      | Value   | Both      | 1 to 8 |
| `Monitor~Bank Prev` | Trigger | Input     |        |
| `Monitor~Bank Next` | Trigger | Input     |        |

Bank navigation is the whole of the monitor's pin surface. The 64 cells themselves carry no pins - the channel label, the input echo, and the editable output cell are panel-only, 192 controls with no pin between them. Read and write channels through `Ch` and `In Ch` instead. How many banks are actually reachable follows `Channel Count`; see [The Plugin Panel](https://freshavlabs.com/docs/lamina-lighting-control/#panel-overview).

### Preset backup pins

| Pin                    | Type    | Direction |
| ---------------------- | ------- | --------- |
| `Presets~Export`       | Text    | Output    |
| `Presets~Import`       | Text    | Both      |
| `Presets~Import Apply` | Trigger | Input     |

See [Preset Backup](https://freshavlabs.com/docs/lamina-lighting-control/#preset-backup).

### Emergency pins

| Pin                      | Type    | Direction |
| ------------------------ | ------- | --------- |
| `Emergency~Fire Trigger` | Toggle  | Input     |
| `Emergency~Active`       | LED     | Output    |
| `Emergency~Name`         | Text    | Both      |
| `Emergency~Save`         | Trigger | Input     |

`Emergency~Fire Trigger` is the alarm contact input. It is a toggle, and it is input-only - it has no panel widget and nothing reads it back out. It is grouped here deliberately so it sits next to the rest of the emergency surface rather than as a loose pin. See [Emergency and Fire Alarm](https://freshavlabs.com/docs/lamina-lighting-control/#emergency).

The preset store is not a pin

The controller keeps its 17 stored looks - `Off`, `P1` through `P15`, and the emergency look - in a hidden text control with no pin and no widget. It is storage, not a control surface. [Preset Backup](https://freshavlabs.com/docs/lamina-lighting-control/#preset-backup) is the supported way to read or write the stored looks.

### Lamina Faders: link

| Pin                     | Type    | Direction |
| ----------------------- | ------- | --------- |
| `Link~Status`           | Status  | Output    |
| `Link~Linked`           | LED     | Output    |
| `Link~Lamina Component` | Text    | Both      |
| `Link~Refresh`          | Trigger | Input     |

See [Lamina Faders](https://freshavlabs.com/docs/lamina-lighting-control/#faders-overview).

### Faders

`N` runs to `Fader Count`.

| Pin               | Type  | Direction | Range    |
| ----------------- | ----- | --------- | -------- |
| `Fader~Fader N`   | Value | Both      | 0 to 255 |
| `Fader~Label N`   | Text  | Both      |          |
| `Fader~Readout N` | Text  | Output    |          |
| `Fader~Channel N` | Text  | Output    |          |

Bind the `Fader` pin rather than the readout - see [Binding Faders to a UCI](https://freshavlabs.com/docs/lamina-lighting-control/#faders-binding).

### Banks

`N` runs to `Bank Count`.

| Pin                                                           | Type    | Direction | Range             |
| ------------------------------------------------------------- | ------- | --------- | ----------------- |
| `Bank~Select`                                                 | Value   | Both      | 1 to `Bank Count` |
| `Bank~Select N`                                               | Toggle  | Both      |                   |
| `Bank~Name N`                                                 | Text    | Both      |                   |
| `Bank~Start N`                                                | Value   | Both      | 1 to 512          |
| `Bank~Name Display`                                           | Text    | Output    |                   |
| `Bank~Auto Deploy`                                            | Trigger | Input     |                   |
| `Bank~Copy`                                                   | Trigger | Input     |                   |
| `Bank~Paste`                                                  | Trigger | Input     |                   |
| `Bank~Scope Name` / `Bank~Scope Values` / `Bank~Scope Labels` | Toggle  | Both      |                   |
| `Bank~Clipboard Status`                                       | Text    | Output    |                   |
| `Bank Up`                                                     | Trigger | Input     |                   |
| `Bank Down`                                                   | Trigger | Input     |                   |
| `Bank Active N`                                               | LED     | Output    |                   |

Bank\~Select and Bank\~Select N are different things

`Bank~Select` with no index is the numeric selector - the SEL field, and the canonical one. `Bank~Select 1`, `Bank~Select 2` and so on are the direct-select buttons, one per bank. They sort next to each other in the pin list and they do not mean the same thing. See [Fader Banks and Copy/Paste](https://freshavlabs.com/docs/lamina-lighting-control/#faders-banks).

The last three - `Bank Up`, `Bank Down`, and `Bank Active N` - are drawn nowhere on the panel and, like the controller's channel pins, carry no tilde group. They exist for a wall plate or a UCI that needs to step banks without the panel being on screen.

## Troubleshooting

### sACN input problems

#### No sACN received

* Turn `Join Multicast` on; it ships off. See [Network and sACN Setup](https://freshavlabs.com/docs/lamina-lighting-control/#network)
* Check the Core is on the same Layer 2 segment as the source. See [Network and sACN Setup](https://freshavlabs.com/docs/lamina-lighting-control/#network)
* Confirm `In Enable` is on and `Universe In` matches the source's universe
* Confirm `Min Priority` is not above the priority the source is sending
* Check `Filter Source IP` and `Filter Source Name` - a filter left from commissioning silently rejects everything else
* Do not wait for `Status` to tell you. An input-side interface failure raises no fault; watch `Input Present`, `Rx Source` and the debug log. See [Live Input and Arbitration](https://freshavlabs.com/docs/lamina-lighting-control/#live-input)

#### Source found but values never update

* Check whether a second source at the same priority acquired first - see the next card
* On an older release this had another cause, see [Known Issues](https://freshavlabs.com/docs/lamina-lighting-control/#known-issues)

#### A source at the same priority will not take over

By design: the first source to arrive holds, and only a strictly higher priority preempts. See [Which source wins](https://freshavlabs.com/docs/lamina-lighting-control/#which-source-wins).

#### Live values look stale after changing universe

Intended: a re-open holds the last values until a new source arrives, and only `In Enable` off clears them. See [When the source stops](https://freshavlabs.com/docs/lamina-lighting-control/#when-the-source-stops). With `Kick` on and a timeout set, the re-open restarts the kick timer and the fallback fires when it runs out. See [Kick](https://freshavlabs.com/docs/lamina-lighting-control/#kick).

### sACN output and licensing

#### The fixtures are dark

* Confirm `Out Enable` is on, and that `Universe Out` matches what the fixtures are patched to
* Check the LICENSE readout. When the demo expires the output stops while everything else keeps working. See [Licensing](https://freshavlabs.com/docs/lamina-lighting-control/#licensing)
* Check the `Status` bar for a fail-closed interface or `Dest IP`, below

#### Status names an interface and output has halted

A named `Out Interface` with no usable IP halts output rather than falling back, see [Network and sACN Setup](https://freshavlabs.com/docs/lamina-lighting-control/#network).

* Restore the interface. Output re-opens on its own a few seconds after the Core sees the interface list change
* If it does not, press `Refresh` in the header. The automatic re-arm fires on a change to the interface list, not on a retry timer, so a fault with an unchanged list waits for the button
* If you did not mean to pin egress to one NIC, set `Out Interface` back to `Auto`

#### Status reads Dest IP is not a valid address

Correct `Dest IP`, see the `Dest IP` row in [Output universe and destination](https://freshavlabs.com/docs/lamina-lighting-control/#output-universe-and-destination).

### Fader problems

#### The faders are greyed out

* Check the `Linked` LED and the `Status` bar first. The whole strip is disabled while Faders is not linked to a controller, and the `Status` reason text names which failure it is. See [Lamina Faders](https://freshavlabs.com/docs/lamina-lighting-control/#faders-overview)
* A single greyed fader whose channel label is blank is mapped past channel 512. See [Fader Banks and Copy/Paste](https://freshavlabs.com/docs/lamina-lighting-control/#faders-banks)

#### A fader moves but the light does not

* If the controller is in an alarm lockdown it refuses channel writes, so the move never reaches the buffer. See [Emergency and Fire Alarm](https://freshavlabs.com/docs/lamina-lighting-control/#emergency)
* If the controller's demo has expired the fader still moves and still writes - it is the controller's sACN output that has stopped. See [Licensing](https://freshavlabs.com/docs/lamina-lighting-control/#licensing)
* A fader with no link or no channel does nothing with the value. See [Binding Faders to a UCI](https://freshavlabs.com/docs/lamina-lighting-control/#faders-binding)

#### A paste landed on the wrong fixtures

Paste applies the copied look to the destination bank's own channels and never writes `Bank Start`. See [Copy and paste a bank](https://freshavlabs.com/docs/lamina-lighting-control/#copy-and-paste-a-bank).

### Preset backup problems

#### An import was rejected

`Import Apply` validates the whole blob before writing anything, so a rejection leaves every stored preset untouched. `Status` carries the reason until an import succeeds or the script restarts, and `fieldcount` is the one a tab-mangled blob produces. The full reason table is in [Preset Backup](https://freshavlabs.com/docs/lamina-lighting-control/#preset-backup).

#### The exported blob has an old preset name

`Export` rebuilds after a save and after a successful import, not when a name or fade is edited. Save or re-import before copying the blob. See [Preset Backup](https://freshavlabs.com/docs/lamina-lighting-control/#preset-backup).

### Debug output

The plugin logs its startup banner, license state, and warnings to the Q-SYS debug console. Set `Debug_Level` to Verbose for deeper diagnostics. The on-block debug button is enabled on all Fresh AV Labs plugins for field troubleshooting - and on the input side it is the only place some failures are reported at all.

## Known Issues

### Before 1.2.5, Status could hide halted output

On versions before 1.2.5, `Status` could read `OK` after a successful `Import Apply` or an alarm release while output was still halted. During an alarm it could read `EMERGENCY - egress active` while no output was leaving.

**Workaround:** update to 1.2.5 or later. On an earlier version, press `Refresh` in the header. The fault returns if `Dest IP` or `Out Interface` is still wrong.

### Before 1.2.0, the receiver could track the plugin's own output

On versions before 1.2.0, the receiver could acquire the plugin's own transmitted frames after a re-open, through multicast loopback. The plugin then held itself as the tracked source, and a console at the same priority was ignored until it claimed a higher one.

**Workaround:** update to 1.2.0 or later. The receiver now ignores packets that carry its own source identity.

## Support

* Support tickets: [freshavlabs.com/support](https://freshavlabs.com/support/)
* Website: [freshavlabs.com](https://freshavlabs.com)
* Email: <support@freshavlabs.com>

Include with a request:

* Q-SYS Designer version
* Core model
* Plugin version, shown under the plugin name in the header
* Your configuration: `Channel Count`, `Preset Count`, `Passthrough`, and whether the fire-alarm path is enabled
* Your sACN setup: universes in and out, `Join Multicast`, the named interfaces, and priorities
* The Locking ID, for a license question
* Debug console output showing the issue
