Log inGet started

Style (asset type)

A style is a UI design-token bundle: colour palette, spacing scale, typography pairs. Styles cascade through the UI theme system — engine default < per-screen style < per-panel style. Authoring a…

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 (colors.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) — exports the token table. Required.
    • README.md — instance documentation. Required.

How to create one

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

How it operates

  1. Registration. Writing init.luau into a .style/ folder indexes the style with the UI theme system.
  2. Token shape. The exported table is hierarchical:
    • color.<name>{r, g, b, a} tables in linear sRGB.
    • spacing.<name> — discrete pixel values.
    • font.<name>{ family, size } pairs. Custom token groups beyond the canonical three are allowed; the UI theme system passes them through to widgets that ask for them.
  3. Cascade. Styles cascade through the theme system: engine default → per-screen style → per-panel style. A widget reads the most-specific token in scope.
  4. Application. ui.applyStyle("<name>") sets the currently-active style globally. screen:setStyle("<name>") scopes a style to one screen. Per-panel style is set on the panel widget.
  5. Hot reload. Editing init.luau reloads the style; widgets under it re-pick tokens on the next layout pass.

Discovery

  • asset.list("style") — every registered style.
  • asset.inspect("<name>") — token surface, source, this type README.
  • cat /zero/source/<name>.style — same summary.

Authoring conventions

  • Use linear-sRGB (0..1 floats) for every colour, not 0..255 bytes. The renderer expects linear values.
  • 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

  • sRGB vs linear. UI looks washed-out or oversaturated → check you're using linear-sRGB floats, not 0..255 bytes.
  • Token-name typos. Misnamed tokens silently miss the cascade and widgets fall back to engine defaults.
  • Missing tokens. A widget asking for color.warn when the style doesn't define it gets the cascade fallback. Inspect the style to confirm the token surface.
  • .componentUiPanel 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.
  • asset-type
  • reference