# Output and fullscreen

## The four places pixels appear

| Destination | Reads | Notes |
|---|---|---|
| **Output monitor** (in-console) | The final program image | Post master-opacity, post mapping, post blackout |
| **Preview monitor** (in-console) | Independent clip audition, or a qualifying live program mirror | See Preview behavior below |
| **Clean output window** — windowed or fullscreen | The same image as the Output monitor | Separate window, titled `ULTIMATE VJ — Output` |
| **Composition preview** in the editors | The composition image | Used by the surface editor |

The clean window and Output monitor read the same final program mailbox. Display scaling, colour
management and physical panel behavior can still affect what appears on a connected screen.

Menu entries live under **Performance**: **`Fullscreen output`** (with one entry per display),
**Open windowed output**, **Close output**, plus **`Blackout`** (⌘B) and **Output settings…** (⌘⇧O). The
Output monitor's own header offers **Fullscreen**, **Open windowed output** / **Close output**,
**Save output snapshot** and **Output settings**.

## Choosing a display

Each entry reads `DISPLAY NAME · WIDTH × HEIGHT`. Displays come from `NSScreen.screens`, with pixels read
from each display's current mode; where the mode cannot be read, dimensions fall back to AppKit's frame
times its backing scale factor and the mode is not considered verified.

**A mode can only be matched to the composition if its native pixels are verified AND both dimensions
fall in 16…4096.** Otherwise the entry reads `· current composition`, meaning the composition keeps its
own size and is scaled to the display instead.

Trying to explicitly match an unverifiable mode reports *"The native display mode is unavailable. Choose a
composition size manually before opening output."*; exceeding 4096 reports *"This display mode exceeds the
supported 4096-pixel composition dimensions."*

### Matching your composition to the display

An unavailable or oversized display mode cannot be matched automatically. You can set supported
composition dimensions manually and scale that output to the display, or match a verified mode
within the supported range.

**Change the composition size** — **Settings → General → COMP SIZE**, or click the gear beside the composition
size in the library sidebar (its tooltip is *Composition size · General settings*):

- `Width` and `Height` fields accept **16 … 4096**, then press **Apply**.
- Presets **720p** (1280 × 720) and **1080p** (1920 × 1080).
- **4K · Native** renders and delivers 3840 × 2160.
- **4K · MetalFX Upscaled** renders the composition at 1920 × 1080, then spatially upscales
  to 3840 × 2160. This choice is disabled when the GPU lacks MetalFX support. It changes
  internal rendering resolution, not the saved 4K delivery dimensions.
- Dimensions and render mode save with the set. Changes keep playback running, but are
  **refused while recording or recording finalization is active**. A successful manual change
  of dimensions resets the mode to Native. MetalFX mode requires a 3840 × 2160 set.
- No performance or visual-quality gain is promised by these source checks.

**Or let the output match the display** — Output settings → Display page:

| Button | Effect |
|---|---|
| **Match selected display resolution** | Sets the composition to the selected display's native resolution |
| **Fullscreen with current composition** | Opens fullscreen keeping your chosen size, scaled onto the display |

The panel explains both: *"Open fullscreen output matches a supported display's native pixel resolution and
shows video only. Fullscreen with current composition preserves your chosen video size and scales it to the
display. Change composition dimensions in General settings. Display, scaling and fullscreen mode update live.
Escape closes clean output."*

If you are recording, remember that composition dimensions must be **even** — see
[Recording](recording.md).

The initial selection prefers the first non-built-in display, falling back to the first screen.

## Preview behavior

Click a clip's eye to audition it without activating program playback or changing the file-audio
handoff. An off-air clip has an independent Preview playhead and seek slider. When the clip is
live, Preview follows that live clock and its separate seek slider is disabled.

**Independent audition is not output-mapped.** There is an optimization for a qualifying sole
live layer: if it is fully opaque, Alpha blended, has no outgoing transition and is the previewed
clip, Preview can mirror the final program mailbox. In that case **mapping, master processing,
master opacity and blackout are visible in Preview too**. Do not treat Preview as always unmapped.

## Fullscreen behaviour

- The window is borderless, covers the **entire** chosen screen including menu and Dock, and sits above
  both on window level. AppKit's frame constraint is overridden so the frame cannot be shrunk.
- The drawable is pinned to the display-mode pixels and does not auto-resize.
- **Escape closes it.** The status line appends `· Escape closes output` while fullscreen.
- The console **stays available**: global presentation options are not changed, so it remains usable on
  any other display. Operator controls are not suppressed. On a single-display Mac the fullscreen window
  covers the console and can take key status — plan accordingly.
- Changing display, scaling or fullscreen mode while output is open reconfigures immediately.
- If you were in Output settings or a help/report sheet, that sheet dismisses before fullscreen opens.

## Windowed output

Default frame is `min(960, visible width × 0.85) × min(540, visible height × 0.8)`, centred on the
selected screen's **visible** frame. Style is titled, closable, miniaturisable and resizable. Minimum size
320 × 180. Closing the window ends output.

## Scaling

**Scaling** offers Fit, Fill and Stretch, default **Fit**, applied over a black canvas. Output settings and
the chosen screen persist with the set.

## Blackout

Footer **`Blackout`**, or **Performance → Blackout**, shortcut **⌘B**. It cuts output in two reinforcing
ways: the render plan is built with master opacity 0, and the output mailbox itself reports no valid
image so the presenter draws black even if a frame arrived. Any in-flight encoded frame is invalidated by
a generation bump.

It also silences file audio. It affects only the output mailbox — the composition preview used by the
editors is not blacked out, so you can keep working while the room is dark.

Blackout resets when runtime state is reset.

## Snapshots

Output monitor → **Save output snapshot** writes a PNG. Output mapping is applied to snapshots, exactly as
it is to the screens and recording.

## Frame rate and cadence

Settings → Performance sets **Render frame rate** to **15, 30 or 60 fps** (default **30**).

Be precise about what this means: **this is a request, not a guarantee.** The app's own diagnostics are
explicit that a requested timer cadence and a reported display mode are configuration, not evidence of
presentation. Status lines report what was requested and flag when a display's refresh rate is below the
request (*"· N fps requested, display mode M Hz"*) or unknown (*"· Display cadence unverified"*).

Internally, frames are produced on a dedicated serial queue and presented with a minimum duration derived
from the requested rate, paced off the previous real display time rather than a CPU timer. A presentation
poll runs faster than the requested rate deliberately, so two timers do not beat against each other.

The status line is the honest place to look. Settings repeat the caveat: *"This is the requested frame
rate. Actual frame production depends on the current set and system load."*

## Settings → Performance readouts

**Render backend** reports Metal or the software fallback. **Native effects kernels** reports whether the
Metal kernels compiled. **Frame production** and **Frame preparation** give measured fps and milliseconds.
**Show playback diagnostics** expands program-frame counts, preview frame sequence, shader runtime status
and any program or preview issues.

**Output settings** changes mark the set dirty and save with it.

## Not verified

- Whether the console genuinely stays usable in practice on a single-display Mac. The source does not
  change presentation options and the output window can take key status; actual keyboard focus behaviour
  was not measured.
- Sustained frame rates on any specific display configuration.
- Whether the reference CPU compositor and the shipping Metal path agree pixel for pixel. They are not
  interchangeable — the CPU one exists as the behavioural test reference and is not referenced by the app.
