# aura-view: Previewing AURA files

<p align="center"><img src="images/aura-logo.svg" alt="AURA" width="320"></p>

`aura-view` displays dialogs, screens, components and `preview` blocks from `.aura` files through the dynamic loader. The native tool uses `BasicHost`: a gray background, full-area screens, components with a margin, and dialogs centered on a white frame. Options supply themes, assets and fonts.

Arguments receive placeholders unless a preview supplies values (`"test-<name>"`, `0`, `false`, `#808080`); records receive values per field and lists of records one entry. Errors leave the last valid version visible and report file, line and column. The preview does not execute an application workflow.

## Architecture: Core and host

| Part | Location | Responsibility |
|---|---|---|
| Core | `libs/aura-preview` (`aura::preview`) | Shadow directory, selection, controls, building through the loader, tapping and inspection, PNG, gallery, server protocol, window, `run()` with all options |
| Host | `aura/preview/host.h` | Application-specific parts: context, device(s), background, area for screens and components, foreground, dialog frames, server options and state, missing translations |
| `BasicHost` | `libs/aura-preview` | Without an application: gray background, full-area screens, components with a margin, dialogs centered on white |

A custom preview tool can implement `Host` and pass its factory to `run()`:

```cpp
int main(int argc, char** argv)
{
	return aura::preview::run(argc, argv, MyHost::create,
		{.name = "my-view"});
}
```

## Usage

```bash
build/dev/tools/aura-view/aura-view examples/hello
```

| Option | Effect |
|---|---|
| `<dir>` | Directory containing `.aura` files, including subdirectories. |
| `--dialog <name>` | Dialog or screen to display; otherwise the first one |
| *(no mode)* | Window. Saved changes appear within half a second. Clicks trigger signals, which go to the log. Errors go to stderr. |
| `--render <file.png>` | Renders once and exits (exit code 2 for errors in the files) |
| `--render-previews <dir> [--compare <refdir>]` | Renders every preview as `<dir>/<device>/<target>-<title>.png`; `--compare` compares against `<refdir>/<device>`: `DIFF`, `NEU` (no reference), and `WEG` (reference without preview) produce exit code 1 |
| `--list-devices` | The host’s devices; `BasicHost` provides one device named `default`. |
| `--lint` | Unknown `theme.` values: errors, exit code 1. Missing translations: warnings when reported by the host. |
| `--server` | Render server for the VS Code preview (see below) |
| `--device <w>x<h>`, `--assets <dir>`, `--fonts <dir>`, `--theme <file.json>` | `BasicHost`: screen size (default 1280x800), images and files used by `source:`, fonts, `theme.<name>` as JSON (`"#rrggbb"` is a color, numbers and `true`/`false` retain their types, anything else is text) |

## Pixel comparison

```bash
build/dev/tools/aura-view/aura-view examples/hello --render-previews /tmp/aura-previews
build/dev/tools/aura-view/aura-view examples/hello --render-previews /tmp/aura-previews --compare references
```

Output is stored under `default/`. Only declared previews are rendered; animations remain at their initial state. Values set later by application C++ code are absent. Review reference images visually after changes.

## Unsaved content

`aura-view` reads from a shadow copy in `/tmp/aura-view-<pid>`, rather than directly from `<dir>`.

- **Content:** The copy consists of files from disk. If the editor has sent unsaved content, it replaces the corresponding file.
- **Writing:** Only changed files are rewritten.
- **Error messages:** Paths in loader messages are mapped back to `<dir>`.

This avoids requiring a separate loader interface for editor content.

## Server protocol

JSON travels over stdin/stdout, one line per request and one line per response, in the same order. Logging goes to stderr.

