---
title: "Style (asset type)"
description: "A style is a UI design-token bundle: colour palette, spacing scale, typography pairs, and the widget classes built from them. Registered with the UI theme system, its classes cascade to every widget…"
section: "Types"
slug: "types-style"
canonical: "https://origozero.ai/docs/types-style"
updated: "2026-09-05T16:41:47.454675381+00:00"
tags: ["asset-type", "reference"]
---

# Style (asset type)

## When to use one

- You're branding a UI surface (game theme, editor theme, dialog
  theme) and want a named token set widgets pick up automatically.
- You want a swappable theme — light vs dark, normal vs accessibility
  contrast.
- You want designers to edit tokens (`color.primary`,
  `spacing.md`) without touching widget code.

If you need per-widget overrides, those go inline on the widget, not
in a style. If you need shader-driven looks, that's a `.shader` +
`.material`.

## Where it lives

- Source: `/zero/source/.../<name>.style/`
- Identity: `<name>` (the `.style` suffix strips).
- Folder shape:
  - `init.luau` (or `init.lua`) — returns the module carrying the
    token table. **Required.**
  - `README.md` — instance documentation. **Required.**
  - `.metadata` — agent-editable tags + free-form fields. **Required.**

## How to create one

```luau
asset.create("style", "<name>")
-- Creates: /zero/source/<name>.style/
--   init.luau   (token scaffold: color / spacing / font)
--   README.md   (instance README template)

-- `folder` places it in a subfolder of /source instead of the root:
asset.create("style", "<name>", { folder = "themes" })
```

## How it operates

1. **Registration.** Writing `init.luau` into a `.style/` folder
   registers the asset — it is listable, inspectable, and referencable
   by identity.
2. **Token shape.** `init.luau` returns a module exposing `M.tokens`,
   one nested table per token category:
   - `color.<name>` / `spacing.<name>` / `font.<name>` are the
     conventional three; a style may declare any category it wants.
   - A value is a literal (a `"#rrggbb"` colour string, a number, an
     array) or a `"$otherToken"` reference resolved during the
     cascade.
   An optional `M.styles` maps a selector — `<widgetType>`,
   `<widgetType>.<className>`, or a bare `.<className>` — to a block
   of style properties, each value a literal or a `$token` reference.
3. **Cascade.** The stylesheet resolves a widget's look in the order
   `type` → `type.class` → `.class` → inline props. Widgets select
   classes with their `classes` (or `class`) prop.
4. **Application.** The UI theme surface takes the style's table:
   `Theme.register(name, tokens_and_styles)` from
   `@builtin::modules.zui.theme` resolves every `$token` in Luau and
   pushes the flat result through `ui.registerTheme`. From there
   `ui.setTheme(name)` makes it the active theme, and
   `ui.useStyles(name)` applies a registered theme's classes
   additively without changing the active one. `ui.defineStyle` /
   `ui.defineStyles` define individual classes directly.
5. **Hot reload.** Editing `init.luau` reloads the asset; re-register
   the style for the change to reach the live stylesheet.

## Discovery

- `asset.list("style")` — every registered style.
- `asset.inspect("<name>")` — `tokenCategories` (the top-level keys of
  the style's `M.tokens` literal, read from its source text), source,
  and this type README.
- `cat /zero/source/<name>.style` — same summary.
- `styleRef:getInitScript()` — the entry script's raw text.

## Authoring conventions

- Write colours the way the theme system reads them — `"#rrggbb"` /
  `"#rrggbbaa"` hex or `rgba(r,g,b,a)` strings.
- Name tokens semantically (`color.primary`, `color.danger`,
  `spacing.gutter`), not by visual value (`color.blue`,
  `spacing.eight`). Semantic names survive theme swaps.
- Keep token names stable. Widgets reference tokens by name —
  renaming a token forces every consumer to update.
- Document `light` / `dark` variants under separate `.style/` folders
  with paired names (`game.style`, `gameDark.style`) rather than
  switching values within one style.

## Common pitfalls

- **Unknown `$token` reference.** A `"$name"` with no matching token
  fails the cascade — `Theme.register` returns
  `false, "token 'a': unknown token: $name"` and the style never
  reaches the stylesheet. Read the error rather than the render.
- **Token reference cycles.** `$a` → `$b` → `$a` is reported as
  `token 'a': cycle detected: a → b → a` at register time.
- **Missing tokens.** A widget asking for `color.warn` when the
  style doesn't define it falls back to the active theme. Inspect the
  style to confirm the token surface.

## Related types

- `.component` — `UiPanel` and other widget components consume
  styles.
- `.material` / `.shader` — for 3D surface looks (different cascade
  system).
- `.package` — to ship styles + components together as a theme
  package.
