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. |
actionPriorities · surfacePriorities · textPriorities
Section titled “actionPriorities · surfacePriorities · textPriorities”Three priority levels, each referencing the intent above. All three required.
Priority counts down: from the thing claiming most of a reader’s attention to the thing claiming least. What that means depends on the purpose, which is why each purpose has its own definition rather than sharing one.
| Field | actionPriorities |
surfacePriorities |
textPriorities |
|---|---|---|---|
primary |
The one thing the screen most wants you to do | A surface that interrupts the page: modal, dialog, alert, sheet | Headlines and titles |
secondary |
A supporting choice | A surface over the page, not instead of it: flyout, menu, popover | Body copy |
auxiliary |
The quietest choice | The page, and everything on it rather than above it: cards, bars, panels | Detail and help: captions, hints, legal |
The first two reference colorIntent, the third 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 |
actionPriorities |
Buttons / links, by priority. |
surface |
surfacePriorities |
Non-interactive containers, by how far above the page they sit. |
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.