-
Notifications
You must be signed in to change notification settings - Fork 8
Authoring Layouts
This page describes the layouts JSON format that EmoTracker packs use to declare every visual arrangement on screen — the items grid, the map view, the broadcast view, the popups behind buttons, the contents of pinned-location cards, and so on.
It's the top of a small hierarchy: read this page first for the general format, the base fields shared by every element, and the layout-engine concepts that aren't tied to one element type. Then jump to the per-element sub-pages for the specific options each element accepts.
New to pack authoring? Read Developer Setup first to wire up VS Code schema validation, then Authoring Items and Authoring Locations — layouts reference items and locations by code, so you'll typically have those declared before you start arranging them visually.
A layout is a tree of layout elements that EmoTracker renders as one logical "view". Some layouts are tied to specific UI surfaces:
| Layout name | Where it's shown |
|---|---|
tracker_default |
The main tracker window's primary view |
tracker_horizontal |
The main tracker window when it's wider than it is tall |
tracker_vertical |
The main tracker window when it's taller than it is wide |
tracker_broadcast |
The Broadcast View window |
tracker_capture_item |
The default item picker for section capture slots |
Other layouts are loaded by name and referenced from somewhere else — typically from a Layout Reference inside a parent layout, or from a Button Popup, or from a section's capture_item_layout field.
The runtime maintains all loaded layouts in LayoutManager, keyed by their name. When EmoTracker needs a layout (e.g., the main window starts up), it asks the manager for the layout with the matching name. If you don't define one, the surface falls back to whatever default the runtime chooses (or nothing).
Layouts are loaded from Lua at pack init time:
-- scripts/init.lua
Tracker:AddLayouts("layouts/tracker.json")
Tracker:AddLayouts("layouts/popups.json")- Paths are relative to the pack root.
- You can split layouts across as many files as you like. Names must be unique across the whole pack — duplicate names are silently ignored after the first.
- Legacy packs may use a single root-level
tracker_layout.json, which EmoTracker still loads automatically. New packs should use explicitTracker:AddLayouts(...)calls. - Items and locations should generally be loaded before layouts, since
itemelements look up items by code at parse time andmapelements need maps to be registered. (Some elements like Layout Reference tolerate late binding, but parse order matters more for layouts than for the other systems.)
Unlike items and locations files (which are arrays), a layouts file is a JSON object at the top level, where each key is the layout name and each value is the root layout element:
Each value is a single root layout element. The element can be any type — typically a Container or one of the panel types (Array, Dock, Canvas, etc.) — and that root element's children form the rest of the tree.
The canonical schema is published in
EmoTracker-Service/sdk/schema/layouts.json. Wire it up in VS Code via Developer Setup → Configuring JSON schema validation so you get autocomplete for every element type and field as you author.
All elements inherit a common set of base fields, parsed in EmoTracker.Data/Layout/LayoutItem.cs:TryParse. These cascade through every type listed below.
| Field | Type | Default | Description |
|---|---|---|---|
type |
string | required | The element type — picks one of the parsers (container, array, image, etc.). See Layout element types below. |
uid |
string | none | Optional unique identifier for this element. If set, the element is registered with LayoutManager and can be looked up at runtime by other code. |
| Field | Type | Default | Description |
|---|---|---|---|
background |
string | none | Background color in web color format (#rrggbb or #aarrggbb for alpha). |
foreground |
string | none | Foreground color in the same format. |
dropshadow |
boolean | false |
Apply a drop-shadow effect to this element when shown in the main window. |
broadcast_shadow |
boolean | false |
Apply a drop-shadow effect to this element when shown in the Broadcast View window. (Independent of dropshadow.) |
hit_test_visible |
boolean | true |
If false, the element and its children ignore mouse input — clicks pass through to whatever is behind them. |
| Field | Type | Default | Description |
|---|---|---|---|
width |
number | auto | Fixed width in layout units. |
height |
number | auto | Fixed height. |
min_width |
number | none | Lower bound. |
min_height |
number | none | Lower bound. |
max_width |
number | none | Upper bound. |
max_height |
number | none | Upper bound. |
scale |
number | 1.0 |
Multiplier applied to the element's measured size. Useful for scaling subtrees up or down. |
Any size field with a value < 0 (the default sentinel) is treated as "not set" — the runtime falls back to auto-sizing based on the element's content and its parent's layout rules.
| Field | Type | Default | Description |
|---|---|---|---|
margin |
string | "0" |
Outer margin. Can be 1, 2, or 4 numbers separated by commas: "5" (uniform), "5, 10" (horizontal, vertical), "5, 10, 5, 10" (left, top, right, bottom). |
h_alignment |
string | "stretch" |
Horizontal alignment within the parent's allocated slot: left, center, right, stretch. |
v_alignment |
string | "stretch" |
Vertical alignment within the parent's allocated slot: top, center, bottom, stretch. |
dock |
string | none | When the parent is a Dock Panel, pins this element to that edge: left, right, top, bottom. The first child without a dock value fills any remaining space. |
canvas_left |
number | none | When the parent is a Canvas Panel, the X coordinate of this element's top-left corner. |
canvas_top |
number | none | When the parent is a Canvas Panel, the Y coordinate of this element's top-left corner. |
canvas_depth |
number | none | Z-order within the Canvas Panel. Higher values draw on top. |
If the user has the Swap Left/Right option enabled in their EmoTracker settings, the runtime automatically swaps:
-
dock: "left"↔dock: "right"for every element it parses - The first and third comma values in any 4-number
margin(so left and right margins also swap)
You don't have to do anything to support it — your layout will mirror itself for users who flip the switch.
The base TryParse runs before each element's type-specific parser, which means:
- A
uidis registered immediately, so an element can reference its ownuidfrom script later in the same load. - Layout-element references (like a Button Popup's
layoutfield, or a Layout Reference'skeyfield) resolve at parse time too — so the referenced layout has to already exist when the referencing element is parsed.
The practical implication: load referenced layouts before the layouts that reference them. The simplest pattern is to load a popups.json file containing all your popup layouts before the main tracker.json that references them.
Pick the sub-page for the element you're authoring. Each sub-page documents its JSON fields, behavior, and at least one example.
| Type | What it's for | Sub-page |
|---|---|---|
container / grid
|
A simple wrapper around one or more children. Multiple children stack on top of each other. | Container |
viewbox |
A container that scales its child to fit the available space. | Container → ViewBox |
array |
A horizontal or vertical list of children. | Array |
canvas |
Free-form positioning of children using canvas_left / canvas_top. |
Canvas |
dock |
Children docked to edges, with the last child filling the remainder. | Dock |
group |
A container with a header bar above its children. | Group |
scroll |
A container with scrollbars when its content overflows. | Scroll |
tabbed |
A tabbed view where each tab contains its own layout. | Tabbed |
button_popup |
A button that, when clicked, displays another layout in a popup. | Button Popup |
| Type | What it's for | Sub-page |
|---|---|---|
item |
A single item lookup by code. | Item |
itemgrid |
A regular grid of items, declared row-by-row. | Item Grid |
image |
A static image, optionally filtered. | Image |
text |
A static text label. | Text |
map |
One or more of the pack's maps. | Map |
layout |
A reference to another loaded layout, embedded inline. | Layout Reference |
recentpins / recent_pins
|
A list of recently pinned locations. | Recent Pinned Locations |
last_cleared_location |
A display of the most recently cleared location. | Last Cleared Location |
The schema currently lists the main 14 types but a few additional ones (
text,viewbox,last_cleared_location) are accepted by the parser even though they're not in the schema'senumfield. They're documented on this wiki because they work — you may see schema-validation warnings in your editor when you use them.
- Developer Setup — tooling, schema validation, Lua/JSON learning resources
- Authoring Items — items the layout displays
- Authoring Locations — locations the map elements pull from
-
Image Filters — the
image_filterspec used byimageandbutton_popup -
layouts.jsonschema — the authoritative JSON schema
- Installation
- Installing and Loading Packages
- Item Types and Mouse Controls
- Map Locations
- Map Location Colors
- Saving and Loading
- Multi-Tab and Window
- Autotracking
- NDI Broadcasting
- Twitch Chat HUD
- Note Taking
- Voice Control
- Keyboard Shortcuts
{ "tracker_default": { "type": "container", "content": { "type": "itemgrid", "rows": [ [ "sword", "shield", "bow", "boomerang" ], [ "hookshot", "lamp", "hammer", "shovel" ] ] } }, "tracker_capture_item": { "type": "container", "content": { ... } } }