ThemeConfig Structure

Every PaperDocument can include an optional theme field of type ThemeConfig. The theme controls how scheme color tokens and font references resolve throughout the entire document.

TYPESCRIPT
interface ThemeConfig {
  name?: string;
  colorScheme?: ThemeColorScheme;
  fontScheme?: ThemeFontScheme;
}

When no theme is provided, the engine uses OOXML defaults (Office-standard colors and Calibri fonts).

Color Scheme Tokens

The ThemeColorScheme interface defines 12 named slots that map to ECMA-376 theme color tokens:

TYPESCRIPT
interface ThemeColorScheme {
  dk1?: string;       // Dark 1 — typically near-black for body text
  lt1?: string;       // Light 1 — typically white for backgrounds
  dk2?: string;       // Dark 2 — secondary dark
  lt2?: string;       // Light 2 — secondary light / off-white
  accent1?: string;   // Primary brand accent
  accent2?: string;
  accent3?: string;
  accent4?: string;
  accent5?: string;
  accent6?: string;
  hlink?: string;     // Hyperlink color
  folHlink?: string;  // Followed hyperlink color
}

All values are 6-digit hex strings (e.g., "#2563EB").

Example Color Scheme

JSON
{
  "colorScheme": {
    "dk1": "#0F2540",
    "lt1": "#FFFFFF",
    "dk2": "#1B3A5C",
    "lt2": "#F8FAFC",
    "accent1": "#2563EB",
    "accent2": "#059669",
    "accent3": "#7C3AED",
    "accent4": "#EA580C",
    "accent5": "#DC2626",
    "accent6": "#0891B2",
    "hlink": "#2563EB",
    "folHlink": "#7C3AED"
  }
}

Font Scheme

The ThemeFontScheme defines heading and body typefaces:

TYPESCRIPT
interface ThemeFontScheme {
  majorLatin?: string;   // Headings — e.g., "Aptos Display"
  minorLatin?: string;   // Body text — e.g., "Aptos"
  majorEa?: string;      // East Asian heading font
  minorEa?: string;      // East Asian body font
}

When a node does not specify an explicit fontFamily, the engine resolves to minorLatin for body text and majorLatin for heading-level placeholder text.

Using Scheme Tokens in Nodes

Any ColorValue property can reference a scheme token by name instead of a hex literal:

JSON
{
  "type": "Text",
  "style": {
    "color": "accent1",
    "backgroundColor": "lt2"
  },
  "content": "Themed text"
}

This makes the output portable: changing the theme recolors every element that uses tokens without editing individual nodes.

Color Modifiers

For derived colors (lighter tints, darker shades), use a ColorModifier object instead of a plain string:

TYPESCRIPT
interface ColorModifier {
  scheme: string;     // "accent1", "dk1", "lt1", etc.
  tint?: number;      // 0-100 (percentage white mixed in)
  shade?: number;     // 0-100 (percentage black mixed in)
  lumMod?: number;    // Luminance modulation (percentage)
  lumOff?: number;    // Luminance offset (0-100)
  satMod?: number;    // Saturation modulation (0-200+)
  satOff?: number;    // Saturation offset
  hueMod?: number;    // Hue modulation
  hueOff?: number;    // Hue offset (degrees * 60000 for OOXML)
  comp?: boolean;     // Complement color
  inv?: boolean;      // Inverse color
  gray?: boolean;     // Convert to grayscale
}

Common Modifier Patterns

JSON
// Light tint of the primary accent (40% white)
{ "scheme": "accent1", "tint": 40 }

// Darkened accent (30% black)
{ "scheme": "accent1", "shade": 30 }

// Desaturated dark color at 75% luminance
{ "scheme": "dk1", "lumMod": 75, "satMod": 50 }

// Complementary color
{ "scheme": "accent1", "comp": true }
The `tint` and `shade` values are percentages (0-100). The engine converts them to OOXML's 0-100000 scale internally. A `tint` of 40 means 40% white is mixed with the base color.

Theme Cascading

Themes cascade from the document level to all child elements:

  1. PaperDocument.theme sets the document-level defaults
  2. Template themes (from .potx files on PaperDocument.template) merge with and can override document-level theme values
  3. Individual node style.color or style.backgroundColor properties override the cascade

When using scheme tokens, the final resolved hex depends on the active theme at render time. This is what makes decks rebrandable: swap the colorScheme and all token-referencing elements update.

Hosted API: accentColor

When using the V2 API with PresentationSpec, the accentColor field sets accent1 in the generated theme:

JSON
{
  "version": "2.0",
  "title": "Brand Deck",
  "accentColor": "#2563EB",
  "slides": [...]
}

The protocol compiler generates a full ThemeConfig with the provided accent as accent1 and derives complementary slots for the remaining accents. For full control over all 12 color slots, use the raw PaperDocument format with an explicit theme field.

Full Theme Example

JSON
{
  "type": "Document",
  "meta": { "title": "Themed Deck" },
  "theme": {
    "name": "Corporate Brand",
    "colorScheme": {
      "dk1": "#0F172A",
      "lt1": "#FFFFFF",
      "dk2": "#1E293B",
      "lt2": "#F1F5F9",
      "accent1": "#2563EB",
      "accent2": "#059669",
      "accent3": "#7C3AED",
      "accent4": "#EA580C",
      "accent5": "#DC2626",
      "accent6": "#0891B2",
      "hlink": "#2563EB",
      "folHlink": "#6366F1"
    },
    "fontScheme": {
      "majorLatin": "Aptos Display",
      "minorLatin": "Aptos"
    }
  },
  "slides": [
    {
      "type": "Slide",
      "children": [
        {
          "type": "View",
          "style": {
            "position": "absolute",
            "left": 60, "top": 100, "width": 300, "height": 80,
            "backgroundColor": { "scheme": "accent1", "tint": 20 },
            "borderColor": "accent1",
            "borderWidth": 1
          },
          "children": [
            { "type": "Text", "style": { "color": "dk1", "fontSize": 14, "padding": 16 }, "content": "Tinted card" }
          ]
        }
      ]
    }
  ]
}
Theming — CmdCal Docs