| Request | Effect |
|---|---|
| `{"cmd":"update","file":"/abs/x.aura","text":"…"}` | Unsaved content of a file |
| `{"cmd":"revert","file":"/abs/x.aura"}` | Use the file on disk again (after saving or closing) |
| `{"cmd":"refresh"}` | Files on disk have changed |
| `{"cmd":"select","name":"Hello"}` | Select another dialog, screen, component, or preview (`"Hello: Sample"`) |
| `{"cmd":"set","name":"view","value":"thanks"}` | Change a state, `bool`, `string`, `int`, or `real` property of the displayed element live |
| `{"cmd":"options","largeText":true,"contrast":false,"language":"EN","scale":1}` | Display options; `scale` scales the PNG |
| `{"cmd":"press","x":160,"y":733,"down":true}` | Finger down (pressed state) or up (`false`, tap on the same node) |
| `{"cmd":"move","x":160,"y":600}` | Finger moves while pressed: `onDrag`; after 10 px it drags a `Scroll` (as in the application, `aura::ui::InputDriver`) |
| `{"cmd":"tap","x":160,"y":733}` | Tap |
| `{"cmd":"render"}` | PNG even if nothing changed |
| `{"cmd":"gallery","file":"/abs/x.aura","scale":0.5}` | `gallery`: the file's previews as PNG (`name`, `title`, `png`); components cropped to their own area at original size, dialogs and screens with `scale` |
| `{"cmd":"inspect","x":160,"y":733}` | Elements at the point, innermost first: `inspect` with `file`, `line`, `column`, `type`, `id`, `name`, and rectangle (`x`, `y`, `width`, `height`) |
| `{"cmd":"frame","ms":40}` | Advance animations by `ms` (at most 1000); PNG if an animation was running |

**Fields in every request:** An optional `"id"` is returned in the response.

**Contents of every response:**

- **Selection:** `roots` with `name`, `type` (`Dialog`, `Screen`, `Component`, `Preview`), `target` (the displayed element), `file`, `line`, and `signals`, plus `current`.
- **Host state:** Additional response fields come from `Host::state()`; `BasicHost` supplies no device selector or language options.
- **Controls:** `controls` for the displayed element: `{name, kind: "state", values, value}`, `{name, kind: "bool", value}`, or `kind` `"text"`, `"int"`, `"real"`.
- **Theme:** `theme`: every `theme.<name>` from the host (`Host::themeValues()`) with its type (`color`, `string`, `bool`, `number`) for completion; `themeColors`: colors as `#aarrggbb` (for editor color swatches). Set values apply per element until `aura-view` exits.
- **Display:** `width`, `height`. Host-specific options go through `Host::setOptions()`; `BasicHost` implements no language or accessibility options.
- **Errors and signals:** `diagnostics` with `file`, `line`, `column`, and `message`. `signals` contains signals triggered since the previous response, with names and arguments as AURA literals. If `error` is present, the request itself was invalid.
- **Image:** `png` as Base64 if the image changed.
- **Animations:** `animating` is `true` while an animation is running (`spin`, `pressSink`, ripple) or a `Scroll` continues moving after a drag. Time only advances in the server with `frame`; without `frame`, animations stand still.

The first response arrives on startup without a request (`id` is `null`).

## VS Code

The extension `tools/aura-vscode` (from 0.3.0; animations from 0.4.0; states and previews from 0.10.0; devices and sidebar from 0.12.0; Preview dropdown and “State …” from 0.13.0; inspector from 0.14.0; values, gallery, colors, definition, and rename from 0.15.0) starts `aura-view --server` for `aura.preview.directory` (default `app/ui`) when the active `.aura` file is inside it, or for the file's own folder otherwise.

Open it with “AURA: Open Preview”, the preview button in the editor title bar, or `Ctrl+K V`.

