Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Theming & Personalization Nodes

Design tokens, multi-theme support, responsive breakpoints, and personalization slots. Theme switching is modeled as a state machine transition (e.g., light to dark).

ThemeNode

A named set of design tokens. Multiple themes can coexist (light, dark, high-contrast). Referenced from VoceDocument.theme and VoceDocument.alternate_themes.

FieldTypeRequiredDescription
node_idstringyesUnique identifier
namestringyesTheme name (e.g., “light”, “dark”)
colorsColorPalettenoColor token definitions
typographyTypographyScalenoTypography token definitions
spacingSpacingScalenoSpacing token definitions
shadowsShadowScalenoShadow scale definitions
radiiRadiusScalenoBorder radius scale definitions
transition_durationDurationnoAnimation duration when switching to theme
transition_easingEasingnoEasing function for theme transition

ColorPalette

Semantic color tokens. Each token is a Color struct (r, g, b, a).

FieldTypeDescription
primaryColorPrimary brand color
primary_foregroundColorText on primary
secondaryColorSecondary brand color
secondary_foregroundColorText on secondary
accentColorAccent color
accent_foregroundColorText on accent
backgroundColorPage background
foregroundColorDefault text color
surfaceColorCard/surface background
surface_foregroundColorText on surface
mutedColorMuted/subtle background
muted_foregroundColorText on muted
border_colorColorDefault border color
errorColorError state color
error_foregroundColorText on error
successColorSuccess state color
success_foregroundColorText on success
warningColorWarning state color
warning_foregroundColorText on warning
infoColorInfo state color
info_foregroundColorText on info

TypographyScale

FieldTypeDescription
font_bodyFontDefinitionBody text font
font_displayFontDefinitionDisplay/heading font
font_monoFontDefinitionMonospace font
size_scale[Length]Size steps (xs through 4xl)
line_height_scale[float32]Line heights matching size_scale indexes
letter_spacingLengthDefault letter spacing

SpacingScale

FieldTypeDescription
baseLengthBase spacing unit (e.g., 4px)
multipliers[float32]Multiplier scale (actual spacing = base * multiplier)
{
  "node_id": "theme-light",
  "name": "light",
  "colors": {
    "primary": { "r": 59, "g": 130, "b": 246, "a": 255 },
    "primary_foreground": { "r": 255, "g": 255, "b": 255, "a": 255 },
    "background": { "r": 255, "g": 255, "b": 255, "a": 255 },
    "foreground": { "r": 17, "g": 24, "b": 39, "a": 255 }
  },
  "spacing": {
    "base": { "value": 4, "unit": "Px" },
    "multipliers": [0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32]
  }
}

PersonalizationSlot

A point in the IR that adapts based on user context: locale, device type, color scheme preference, A/B test cohort, or custom conditions.

FieldTypeRequiredDescription
node_idstringyesUnique identifier
namestringnoHuman-readable name
variants[PersonalizationVariant]yesList of conditional variants
default_variant_indexint32noFallback variant index (default 0)

PersonalizationVariant

FieldTypeRequiredDescription
conditions[PersonalizationCondition]yesAll conditions must be true to activate
show_nodes[string]noNode IDs to show when active
hide_nodes[string]noNode IDs to hide when active
overrides[PropertyOverride]noProperty overrides to apply

PersonalizationCondition

FieldTypeDescription
condition_typePersonalizationConditionTypeLocale, DeviceType, ColorScheme, ReducedMotion, HighContrast, Viewport, Custom
operatorstringComparison: “eq”, “neq”, “gt”, “lt”, “gte”, “lte”, “contains”
valuestringValue to compare against
{
  "node_id": "mobile-variant",
  "name": "mobile-layout",
  "variants": [
    {
      "conditions": [
        { "condition_type": "DeviceType", "operator": "eq", "value": "mobile" }
      ],
      "hide_nodes": ["desktop-sidebar"],
      "show_nodes": ["mobile-nav"]
    }
  ],
  "default_variant_index": 0
}

ResponsiveRule

Adapts layout based on viewport dimensions using explicit breakpoints with property overrides. Unlike CSS media queries, there is no cascading.

FieldTypeRequiredDescription
node_idstringyesUnique identifier
breakpoints[Breakpoint]yesBreakpoint definitions
responsive_overrides[ResponsiveOverride]yesPer-breakpoint property overrides

Breakpoint

FieldTypeRequiredDescription
namestringyesBreakpoint name (e.g., “sm”, “md”, “lg”)
min_widthLengthyesMinimum viewport width for this breakpoint

ResponsiveOverride

FieldTypeRequiredDescription
breakpoint_namestringyesWhich breakpoint this applies at
overrides[PropertyOverride]yesProperty overrides at this breakpoint

PropertyOverride

FieldTypeRequiredDescription
target_node_idstringyesNode to override
propertystringyesProperty name to override
valuestringyesNew value at this breakpoint
{
  "node_id": "responsive-grid",
  "breakpoints": [
    { "name": "sm", "min_width": { "value": 640, "unit": "Px" } },
    { "name": "lg", "min_width": { "value": 1024, "unit": "Px" } }
  ],
  "responsive_overrides": [
    {
      "breakpoint_name": "sm",
      "overrides": [
        { "target_node_id": "content-grid", "property": "grid_columns", "value": "1" }
      ]
    },
    {
      "breakpoint_name": "lg",
      "overrides": [
        { "target_node_id": "content-grid", "property": "grid_columns", "value": "3" }
      ]
    }
  ]
}