# Unity runtime

> Run Envy game UI in Unity 6.3+ with the EnvyUI component: UI Toolkit elements, data binding, events, animation, overlays, translations and live reload in the editor.

Source: https://envyui.com/docs/unity

The Unity runtime is a package, `com.mythicbrain.envy-ui`, shipped as C# source. The `EnvyUI` component reads a `.envy.json` document and rebuilds it in UI Toolkit at runtime, so there's no generated UI to keep in sync. Buttons take clicks and taps, and the arrow keys or a gamepad move focus, with the Input System or the old Input Manager.

Requires Unity 6.3 or newer, the first version with the vector graphics module it draws SVG images with. It's tested on Unity 6.6.

## Install

1. In Envy, export the **Unity package** (**Hand off › Unity package…**) and unzip it into the root of your Unity project, next to `Assets/`. It adds `Packages/com.mythicbrain.envy-ui`, your document in `Assets/UI/` and a demo script, `Assets/EnvyDemo.cs`. Unity picks the package up on its own.
2. `.envy.json` and `.envy` files import as **EnvyDocument** assets.
3. To try it, add the **EnvyDemo** component to an empty GameObject (its Document fills itself in) and press Play. In your own scenes, add an **EnvyUI** component, or let a script add it:

```csharp
using Envy;
using UnityEngine;

public class GameUI : MonoBehaviour
{
    public EnvyDocument document; // Assets/UI/my_ui.envy.json

    EnvyUI ui;

    void Awake()
    {
        ui = gameObject.AddComponent<EnvyUI>();
        ui.UiEvent += OnUiEvent;
        ui.LoadDocument(document);
        ui.SetData("player.hp", 40);
        ui.FocusFirstButton();
    }

    void OnUiEvent(string evt, string payload)
    {
        switch (evt)
        {
            case "new_hunt":
                StartNewHunt();
                break;
        }
    }
}
```

The [AI handoff package](/docs/handoff#the-ai-handoff-package) also writes a controller like this one for your document, `unity/<Name>UI.cs`, with typed setters and a `case` for every event the UI sends.

## Live reload

While the game runs in the Unity editor, save the document from Envy over its file in `Assets/UI/` (see [Projects and saving](/docs/projects#saving-to-a-file)). The running UI reloads in place.

- The reload keeps the data the game set, the open screen and its overlays. `DocumentReloaded` fires.
- It watches `.envy.json` files. Projects (`.envy`) aren't watched.
- Built players never reload. `hotReload = false` turns it off in the editor too.

## Fonts

Fonts embedded in the document (Envy: **Assets › Fonts**, or **Embed** under the font picker) are used as they are, WOFF and WOFF2 included. For other families, map a font asset or a TTF/OTF `Font` in **EnvyUI › Fonts**, per family and weight. A mapping wins over an embedded font of the same family. A family with neither uses an installed font of that name, then Unity's default.

## Inspector fields

| Field | Meaning |
|---|---|
| `document` | An imported `.envy.json` or `.envy` (an EnvyDocument asset) |
| `documentJson` | Or the document as a TextAsset |
| `documentPath` | Or a file path, absolute or relative to StreamingAssets |
| `startScreen` | Screen to show first, by name or id. Empty shows the first screen |
| `scaleMode` | `Fit` (default) scales the design resolution into the panel and stretches to its aspect, like the web runtime |
| `safeAreaMargins` | Safe-area margins in pixels (left, top, right, bottom) for screens set to keep inside the safe area. `-1` reads the device's safe area on mobile |
| `autoplay` | Play autoplay animations when a screen opens (default on) |
| `useSampleData` | Start with the document's sample data (default on) |
| `hotReload` | Reload the document when its file changes, in the editor (default on) |
| `locale` | Locale for translated text, like `"de"`, or `"pseudo"`. Empty shows the base text |
| `cancelClosesOverlay` | Cancel (Escape, gamepad B) closes the top overlay (default on) |
| `fonts` | Family and weight → font asset or `Font`, for fonts the document doesn't embed |
| `panelSettings` | Panel settings for the UIDocument EnvyUI creates. Empty draws 1:1 pixels over the scene. EnvyUI uses the GameObject's own UIDocument when it has one |
| `sortingOrder` | Draw order of that panel; higher draws on top (default 100) |

## Methods

| Method | Does |
|---|---|
| `Goto(screen, transition = null)` | Shows a screen by name or id. `transition` overrides the screen's own |
| `Push(screen, transition = null)`, `Pop()` | Opens an overlay, closes the top one |
| `Cancel()` | Closes the top overlay as Cancel does: presses its cancel button, else pops |
| `GetStack()`, `GetScreenNames()` | The open screens (base first), the game's screens |
| `SetData(path, value)`, `MergeData(patch)` | Changes data |
| `GetData(path = "")` | A value, or all data with no path |
| `Play(anim)`, `Stop(anim = "")`, `IsPlaying(anim)` | Animations. `Stop()` with no name stops them all |
| `SetLocale(locale)`, `GetLocales()` | Language. `SetLocale` returns the locale it matched |
| `GetElement(nameOrId)` | The VisualElement built for a layer |
| `FocusFirstButton()` | Starts keyboard and gamepad navigation on the initial button, else the first one |
| `Press(button)` | Presses a button from code, by name or id |
| `LoadDocument(asset)`, `LoadFile(path)`, `LoadJson(text)` | Loads another document |
| `Reload()` | Loads the assigned document again |

`Goto`, `Push`, `Pop`, `Play` and the loaders return `true` when they worked. `CurrentScreenName` is the name of the screen on top.

## Events

| Event | When |
|---|---|
| `UiEvent(evt, payload)` | A button emitted an event. `onUiEvent` is the same as a UnityEvent, to wire in the Inspector |
| `ScreenChanged(name)` | A new screen shows: `Goto`, `Push` or `Pop` ran. `onScreenChanged` is the UnityEvent |
| `DataChanged(data)` | Data changed |
| `DocumentReloaded` | The document changed on disk and was reloaded |

## How it's drawn

| Envy | UI Toolkit |
|---|---|
| Anchors and offsets | Absolute `left` / `top` / `right` / `bottom`, in % and px |
| Auto layout (and wrap) | Flexbox |
| Fill, border, radius | Background color, borders, border radii |
| Shadows, gradients | Meshes from `generateVisualContent`; a shape's shadow is a drop-shadow filter |
| Shapes | `Painter2D` |
| Text | `TextElement` with TextCore font assets |
| Images (fit, nine-slice, tint), SVG | Background image, nine-slice, tint; `VectorImage` |
| Layer and background blur | Blur filters |

Text is drawn from signed distance fields, so glyphs look about 10% lighter than in Chrome at the same size and weight; weights still match each other. See [known differences](/docs/differences) for the rest.

## Tests

The package has EditMode and PlayMode tests, and they read the same fixtures as the Godot tests:

```sh
Unity -batchmode -nographics -projectPath runtimes/unity -runTests -testPlatform EditMode -testResults edit.xml
Unity -batchmode -projectPath runtimes/unity -runTests -testPlatform PlayMode -testResults play.xml
```

PlayMode draws, so it runs without `-nographics`.
