Demo brands only. All brand configurations bundled with the Substrate engine, and all brand names used in examples throughout these docs, are fictional demonstrations created to exercise the engine. They do not represent clients or customers of Substrate or its authors, and no affiliation with, sponsorship by, or endorsement from any real company is implied.
File layout
Two shapes are supported, and which one you get depends entirely on the directory structure.- Brand family
- Flat brand
A family directory holds a shared Each sub-brand becomes its own brand, with the merged slug
config.global.yaml, and each sub-brand directory holds a config.yaml containing only its deltas. Most of the engine’s bundled demo brands ship this way. For a fictional airline family, Aurora Airways:{parent}-{sub} — aurora-rewards. See Inheritance for the merge rules.Keys are authored in kebab-case and normalized to camelCase at load.
heading-family becomes headingFamily, duration-base becomes durationBase, and so on throughout the schema. The exception is named-resource maps — intents, gradients, ramps, materials, rampOutputs — whose direct child keys are your own identifiers and round-trip verbatim one level deep. The scheme-track grammar keys (scheme-end, scheme-track, from-intent) also keep their kebab spelling at any depth, because the kernel consumes them that way. This rule holds for every config page in this section.The required sections
Seven sections are non-optional. A config missing any of them is incomplete, and a config missing the required intents fails to load outright. Here is an example foundation for the fictional Acme brand (src/brands/acme/config.global.yaml), trimmed to the required sections:
Every section at a glance
Field-by-field detail, defaults, and a worked example for every section live in the Config Schema reference — each row links straight to it. The authoring guides in this section cover the why per domain.What the loader does with it
Discovery is a directory scan. For each directory under the brands root, the loader checks forconfig.global.yaml (family) or config.yaml (flat), parses the YAML, normalizes the keys, deep-merges family and sub-brand layers where both exist, and stamps the slug from the directory structure. That slug is what appears in generated CSS as [data-brand="aurora-rewards"].
Two validations run at load. The intent roster must contain brand and neutral, or the load throws a missing-required-intent error. Any intent using scheme-track grammar is desugared and validated, including reference cycles and unknown intent names.
Explore each config section
Color
The open intents map, hue and chroma, scheme tracks, and the solver primitives each intent produces.
Typography
Base size, scale ratio, and the continuous power-of-ratio model that replaces a step ladder.
Spacing & Density
One space unit, multiplied at each use site by the runtime density and scale factors.
Motion
Base duration and easing, and how the motion factor scales them at runtime.
Core Concepts
Why the values are computed at runtime rather than baked, and how the preference vector drives them.
Multi-Brand
Families, sub-brands, deltas-only authoring, and the per-brand output tree.