# Control Surfaces

Build a touch view of your Dashboard with buttons, faders, knobs, XY pads, color pickers and labels. A Surface sends OSC signals through [Bindings](https://unilighter.cc/info/for-ai/docs/bindings.md) to your existing controls: for example, a dimmer fader, a held strobe cue or two separate Pan/Tilt parameters.

The editor and local control work in the web console, Unilighter Desktop and Unilighter Solo. Sharing with guest phones or tablets currently requires Unilighter Desktop and a local network.

## Create a Surface

1. Open **Dashboard**, then click **Surfaces** in its toolbar.
2. Click **New Surface**. New surfaces are named **Surface 1**, **Surface 2**, and so on. Rename the current one in **Surface name**; use the surface selector when your project has several.
3. Choose **Canvas**: **Landscape · 16:9**, **Portrait · 9:16**, or **Custom size**. The default is 1280 × 720 logical units. Use equal width and height for a square canvas.
4. Click **Add control**, search or choose a control, and place it. The toolbar adds it at the center. Double-click or right-click empty canvas to open the same menu and add it at that position.
5. Drag a control to move it, or drag its corner handle to resize it. Grid snapping is always enabled. Select a control to edit its label, behavior, binding and appearance in the right inspector.
6. Use **Save** in the console top bar to save the project.

**Shift+D** duplicates the selected control; **Delete** removes it. These shortcuts do not act while you are typing in a field. **Position & size** provides precise coordinates and dimensions. Changing the canvas size scales the layout to keep controls accessible. Resizing a **Text label** also scales its text.

The toolbar's **Duplicate** and **Delete** act on the whole surface. Surface definitions and bindings travel with the project through local or cloud saves and export/import. Existing projects start with an empty list of surfaces.

## Choose what each control sends

Every input uses floating-point arguments. Continuous values range from `0` to `1`.

| Control | Outgoing signal |
| --- | --- |
| Button — Trigger | An ordered `1`, then `0` pulse on each press. |
| Button — Hold | `1` on press; `0` on release. |
| Button — Toggle | The new state, `0` or `1`. |
| Fader / Knob | One value. |
| XY pad | Two arguments: X, then Y. |
| Color picker | Three arguments: Hue, Saturation, Value (brightness), in HSV order. |
| Text label | No signal; use it to name sections or give instructions. |

Set a button's **Button behavior** to match its purpose. Set **Starting values** for the input display when the project opens. Restoring these values does not send commands or activate cues.

## Connect to Dashboard controls

A surface needs a binding before it affects your show.

1. Open **Dashboard** once after loading the project so its target controls are registered. Until then, the surface shows a waiting notice and input is discarded.
2. Enable **Assign Mode** with the controller icon in the top navigation bar.
3. Click the destination control on Dashboard, then choose the **Surface** tab in the assignment dialog.
4. Choose your surface and its input control. For an XY pad, select **X** or **Y**. For a color picker, select **Hue**, **Saturation** or **Value**. Single-channel inputs are selected automatically.
5. Continuous inputs use **Absolute** automatically. For button inputs, choose **Mode** as needed; see [OSC binding modes](https://unilighter.cc/info/for-ai/docs/bindings.md#osc-binding-modes).
6. Add a descriptive **Label** and click **Add**. Leave Assign Mode before operating the surface.

For Pan/Tilt, assign the pad's X channel to the target Pan control, then repeat with Y and Tilt. A multichannel source does not assign all destinations at once. **Already assigned** shows existing mappings for the selected signal/channel.

Use a Hold source and Absolute binding for a held target. Absolute sets a target Toggle button to the incoming on/off state; a Trigger target responds only to a positive event, and a Hold target handles press and release.

### Control key and address

**Binding address** opens by default in the inspector. **Control key** identifies the signal; new keys start at `button-1`, `fader-1`, and similar numbered names. The default OSC address is `/surfaces/{control-key}`, for example `/surfaces/fader-1`.

**Label** changes only the visible caption. Changing the key or **Custom OSC address** changes the outgoing signal, so existing bindings need reassignment. The editor warns before applying that address change.

Keys are unique within a surface. The same key on different surfaces intentionally reaches the same bindings. Duplicating a surface preserves keys and addresses; duplicating an individual control gives it a new key and default address. Neither copy inherits a shared link.

Both **OSC** and **Surface** assignment tabs create ordinary OSC bindings. The OSC tab also accepts address patterns and **Learn**; see [Assign Mode & Bindings](https://unilighter.cc/info/for-ai/docs/bindings.md).

## Try it and fit the screen

Click **Try it** beside the current surface settings to hide the editor and operate the controls. **Exit control** returns to editing. **Fullscreen** requires a click; on a rectangular canvas the console tries to lock the matching orientation. If the browser cannot do that, rotate the device when prompted. A square custom canvas keeps the current orientation.

The control view fills the available area. Control positions and frames scale independently horizontally and vertically; text, inner spacing, outlines and corner radii scale uniformly, so letters retain their shape.

In **Appearance**, choose **Stretch** to fill the frame, or **Keep proportions** to center proportionate content inside it. Buttons, faders and labels default to Stretch; knobs, XY pads and color pickers default to Keep proportions.

## Share from Desktop

1. Connect Unilighter Desktop and the guest device to the same local network.
2. Open the surface, click **Share**, then **Publish Surface**.
3. Choose the reachable **LAN address**. Scan the QR code or use **Copy Link**; both contain the same secret link.
4. Open that link on the guest device. No account, pairing code or host approval is needed. The guest gets only this surface, **Fullscreen**, and a connection status.

Keep the link private: anyone who has it and can reach the workstation can operate that surface. The sharing dialog lists connected guests. Several surfaces and guests can operate together.

Publishing a surface does not enable access to the full Remote Dashboard. That permission remains separate in **Settings → Remote control**. The shared local server stays running while either Dashboard access or a surface publication needs it. See [Desktop Remote Control](https://unilighter.cc/info/for-ai/docs/desktop/remote-control.md).

### Pause, revoke and reuse links

- **Pause access** stops guest control; **Resume access** restores it with the same link.
- **Revoke link** invalidates the old link. Publishing again creates a new one.
- Links survive closing/reopening the project and restarting Unilighter Desktop. Sharing records stay on that workstation, separately from the portable project.
- If the project is closed, another project is open, or Dashboard is not ready, guests wait. Control resumes automatically once the correct project and its Dashboard controls are ready. Commands entered while waiting are not replayed.
- Deleting a surface revokes its publication. Duplicated projects and surfaces do not inherit published links.
- A link still needs the same reachable workstation address and port. If the LAN address changes, choose the new address and copy the updated URL; the secret remains the same.

## Connection loss and current limits

Held actions release when their source lets go, disconnects, or is removed by editing. Pausing access or loading another project also releases affected holds. Overlapping sources keep the action held until the last source releases. A detected disconnect releases immediately; a silent network failure is detected by heartbeat timeout, so release can take approximately 12 seconds. Disconnected input is discarded, rather than replayed after reconnection.

Editor changes reach connected guests immediately. Input values synchronize between connections to the same surface. Changes made directly on Dashboard or through MIDI do not return to the surface, so its display is not feedback of the target's actual state.

These OSC bindings currently receive surface input inside the console. A native network OSC receiver and internet-based guest surface sessions are not available yet.

