DocsShip

Unity runtime

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:
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 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). 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 for the rest.

Tests

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

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.

Updated View as Markdown