Schema reference
The standard is three lexicons (AT Protocol schemas) under the place.mode.standard.* namespace. Two are records you save to your account; one is a set of shared type definitions the others reuse.
| Lexicon | Kind | What it is |
|---|---|---|
place.mode.standard.theme |
record | A saved theme — one complete look, keyed by the expression it serves. |
place.mode.standard.profile |
record | Your participation (no default-theme pointer). |
place.mode.standard.defs |
definitions | Shared building blocks the theme record references. |
place.mode.standard.theme
Section titled “place.mode.standard.theme”One complete look, saved to your account. Its record key is the expression it serves — …/theme/dark, …/theme/com.homedepot.easter, …/theme/default — so a repo holds at most one theme per expression (a second write to the same key overwrites). You can still publish many themes; each just serves a distinct expression. The record is self-contained: it carries its own full copy of the values and references no other theme.
| Field | Type | Required | Notes |
|---|---|---|---|
| (record key) | string · valid rkey | ✓ | The expression this theme serves (dark, com.homedepot.easter, default). Case-sensitive; any valid record key is a safe data-mode token (the delimiters data-mode uses — / and whitespace — can’t appear in one). This is the identity — there is no expresses field, and displayName below is presentation only. See Common expressions. |
displayName |
string · ≤64 graphemes | — | Optional display name, presentation only — identity and matching stay on the record key; an app never matches or dedupes on it. (Same limits as a Bluesky profile’s displayName.) |
description |
string · ≤256 graphemes | — | Optional human-readable description. |
aspects |
aspects |
✓ | The theme’s renderable style, grouped by aspect — the only part rendered to CSS variables. A required container; each aspect inside is optional but complete when present. |
fonts |
array of fontDescriptor |
— | Font faces the theme’s text relies on — theme-level assets referenced by text.*.family, rendered to document-global @font-face (not variables), which is why they sit here beside aspects rather than inside it. Optional. |
createdAt |
string · datetime | ✓ | ISO-8601 timestamp. |
// saved at rkey "dark" → at://did:plc:…/place.mode.standard.theme/dark{ "$type": "place.mode.standard.theme", "displayName": "Midnight Ride", "description": "My dark look.", "aspects": { "color": { "control": { "background": "#0b1020", "foreground": "#e6e9f5", "border": "#1c2540" }, "action": { "primary": { "…": "…" }, "secondary": { "…": "…" }, "auxiliary": { "…": "…" } }, "surface": { "primary": { "…": "…" }, "secondary": { "…": "…" }, "auxiliary": { "…": "…" } } } }, "createdAt": "2026-07-09T00:00:00Z"}place.mode.standard.profile
Section titled “place.mode.standard.profile”A singleton (record key self) that declares you participate in the standard. It’s a participation flag and the anchor for domain verification — and the natural home for future user-level settings. There is no default-theme pointer: your baseline look is simply the theme you saved at the reserved record key default, matched like any other concept (see Common expressions).
| Field | Type | Required | Notes |
|---|---|---|---|
createdAt |
string · datetime | ✓ |
{ "$type": "place.mode.standard.profile", "createdAt": "2026-07-09T00:00:00Z"}place.mode.standard.defs
Section titled “place.mode.standard.defs”The shared building blocks. The theme record references these by name — you never write them standalone. This is where the 33 intents live, grouped by aspect.
aspects
Section titled “aspects”The container the theme record’s aspects field points at — the renderable style, grouped by aspect. Each aspect is optional but complete when present; new aspects (motion, density, …) are added here as the core grows.
| Field | References | Notes |
|---|---|---|
color |
colorAspect |
The 21 color intents. Optional, complete when present. |
typography |
typographyAspect |
The 12 text intents. Optional, complete when present. (Fonts its text relies on are theme-level — see the theme’s fonts.) |
colorIntent
Section titled “colorIntent”The three color values for one purpose. All required.
| Field | Type | Notes |
|---|---|---|
background |
string · ≤128 | Any CSS <color>. |
foreground |
string · ≤128 | Text / icon color. |
border |
string · ≤128 | Border color. |
textIntent
Section titled “textIntent”Typography metrics for one text priority. All required. (No color — a text’s color comes from the surface it sits on.)
| Field | Type | Notes |
|---|---|---|
size |
string · ≤128 | CSS <length-percentage> (e.g. 1rem). |
weight |
string · ≤128 | CSS <font-weight>. |
family |
string · ≤256 | CSS font-family; matched to a fonts entry by name. |
lineHeight |
string · ≤128 | CSS line-height. |
colorPriorities · textPriorities
Section titled “colorPriorities · textPriorities”Three priority levels, each referencing the intent above. All three required.
| Field | References |
|---|---|
primary |
colorIntent / textIntent |
secondary |
colorIntent / textIntent |
auxiliary |
colorIntent / textIntent |
colorAspect
Section titled “colorAspect”The complete color aspect — 21 intents. All required.
| Field | References | Purpose |
|---|---|---|
control |
colorIntent |
Form inputs. No priority — all controls are peers. |
action |
colorPriorities |
Buttons / links, by priority. |
surface |
colorPriorities |
Non-interactive containers, by priority. |
typographyAspect
Section titled “typographyAspect”The complete typography aspect — 12 text intents.
| Field | Type | Required | Notes |
|---|---|---|---|
text |
textPriorities |
✓ | The 12 text intents. |
The font faces the text relies on are not part of this aspect — they’re theme-level assets in the theme’s fonts, matched to a text.*.family by name. (An aspect renders to scoped variables; fonts render to document-global @font-face, so they live separately.)
fontDescriptor
Section titled “fontDescriptor”One CSS @font-face. Per the CSS spec only two things are necessary, so only family is schema-required and a source (src or file) is required by the standard. A minimal entry is { family, src }.
| Field | Type | Required | Notes |
|---|---|---|---|
family |
string · ≤256 | ✓ | The font-family name. |
src |
string · ≤1024 | see note | A URL, or a CSS src value. |
file |
blob · font/* · ≤5 MB | see note | A font file stored on your account; preferred over src (it travels with you and can’t rot). |
weight |
string · ≤32 | — | font-weight descriptor or range. |
style |
string · ≤32 | — | font-style. |
stretch |
string · ≤64 | — | font-stretch / width. |
unicodeRange |
string · ≤2048 | — | unicode-range — lets several entries share one family for subsetting. |
display |
string · ≤32 | — | font-display. |
From value to CSS
Section titled “From value to CSS”Each intent’s path becomes a CSS custom property — color.surface.primary.background → --color-surface-primary-background (camelCase segments kebab-cased: lineHeight → line-height). That deterministic naming is what lets one person’s theme travel between apps. An app applies a theme by setting those variables on an element marked with a data-mode attribute (never :root) and ranking competing sources with cascade layers; the Mode Contract has the full rules for emitting and resolving these.