Values & literals

In Milda a value knows what it is. Colours are space-aware functions, dimensions carry their units, and durations are times - not opaque strings. Because every literal self-types, the language can tell a colour from a length from a duration, and flag a value that lands in the wrong slot.

Most of the time you name values as tokens and reference those tokens everywhere else. Literals are how you define a token, and the occasional one-off. This page is the vocabulary of literals themselves.

#Colours are functions, not strings

A leading # starts a comment in Milda, so a colour can't be a #rrggbb string. Instead, colours are written as space-aware functions. Each names its colour space, so the value is unambiguous rather than a string a target has to guess at:

milda
hex(ffffff)          # sRGB, RRGGBB
hex(ffffffcc)        # RRGGBBAA - the last byte is alpha
rgb(255 0 0)         # sRGB, 0-255 channels
srgb(1 0 0)          # sRGB, 0-1 channels
srgb(1 1 1 0.8)      # a trailing number is alpha
p3(1 0 0)            # display-p3
oklch(0.62 0.19 256) # OKLCH: lightness, chroma, hue
hsl(210 1 0.5)       # HSL

The available spaces are hex, rgb, srgb, p3, oklch, and hsl. They round-trip exactly: the parser and the emitter are symmetric, so a colour you write is the colour that comes back out.

#Dimensions carry their units

A number with a unit is a dimension, not a bare number. Milda understands CSS-style units so the value keeps its meaning across targets:

milda
8px       # pixels
0.5rem    # root-relative
1.5em     # element-relative
50%       # percentage
0rem      # zero still carries a unit

A number with no unit stays a plain number (a count, a weight, an opacity). The unit is what makes it a length.

#Durations are times

Time units make a duration, used by motion tokens and transitions:

milda
150ms   # milliseconds
2s      # seconds

#Font weight is its own type

Font weight is a first-class numeric token type, so a weight scale reads as data rather than magic strings:

milda
token weight/light   : font-weight = 300
token weight/regular : font-weight = 400
token weight/medium  : font-weight = 500
token weight/bold    : font-weight = 700

#Composite typography

A typography token bundles the parts of a text style. Its dimensional members use unit literals directly:

milda
token text-size/3 : typography = {
  role: "body"
  size: 1rem
  line: 1.5rem
  tracking: "0em"
}

Which of those axes a component actually paints is chosen with typography facets - font, weight, and slant - covered in Facets & tokens.

#Literals are self-typing

Because each literal carries its own kind, the language checks it against the token's declared type. A colour in a dimension slot, or a length where a colour belongs, is caught before anything is generated:

milda
token bad : color = 8px   # error: a dimension literal in a color slot
This powers the editors
Self-typing is what lets your editor flag a mistyped value inline, and colour a hex(...) differently from a keyword, without running a generator.

#The raw escape hatch

When a value genuinely can't be expressed as a typed literal, raw passes a string through verbatim. It is a deliberate, visible escape hatch - not the default:

milda
token odd : color = raw "color-mix(in oklch, red, blue)"

Prefer a typed literal wherever one exists; reach for raw only when the model has no honest way to say it, so the exception stays obvious in review.