Osy#the first language built for agents
Agents firstAgentic appsWorkflowsDurable Execution — built inSecurityTestingThe editorThe UI modelOne program

Reference / UI

compiling with a different theme

osy compile --theme <file> — dress an app in a theme it does not declare

`--theme <file>` compiles an app with the theme in that file INSTEAD of its own. It is a replacement, never a merge, so the look you get is one you can point at a file for. Use it to present several apps consistently, or to ship one app under more than one brand.

stable1 example compiled by CIuithemetokenscli

Signature#

osy compile  --theme <file>
osy validate --theme <file>

Summary#

An app's look lives in its theme block (theme tokens). --theme <file> compiles the app with a different one, without editing a line of it:

$ osy validate --theme ../brand/acme.osy     # offline, no database — check it resolves first
$ osy compile  --theme ../brand/acme.osy     # then compile the app wearing it

Two things this is for:

  • One brand, many apps. A theme cannot be imported across apps — a manifest globs its own directory — so sharing a house style otherwise means copying a file into every project. One file passed at compile time dresses all of them.
  • Presenting several apps together. Documentation and demos show an app to explain a feature. When the apps each have their own palette, a reader compares styling instead of reading the point. Compile them under one theme for the occasion; the apps keep their own.

What it does#

--theme takes the theme block out of the app's own sources and puts the one in your file there instead. The rest of the app — its entities, its pages, its components — compiles exactly as it always does; only the tokens change. Nothing in the app has to be written differently to be themeable this way.

It replaces, it does not merge#

Every theme declaration in the app's own sources is removed, and the file you pass supplies the theme. Tokens the app declared and the override omits are gone, not inherited.

This is deliberate. A merge would produce a theme that exists in neither file — so the thing on screen could not be reproduced by compiling anything, which is exactly what you need from a screenshot or a shipped build.

A token the override lacks is an error, by name#

Because it replaces, an app that names a token your file does not declare will not compile:

model/chrome.osy:12:53  ERROR  RESOLVE_ERROR  UI: the `Colors` group declares no token 'Bulb'
  — its tokens are Bg, Border, Danger, Muted, OnBg, OnPrimary, Primary, Success, Surface, …

That is the useful answer, not an obstacle: it tells you either to add the token to your theme, or that this app's look is not substitutable. An app built on a handful of semantic colours takes almost any theme; one whose palette is its subject — a game, a visual demo — will list everything it needs, which is a fair description of why it should keep its own.

So a theme meant to dress several apps is a superset: it declares every token those apps name. Start from the kit's own token names (theme tokens) — an app that shadows kit tokens rather than inventing parallel ones is an app almost any override fits.

The swap is announced#

Every run says what it did:

⚠ theme override: acme.osy replaces `Doc` in model/theme.osy.

The app is not wearing its own look, so the output says so — a build or a screenshot taken from it should never be mistaken for the app as it ships.

What goes in the file you pass#

One theme block, and normally nothing else:

theme Docs {
  Colors {
    Primary   = "#125E7A";
    OnPrimary = "#FFFFFF";
    Bg        = "#FAF9F7";
    OnBg      = "#14181D";
    Surface   = "#FFFFFF";
    Border    = "#E4E2DC";
  }
  Radius { Md = "10px"; }
}

A file declaring no theme is refused, and so is one declaring two — with two, which one dressed the app would depend on declaration order, which is not something you should have to know to read a screenshot.

Anything else in the file compiles as usual, and a theme block in the app that shares a file with components loses only the block: the rest of the file is untouched.

See also#

Related

theme tokens

A `theme` block names your app's design tokens — colors, spacing, radii, and more — as reusable values. A token can…

color palettes

`Palette.From("#seed")` turns one brand color into a full ramp of shades. A bare reference (`Primary`) is the seed…

Osyrin.Ui (the UI kit)

The bundled UI kit — ready-made styled controls like `Button`, the shared design-system vocabularies (`Tone`, `Size`)…