- **Live:** While typing (after `aura.preview.delay`, default 150 ms), unsaved content is sent to the server. Saving or closing switches back to disk, and disk changes trigger `refresh`.
- **Selection:** The preview displays the dialog, component, or preview containing the cursor (“Follow Cursor”). Choosing another entry in the selection list disables following. Opening or switching to another `.aura` file enables it again; if the file belongs to a different tree, `aura-view` restarts for that tree. “Source” jumps to the definition.
- **Errors:** Errors appear as diagnostics in the editor and Problems panel. The preview then displays the last error-free version with a red border.
- **Values:** Text and number properties of the displayed element appear in the “Values” menu and update while typing (after 250 ms).
- **Gallery:** “Gallery” displays all previews from the displayed element's file as tiles, with components cropped. Clicking displays that preview. Tiles follow changes to files and options.
- **Colors in the editor:** Colors such as `#c3000f` and `#80ffffff` have a swatch and color picker. `theme.mainColor` and similar values display a swatch using the running preview's value (from the host theme); hovering shows the value.
- **Go to Definition (F12) and Rename (F2):** Components, records, dialogs, and screens throughout the UI tree; IDs within their root; root properties, states, and signals. `label:` on an instance or `view:` in a preview also leads to the declaration; `line.description` or `row.tiles` (including through `repeat` variables) leads to the record field. Rename supports components, records, dialogs, screens, and IDs; occurrences in C++ code (`views::Name`, `buildName`, `NameArgs`, `->id`) are reported, not modified.
- **Inspector:** Holding Ctrl (Cmd) shows the element under the mouse with a frame, type, ID, size, and source. Ctrl+click jumps to its location in the `.aura` file, preferring the displayed element's file (a component instance there rather than the component's internals); a displayed preview remains selected. The loader records the origin on every node (`Node::origin`, dynamic mode only).
- **Clicks:** Holding the mouse button means finger down, enabling the pressed state. Releasing is the tap. Triggered signals appear below the image.
- **States:** Below the toolbar are the displayed element's states (dropdown) and `bool` properties (checkboxes); changes apply immediately without rebuilding.
- **Devices and options:** Device selection, language and accessibility require a custom host. `BasicHost` takes its size from `--device` at startup.
- **Previews:** If the displayed element has previews, select one in the “Preview” dropdown next to the states (“Default” = placeholders). States are labeled “State view”, etc.: they change a value live, like the application; a preview supplies a fixed set of values. The selection list only contains dialogs, screens, and components.
- **Options:** “Large Text” and “High Contrast” in the “Accessibility” menu (which indicates what is enabled), language, and zoom (fit, 50–200%, Ctrl + mouse wheel).
- **Sidebar:** The AURA icon in the activity bar opens preview settings (device, accessibility, language, follow cursor, animations, restart).
- **Animations:** With “Play”, the preview requests frames while the server reports `animating`: at most every 33 ms, one at a time, using actual elapsed time (at most 100 ms per frame). Without an active animation this costs nothing. “Pause” stops time, including `pressSink` when clicking. The choice applies to all previews and is retained.
- **Restart:** Restarts `aura-view`, for example after a build. If the server has crashed, the preview reports it. Output appears in the “AURA Preview” channel.

Configuration for a native AURA workspace (`settings.json`):

```json
{
  "aura.preview.directory": "${workspaceFolder}/examples/hello",
  "aura.preview.command": "${workspaceFolder}/build/dev/tools/aura-view/aura-view",
  "aura.preview.env": {},
  "aura.preview.args": [],
  "aura.preview.delay": 150
}
```

## Limitations

- **Application state:** Values the application sets through IDs after building (LEDs, selected tabs, rows and cells built by C++) are absent.
- **Animations:** Only animations defined in AURA run (`pressSink`, `spin`, `Rive`), not application animations (video, flyouts). `--render` shows the initial state.
- **Background:** Dialogs have the simple background behind them, rather than the screen over which the dialog opens in the application.

### Interactive property signals

The preview does not execute the C++ application. For a signal following the pattern
`countChanged(int value)`, it automatically copies the single argument into the
mutable `count` property. Names and value types must match; states only accept
declared values. Other signals are displayed as before. The value survives a
preview rebuild.

Inline handlers such as `onTap: { state.count += 1; }` run in the application, loader and preview; see [Inline scripts](inline-scripts.md).
