# Architecture and data contracts

Paths below are relative to the demo Base COMP (`lighting_matrix_demo`). The final exported DATs are authoritative; upgrade scripts retain earlier definitions that later stages replace.

```mermaid
flowchart LR
  TOP[Source TOP] --> Media[media_input: 8x8 conversion]
  Media --> Effects[lighting_effects: background + reactive]
  Events[Physical / virtual button events] --> Effects
  Effects --> Route[external_source]
  Route --> Matrix[matrix: Manual / External / Add]
  Manual[Stored manual values] --> Matrix
  Matrix --> Preview[controller_ui and 8x8 TOP]
  Matrix --> Adapter[apc_mini_mk2_adapter]
  Effects --> Small[small_button_lights]
  Small --> Adapter
```

## Components

| Component | Responsibility |
|---|---|
| `matrix/manual_controls` | Select/load/apply/fill/clear stored cells. |
| `matrix/matrix_state` | Persistent `manual_values` table and final mode combination. |
| `matrix/input_processing` | Validate/normalize the external 64-sample CHOP. |
| `matrix/preview` | Exact pixel TOP and original clickable matrix preview. |
| `controller_ui` | Full APC-style panel; final colors come from matrix output. |
| `lighting_effects` | Eighty-position renderers, press events, two layers, independent speeds. No MIDI output code. |
| `media_input` | TOP connector → Resolution TOP → Script CHOP conversion. |
| `external_source` | Legacy routing Switch CHOP. Current UI selects index 0, the composed effects output, even for media. Index 1 remains a direct-media bypass for network use. |
| `small_button_lights` | Separate manual/external/add state for 16 fixed-color LEDs. Shares matrix Mode. |
| `apc_mini_mk2_adapter` | Device map, input decoding, output quantization and SysEx/Note On messages. |
| `effect_settings_window` | Bordered centered Window COMP for `color_ripple_controls`. |
| `chase_example` | Original standalone CHOP example, retained but disconnected from the final route. |
| `media_example` | Generated quadrant test TOP. Replace its connection with media. |

## Matrix CHOP interface

| Item | Contract |
|---|---|
| Input | `matrix/external_in`, first CHOP connector of `matrix` |
| Output | `matrix/matrix_data` |
| Channels | `r`, `g`, `b`, `brightness` |
| Samples | Exactly 64 per channel; sample `row*8+column` |
| Orientation | `(0,0)` top-left; rows/columns 0–7 |
| Values | Finite floats 0–1; out-of-range clamps; non-finite becomes zero |
| Invalid source | Missing required channel or wrong sample count makes the entire external layer black; extra channels are ignored |
| Combination | Manual, External, or channel-by-channel clamped Add |

`matrix/matrix_pixels` is exactly 8×8 RGBA: RGB = final color × brightness, alpha = 1. The original enlarged TOP preview uses nearest filtering. The full panel's separate pad faces read the same CHOP values; selection borders are UI decoration. NumPy indexing for the TOP is `[7-row, column]`.

## Media interface

Connect any TOP to the first TOP input of `media_input`. `pixels_8x8` uses high-quality downsampling to custom resolution 8×8. `top_to_matrix` synchronously reads only that 8×8 result, reverses scanline order, and outputs the matrix format. Alpha × `media_input.Level` becomes brightness; RGB and alpha are sanitized/clamped. `sampled_pixels` is the pre-composition TOP, not the final display.

Media enters the background compositor when `Preset=media`; `lighting_effects.Level` scales its brightness. The input TOP network controls playback. No movie decoder, crop control, or camera capture node is created automatically.

## Small-LED interface

`small_button_lights/external_in` accepts 16 samples named `level` and `blink`, each 0–1. Samples 0–7 are bottom buttons left-to-right; 8–15 are side buttons top-to-bottom. Missing channels/samples produce zero for the affected reads. Non-finite input becomes zero.

`small_button_lights/button_data` outputs `level`, `blink`, and `state` (0 off, 1 on, 2 blink). The adapter's second CHOP connector consumes `state`. The full panel uses that state; a blinking virtual LED uses an illustrative 1 Hz clock, not synchronized hardware blink phase.

## Effect renderer contract

Each `lighting_effects/preset_NAME` DAT exposes `render(t, speed, level, events)` and returns 80 `(r,g,b,brightness)` tuples in 0–1:

- 0–63: matrix pads, row-major.
- 64–71: bottom buttons at `(x=0..7, y=8)`.
- 72–79: side buttons at `(x=8, y=0..7)`.

Events are `(birth_time, logical_index)` pairs, bounded to the latest 32, with time pruning. Held inputs are tracked separately by source and index. The background receives an empty event list; the reactive layer receives press/repeat events.

For pads, reactive alpha blends over the emitted background RGB: `base_rgb * base_brightness * (1-alpha) + reactive_rgb * alpha`. The result has brightness 1. This differs from matrix Add mode. Small-LED layers combine intensity before hardware thresholding.

Add an effect by defining its renderer, registering a menu choice and UI action in the appropriate layer, and validating its output. There is no automatic plugin discovery. Keep controller-specific messages in the adapter.

## Hardware adapter connection points

`TO_APC_MINI_MK2_ADAPTER` carries the final 64-cell CHOP to adapter input 1; `small_button_lights/button_data` carries input 2. A future output adapter can consume those documented outputs. No DMX, Art-Net, LED-strip, or other hardware adapter is implemented.
