OPF
SpecAuthoring schema referenceView source

Presentation

Open-source JSON format for describing PowerPoint presentations. Agents describe narratives, content, audience, reusable assets, and design — the engine handles OOXML complexity. Content references (Slide.layout, design.theme, design.colorScheme / design.colorScheme.id, design.fontScheme / design.fontScheme.id, narrative, audience, purpose and tone, and the colorScheme / fontScheme a theme record names) point at catalog records. Each is a bare 'id' or a 'name:id' whose prefix names a group in 'catalogs'. A bare id resolves in catalogs.custom, then in the records embedded under catalogs.default, then in the catalog the host registered for catalogs.default.source (or the host's default catalog when 'default' is omitted); 'name:id' resolves in catalogs.<name>, then in the catalog the host registered for its source. A reference that resolves nowhere is the warning opf/unresolved-reference, and the slide uses automatic composition or the engine default. Engines never fetch a catalog: a saved document embeds every record it uses, and hosts register any other catalog by its source string. See docs/default-catalog.md. chart.type, the language tag and the keys of Organization.socials / Speaker.socials are engine vocabularies, validated directly with no catalog lookup. When a document names no theme, colour scheme or font scheme, every engine uses the same small engine defaults (spec/reference/engine-defaults.json). Asset references use 'asset:<id>' strings that point into the top-level assets registry, and content color fields (rich-text runs, styled table cells) accept hex values, color-scheme slot/role names, or 'var:<id>' references into the top-level variables map.

Schema $id
https://openpresentation.org/schema/opf/v1
Type
object
Source
spec/schemas/opf.schema.json
Fields
24 · 1 required

Field index

FieldTypeReq.DefaultDescription
$schemaconst——Optional OPF schema version. When omitted, validators and engines should assume the latest supported OPF schema.
$schema · Allowed values
"https://openpresentation.org/schema/opf/v1"
namestring——Display name of the presentation for GUI/TUI lists, library/search indexing, OS-level metadata, and default export filenames. This is deck identity, not slide content. Use slides[].title and slides[].subtitle for text that should appear on presented slides. Also the built-in variable 'deck.name'.
descriptionstring——Free-form prose describing what this presentation is about. Used by agents and humans as a deck-level summary; complements purpose (the goal) and narrative (the structured storyline). Round-trips to OOXML 'docProps/core.xml' as '<dc:description>' (PowerPoint surfaces this as the 'Comments' field in File → Properties). Also the built-in variable 'deck.description'.
filenamestring——Optional base filename for exports (without extension). The opf CLI (convert) and the editor strip a trailing .pptx, .pdf, .png, or .svg (case-insensitive) and append the target format's extension. When omitted, they slugify name; with no usable name the CLI uses the input file name and the editor uses 'presentation'. See /docs/opf for full validation rules.
organizationref:Organization | array<ref:Organization>——Organization associated with the presentation, usually the presenting company. Array form supports hosts, partners, clients, and sponsors. The primary organization (Organization.role 'primary', else the first item) supplies the cover and section logo, the 'socials' header/footer field and the 'organization.<field>' built-in variables; the others are available by id as 'organization.<id>.<field>' and are not drawn automatically.
speakerref:Speaker | array<ref:Speaker>——Person presenting the deck. Array form supports panels and multi-speaker decks. The first speaker is the primary speaker: the built-in variables 'speaker.<field>' read it, 'speakers' lists every name, and 'speaker.<id>.<field>' addresses one by id. A speaker is drawn nowhere else.
authorstring | array<string>——Optional credit for the person who authored or contributed to the deck, distinct from speaker. Array form supports multiple contributors. Round-trips to OOXML 'docProps/core.xml' as '<dc:creator>' (semicolon-joined when multiple) and seeds '<cp:lastModifiedBy>' on first write; subsequent edits in PowerPoint overwrite '<cp:lastModifiedBy>' with the editing user. Also the built-in variable 'deck.author' (an array joined with ', ').
audiencestring | ref:Audience | array<string | ref:Audience>——Intended audiences for the presentation. Accepts any of: - A single string: an audiences reference ('executive', or 'acme:board' for a record of the catalogs.acme group), or free-form text ('Series B investors'). A string that is a bare id or 'name:id' is a reference; any other string is free text and is never looked up. - A single inline Audience object, for custom audience metadata or overrides on a referenced record. Object form has the fields of https://openpresentation.org/schema/opf-audience/v1. - An array of strings and/or inline Audience objects, for more than one audience. A reference resolves like every content reference (see catalogs); one that resolves nowhere is the warning opf/unresolved-reference. Nothing is drawn from the audience.
purposestring | ref:Purpose——Primary goal of the presentation. Accepts either: - A string: a purposes reference ('decide', or 'acme:fundraise' for a record of the catalogs.acme group), or a free-form goal ('Raise a Series B round of $30M'). A string that is a bare id or 'name:id' is a reference; any other string is free text and is never looked up. - An inline Purpose object for custom purpose metadata or overrides on a referenced record. Object form has the fields of https://openpresentation.org/schema/opf-purpose/v1. A reference resolves like every content reference (see catalogs); one that resolves nowhere is the warning opf/unresolved-reference. Nothing is drawn from the purpose.
languageref:LanguageTag | ref:Language——Language of the presentation content, an engine vocabulary: a BCP-47 language tag, validated directly with no catalog lookup. Accepts either: - A BCP-47 tag ('en-US', 'en-GB', 'ja', 'zh-Hans', 'ar-SA'). - An inline Language object: a 'bcp47' tag plus overrides of what engines know about it (name, ooxmlLang, script, direction, the script font schemes). Engines know the script, base direction, OOXML language tag and default script fonts of the tags in spec/reference/engine-vocabularies.json; any other well-formed tag is accepted and its script is inferred from the tag. Language names and descriptions are catalog display metadata, not part of the document.
toneref:CatalogReference | ref:Tone——Desired tone for the presentation. Accepts either: - A tones reference: a bare id ('formal') or 'name:id' for a record of a named catalogs group. - An inline Tone object for custom tone metadata or overrides on a referenced record. Object form has the fields of https://openpresentation.org/schema/opf-tone/v1. A reference resolves like every content reference (see catalogs); one that resolves nowhere is the warning opf/unresolved-reference. Nothing is drawn from the tone.
takeawaystring | array<string>——Audience-facing takeaway the presentation should leave behind. Array form supports multiple takeaways. Deck-level intent used by AI to seed and pressure-test slide content.
durationinteger——Target presentation duration, as an integer number of minutes. The opf-render presenter view counts the elapsed time against it, and core validate warns when it lies outside the resolved narrative's 'duration' range. Agents can also use it to set pace and depth. Nothing else reads it: the preview and the PPTX export draw no duration.
tagsarray<string>——Free-form labels used for categorization, search, and filtering. Lowercase kebab-case is recommended for consistency across a deck library.
designref:Design——Optional design system covering theme, color scheme, font scheme, dimensions, background, logo, watermark, header, and footer applied to the deck. When omitted, engines use their default design configuration.
variablesref:Variables——Optional named variables: deck colors referenced as 'var:<id>' (the original use), and typed content variables (text, number, date, image, url, list) referenced inline as '{{<id>}}' or whole as 'var:<id>'. Variables are what makes a deck a fillable template when combined with 'template': true. Color variables complement the color scheme: scheme slots and roles stay the primary vocabulary; variables cover deck-specific named colors that have no scheme slot. Built-in variables ('{{speaker.name}}', 'var:organization.logo', 'deck.name', ...) need no declaration; see Variables.
templateboolean—falseMarks this document as a template: an incomplete OPF file. A template declares variables (top-level 'variables') and references them from content, and may leave required variables unfilled; validation then reports the unfilled variables instead of failing, and previews and exports use each variable's 'example'. Filling a template (resolveVariables, or 'opf fill') returns a normal deck with this marker removed. Absent or false: a normal deck, where an unfilled required variable is an error. See docs/templates-and-variables.md.
narrativeref:CatalogReference——The deck's narrative plan, by reference: a bare narratives id ('classic-story') or 'name:id' for a record of a named catalogs group ('acme:founder-pitch'). The deck holds only this pointer; the plan (the arc, its beats and what each beat must do) lives in the record, which has the fields of https://openpresentation.org/schema/opf-narrative/v1. A narrative the document defines itself is a record in catalogs.custom.narratives, referenced here by its key. Slides link themselves to beats with slides[].beat. Core validate warns about a slides[].beat id the resolved narrative does not define and about a root 'duration' outside its 'duration' range, and reports a beat that no slide references. The preview and the PPTX export draw nothing from the narrative; opf-pptx stores the reference for round-trip. The reference resolves like every content reference (see catalogs); one that resolves nowhere is the warning opf/unresolved-reference, never an error. Deck-level concerns that are not part of the storyline (audience, tone, takeaway, duration) live as siblings on the presentation root.
slidesarray<ref:Slide>yes—Ordered array of slides that make up the presentation.
referencesarray<ref:Reference>——Sources that text runs cite with 'cite'. Ids are unique. A cited reference is listed in the footnote area of every slide that cites it, with a marker number assigned per deck in order of first use; a reference no run cites is the warning opf/unused-reference. referencesSlide() turns the cited references into an ordinary list slide.
datasetsref:Datasets——Optional shared data tables, keyed by id. A chart ('chart.data': { "dataset": "<id>" }) or a table ('table': { "dataset": "<id>" }) references one instead of holding its own copy; engines inline the reference before composing, rendering or exporting. A dataset nothing references is the warning opf/unused-dataset. See docs/chart-table-data.md.
assetsref:Assets——Optional reusable asset registry for images, data files, videos, documents, fonts, and other resources referenced elsewhere in the deck via 'asset:<id>' strings.
catalogsref:Catalogs——The catalog records this document embeds, grouped by the catalog they came from: 'default' (the catalog bare ids come from), 'custom' (records the document defines itself) and any number of named catalogs ('acme', referenced as 'acme:<id>'). A saved document embeds every record it references, so it renders the same with no catalog registered. See Catalogs.
extensionsobject——Custom data passthrough for agent workflows; ignored by the engine but preserved across read/write round-trips.

$schema

typeconstrequirednodefault—

Optional OPF schema version. When omitted, validators and engines should assume the latest supported OPF schema.

$schema · Allowed values
"https://openpresentation.org/schema/opf/v1"
$schema.json
{
  "$schema": "https://openpresentation.org/schema/opf/v1"
}

name

typestringrequirednodefault—

Display name of the presentation for GUI/TUI lists, library/search indexing, OS-level metadata, and default export filenames. This is deck identity, not slide content. Use slides[].title and slides[].subtitle for text that should appear on presented slides. Also the built-in variable 'deck.name'.

name.json
{
  "name": "Q4 2026 Business Review"
}

description

typestringrequirednodefault—

Free-form prose describing what this presentation is about. Used by agents and humans as a deck-level summary; complements purpose (the goal) and narrative (the structured storyline). Round-trips to OOXML 'docProps/core.xml' as '<dc:description>' (PowerPoint surfaces this as the 'Comments' field in File → Properties). Also the built-in variable 'deck.description'.

description.json
{
  "description": "Quarterly business review covering revenue, product, and hiring milestones for the executive team."
}

filename

typestringrequirednodefault—

Optional base filename for exports (without extension). The opf CLI (convert) and the editor strip a trailing .pptx, .pdf, .png, or .svg (case-insensitive) and append the target format's extension. When omitted, they slugify name; with no usable name the CLI uses the input file name and the editor uses 'presentation'. See /docs/opf for full validation rules.

filename.json
{
  "filename": "q4-2026-business-review"
}

organization

typeref:Organization | array<ref:Organization>requirednodefault—

Organization associated with the presentation, usually the presenting company. Array form supports hosts, partners, clients, and sponsors. The primary organization (Organization.role 'primary', else the first item) supplies the cover and section logo, the 'socials' header/footer field and the 'organization.<field>' built-in variables; the others are available by id as 'organization.<id>.<field>' and are not drawn automatically.

organization (oneOf 1).role · Allowed values
"primary""partner""client""sponsor""host"
organization (oneOf 1).socials (property names) · Allowed values
"linkedin""x""github""youtube""instagram""facebook""tiktok""threads""mastodon""bluesky"

speaker

typeref:Speaker | array<ref:Speaker>requirednodefault—

Person presenting the deck. Array form supports panels and multi-speaker decks. The first speaker is the primary speaker: the built-in variables 'speaker.<field>' read it, 'speakers' lists every name, and 'speaker.<id>.<field>' addresses one by id. A speaker is drawn nowhere else.

speaker (oneOf 1).socials (property names) · Allowed values
"linkedin""x""github""youtube""instagram""facebook""tiktok""threads""mastodon""bluesky"

author

typestring | array<string>requirednodefault—

Optional credit for the person who authored or contributed to the deck, distinct from speaker. Array form supports multiple contributors. Round-trips to OOXML 'docProps/core.xml' as '<dc:creator>' (semicolon-joined when multiple) and seeds '<cp:lastModifiedBy>' on first write; subsequent edits in PowerPoint overwrite '<cp:lastModifiedBy>' with the editing user. Also the built-in variable 'deck.author' (an array joined with ', ').

author.json
{
  "author": "Bob Lee"
}

audience

typestring | ref:Audience | array<string | ref:Audience>requirednodefault—

Intended audiences for the presentation. Accepts any of: - A single string: an audiences reference ('executive', or 'acme:board' for a record of the catalogs.acme group), or free-form text ('Series B investors'). A string that is a bare id or 'name:id' is a reference; any other string is free text and is never looked up. - A single inline Audience object, for custom audience metadata or overrides on a referenced record. Object form has the fields of https://openpresentation.org/schema/opf-audience/v1. - An array of strings and/or inline Audience objects, for more than one audience. A reference resolves like every content reference (see catalogs); one that resolves nowhere is the warning opf/unresolved-reference. Nothing is drawn from the audience.

audience (oneOf 2).seniority · Allowed values
"ic""manager""director""vp""c-suite""mixed"
audience (oneOf 2).technicalFluency · Allowed values
"low""medium""high""mixed"
audience (oneOf 2).decisionPower · Allowed values
"informational""advisory""decision-maker"
audience.json
{
  "audience": "executive"
}

purpose

typestring | ref:Purposerequirednodefault—

Primary goal of the presentation. Accepts either: - A string: a purposes reference ('decide', or 'acme:fundraise' for a record of the catalogs.acme group), or a free-form goal ('Raise a Series B round of $30M'). A string that is a bare id or 'name:id' is a reference; any other string is free text and is never looked up. - An inline Purpose object for custom purpose metadata or overrides on a referenced record. Object form has the fields of https://openpresentation.org/schema/opf-purpose/v1. A reference resolves like every content reference (see catalogs); one that resolves nowhere is the warning opf/unresolved-reference. Nothing is drawn from the purpose.

purpose.json
{
  "purpose": "Raise a Series B round of $30M"
}

language

typeref:LanguageTag | ref:Languagerequirednodefault—

Language of the presentation content, an engine vocabulary: a BCP-47 language tag, validated directly with no catalog lookup. Accepts either: - A BCP-47 tag ('en-US', 'en-GB', 'ja', 'zh-Hans', 'ar-SA'). - An inline Language object: a 'bcp47' tag plus overrides of what engines know about it (name, ooxmlLang, script, direction, the script font schemes). Engines know the script, base direction, OOXML language tag and default script fonts of the tags in spec/reference/engine-vocabularies.json; any other well-formed tag is accepted and its script is inferred from the tag. Language names and descriptions are catalog display metadata, not part of the document.

language (oneOf 2).direction · Allowed values
"ltr""rtl"
language.json
{
  "language": "en-US"
}

tone

typeref:CatalogReference | ref:Tonerequirednodefault—

Desired tone for the presentation. Accepts either: - A tones reference: a bare id ('formal') or 'name:id' for a record of a named catalogs group. - An inline Tone object for custom tone metadata or overrides on a referenced record. Object form has the fields of https://openpresentation.org/schema/opf-tone/v1. A reference resolves like every content reference (see catalogs); one that resolves nowhere is the warning opf/unresolved-reference. Nothing is drawn from the tone.

tone.json
{
  "tone": "formal"
}

takeaway

typestring | array<string>requirednodefault—

Audience-facing takeaway the presentation should leave behind. Array form supports multiple takeaways. Deck-level intent used by AI to seed and pressure-test slide content.

takeaway.json
{
  "takeaway": "Agent latency is the new bottleneck for AI products."
}

duration

typeintegerrequirednodefault—

Target presentation duration, as an integer number of minutes. The opf-render presenter view counts the elapsed time against it, and core validate warns when it lies outside the resolved narrative's 'duration' range. Agents can also use it to set pace and depth. Nothing else reads it: the preview and the PPTX export draw no duration.

tags

typearray<string>requirednodefault—

Free-form labels used for categorization, search, and filtering. Lowercase kebab-case is recommended for consistency across a deck library.

tags.json
{
  "tags": [
    "qbr",
    "internal",
    "fy26-q4"
  ]
}

design

typeref:Designrequirednodefault—

Optional design system covering theme, color scheme, font scheme, dimensions, background, logo, watermark, header, and footer applied to the deck. When omitted, engines use their default design configuration.

design.fontScheme (oneOf 2).type · Allowed values
"sans-serif", "serif", "monospace"
design.fontScheme (oneOf 2).app · Allowed values
"powerpoint", "google-slides"
design.fontScheme (oneOf 2).languageFamily · Allowed values
"latin", "ea", "cs", "eastAsian", "complexScript"
design.dimensions · Named choices (see schema for other values and constraints)
"16:9", "4:3", "16:10", "1:1", "4:5", "9:16", "letter", "a4", "widescreen", "standard"
design.dimensions (oneOf 2).preset · Allowed values
"16:9", "4:3", "16:10", "1:1", "4:5", "9:16", "letter", "a4", "widescreen", "standard"
design.background · Named choices (see schema for other values and constraints)
"light1", "light2", "dark1", "dark2"
design.background (oneOf 2) (oneOf 1).type · Allowed values
"theme"
design.background (oneOf 2) (oneOf 1).slot · Allowed values
"light1", "light2", "dark1", "dark2"
design.background (oneOf 2) (oneOf 2).type · Allowed values
"solid"
design.background (oneOf 2) (oneOf 2).color · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
design.background (oneOf 2) (oneOf 3).tone · Allowed values
"dark", "light"
design.background (oneOf 2) (oneOf 3).type · Allowed values
"gradient"
design.background (oneOf 2) (oneOf 3).gradient.stops[].color · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
design.background (oneOf 2) (oneOf 4).tone · Allowed values
"dark", "light"
design.background (oneOf 2) (oneOf 4).type · Allowed values
"image"
design.background (oneOf 2) (oneOf 4).fit · Allowed values
"cover", "contain", "stretch", "tile"
design.background (oneOf 2) (oneOf 4).recolor · Named choices (see schema for other values and constraints)
"grayscale"
design.background (oneOf 2) (oneOf 4).recolor (oneOf 2).dark · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
design.background (oneOf 2) (oneOf 4).recolor (oneOf 2).light · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
design.background (oneOf 2) (oneOf 4).overlay.color · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
design.background (oneOf 2) (oneOf 4).overlay.edge · Allowed values
"top", "bottom", "left", "right"
design.background (oneOf 2) (oneOf 5).type · Allowed values
"pattern"
design.background (oneOf 2) (oneOf 5).pattern.foregroundColor · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
design.background (oneOf 2) (oneOf 5).pattern.backgroundColor · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
design.variant · Named choices (see schema for other values and constraints)
"light1", "light2", "dark1", "dark2"
design.variant (oneOf 2).background · Allowed values
"light1", "light2", "dark1", "dark2"
design.variant (oneOf 2).accents[] · Allowed values
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6"
design.logo · Named choices (see schema for other values and constraints)
false
design.watermark · Named choices (see schema for other values and constraints)
false
design.header · Named choices (see schema for other values and constraints)
false
design.footer · Named choices (see schema for other values and constraints)
false
design.titleAlignment · Allowed values
"left", "center", "right"
design.contentAlignment · Allowed values
"left", "center", "right"
design.contentDirection · Allowed values
"horizontal", "vertical"
design.chartPrimary · Allowed values
"none", "top", "bottom", "left", "right"
design.imageFit · Allowed values
"cover", "contain", "stretch"
design.listBullet · Allowed values
"character", "image", "none"

variables

typeref:Variablesrequirednodefault—

Optional named variables: deck colors referenced as 'var:<id>' (the original use), and typed content variables (text, number, date, image, url, list) referenced inline as '{{<id>}}' or whole as 'var:<id>'. Variables are what makes a deck a fillable template when combined with 'template': true. Color variables complement the color scheme: scheme slots and roles stay the primary vocabulary; variables cover deck-specific named colors that have no scheme slot. Built-in variables ('{{speaker.name}}', 'var:organization.logo', 'deck.name', ...) need no declaration; see Variables.

variables.* (oneOf 2).type · Allowed values
"color"
variables.* (oneOf 3).type · Allowed values
"text"
variables.* (oneOf 4).type · Allowed values
"number"
variables.* (oneOf 5).type · Allowed values
"date"
variables.* (oneOf 6).type · Allowed values
"image"
variables.* (oneOf 7).type · Allowed values
"url"
variables.* (oneOf 8).type · Allowed values
"list"

template

typebooleanrequirednodefaultfalse

Marks this document as a template: an incomplete OPF file. A template declares variables (top-level 'variables') and references them from content, and may leave required variables unfilled; validation then reports the unfilled variables instead of failing, and previews and exports use each variable's 'example'. Filling a template (resolveVariables, or 'opf fill') returns a normal deck with this marker removed. Absent or false: a normal deck, where an unfilled required variable is an error. See docs/templates-and-variables.md.

narrative

typeref:CatalogReferencerequirednodefault—

The deck's narrative plan, by reference: a bare narratives id ('classic-story') or 'name:id' for a record of a named catalogs group ('acme:founder-pitch'). The deck holds only this pointer; the plan (the arc, its beats and what each beat must do) lives in the record, which has the fields of https://openpresentation.org/schema/opf-narrative/v1. A narrative the document defines itself is a record in catalogs.custom.narratives, referenced here by its key. Slides link themselves to beats with slides[].beat. Core validate warns about a slides[].beat id the resolved narrative does not define and about a root 'duration' outside its 'duration' range, and reports a beat that no slide references. The preview and the PPTX export draw nothing from the narrative; opf-pptx stores the reference for round-trip. The reference resolves like every content reference (see catalogs); one that resolves nowhere is the warning opf/unresolved-reference, never an error. Deck-level concerns that are not part of the storyline (audience, tone, takeaway, duration) live as siblings on the presentation root.

narrative.json
{
  "narrative": "classic-story"
}

slides

typearray<ref:Slide>requiredyesdefault—

Ordered array of slides that make up the presentation.

slides[].type · Allowed values
"text", "list", "image", "chart", "table", "video", "code", "metric", "quote", "timeline"
slides[].numbering · Named choices (see schema for other values and constraints)
"arabic", "roman-upper", "roman-lower", "alpha-upper", "alpha-lower"
slides[].numbering (oneOf 2).style · Allowed values
"arabic", "roman-upper", "roman-lower", "alpha-upper", "alpha-lower"
slides[].numbering (oneOf 2).suffix · Allowed values
"period", "paren", "paren-both"
slides[].numbering (oneOf 3)[] · Named choices (see schema for other values and constraints)
"arabic", "roman-upper", "roman-lower", "alpha-upper", "alpha-lower"
slides[].chart.type · Allowed values
"100pct-stacked-area", "100pct-stacked-bar", "100pct-stacked-column", "area", "bar", "box-and-whisker", "column", "combo", "doughnut", "filled-radar", "funnel", "histogram", "line", "line-with-markers", "pareto", "pie", "radar", "radar-with-markers", "scatter", "stacked-area", "stacked-bar", "stacked-column", "stacked-line", "stacked-line-with-markers", "treemap", "waterfall", "world"
slides[].chart.legend · Allowed values
"none", "top", "bottom", "left", "right"
slides[].chart.dataLabels (oneOf 2).content[] · Allowed values
"value", "percent", "category"
slides[].chart.dataLabels (oneOf 2).position · Allowed values
"auto", "center", "inside-end", "inside-base", "outside-end", "above", "below", "left", "right"
slides[].chart.colors[] · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
slides[].table.columns[] (oneOf 3).style.fill · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
slides[].table.columns[] (oneOf 3).style.color · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
slides[].table.columns[] (oneOf 3).style.align · Allowed values
"left", "center", "right"
slides[].table.columns[] (oneOf 3).style.verticalAlign · Allowed values
"top", "middle", "bottom"
slides[].table.columns[] (oneOf 3).style.borders.top.color · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
slides[].table.columns[] (oneOf 3).style.borders.top.dash · Allowed values
"solid", "dash", "dot"
slides[].metric (oneOf 3).trend · Allowed values
"up", "down", "flat"
slides[].metric (oneOf 3).sentiment · Allowed values
"positive", "negative", "neutral"
slides[].timeline (oneOf 1)[].status · Allowed values
"done", "current", "planned"
slides[].caption (oneOf 3).position · Allowed values
"below", "above"
slides[].caption (oneOf 3).align · Allowed values
"left", "center", "right"
slides[].blocks[].type · Allowed values
"text", "list", "image", "chart", "table", "video", "code", "metric", "quote", "timeline", "group"
slides[].blocks[].numbering · Named choices (see schema for other values and constraints)
"arabic", "roman-upper", "roman-lower", "alpha-upper", "alpha-lower"
slides[].blocks[].columns · Named choices (see schema for other values and constraints)
"auto"
slides[].blocks[].fit · Allowed values
"cover", "contain", "stretch"
slides[].blocks[].shape · Allowed values
"rectangle", "rounded", "circle", "hexagon"
slides[].blocks[].border.color · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
slides[].blocks[].recolor · Named choices (see schema for other values and constraints)
"grayscale"
slides[].blocks[].recolor (oneOf 2).dark · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
slides[].blocks[].recolor (oneOf 2).light · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
slides[].blocks[].overlay.color · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
slides[].blocks[].overlay.edge · Allowed values
"top", "bottom", "left", "right"
slides[].blocks[].placement.edge · Allowed values
"left", "right", "top", "bottom"
slides[].blocks[].composition.mode · Allowed values
"auto", "grid", "row", "column"
slides[].blocks[].composition.overflow · Allowed values
"warn", "error"
slides[].design (allOf 1).fontScheme (oneOf 2).type · Allowed values
"sans-serif", "serif", "monospace"
slides[].design (allOf 1).fontScheme (oneOf 2).app · Allowed values
"powerpoint", "google-slides"
slides[].design (allOf 1).fontScheme (oneOf 2).languageFamily · Allowed values
"latin", "ea", "cs", "eastAsian", "complexScript"
slides[].design (allOf 1).dimensions · Named choices (see schema for other values and constraints)
"16:9", "4:3", "16:10", "1:1", "4:5", "9:16", "letter", "a4", "widescreen", "standard"
slides[].design (allOf 1).dimensions (oneOf 2).preset · Allowed values
"16:9", "4:3", "16:10", "1:1", "4:5", "9:16", "letter", "a4", "widescreen", "standard"
slides[].design (allOf 1).background · Named choices (see schema for other values and constraints)
"light1", "light2", "dark1", "dark2"
slides[].design (allOf 1).background (oneOf 2) (oneOf 1).type · Allowed values
"theme"
slides[].design (allOf 1).background (oneOf 2) (oneOf 1).slot · Allowed values
"light1", "light2", "dark1", "dark2"
slides[].design (allOf 1).background (oneOf 2) (oneOf 2).type · Allowed values
"solid"
slides[].design (allOf 1).background (oneOf 2) (oneOf 2).color · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
slides[].design (allOf 1).background (oneOf 2) (oneOf 3).tone · Allowed values
"dark", "light"
slides[].design (allOf 1).background (oneOf 2) (oneOf 3).type · Allowed values
"gradient"
slides[].design (allOf 1).background (oneOf 2) (oneOf 3).gradient.stops[].color · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
slides[].design (allOf 1).background (oneOf 2) (oneOf 4).tone · Allowed values
"dark", "light"
slides[].design (allOf 1).background (oneOf 2) (oneOf 4).type · Allowed values
"image"
slides[].design (allOf 1).background (oneOf 2) (oneOf 4).fit · Allowed values
"cover", "contain", "stretch", "tile"
slides[].design (allOf 1).background (oneOf 2) (oneOf 4).recolor · Named choices (see schema for other values and constraints)
"grayscale"
slides[].design (allOf 1).background (oneOf 2) (oneOf 5).type · Allowed values
"pattern"
slides[].design (allOf 1).background (oneOf 2) (oneOf 5).pattern.foregroundColor · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
slides[].design (allOf 1).background (oneOf 2) (oneOf 5).pattern.backgroundColor · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
slides[].design (allOf 1).variant · Named choices (see schema for other values and constraints)
"light1", "light2", "dark1", "dark2"
slides[].design (allOf 1).variant (oneOf 2).background · Allowed values
"light1", "light2", "dark1", "dark2"
slides[].design (allOf 1).variant (oneOf 2).accents[] · Allowed values
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6"
slides[].design (allOf 1).logo · Named choices (see schema for other values and constraints)
false
slides[].design (allOf 1).watermark · Named choices (see schema for other values and constraints)
false
slides[].design (allOf 1).header · Named choices (see schema for other values and constraints)
false
slides[].design (allOf 1).footer · Named choices (see schema for other values and constraints)
false
slides[].design (allOf 1).titleAlignment · Allowed values
"left", "center", "right"
slides[].design (allOf 1).contentAlignment · Allowed values
"left", "center", "right"
slides[].design (allOf 1).contentDirection · Allowed values
"horizontal", "vertical"
slides[].design (allOf 1).chartPrimary · Allowed values
"none", "top", "bottom", "left", "right"
slides[].design (allOf 1).imageFit · Allowed values
"cover", "contain", "stretch"
slides[].design (allOf 1).listBullet · Allowed values
"character", "image", "none"
slides.json
{
  "slides": [
    {
      "title": "A first slide"
    }
  ]
}

references

typearray<ref:Reference>requirednodefault—

Sources that text runs cite with 'cite'. Ids are unique. A cited reference is listed in the footnote area of every slide that cites it, with a marker number assigned per deck in order of first use; a reference no run cites is the warning opf/unused-reference. referencesSlide() turns the cited references into an ordinary list slide.

references.json
{
  "references": [
    {
      "id": "gartner-2026",
      "text": "Gartner, Market Guide for Presentation Tooling, 2026",
      "url": "https://www.gartner.com"
    }
  ]
}

datasets

typeref:Datasetsrequirednodefault—

Optional shared data tables, keyed by id. A chart ('chart.data': { "dataset": "<id>" }) or a table ('table': { "dataset": "<id>" }) references one instead of holding its own copy; engines inline the reference before composing, rendering or exporting. A dataset nothing references is the warning opf/unused-dataset. See docs/chart-table-data.md.

assets

typeref:Assetsrequirednodefault—

Optional reusable asset registry for images, data files, videos, documents, fonts, and other resources referenced elsewhere in the deck via 'asset:<id>' strings.

catalogs

typeref:Catalogsrequirednodefault—

The catalog records this document embeds, grouped by the catalog they came from: 'default' (the catalog bare ids come from), 'custom' (records the document defines itself) and any number of named catalogs ('acme', referenced as 'acme:<id>'). A saved document embeds every record it references, so it renders the same with no catalog registered. See Catalogs.

catalogs.default · Named choices (see schema for other values and constraints)
false

extensions

typeobjectrequirednodefault—

Custom data passthrough for agent workflows; ignored by the engine but preserved across read/write round-trips.

Complete definition constraints
Schema constraints
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://openpresentation.org/schema/opf/v1",
  "$comment": "The v1 in the $id is the pre-1.0 line, not a frozen contract: this schema may change in any 0.x minor release. The release that produced this copy is the version of the @openpresentation/opf package it came from (opf --version; opf schemas lists it next to each id). See docs/schema-versioning.md.",
  "title": "Presentation",
  "description": "Open-source JSON format for describing PowerPoint presentations. Agents describe narratives, content, audience, reusable assets, and design — the engine handles OOXML complexity.\n\nContent references (Slide.layout, design.theme, design.colorScheme / design.colorScheme.id, design.fontScheme / design.fontScheme.id, narrative, audience, purpose and tone, and the colorScheme / fontScheme a theme record names) point at catalog records. Each is a bare 'id' or a 'name:id' whose prefix names a group in 'catalogs'. A bare id resolves in catalogs.custom, then in the records embedded under catalogs.default, then in the catalog the host registered for catalogs.default.source (or the host's default catalog when 'default' is omitted); 'name:id' resolves in catalogs.<name>, then in the catalog the host registered for its source. A reference that resolves nowhere is the warning opf/unresolved-reference, and the slide uses automatic composition or the engine default. Engines never fetch a catalog: a saved document embeds every record it uses, and hosts register any other catalog by its source string. See docs/default-catalog.md.\n\nchart.type, the language tag and the keys of Organization.socials / Speaker.socials are engine vocabularies, validated directly with no catalog lookup. When a document names no theme, colour scheme or font scheme, every engine uses the same small engine defaults (spec/reference/engine-defaults.json). Asset references use 'asset:<id>' strings that point into the top-level assets registry, and content color fields (rich-text runs, styled table cells) accept hex values, color-scheme slot/role names, or 'var:<id>' references into the top-level variables map.",
  "type": "object",
  "required": [
    "slides"
  ],
  "additionalProperties": false,
  "properties": {
    "$schema": {
      "type": "string",
      "const": "https://openpresentation.org/schema/opf/v1",
      "description": "Optional OPF schema version. When omitted, validators and engines should assume the latest supported OPF schema."
    },
    "name": {
      "type": "string",
      "description": "Display name of the presentation for GUI/TUI lists, library/search indexing, OS-level metadata, and default export filenames. This is deck identity, not slide content. Use slides[].title and slides[].subtitle for text that should appear on presented slides. Also the built-in variable 'deck.name'.",
      "examples": [
        "Q4 2026 Business Review",
        "Series B Pitch — Acme",
        "The Future of Agentic Workflows"
      ]
    },
    "description": {
      "type": "string",
      "description": "Free-form prose describing what this presentation is about. Used by agents and humans as a deck-level summary; complements purpose (the goal) and narrative (the structured storyline). Round-trips to OOXML 'docProps/core.xml' as '<dc:description>' (PowerPoint surfaces this as the 'Comments' field in File → Properties). Also the built-in variable 'deck.description'.",
      "examples": [
        "Quarterly business review covering revenue, product, and hiring milestones for the executive team."
      ]
    },
    "filename": {
      "type": "string",
      "description": "Optional base filename for exports (without extension). The opf CLI (convert) and the editor strip a trailing .pptx, .pdf, .png, or .svg (case-insensitive) and append the target format's extension. When omitted, they slugify name; with no usable name the CLI uses the input file name and the editor uses 'presentation'. See /docs/opf for full validation rules.",
      "examples": [
        "q4-2026-business-review",
        "acme-series-b-pitch"
      ]
    },
    "organization": {
      "oneOf": [
        {
          "$ref": "#/$defs/Organization"
        },
        {
          "type": "array",
          "items": {
            "$ref": "#/$defs/Organization"
          },
          "minItems": 1
        }
      ],
      "description": "Organization associated with the presentation, usually the presenting company. Array form supports hosts, partners, clients, and sponsors. The primary organization (Organization.role 'primary', else the first item) supplies the cover and section logo, the 'socials' header/footer field and the 'organization.<field>' built-in variables; the others are available by id as 'organization.<id>.<field>' and are not drawn automatically."
    },
    "speaker": {
      "oneOf": [
        {
          "$ref": "#/$defs/Speaker"
        },
        {
          "type": "array",
          "items": {
            "$ref": "#/$defs/Speaker"
          },
          "minItems": 1
        }
      ],
      "description": "Person presenting the deck. Array form supports panels and multi-speaker decks. The first speaker is the primary speaker: the built-in variables 'speaker.<field>' read it, 'speakers' lists every name, and 'speaker.<id>.<field>' addresses one by id. A speaker is drawn nowhere else."
    },
    "author": {
      "oneOf": [
        {
          "type": "string"
        },
        {
          "type": "array",
          "items": {
            "type": "string"
          },
          "minItems": 1
        }
      ],
      "description": "Optional credit for the person who authored or contributed to the deck, distinct from speaker. Array form supports multiple contributors. Round-trips to OOXML 'docProps/core.xml' as '<dc:creator>' (semicolon-joined when multiple) and seeds '<cp:lastModifiedBy>' on first write; subsequent edits in PowerPoint overwrite '<cp:lastModifiedBy>' with the editing user. Also the built-in variable 'deck.author' (an array joined with ', ').",
      "examples": [
        "Bob Lee",
        [
          "Bob Lee",
          "Carla Diaz"
        ]
      ]
    },
    "audience": {
      "oneOf": [
        {
          "type": "string"
        },
        {
          "$ref": "#/$defs/Audience"
        },
        {
          "type": "array",
          "items": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "$ref": "#/$defs/Audience"
              }
            ]
          },
          "minItems": 1
        }
      ],
      "description": "Intended audiences for the presentation. Accepts any of:\n- A single string: an audiences reference ('executive', or 'acme:board' for a record of the catalogs.acme group), or free-form text ('Series B investors'). A string that is a bare id or 'name:id' is a reference; any other string is free text and is never looked up.\n- A single inline Audience object, for custom audience metadata or overrides on a referenced record. Object form has the fields of https://openpresentation.org/schema/opf-audience/v1.\n- An array of strings and/or inline Audience objects, for more than one audience.\n\nA reference resolves like every content reference (see catalogs); one that resolves nowhere is the warning opf/unresolved-reference. Nothing is drawn from the audience.",
      "examples": [
        "executive",
        "Biology Students and Wildlife Enthusiasts",
        [
          "executive"
        ],
        [
          "board",
          "c-suite"
        ],
        {
          "id": "executive",
          "attentionBudgetMinutes": 20
        },
        [
          "Series B investors",
          "acme:board"
        ],
        [
          {
            "id": "executive",
            "attentionBudgetMinutes": 20
          },
          {
            "name": "Regional Sales Leaders",
            "seniority": "director",
            "technicalFluency": "medium",
            "decisionPower": "advisory"
          }
        ]
      ]
    },
    "purpose": {
      "oneOf": [
        {
          "type": "string"
        },
        {
          "$ref": "#/$defs/Purpose"
        }
      ],
      "description": "Primary goal of the presentation. Accepts either:\n- A string: a purposes reference ('decide', or 'acme:fundraise' for a record of the catalogs.acme group), or a free-form goal ('Raise a Series B round of $30M'). A string that is a bare id or 'name:id' is a reference; any other string is free text and is never looked up.\n- An inline Purpose object for custom purpose metadata or overrides on a referenced record. Object form has the fields of https://openpresentation.org/schema/opf-purpose/v1.\n\nA reference resolves like every content reference (see catalogs); one that resolves nowhere is the warning opf/unresolved-reference. Nothing is drawn from the purpose.",
      "examples": [
        "Raise a Series B round of $30M",
        "align",
        "educate",
        "acme:fundraise",
        {
          "id": "decide",
          "outcome": "Approve the Q4 hiring plan"
        },
        {
          "name": "Secure renewal",
          "outcome": "Customer signs a 12-month renewal"
        }
      ]
    },
    "language": {
      "oneOf": [
        {
          "$ref": "#/$defs/LanguageTag"
        },
        {
          "$ref": "#/$defs/Language"
        }
      ],
      "description": "Language of the presentation content, an engine vocabulary: a BCP-47 language tag, validated directly with no catalog lookup. Accepts either:\n- A BCP-47 tag ('en-US', 'en-GB', 'ja', 'zh-Hans', 'ar-SA').\n- An inline Language object: a 'bcp47' tag plus overrides of what engines know about it (name, ooxmlLang, script, direction, the script font schemes).\n\nEngines know the script, base direction, OOXML language tag and default script fonts of the tags in spec/reference/engine-vocabularies.json; any other well-formed tag is accepted and its script is inferred from the tag. Language names and descriptions are catalog display metadata, not part of the document.",
      "examples": [
        "en-US",
        "en-GB",
        "es-MX",
        "ja",
        "fr",
        {
          "bcp47": "en-US",
          "fontScheme": "aptos",
          "googleFontScheme": "roboto"
        },
        {
          "bcp47": "ar-SA",
          "name": "Arabic (Saudi Arabia)",
          "direction": "rtl",
          "script": "Arab"
        }
      ]
    },
    "tone": {
      "oneOf": [
        {
          "$ref": "#/$defs/CatalogReference"
        },
        {
          "$ref": "#/$defs/Tone"
        }
      ],
      "description": "Desired tone for the presentation. Accepts either:\n- A tones reference: a bare id ('formal') or 'name:id' for a record of a named catalogs group.\n- An inline Tone object for custom tone metadata or overrides on a referenced record. Object form has the fields of https://openpresentation.org/schema/opf-tone/v1.\n\nA reference resolves like every content reference (see catalogs); one that resolves nowhere is the warning opf/unresolved-reference. Nothing is drawn from the tone.",
      "examples": [
        "formal",
        "casual",
        "inspirational",
        "technical",
        "persuasive",
        "acme:house-voice",
        {
          "id": "formal",
          "voiceCues": [
            "Use precise, concise language."
          ]
        },
        {
          "name": "Founder direct",
          "voiceCues": [
            "Use first person sparingly.",
            "Make the ask concrete."
          ]
        }
      ]
    },
    "takeaway": {
      "oneOf": [
        {
          "type": "string"
        },
        {
          "type": "array",
          "items": {
            "type": "string"
          },
          "minItems": 1
        }
      ],
      "description": "Audience-facing takeaway the presentation should leave behind. Array form supports multiple takeaways. Deck-level intent used by AI to seed and pressure-test slide content.",
      "examples": [
        "Agent latency is the new bottleneck for AI products.",
        [
          "Agent latency is the new bottleneck for AI products.",
          "Our runtime is 8x faster than the next-best option.",
          "Customers see ROI within the first quarter."
        ]
      ]
    },
    "duration": {
      "type": "integer",
      "minimum": 1,
      "description": "Target presentation duration, as an integer number of minutes. The opf-render presenter view counts the elapsed time against it, and core validate warns when it lies outside the resolved narrative's 'duration' range. Agents can also use it to set pace and depth. Nothing else reads it: the preview and the PPTX export draw no duration."
    },
    "tags": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Free-form labels used for categorization, search, and filtering. Lowercase kebab-case is recommended for consistency across a deck library.",
      "examples": [
        [
          "qbr",
          "internal",
          "fy26-q4"
        ],
        [
          "pitch",
          "fundraising",
          "confidential"
        ]
      ]
    },
    "design": {
      "$ref": "#/$defs/Design",
      "description": "Optional design system covering theme, color scheme, font scheme, dimensions, background, logo, watermark, header, and footer applied to the deck. When omitted, engines use their default design configuration."
    },
    "variables": {
      "$ref": "#/$defs/Variables",
      "description": "Optional named variables: deck colors referenced as 'var:<id>' (the original use), and typed content variables (text, number, date, image, url, list) referenced inline as '{{<id>}}' or whole as 'var:<id>'. Variables are what makes a deck a fillable template when combined with 'template': true. Color variables complement the color scheme: scheme slots and roles stay the primary vocabulary; variables cover deck-specific named colors that have no scheme slot. Built-in variables ('{{speaker.name}}', 'var:organization.logo', 'deck.name', ...) need no declaration; see Variables."
    },
    "template": {
      "type": "boolean",
      "description": "Marks this document as a template: an incomplete OPF file. A template declares variables (top-level 'variables') and references them from content, and may leave required variables unfilled; validation then reports the unfilled variables instead of failing, and previews and exports use each variable's 'example'. Filling a template (resolveVariables, or 'opf fill') returns a normal deck with this marker removed. Absent or false: a normal deck, where an unfilled required variable is an error. See docs/templates-and-variables.md.",
      "default": false
    },
    "narrative": {
      "$ref": "#/$defs/CatalogReference",
      "description": "The deck's narrative plan, by reference: a bare narratives id ('classic-story') or 'name:id' for a record of a named catalogs group ('acme:founder-pitch'). The deck holds only this pointer; the plan (the arc, its beats and what each beat must do) lives in the record, which has the fields of https://openpresentation.org/schema/opf-narrative/v1. A narrative the document defines itself is a record in catalogs.custom.narratives, referenced here by its key.\n\nSlides link themselves to beats with slides[].beat. Core validate warns about a slides[].beat id the resolved narrative does not define and about a root 'duration' outside its 'duration' range, and reports a beat that no slide references. The preview and the PPTX export draw nothing from the narrative; opf-pptx stores the reference for round-trip.\n\nThe reference resolves like every content reference (see catalogs); one that resolves nowhere is the warning opf/unresolved-reference, never an error.\n\nDeck-level concerns that are not part of the storyline (audience, tone, takeaway, duration) live as siblings on the presentation root.",
      "examples": [
        "classic-story",
        "problem-solution",
        "scqa",
        "pitch-deck",
        "acme:founder-pitch"
      ]
    },
    "slides": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/Slide"
      },
      "minItems": 1,
      "description": "Ordered array of slides that make up the presentation."
    },
    "references": {
      "type": "array",
      "items": {
        "$ref": "#/$defs/Reference"
      },
      "description": "Sources that text runs cite with 'cite'. Ids are unique. A cited reference is listed in the footnote area of every slide that cites it, with a marker number assigned per deck in order of first use; a reference no run cites is the warning opf/unused-reference. referencesSlide() turns the cited references into an ordinary list slide.",
      "examples": [
        [
          {
            "id": "gartner-2026",
            "text": "Gartner, Market Guide for Presentation Tooling, 2026",
            "url": "https://www.gartner.com"
          }
        ]
      ]
    },
    "datasets": {
      "$ref": "#/$defs/Datasets",
      "description": "Optional shared data tables, keyed by id. A chart ('chart.data': { \"dataset\": \"<id>\" }) or a table ('table': { \"dataset\": \"<id>\" }) references one instead of holding its own copy; engines inline the reference before composing, rendering or exporting. A dataset nothing references is the warning opf/unused-dataset. See docs/chart-table-data.md."
    },
    "assets": {
      "$ref": "#/$defs/Assets",
      "description": "Optional reusable asset registry for images, data files, videos, documents, fonts, and other resources referenced elsewhere in the deck via 'asset:<id>' strings."
    },
    "catalogs": {
      "$ref": "#/$defs/Catalogs",
      "description": "The catalog records this document embeds, grouped by the catalog they came from: 'default' (the catalog bare ids come from), 'custom' (records the document defines itself) and any number of named catalogs ('acme', referenced as 'acme:<id>'). A saved document embeds every record it references, so it renders the same with no catalog registered. See Catalogs."
    },
    "extensions": {
      "type": "object",
      "description": "Custom data passthrough for agent workflows; ignored by the engine but preserved across read/write round-trips."
    }
  },
  "$defs": {
    "Assets": {
      "type": "object",
      "description": "Reusable asset registry for resources used by slides, charts, metadata, and design. Keys are stable asset ids referenced elsewhere as 'asset:<id>'. Each asset can be a source string or an object with src plus optional metadata.",
      "propertyNames": {
        "pattern": "^[a-zA-Z0-9][a-zA-Z0-9._-]*$"
      },
      "additionalProperties": {
        "$ref": "#/$defs/Asset"
      },
      "examples": [
        {
          "acme-logo": "./assets/acme-logo.svg",
          "watermark": {
            "src": "./assets/watermark.png",
            "alt": "Acme watermark"
          },
          "revenue": {
            "src": "./data/revenue.csv",
            "mediaType": "text/csv"
          }
        }
      ]
    },
    "Asset": {
      "description": "Reusable or inline resource. A string is shorthand for { \"src\": value }. Source strings accept 'asset:<id>' references, HTTPS URLs, data URIs, relative paths resolved against the OPF file location, or local filesystem paths. Use object form when metadata such as alt text, title or mediaType matters.",
      "oneOf": [
        {
          "type": "string",
          "examples": [
            "asset:acme-logo",
            "https://cdn.acme.com/image.png",
            "./assets/image.png",
            "data:image/png;base64,..."
          ]
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "src"
          ],
          "properties": {
            "src": {
              "type": "string",
              "description": "Resource source. Accepts an 'asset:<id>' reference, HTTPS URL, data URI, relative path resolved against the OPF file location, or local filesystem path.",
              "examples": [
                "asset:acme-logo",
                "./assets/logo.svg",
                "https://cdn.acme.com/logo.png",
                "data:image/svg+xml;base64,...",
                "/Users/alice/decks/data/revenue.csv"
              ]
            },
            "alt": {
              "type": "string",
              "description": "Alternative text for images and other visual assets."
            },
            "title": {
              "type": "string",
              "description": "Human-readable asset title for editors and asset pickers."
            },
            "description": {
              "type": "string",
              "description": "Optional notes about the asset's contents, provenance, or intended use."
            },
            "mediaType": {
              "type": "string",
              "description": "Optional MIME media type when it cannot be inferred from src.",
              "examples": [
                "image/svg+xml",
                "image/png",
                "text/csv",
                "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
              ]
            }
          }
        }
      ]
    },
    "Audience": {
      "type": "object",
      "description": "Inline audience metadata for the presentation. Use 'id' to reference an audiences record (a bare id or 'name:id') and override selected fields, or use 'name' for a custom inline audience.",
      "anyOf": [
        {
          "required": [
            "id"
          ]
        },
        {
          "required": [
            "name"
          ]
        }
      ],
      "properties": {
        "id": {
          "$ref": "#/$defs/CatalogReference",
          "description": "Optional audiences reference (a bare id or 'name:id') resolved before applying the inline overrides.",
          "examples": [
            "executive",
            "board",
            "engineering-team"
          ]
        },
        "name": {
          "type": "string",
          "description": "Human-readable audience name shown in pickers."
        },
        "summary": {
          "type": "string",
          "description": "One-sentence positioning of the audience."
        },
        "description": {
          "type": "string",
          "description": "Longer prose describing the audience and how to address them."
        },
        "seniority": {
          "type": "string",
          "enum": [
            "ic",
            "manager",
            "director",
            "vp",
            "c-suite",
            "mixed"
          ],
          "description": "Typical seniority level of the audience."
        },
        "technicalFluency": {
          "type": "string",
          "enum": [
            "low",
            "medium",
            "high",
            "mixed"
          ],
          "description": "Typical technical fluency of the audience."
        },
        "decisionPower": {
          "type": "string",
          "enum": [
            "informational",
            "advisory",
            "decision-maker"
          ],
          "description": "Whether the audience is expected to be informed, advise, or decide."
        },
        "attentionBudgetMinutes": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Realistic upper bound on focused attention for a single presentation, in minutes."
        },
        "recommendedNarratives": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Soft cross-link: narrative ids that work well for this audience, for picker UIs. Never resolved, embedded or validated as references."
        },
        "recommendedTones": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Soft cross-link: tone ids that work well for this audience, for picker UIs. Never resolved, embedded or validated as references."
        },
        "tags": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Free-form labels for filtering and search."
        }
      }
    },
    "Purpose": {
      "type": "object",
      "description": "Inline purpose metadata for the presentation. Use 'id' to reference a purposes record (a bare id or 'name:id') and override selected fields, or use 'name' for a custom inline purpose.",
      "anyOf": [
        {
          "required": [
            "id"
          ]
        },
        {
          "required": [
            "name"
          ]
        }
      ],
      "properties": {
        "id": {
          "$ref": "#/$defs/CatalogReference",
          "description": "Optional purposes reference (a bare id or 'name:id') resolved before applying the inline overrides.",
          "examples": [
            "inform",
            "decide",
            "align",
            "persuade",
            "educate"
          ]
        },
        "name": {
          "type": "string",
          "description": "Human-readable purpose name shown in pickers."
        },
        "summary": {
          "type": "string",
          "description": "One-sentence positioning of the purpose."
        },
        "description": {
          "type": "string",
          "description": "Longer prose describing when to use this purpose and how it should shape a deck."
        },
        "outcome": {
          "type": "string",
          "description": "Desired audience outcome after the presentation."
        },
        "successCriteria": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Observable signals that the deck accomplished this purpose."
        },
        "recommendedNarratives": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Soft cross-link: narrative ids that work well for this purpose, for picker UIs. Never resolved, embedded or validated as references."
        },
        "recommendedTones": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Soft cross-link: tone ids that work well for this purpose, for picker UIs. Never resolved, embedded or validated as references."
        },
        "tags": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Free-form labels for filtering and search."
        }
      }
    },
    "Language": {
      "type": "object",
      "description": "Inline language metadata for the presentation: a BCP-47 'bcp47' tag plus overrides of what engines know about it. Languages are an engine vocabulary, not catalog records, so there is no 'id'.",
      "required": [
        "bcp47"
      ],
      "not": {
        "required": [
          "id"
        ]
      },
      "properties": {
        "name": {
          "type": "string",
          "description": "Human-readable language name.",
          "examples": [
            "English",
            "English (United Kingdom)",
            "Arabic (Saudi Arabia)"
          ]
        },
        "bcp47": {
          "$ref": "#/$defs/LanguageTag",
          "description": "BCP-47 language tag used for locale-aware rendering, proofing, and accessibility metadata. Use 'en-GB' for UK English; 'en-UK' is not a valid BCP-47 region form.",
          "examples": [
            "en",
            "en-US",
            "en-GB",
            "ar-SA",
            "zh-Hans"
          ]
        },
        "ooxmlLang": {
          "type": "string",
          "description": "Culture tag for OOXML text-run language attributes (a:rPr/@lang, a:endParaRPr/@lang), in the language-[Script-]REGION form Office recognizes (e.g. 'ja-JP', 'ar-SA', 'ms-MY', 'nb-NO', 'fil-PH', 'zh-CN'). Without it, engines emit the curated tag of their language vocabulary (spec/reference/engine-vocabularies.json) for a tag without a region, and a region-bearing tag as written. Curated rather than inferred so output does not depend on the runtime's locale data.",
          "examples": [
            "en-US",
            "ja-JP",
            "ar-SA",
            "ms-MY",
            "nb-NO",
            "zh-CN"
          ]
        },
        "code": {
          "type": "string",
          "description": "ISO 639-3 or 639-2 language code carried for engines that prefer ISO codes.",
          "examples": [
            "ENG",
            "ARA",
            "JPN",
            "ZHO"
          ]
        },
        "direction": {
          "type": "string",
          "enum": [
            "ltr",
            "rtl"
          ],
          "description": "Base text direction for the language. When omitted, engines derive it from the script: Arabic (Arab), Hebrew (Hebr), Syriac (Syrc), Thaana (Thaa), N'Ko (Nkoo), Adlam (Adlm), Samaritan (Samr), Mandaic (Mand) and Hanifi Rohingya (Rohg) are right-to-left; every other script is left-to-right. The engine language vocabulary (spec/reference/engine-vocabularies.json) states it for the tags it knows."
        },
        "script": {
          "type": "string",
          "description": "ISO 15924 script code of the language's writing system. The script selects the OOXML font slot the language's text uses: East Asian scripts (Hans, Hant, Hani, Jpan, Kore, Hang, Hira, Kana, Bopo, Yiii) use the eastAsian slot; complex scripts (for example Arab, Hebr, Syrc, Thaa, Deva, Beng, Guru, Gujr, Orya, Taml, Telu, Knda, Mlym, Sinh, Thai, Laoo, Tibt, Mymr, Khmr, Mong) use the complexScript slot; every other script (Latn, Cyrl, Grek, Armn, Geor, Ethi, ...) uses the latin slot. When omitted, engines infer it from the BCP-47 tag. The engine language vocabulary (spec/reference/engine-vocabularies.json) states it for the tags it knows. See docs/programs/font-fidelity-everywhere/script-font-model.md.",
          "examples": [
            "Latn",
            "Cyrl",
            "Grek",
            "Arab",
            "Hebr",
            "Jpan",
            "Kore",
            "Hans",
            "Hant",
            "Deva",
            "Thai"
          ]
        },
        "fontScheme": {
          "$ref": "#/$defs/CatalogReference",
          "description": "Font-scheme reference (a bare id or 'name:id') for this language's script slot when targeting PowerPoint output. Its major/minor families fill the language's script slot (eastAsian or complexScript, chosen by 'script') unless the effective design font scheme sets that slot itself; the latin slot always follows the design font scheme. Without it, engines use the default script fonts of their language vocabulary."
        },
        "googleFontScheme": {
          "$ref": "#/$defs/CatalogReference",
          "description": "Font-scheme reference (a bare id or 'name:id') used in place of 'fontScheme' when resolving script fonts for Google Slides output."
        },
        "summary": {
          "type": "string",
          "description": "One-sentence note about coverage or font defaults."
        },
        "description": {
          "type": "string",
          "description": "Longer prose describing the language record and any font-pairing rationale."
        },
        "tags": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Free-form labels for filtering and search."
        }
      }
    },
    "Tone": {
      "type": "object",
      "description": "Inline tone metadata for the presentation. Use 'id' to reference a tones record (a bare id or 'name:id') and override selected fields, or use 'name' for a custom inline tone.",
      "anyOf": [
        {
          "required": [
            "id"
          ]
        },
        {
          "required": [
            "name"
          ]
        }
      ],
      "properties": {
        "id": {
          "$ref": "#/$defs/CatalogReference",
          "description": "Optional tones reference (a bare id or 'name:id') resolved before applying the inline overrides.",
          "examples": [
            "formal",
            "casual",
            "technical",
            "persuasive"
          ]
        },
        "name": {
          "type": "string",
          "description": "Human-readable tone name shown in pickers."
        },
        "summary": {
          "type": "string",
          "description": "One-sentence positioning of the tone."
        },
        "description": {
          "type": "string",
          "description": "Longer prose describing the tone and the kinds of decks it suits."
        },
        "voiceCues": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Short directives that shape AI generation toward this tone."
        },
        "avoid": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Anti-patterns that AI generation should not produce when this tone is active."
        },
        "samplePhrases": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Short example phrases that exemplify this tone."
        },
        "recommendedNarratives": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Soft cross-link: narrative ids this tone pairs well with, for picker UIs. Never resolved, embedded or validated as references."
        },
        "tags": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Free-form labels for filtering and search."
        }
      }
    },
    "Organization": {
      "type": "object",
      "description": "An organization associated with the presentation, typically the presenting company, but also hosts, partners, clients, or sponsors. The primary organization (role 'primary', else the first one) supplies the cover and section logo (unless design.logo overrides it) and the 'socials' header/footer field (its socials). Every field is also a built-in variable ('{{organization.name}}', 'organization.<id>.<field>'), and every logo a slide-scoped image ('var:organization.logo.icon', 'var:organization.<id>.logo'). Nothing else about an organization is drawn automatically. See docs/templates-and-variables.md.",
      "required": [
        "id",
        "name"
      ],
      "properties": {
        "id": {
          "type": "string",
          "pattern": "^[a-zA-Z0-9_-]+$",
          "description": "Stable identifier for the organization, used to reference it from Speaker.organizationId and to address it in built-in variables as 'organization.<id>.<field>'. Must be unique among organizations (a duplicate is a validation error).",
          "examples": [
            "acme",
            "acme-corp",
            "devconf-2026"
          ]
        },
        "name": {
          "type": "string",
          "description": "Display name. The built-in variable 'organization.name' (primary organization) or 'organization.<id>.name' carries it into any string, such as a header or footer text of '{{organization.name}}'.",
          "examples": [
            "Acme Corp",
            "DevConf 2026",
            "Beta Industries"
          ]
        },
        "legalName": {
          "type": "string",
          "description": "Optional legal entity name when it differs from the display name. Never drawn automatically; available as the built-in variable 'organization.legalName'.",
          "examples": [
            "Acme Corporation, Inc.",
            "Beta Industries, LLC"
          ]
        },
        "logo": {
          "oneOf": [
            {
              "$ref": "#/$defs/Asset"
            },
            {
              "$ref": "#/$defs/OrganizationLogo"
            }
          ],
          "description": "The organization's logo. A path, URL or Asset is one logo for every shape; an object gives up to four shapes (full, stacked, icon, wordmark), each a path or Asset, or { onLight, onDark } for the two backgrounds. A path is resolved against the OPF file location; an HTTPS URL, data URI or 'asset:<id>' reference works too. SVG (preferred for vector logos) or PNG with transparency are typical. The primary organization's full logo (role 'primary', else the first organization) is drawn on cover and section slides unless design.logo names another or is false. Every logo is also a slide-scoped built-in image, placed with a whole-field reference in any image field: 'var:organization.logo' (the full logo), 'var:organization.logo.icon' (likewise stacked, wordmark, full), and 'var:organization.<id>.logo' or 'var:organization.<id>.logo.<shape>' for another organization. A missing shape falls back to full, and full to the first defined of wordmark, stacked and icon. The onLight or onDark value is chosen for each slide's background; a missing one uses the other. See docs/templates-and-variables.md and docs/design-resolution.md.",
          "examples": [
            "./assets/acme-logo.svg",
            {
              "full": "./assets/acme-logo.svg",
              "icon": "./assets/acme-mark.svg"
            },
            {
              "full": {
                "onLight": "./assets/acme-logo.svg",
                "onDark": "./assets/acme-logo-white.svg"
              },
              "icon": "./assets/acme-mark.svg"
            },
            "https://cdn.acme.com/logo.svg",
            "asset:acme-logo"
          ]
        },
        "domain": {
          "type": "string",
          "description": "Bare internet domain for the organization. Never drawn automatically and not used to look up assets; available as the built-in variable 'organization.domain'.",
          "examples": [
            "acme.com",
            "beta-industries.io",
            "devconf.org"
          ]
        },
        "email": {
          "type": "string",
          "format": "email",
          "description": "General contact email for the organization. Never drawn automatically; available as the built-in variable 'organization.email'.",
          "examples": [
            "hello@acme.com",
            "sales@acme.com",
            "info@beta-industries.io"
          ]
        },
        "phone": {
          "type": "string",
          "description": "Main contact phone number for the organization. E.164 format is recommended. Never drawn automatically; available as the built-in variable 'organization.phone'.",
          "examples": [
            "+14155551234",
            "+442071838750"
          ]
        },
        "tagline": {
          "type": "string",
          "description": "Short tagline. Never drawn automatically (cover slides do not show it); available as the built-in variable 'organization.tagline', for example in a footer 'text' of '{{organization.tagline}}'.",
          "examples": [
            "Build the future of work",
            "Infrastructure for AI agents",
            "Where teams ship faster"
          ]
        },
        "role": {
          "type": "string",
          "enum": [
            "primary",
            "partner",
            "client",
            "sponsor",
            "host"
          ],
          "description": "Role of the organization relative to the presentation. Only 'primary' has behavior: it selects the primary organization (cover and section logo, the 'socials' header/footer field, and the 'organization.<field>' built-ins). When no organization has role 'primary', the first one is primary. 'partner', 'client', 'sponsor' and 'host' are descriptive labels that change nothing."
        },
        "socials": {
          "$ref": "#/$defs/Socials",
          "description": "Optional social media handles or URLs for the organization. The primary organization's socials render in header/footer zones that set socials: true; otherwise they are authoring metadata."
        }
      }
    },
    "Speaker": {
      "type": "object",
      "description": "A person presenting the deck. A speaker is drawn only through built-in variables ('{{speaker.name}}' inside any string, a header or footer text included, and 'var:speaker.photo' as a whole image field). No layout, cover or bio slide places a speaker on its own. See docs/templates-and-variables.md.",
      "required": [
        "id",
        "name"
      ],
      "properties": {
        "id": {
          "type": "string",
          "pattern": "^[a-zA-Z0-9_-]+$",
          "description": "Stable identifier for the speaker. Must be unique among speakers (a duplicate is a validation error). Addresses this speaker in built-in variables as 'speaker.<id>.<field>', such as '{{speaker.alice.title}}'.",
          "examples": [
            "alice",
            "alice-chen",
            "speaker-1"
          ]
        },
        "name": {
          "type": "string",
          "description": "Display name. Built-in variable 'speaker.name' (first speaker) or 'speaker.<id>.name'; every name is listed by 'speakers'.",
          "examples": [
            "Alice Chen",
            "Bob Lee",
            "Dr. Carla Diaz"
          ]
        },
        "title": {
          "type": "string",
          "description": "Role or title. Built-in variable 'speaker.title' (or 'speaker.<id>.title'), for example in a footer text of '{{speaker.name}}, {{speaker.title}}'.",
          "examples": [
            "VP of Engineering",
            "Founder & CEO",
            "Chief Product Officer",
            "Senior Staff Engineer"
          ]
        },
        "photo": {
          "$ref": "#/$defs/Asset",
          "description": "Source for the speaker's headshot image. Accepts an HTTPS URL, data URI, relative path (resolved against the OPF file location), local path, or 'asset:<id>' reference. Common formats are JPG or PNG; SVG is not appropriate for photographic content. Never drawn automatically: it is the built-in image variable 'speaker.photo' (or 'speaker.<id>.photo'), placed with 'var:speaker.photo' in a slide's image field. It also round-trips through PPTX provenance.",
          "examples": [
            "https://cdn.acme.com/headshots/alice.jpg",
            "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAABAAEDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAr/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/EABQRAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEAAhEDEQA/AJ//2Q==",
            "./assets/photos/alice.png",
            "asset:photo-alice"
          ]
        },
        "email": {
          "type": "string",
          "format": "email",
          "description": "Contact email. Never drawn automatically; available as the built-in variable 'speaker.email'.",
          "examples": [
            "alice@acme.com",
            "alice.chen@acme.com"
          ]
        },
        "phone": {
          "type": "string",
          "description": "Contact phone number for the speaker. E.164 format is recommended. Never drawn automatically; available as the built-in variable 'speaker.phone'.",
          "examples": [
            "+14155551234",
            "+442071838750"
          ]
        },
        "bio": {
          "type": "string",
          "description": "Short biographical paragraph. Never drawn automatically; available as the built-in variable 'speaker.bio', for a bio or 'about the speaker' slide you write.",
          "examples": [
            "Alice leads engineering at Acme, where she's spent the last six years scaling distributed systems from prototype to billions of requests per day. Previously, she was a staff engineer at Google."
          ]
        },
        "organizationId": {
          "type": "string",
          "description": "Reference to an Organization.id in organization; it must name an existing organization (a validation error otherwise). Attribution metadata for hosts: no engine draws it or changes which organization is primary because of it.",
          "examples": [
            "acme",
            "beta",
            "devconf-2026"
          ]
        },
        "socials": {
          "$ref": "#/$defs/Socials",
          "description": "Optional social media handles or URLs for the speaker. Authoring metadata only: nothing draws speaker socials and there is no built-in variable for them (the 'socials' header/footer field draws the primary organization's socials)."
        }
      }
    },
    "Socials": {
      "type": "object",
      "description": "Social media handles or URLs, keyed by platform. The keys are an engine vocabulary validated directly (no catalog lookup): engines link a handle with the platform's URL pattern and handle prefix (spec/reference/engine-vocabularies.json). Each value is a string, either a full URL or a platform handle (e.g., '@acme'). Brand colours and icons are catalog display metadata for authoring UIs; engines render the profile URL, not icons or brand colours. Used both for organization and speaker records.",
      "additionalProperties": {
        "type": "string",
        "description": "Handle or URL for the platform identified by the property key."
      },
      "examples": [
        {
          "linkedin": "https://linkedin.com/in/alice-chen",
          "x": "@alicechen",
          "github": "alicechen"
        },
        {
          "linkedin": "https://linkedin.com/company/acme",
          "bluesky": "acme.bsky.social",
          "mastodon": "https://hachyderm.io/@acme"
        }
      ],
      "propertyNames": {
        "enum": [
          "linkedin",
          "x",
          "github",
          "youtube",
          "instagram",
          "facebook",
          "tiktok",
          "threads",
          "mastodon",
          "bluesky"
        ],
        "description": "Platform key, one of the engine's social platforms."
      }
    },
    "Design": {
      "type": "object",
      "description": "Visual design system applied to the presentation; individual slides may override fields via Slide.design.",
      "properties": {
        "theme": {
          "$ref": "#/$defs/CatalogReference",
          "description": "Theme for the deck: a themes reference, a bare id ('minimal') or 'name:id' ('acme:brand'). The theme supplies the default colour scheme, font scheme, background and dimensions; design.colorScheme, design.fontScheme, design.background and design.dimensions override it field by field. A reference that resolves nowhere is the warning opf/unresolved-reference and engines use the engine default theme.",
          "examples": [
            "minimal",
            "classic",
            "bold",
            "acme:brand"
          ]
        },
        "colorScheme": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "$ref": "#/$defs/ColorScheme"
            }
          ],
          "description": "Color scheme for the presentation. Accepts two forms:\n- A colorSchemes reference: a bare id ('cool-horizon') or 'name:id' ('acme:ocean').\n- Object form: a ColorScheme with an optional 'id' reference as the base plus slot/role overrides. Without 'id', the overrides apply on top of the engine default colour scheme.\n\nWithout either, the theme's colorScheme applies, then the engine default colour scheme.",
          "examples": [
            "cool-horizon",
            "boost",
            "burnt-orange",
            {
              "id": "cool-horizon",
              "accent1": "#FF6F61"
            }
          ]
        },
        "fontScheme": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "$ref": "#/$defs/FontScheme"
            }
          ],
          "description": "Font scheme for heading, body, accent, and code text. Accepts two forms:\n- A fontSchemes reference: a bare id ('aptos') or 'name:id' ('acme:inter').\n- Object form: a FontScheme with an optional 'id' reference as the base plus pair/role overrides.\n\nWithout either, the theme's fontScheme applies, then the engine default font scheme.",
          "examples": [
            "aptos",
            "tenorite",
            {
              "id": "aptos",
              "heading": "Inter"
            }
          ]
        },
        "dimensions": {
          "oneOf": [
            {
              "$ref": "#/$defs/DimensionPreset"
            },
            {
              "$ref": "#/$defs/Dimensions"
            }
          ],
          "description": "Slide dimensions and aspect ratio. String shorthand such as 'widescreen' is equivalent to { preset: 'widescreen' }.",
          "examples": [
            "widescreen",
            "16:9",
            {
              "preset": "16:10"
            }
          ]
        },
        "background": {
          "oneOf": [
            {
              "$ref": "#/$defs/BackgroundShortcut"
            },
            {
              "$ref": "#/$defs/Background"
            }
          ],
          "description": "Default slide background applied across the deck unless overridden on a slide (slides.N.design.background); the resolved theme's background is the fallback. A background is the only canvas fill and never moves content. String shorthand accepts theme slots ('light1', 'light2', 'dark1', 'dark2'), hex colors, or an image source starting with 'asset:', 'https://', 'data:', './' or '../' (a cover image); object forms support theme, solid, gradient, image, or pattern fills.",
          "examples": [
            "dark1",
            "#ffff00",
            {
              "type": "theme",
              "slot": "light1"
            }
          ]
        },
        "variant": {
          "oneOf": [
            {
              "$ref": "#/$defs/ThemeBackgroundSlot"
            },
            {
              "$ref": "#/$defs/ColorVariant"
            }
          ],
          "description": "Optional color variant, as a background slot ('light1', 'light2', 'dark1', 'dark2'; the same as { background: slot }) or the object form, which is needed only for an accent order: which slot of the color scheme is the slide background (and so which are the text and the alternate surface), and optionally the order of the accents. A variant is a mapping over the same twelve-slot scheme, as PowerPoint's color map is, never a second scheme. Without it the background decides: a theme-slot background ('dark1', { type: 'theme', slot }) is the variant of that slot, a picture or gradient takes its 'tone', and any other background picks light or dark by its luminance. A slide's variant replaces the deck's whole, including its accent order.",
          "examples": [
            "dark1",
            {
              "background": "light1",
              "accents": [
                "accent2",
                "accent1",
                "accent3",
                "accent4",
                "accent5",
                "accent6"
              ]
            }
          ]
        },
        "logo": {
          "oneOf": [
            {
              "type": "string",
              "pattern": "^var:organization(\\.[A-Za-z0-9_-]+)?\\.logo(\\.(full|stacked|icon|wordmark))?$"
            },
            {
              "type": "boolean",
              "const": false
            }
          ],
          "description": "Which logo covers, section dividers and picture bullets draw. Logos live on the organization (Organization.logo); without this field covers and sections draw the primary organization's full logo and picture bullets its icon. A logo reference overrides that: 'var:organization.beta.logo' draws organization beta's logo, and a reference that names a shape ('var:organization.logo.wordmark') draws that shape everywhere this field applies. false draws no logo. A slide's design.logo overrides the deck's; absence inherits. An override naming an organization without a logo draws nothing (validation warns). Placement (reference engines, vetoable): on a cover or section slide (no body payload on a heading-only layout such as title, title-subtitle or section-divider, or no layout) the logo is drawn at the top-left of the free area, inside the slide padding and below any header furniture, in a box 56 reference pixels tall and at most four times as wide; the tag/title/subtitle group then centers in the remaining span. Content slides never get an automatic logo; a header or footer zone places one with image: 'var:organization.logo.icon'. composeSlide returns the cover box as geometry.logo.",
          "examples": [
            "var:organization.logo.wordmark",
            "var:organization.beta.logo",
            false
          ]
        },
        "watermark": {
          "oneOf": [
            {
              "type": "boolean",
              "const": false
            },
            {
              "$ref": "#/$defs/Asset"
            },
            {
              "$ref": "#/$defs/Watermark"
            }
          ],
          "description": "Optional decorative watermark applied across slides: an image or a text stamp, in the fixed frame and at the opacity described on Watermark. Use false to suppress an inherited watermark in slide-level design; a string or Asset is the image at opacity 0.08.",
          "examples": [
            false,
            "asset:watermark",
            {
              "src": "asset:watermark",
              "opacity": 0.08
            },
            {
              "text": "DRAFT",
              "opacity": 0.1
            }
          ]
        },
        "header": {
          "oneOf": [
            {
              "type": "boolean",
              "const": false
            },
            {
              "$ref": "#/$defs/HeaderFooter"
            }
          ],
          "description": "Repeated header furniture rendered outside the main slide content. Use false to suppress an inherited header.",
          "examples": [
            false,
            {
              "left": {
                "text": "{{slide.section}}"
              },
              "right": {
                "image": "var:organization.logo.icon"
              }
            }
          ]
        },
        "footer": {
          "oneOf": [
            {
              "type": "boolean",
              "const": false
            },
            {
              "$ref": "#/$defs/HeaderFooter"
            }
          ],
          "description": "Repeated footer furniture rendered outside the main slide content. Use false to suppress an inherited footer.",
          "examples": [
            false,
            {
              "left": {
                "image": "var:organization.logo.icon"
              },
              "center": {
                "text": "Confidential"
              },
              "right": {
                "text": "{{slide.number}}"
              }
            }
          ]
        },
        "titleAlignment": {
          "type": "string",
          "enum": [
            "left",
            "center",
            "right"
          ],
          "description": "Default horizontal alignment for the title heading area (the title and the tag) in resolved layouts. Effective value: the slide's design, then the deck's design, then the theme's design.titleAlignment, then the layout record's design.titleAlignment, then the engine default."
        },
        "contentAlignment": {
          "type": "string",
          "enum": [
            "left",
            "center",
            "right"
          ],
          "description": "Default horizontal alignment for body/content regions in resolved layouts. Effective value: the slide's design, then the deck's design, then the theme's design.contentAlignment, then the layout record's design.contentAlignment, then the engine default. The tag follows titleAlignment (and so does a subtitle in the title area, as on a cover) unless the slide's own design sets contentAlignment."
        },
        "contentBox": {
          "type": "boolean",
          "description": "Whether body/content regions are rendered inside a visible card or surface. Effective value: the slide's design, then the deck's design, then the theme's design.contentBox, then the layout record's design.contentBox, then the engine default."
        },
        "contentDirection": {
          "type": "string",
          "enum": [
            "horizontal",
            "vertical"
          ],
          "description": "Axis along which parallel body content is arranged: 'vertical' is a column, 'horizontal' a row. Effective value: the slide's design, then the deck's design, then the theme's design.contentDirection, then the layout record's design.contentDirection. On a slide with a template layout (OPF 0.19) it turns every flowing region of the slide into one row or one column, below the slide's own composition.mode, columns and weights, which arrange its first primary flowing region. On an automatic slide (and a 0.18 record) it sets the root arrangement mode when no composition.mode is set on the slide or on its layout record. Promoted regions (left, top:left, ...) keep their explicit geometry and nested groups keep their own composition."
        },
        "chartPrimary": {
          "type": "string",
          "enum": [
            "none",
            "top",
            "bottom",
            "left",
            "right"
          ],
          "description": "Where the primary chart sits relative to supporting content. Effective value: slide design, then deck design, then the layout record's design.chartPrimary. It applies to automatic slides only; a template layout says the same with its regions (chart-beside). When the slide has no promoted regions and no composition.mode of its own, and its root nodes mix at least one chart with other content, the first chart becomes a primary track and the other nodes form one synthetic sub-grid: 'left'/'right' is a two-track row and 'top'/'bottom' a two-track column, weighted 3:2 in favor of the chart; explicit root columns and weights are ignored while it applies. 'none' (the default) keeps the ordinary automatic grid with equal weight. Automatic composition builds direct content groups; template regions remain authoritative."
        },
        "imageFit": {
          "type": "string",
          "enum": [
            "cover",
            "contain",
            "stretch"
          ],
          "description": "Default fit of image blocks (and Slide.image) that set no fit of their own: 'cover' fills the frame and crops what overflows around the block's focus, 'contain' shows the whole picture in a frame of its own proportions, centered across and placed down the cell by the region's anchor (top by default), 'stretch' scales it to the frame exactly. Effective value: the slide's design, then the deck's design, then the theme's design.imageFit, then the layout record's design.imageFit, then 'cover'; a slide composed with no layout shows its pictures whole ('contain') instead. Backgrounds set their own fit."
        },
        "listBullet": {
          "type": "string",
          "enum": [
            "character",
            "image",
            "none"
          ],
          "description": "Marker style for items and bullets lists. Effective value: the slide's design, then the deck's design, then the theme's design.listBullet, then the layout record's design.listBullet, then 'character'. 'character' (the default) draws the glyph marker. 'image' draws the primary organization's icon logo (or the organization and shape design.logo names; the onDark value on dark backgrounds) as a picture bullet: a square with side 0.65 times the marker's font size whose bottom sits on the marker baseline, so list geometry does not change. Without a logo the glyph is drawn and the engine reports unresolved-content at this field. 'none' draws no marker and no hanging indent, so each entry's text (and its description) starts at the left edge of the list: use it for label-and-description lists such as pillars, team members and questions with answers. Nested levels keep their indent. A list that sets numbering still draws its numbers."
        },
        "mirror": {
          "type": "boolean",
          "description": "Draw the slide's template layout mirrored (OPF 0.19): each row's cells and the column sizes reversed, so a 'beside' layout puts its picture, chart or table at the end. Logical: a right-to-left deck mirrors on top. Binding and reading order do not change. Effective value: the slide's design, then the deck's design, then the layout record's design.mirror, then false. Slides without a template layout ignore it."
        }
      }
    },
    "ColorScheme": {
      "type": "object",
      "description": "Color palette used by the design system. Every slot and role is a hex color ('#RGB', '#RRGGBB' or '#RRGGBBAA'); a color-scheme name or a 'var:<id>' reference is not valid here, because those resolve through the scheme. The slot fields (accent1-accent6, dark1, dark2, light1, light2, hyperlink, followedHyperlink) mirror color-scheme.schema.json (https://openpresentation.org/schema/opf-color-scheme/v1) so library records and inline OPF overrides are interchangeable on those fields.\n\nTwo parallel models are supported and may be mixed:\n- OOXML slots - the 12-slot PowerPoint theme model that round-trips directly to OOXML. Use these for full control over the palette as PowerPoint sees it.\n- Abstract roles (primary, secondary, accent, background, surface, text, textSecondary) - OPF-specific semantic aliases the engine maps onto the OOXML slots. Convenient for inline overrides without thinking in slot numbers; not part of the catalog record schema.\n\nIn design.colorScheme, 'id' resolves a colorSchemes record as the base; slot and role overrides on the same object take precedence over the resolved scheme. The string form of design.colorScheme is equivalent to setting only 'id'.",
      "properties": {
        "id": {
          "$ref": "#/$defs/CatalogReference",
          "description": "Colour-scheme reference (a bare id or 'name:id') resolved as the base; slot and role overrides on the surrounding ColorScheme object take precedence over the resolved scheme.",
          "examples": [
            "cool-horizon",
            "boost",
            "burnt-orange",
            "ocean-depth",
            "corporate-blue"
          ]
        },
        "accent1": {
          "$ref": "#/$defs/HexColor",
          "description": "Accent 1 color (hex). Mirrors the OOXML accent1 slot.",
          "examples": [
            "#2874A6",
            "#FD3223",
            "#F77F00"
          ]
        },
        "accent2": {
          "$ref": "#/$defs/HexColor",
          "description": "Accent 2 color (hex). Mirrors the OOXML accent2 slot.",
          "examples": [
            "#1B4F72",
            "#0308DB",
            "#D62828"
          ]
        },
        "accent3": {
          "$ref": "#/$defs/HexColor",
          "description": "Accent 3 color (hex). Mirrors the OOXML accent3 slot.",
          "examples": [
            "#5499C7",
            "#4F4955",
            "#003049"
          ]
        },
        "accent4": {
          "$ref": "#/$defs/HexColor",
          "description": "Accent 4 color (hex). Mirrors the OOXML accent4 slot.",
          "examples": [
            "#7BDBB2",
            "#A1DB30",
            "#FCBF49"
          ]
        },
        "accent5": {
          "$ref": "#/$defs/HexColor",
          "description": "Accent 5 color (hex). Mirrors the OOXML accent5 slot.",
          "examples": [
            "#3AC67A",
            "#0682FE",
            "#EAE2B7"
          ]
        },
        "accent6": {
          "$ref": "#/$defs/HexColor",
          "description": "Accent 6 color (hex). Mirrors the OOXML accent6 slot.",
          "examples": [
            "#24A89E",
            "#FC03BE",
            "#BFBFBF"
          ]
        },
        "dark1": {
          "$ref": "#/$defs/HexColor",
          "description": "Dark 1 color (hex). Typically the deepest neutral; OOXML dark1.",
          "examples": [
            "#000000"
          ]
        },
        "dark2": {
          "$ref": "#/$defs/HexColor",
          "description": "Dark 2 color (hex). Secondary dark; OOXML dark2.",
          "examples": [
            "#011842",
            "#2C2C2C"
          ]
        },
        "light1": {
          "$ref": "#/$defs/HexColor",
          "description": "Light 1 color (hex). Typically the slide canvas; OOXML lt1.",
          "examples": [
            "#FFFFFF"
          ]
        },
        "light2": {
          "$ref": "#/$defs/HexColor",
          "description": "Light 2 color (hex). Secondary light surface; OOXML lt2.",
          "examples": [
            "#F0F0F0",
            "#F3F7FF"
          ]
        },
        "hyperlink": {
          "$ref": "#/$defs/HexColor",
          "description": "Hyperlink color (hex). OOXML hlink. Link runs with no color of their own are drawn underlined in it, in the preview and in PowerPoint, unless it has under 4.5:1 contrast against the slide background, then in the slide text color.",
          "examples": [
            "#0563C1",
            "#0066CC"
          ]
        },
        "followedHyperlink": {
          "$ref": "#/$defs/HexColor",
          "description": "Followed-hyperlink color (hex). OOXML folHlink.",
          "examples": [
            "#954F72",
            "#551A8B"
          ]
        },
        "primary": {
          "$ref": "#/$defs/HexColor",
          "description": "Abstract role: primary brand color (hex). The engine maps this onto an OOXML accent slot when serializing.",
          "examples": [
            "#1E40AF",
            "#0F172A"
          ]
        },
        "secondary": {
          "$ref": "#/$defs/HexColor",
          "description": "Abstract role: secondary brand color (hex).",
          "examples": [
            "#3B82F6",
            "#64748B"
          ]
        },
        "accent": {
          "$ref": "#/$defs/HexColor",
          "description": "Abstract role: accent color used for highlights and emphasis (hex).",
          "examples": [
            "#F59E0B",
            "#22D3EE"
          ]
        },
        "background": {
          "$ref": "#/$defs/HexColor",
          "description": "Abstract role: default slide background color (hex), used when the design names no single-color background (and for gradient and picture backgrounds). Overrides light1 as that default.",
          "examples": [
            "#FFFFFF",
            "#0B1220"
          ]
        },
        "surface": {
          "$ref": "#/$defs/HexColor",
          "description": "Abstract role: color for elevated surfaces such as cards and panels (hex). Overrides the default of light2 (dark2 on a dark slide).",
          "examples": [
            "#F8FAFC",
            "#1E293B"
          ]
        },
        "text": {
          "$ref": "#/$defs/HexColor",
          "description": "Abstract role: primary body text color (hex). Overrides dark1 on a light slide only; a dark slide always uses light1.",
          "examples": [
            "#0F172A",
            "#F8FAFC"
          ]
        },
        "textSecondary": {
          "$ref": "#/$defs/HexColor",
          "description": "Abstract role: secondary or muted text color used for captions and supporting copy (hex). Overrides the default of dark2 (light2 on a dark slide).",
          "examples": [
            "#475569",
            "#94A3B8"
          ]
        }
      }
    },
    "FontScheme": {
      "type": "object",
      "description": "Typography selections used by the design system. The pair fields (major, minor) and refinement fields (type, app, languageFamily) mirror font-scheme.schema.json (https://openpresentation.org/schema/opf-font-scheme/v1) so library records and inline OPF overrides are interchangeable on those fields.\n\nTwo parallel models are supported and may be mixed:\n- OOXML pairs (major, minor) - heading and body family names that round-trip directly to PowerPoint majorFont/minorFont entries.\n- Abstract roles (heading, body, accent, code) - OPF-specific font family names the engine maps onto the OOXML pair when serializing. Convenient for inline overrides and for adding accent/code roles that don't have a direct OOXML slot. Catalog records may also carry 'code' (for example the consolas and courier-new records); heading, body and accent are not part of the catalog record schema. A role is a family name only: weight, style and tracking come from the text styles, and PowerPoint has no numeric weight.\n\nIn design.fontScheme, 'id' resolves a fontSchemes record as the base; pair and role overrides on the same object take precedence over the resolved scheme. The string form of design.fontScheme is equivalent to setting only 'id'.",
      "properties": {
        "id": {
          "$ref": "#/$defs/CatalogReference",
          "description": "Font-scheme reference (a bare id or 'name:id') resolved as the base; field overrides on the surrounding FontScheme object take precedence over the resolved scheme.",
          "examples": [
            "aptos",
            "tenorite",
            "seaford",
            "noto-sans",
            "modern-sans",
            "classic-serif"
          ]
        },
        "major": {
          "type": "string",
          "description": "Heading (major) font family — mirrors the OOXML majorFont entry. Pairs with 'minor'.",
          "examples": [
            "Aptos Display",
            "Calibri",
            "Microsoft YaHei",
            "Arial Black"
          ]
        },
        "minor": {
          "type": "string",
          "description": "Body (minor) font family — mirrors the OOXML minorFont entry. Pairs with 'major'.",
          "examples": [
            "Aptos",
            "Calibri",
            "Microsoft YaHei",
            "Arial"
          ]
        },
        "eastAsian": {
          "type": "object",
          "additionalProperties": false,
          "minProperties": 1,
          "description": "East Asian script fonts. Maps to the OOXML a:ea element of majorFont (major) and minorFont (minor), and to run-level a:ea. When set, they fill the eastAsian slot for every language; when omitted, the slot comes from this scheme's own major/minor when languageFamily is 'ea' and the scheme's languages list is empty or names the presentation language, then from the presentation language's font scheme for East Asian languages, and otherwise from the latin (major/minor) families. A missing 'major' or 'minor' falls back to the other.",
          "properties": {
            "major": {
              "type": "string",
              "description": "Heading (major) eastAsian font family — mirrors majorFont a:ea.",
              "examples": [
                "Noto Sans JP",
                "Meiryo",
                "Microsoft YaHei"
              ]
            },
            "minor": {
              "type": "string",
              "description": "Body (minor) eastAsian font family — mirrors minorFont a:ea.",
              "examples": [
                "Noto Sans JP",
                "Meiryo",
                "Microsoft YaHei"
              ]
            }
          }
        },
        "complexScript": {
          "type": "object",
          "additionalProperties": false,
          "minProperties": 1,
          "description": "Complex-script fonts (for example Arabic, Hebrew, Indic and Thai). Maps to the OOXML a:cs element of majorFont (major) and minorFont (minor), and to run-level a:cs. When set, they fill the complexScript slot for every language; when omitted, the slot comes from this scheme's own major/minor when languageFamily is 'cs' and the scheme's languages list is empty or names the presentation language, then from the presentation language's font scheme for complex-script languages, and otherwise from the latin (major/minor) families. A missing 'major' or 'minor' falls back to the other.",
          "properties": {
            "major": {
              "type": "string",
              "description": "Heading (major) complexScript font family — mirrors majorFont a:cs.",
              "examples": [
                "Noto Sans Arabic",
                "Arial",
                "Mangal"
              ]
            },
            "minor": {
              "type": "string",
              "description": "Body (minor) complexScript font family — mirrors minorFont a:cs.",
              "examples": [
                "Noto Sans Arabic",
                "Arial",
                "Mangal"
              ]
            }
          }
        },
        "type": {
          "type": "string",
          "enum": [
            "sans-serif",
            "serif",
            "monospace"
          ],
          "description": "High-level typographic class of the scheme."
        },
        "app": {
          "type": "string",
          "enum": [
            "powerpoint",
            "google-slides"
          ],
          "description": "Target application this font pairing is intended for. Metadata for pickers and catalog filters: no engine changes its output by it."
        },
        "languageFamily": {
          "type": "string",
          "enum": [
            "latin",
            "ea",
            "cs",
            "eastAsian",
            "complexScript"
          ],
          "description": "Font-language family this scheme is intended for: 'latin' for Latin-script content, 'ea' (or 'eastAsian', the same value) for East Asian scripts, 'cs' (or 'complexScript', the same value) for Complex Scripts. The long names match the 'eastAsian' and 'complexScript' slot keys; the short names match the OOXML a:ea and a:cs elements; core reads both spellings as one value. As the design font scheme, an 'ea'/'eastAsian' or 'cs'/'complexScript' scheme also fills that script slot with its own major/minor families when its languages list is empty or names the presentation language."
        },
        "heading": {
          "type": "string",
          "description": "Abstract role: font family name used for slide titles and headings. Maps onto the OOXML major slot when serializing."
        },
        "body": {
          "type": "string",
          "description": "Abstract role: font family name used for body copy. Maps onto the OOXML minor slot when serializing."
        },
        "accent": {
          "type": "string",
          "description": "Abstract role: font family name used for accent text. When set, the slide tag (eyebrow) and the quote body use this family instead of the body and heading families; nothing else changes. resolveFontFamilies() returns it as accent only when the scheme defines it. No direct OOXML slot: PPTX export writes it on those runs, and the theme fonts stay major/minor."
        },
        "code": {
          "type": "string",
          "description": "Abstract role: monospaced font family name used for code blocks and for inline code runs (TextRun.code). No direct OOXML slot. Resolution: this override, then the resolved font-scheme record's 'code' (for example Consolas for the consolas scheme), then the engine fallback Roboto Mono. Heading and body families are never used as the code fallback."
        }
      }
    },
    "SlideDesign": {
      "description": "A slide's design: every Design field except dimensions. A PPTX has one slide size, so the size is set once, on the deck's design.dimensions (or its theme), and a slide's design cannot set it. A slide-level theme whose resolved dimensions differ from the deck's is a validate warning (opf/slide-theme-dimensions); exporting such a deck to PPTX fails with mixed-slide-dimensions.",
      "allOf": [
        {
          "$ref": "#/$defs/Design"
        },
        {
          "not": {
            "required": [
              "dimensions"
            ]
          }
        }
      ]
    },
    "DimensionPreset": {
      "type": "string",
      "enum": [
        "16:9",
        "4:3",
        "16:10",
        "1:1",
        "4:5",
        "9:16",
        "letter",
        "a4",
        "widescreen",
        "standard"
      ],
      "description": "Named preset; sets aspect ratio and physical size. 16:9 ('widescreen'): 13.333 x 7.5 in, PowerPoint's Widescreen. 4:3 ('standard'): 10 x 7.5 in. 16:10: 10 x 6.25 in. letter (11 x 8.5 in) and a4 (11.69 x 8.27 in) are paper sizes, not PowerPoint's Letter Paper or A4 Paper. 1:1, 4:5 and 9:16 are 7.5 in on the short edge."
    },
    "Dimensions": {
      "type": "object",
      "description": "Slide dimensions: a preset, or custom inches that override it. PowerPoint's Letter Paper (10 x 7.5 in), A4 Paper (10.8333 x 7.5 in) and On-screen Show (16:9) (10 x 5.625 in) are not OPF presets; use widthInches and heightInches. docs/slide-sizes.md compares every preset.",
      "properties": {
        "preset": {
          "$ref": "#/$defs/DimensionPreset"
        },
        "widthInches": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Custom slide width in inches; overrides the preset width when provided."
        },
        "heightInches": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Custom slide height in inches; overrides the preset height when provided."
        }
      }
    },
    "ThemeBackgroundSlot": {
      "type": "string",
      "description": "PowerPoint theme-controlled slide background slot from the active color scheme. These are slots, not assumptions about actual colors: light1 is usually white and dark1 is usually black by convention, but the color scheme controls the real values.",
      "enum": [
        "light1",
        "light2",
        "dark1",
        "dark2"
      ]
    },
    "HexColor": {
      "type": "string",
      "pattern": "^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$",
      "description": "Hex color shorthand accepted by selected string fields.",
      "examples": [
        "#fff",
        "#ffff00",
        "#0F172AFF"
      ]
    },
    "ColorRef": {
      "anyOf": [
        {
          "$ref": "#/$defs/HexColor"
        },
        {
          "type": "string",
          "enum": [
            "accent1",
            "accent2",
            "accent3",
            "accent4",
            "accent5",
            "accent6",
            "dark1",
            "dark2",
            "light1",
            "light2",
            "hyperlink",
            "followedHyperlink",
            "primary",
            "secondary",
            "accent",
            "background",
            "surface",
            "surfaceAlt",
            "text",
            "textSecondary"
          ]
        },
        {
          "type": "string",
          "pattern": "^var:[a-z][a-z0-9-]*$"
        }
      ],
      "description": "A color value or reference, enforced on styled table cell fill and text colors, cell border colors, solid background colors, gradient stop colors and pattern foreground and background colors. Three forms:\n- Literal hex: '#RGB', '#RRGGBB', or '#RRGGBBAA'.\n- Color-scheme name, resolved through the effective color scheme after design resolution: an OOXML slot ('accent1'-'accent6', 'dark1', 'dark2', 'light1', 'light2', 'hyperlink', 'followedHyperlink') or an abstract role ('primary', 'secondary', 'accent', 'background', 'surface', 'surfaceAlt', 'text', 'textSecondary'). Roles resolve through the same role-to-slot mapping engines already apply to color schemes. 'surfaceAlt' has no slot: it is the alternate surface of banded table rows, derived from 'surface' and 'text' (the surface mixed a tenth of the way towards the text color, further when needed, so it always differs visibly from 'surface' and keeps 4.5:1 text contrast; core surfaceAltColor).\n- Variable reference: 'var:<id>' into the top-level variables map.\n\nNames keep content theme-portable: re-theming the deck updates every named reference, where a literal hex stays frozen. Unknown 'var:' ids produce a validation warning, never an error, and engines fall back to their default text color. TextRun.color documents the same three forms but remains an open string so imported decks with unrecognized run colors stay valid; validators warn there instead of erroring.",
      "examples": [
        "#0F4C81",
        "accent2",
        "text",
        "var:risk"
      ]
    },
    "Variables": {
      "type": "object",
      "propertyNames": {
        "pattern": "^[a-z][a-z0-9-]*$"
      },
      "additionalProperties": {
        "$ref": "#/$defs/Variable"
      },
      "description": "Named variables, keyed by stable kebab-case id. A variable is a typed, named value the deck declares once and uses in many places: a color ('var:<id>' in color fields, the original use), or content that fills a template (text, number, date, image, url, list). Content is referenced inline as '{{<id>}}' inside any string, or whole as 'var:<id>' in a field of the matching type; '\\{{' writes a literal '{{'. A hex string is shorthand for a color variable. A variable with no 'value' is unfilled: expected in a template (root 'template': true), an error in a normal deck. Engines resolve variables with resolveVariables() before composing, rendering or exporting, so a template plus its values previews and exports exactly like the equivalent hand-written deck. Read-only built-in variables come from the deck's own metadata and use dotted names that a user id can never take: 'deck.name', 'deck.description', 'deck.author', 'speaker.name|title|email|phone|bio|photo' (first speaker), 'speakers' (every speaker's name, a list), 'organization.name|legalName|tagline|domain|email|phone' (primary organization), and 'speaker.<id>.<field>' / 'organization.<id>.<field>' by id. They are written the same two ways ('{{speaker.name}}', 'var:speaker.photo'), are never declared, and an unknown built-in path is a validation error; a known one with no source value resolves to nothing with a warning. The id 'speakers' is reserved. Three built-ins are slide-scoped and written only as inline tokens: '{{slide.number}}' (the displayed slide number after pagination), '{{slide.section}}' (the slide's section) and '{{deck.slideCount}}' (the number of slides after pagination). resolveVariables() leaves them as written; they resolve per slide as it is composed (resolveSlideVariables(), and header/footer text in layoutFurniture()), so every 'slide.' name is reserved and 'var:slide.*' or 'var:deck.slideCount' is a validation error. Organization logos are slide-scoped whole-field images: 'var:organization.logo', 'var:organization.logo.<shape>' (full, stacked, icon, wordmark), 'var:organization.<id>.logo' and 'var:organization.<id>.logo.<shape>' resolve per slide to the onLight or onDark asset for its background. See docs/templates-and-variables.md.",
      "examples": [
        {
          "risk": "#B42318",
          "highlight": {
            "type": "color",
            "value": "#0F4C81",
            "description": "Brand highlight for emphasized runs."
          }
        },
        {
          "client-name": {
            "type": "text",
            "example": "Acme Corp",
            "description": "Customer the deck is for."
          },
          "revenue": {
            "type": "number",
            "example": 1250000,
            "format": "$#,##0"
          },
          "review-date": {
            "type": "date",
            "example": "2026-10-01"
          }
        }
      ]
    },
    "Variable": {
      "oneOf": [
        {
          "$ref": "#/$defs/HexColor"
        },
        {
          "$ref": "#/$defs/ColorVariable"
        },
        {
          "$ref": "#/$defs/TextVariable"
        },
        {
          "$ref": "#/$defs/NumberVariable"
        },
        {
          "$ref": "#/$defs/DateVariable"
        },
        {
          "$ref": "#/$defs/ImageVariable"
        },
        {
          "$ref": "#/$defs/UrlVariable"
        },
        {
          "$ref": "#/$defs/ListVariable"
        }
      ],
      "description": "A single named variable: a hex string (shorthand for a color variable) or an object whose 'type' is color, text, number, date, image, url or list. 'value' is the current value and is optional: a variable with no value is unfilled, which a template allows and a normal deck does not. 'example' only illustrates the slot (fill forms, template previews) and never reaches output.",
      "examples": [
        "#B42318",
        {
          "type": "color",
          "value": "#B42318",
          "description": "Risk emphasis."
        },
        {
          "type": "text",
          "example": "Acme Corp"
        },
        {
          "type": "list",
          "value": [
            "Faster",
            "Cheaper"
          ]
        }
      ]
    },
    "ColorVariable": {
      "type": "object",
      "required": [
        "type"
      ],
      "additionalProperties": false,
      "properties": {
        "type": {
          "type": "string",
          "const": "color",
          "description": "Variable kind. One of color, text, number, date, image, url or list."
        },
        "value": {
          "$ref": "#/$defs/HexColor",
          "description": "Hex color this variable resolves to."
        },
        "required": {
          "type": "boolean",
          "default": true,
          "description": "Whether the variable must be filled. Defaults to true: a variable with no 'value' is unfilled, and an unfilled required variable is an error in a normal deck and expected in a template. Set false for an optional slot: an unfilled optional variable resolves to empty text (inline tokens) or the field that references it is omitted."
        },
        "label": {
          "type": "string",
          "description": "Optional short human label for forms and fill panels."
        },
        "description": {
          "type": "string",
          "description": "Optional prose describing what the variable is for, surfaced by pickers, fill forms and agents."
        },
        "example": {
          "$ref": "#/$defs/HexColor",
          "description": "Illustrative color shown in fill forms and used when a template is previewed with examples. Never written to output."
        }
      },
      "description": "A named color. Content color fields reference it as 'var:<id>'. Colors resolve at render time through the ordinary color-reference path, so a color variable keeps working as before."
    },
    "TextVariable": {
      "type": "object",
      "required": [
        "type"
      ],
      "additionalProperties": false,
      "properties": {
        "type": {
          "type": "string",
          "const": "text",
          "description": "Variable kind. One of color, text, number, date, image, url or list."
        },
        "value": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "array",
              "items": {
                "$ref": "#/$defs/TextRun"
              }
            }
          ],
          "description": "Text this variable resolves to: a plain string, or TextRun[] for rich text."
        },
        "required": {
          "type": "boolean",
          "default": true,
          "description": "Whether the variable must be filled. Defaults to true: a variable with no 'value' is unfilled, and an unfilled required variable is an error in a normal deck and expected in a template. Set false for an optional slot: an unfilled optional variable resolves to empty text (inline tokens) or the field that references it is omitted."
        },
        "label": {
          "type": "string",
          "description": "Optional short human label for forms and fill panels."
        },
        "description": {
          "type": "string",
          "description": "Optional prose describing what the variable is for, surfaced by pickers, fill forms and agents."
        },
        "example": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "array",
              "items": {
                "$ref": "#/$defs/TextRun"
              }
            }
          ],
          "description": "Illustrative text shown in fill forms and used when a template is previewed with examples. Never written to output."
        }
      },
      "description": "Text content. Plain string or rich TextRun[]. Insert it inline as '{{<id>}}' inside any string (rich text is flattened to plain text there), or reference it whole as 'var:<id>' in a field that accepts string or TextRun[] (the rich runs are kept)."
    },
    "NumberVariable": {
      "type": "object",
      "required": [
        "type"
      ],
      "additionalProperties": false,
      "properties": {
        "type": {
          "type": "string",
          "const": "number",
          "description": "Variable kind. One of color, text, number, date, image, url or list."
        },
        "value": {
          "type": "number",
          "description": "Number this variable resolves to."
        },
        "required": {
          "type": "boolean",
          "default": true,
          "description": "Whether the variable must be filled. Defaults to true: a variable with no 'value' is unfilled, and an unfilled required variable is an error in a normal deck and expected in a template. Set false for an optional slot: an unfilled optional variable resolves to empty text (inline tokens) or the field that references it is omitted."
        },
        "label": {
          "type": "string",
          "description": "Optional short human label for forms and fill panels."
        },
        "description": {
          "type": "string",
          "description": "Optional prose describing what the variable is for, surfaced by pickers, fill forms and agents."
        },
        "example": {
          "type": "number",
          "description": "Illustrative number shown in fill forms and used when a template is previewed with examples. Never written to output."
        },
        "format": {
          "$ref": "#/$defs/NumberFormat",
          "description": "Display pattern used by '{{<id>}}' (the shared NumberFormat syntax). A literal prefix, a numeric part of '#', '0', ',' and '.', and a literal suffix. '0' pads digits, '#' is optional, ',' groups thousands, digits after '.' fix the decimals ('0' required, '#' optional), and a '%' in the suffix scales by 100. English separators only. Absent: the shortest decimal form."
        }
      },
      "description": "A number. '{{<id>}}' inserts it as text using 'format'; 'var:<id>' as a whole field supplies the number itself (chart values, font sizes)."
    },
    "NumberFormat": {
      "type": "string",
      "description": "Number display pattern, shared by NumberVariable.format, data column formats (DataColumn.format) and table cell formats (StyledTableCell.format). An optional literal prefix, a numeric part of '#', '0', ',' and '.', and an optional literal suffix. '0' pads digits, '#' is optional, ',' groups thousands, digits after '.' fix the decimals ('0' required, '#' optional), and a '%' in the prefix or suffix multiplies the value by 100. English separators only. A format applies only to number values; strings, booleans, null and rich runs display unchanged. A column or cell format that is not a valid pattern is a 'number-format-invalid' error. The PPTX export writes it as the equivalent Excel number format code.",
      "examples": [
        "#,##0",
        "0.0",
        "$#,##0.00",
        "0.#%",
        "0%",
        "#,##0.0M",
        "#,##0 units"
      ]
    },
    "DateVariable": {
      "type": "object",
      "required": [
        "type"
      ],
      "additionalProperties": false,
      "properties": {
        "type": {
          "type": "string",
          "const": "date",
          "description": "Variable kind. One of color, text, number, date, image, url or list."
        },
        "value": {
          "type": "string",
          "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
          "description": "ISO calendar date (YYYY-MM-DD) this variable resolves to."
        },
        "required": {
          "type": "boolean",
          "default": true,
          "description": "Whether the variable must be filled. Defaults to true: a variable with no 'value' is unfilled, and an unfilled required variable is an error in a normal deck and expected in a template. Set false for an optional slot: an unfilled optional variable resolves to empty text (inline tokens) or the field that references it is omitted."
        },
        "label": {
          "type": "string",
          "description": "Optional short human label for forms and fill panels."
        },
        "description": {
          "type": "string",
          "description": "Optional prose describing what the variable is for, surfaced by pickers, fill forms and agents."
        },
        "example": {
          "type": "string",
          "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
          "description": "Illustrative ISO date shown in fill forms and used when a template is previewed with examples. Never written to output."
        },
        "format": {
          "type": "string",
          "description": "Date display pattern, the same LDML-style tokens as header/footer dateFormat: yyyy, yy, MMMM, MMM, MM, M, dd, d, EEEE, EEE and quoted literals. English names. Default 'MMMM d, yyyy'.",
          "examples": [
            "MMMM d, yyyy",
            "dd MMM yyyy",
            "M/d/yyyy",
            "EEEE, MMMM d"
          ]
        }
      },
      "description": "A calendar date as an ISO YYYY-MM-DD string. No time zone and no clock are involved. '{{<id>}}' inserts it formatted with 'format'."
    },
    "ImageVariable": {
      "type": "object",
      "required": [
        "type"
      ],
      "additionalProperties": false,
      "properties": {
        "type": {
          "type": "string",
          "const": "image",
          "description": "Variable kind. One of color, text, number, date, image, url or list."
        },
        "value": {
          "$ref": "#/$defs/Asset",
          "description": "Image source this variable resolves to."
        },
        "required": {
          "type": "boolean",
          "default": true,
          "description": "Whether the variable must be filled. Defaults to true: a variable with no 'value' is unfilled, and an unfilled required variable is an error in a normal deck and expected in a template. Set false for an optional slot: an unfilled optional variable resolves to empty text (inline tokens) or the field that references it is omitted."
        },
        "label": {
          "type": "string",
          "description": "Optional short human label for forms and fill panels."
        },
        "description": {
          "type": "string",
          "description": "Optional prose describing what the variable is for, surfaced by pickers, fill forms and agents."
        },
        "example": {
          "$ref": "#/$defs/Asset",
          "description": "Illustrative image source shown in fill forms and used when a template is previewed with examples. Never written to output."
        }
      },
      "description": "An image source: any Asset (an 'asset:<id>' reference, HTTPS URL, data URI, relative or local path, or an object with src, alt and metadata). Reference it whole as 'var:<id>' in an image, asset or src field; '{{<id>}}' inserts the source string."
    },
    "UrlVariable": {
      "type": "object",
      "required": [
        "type"
      ],
      "additionalProperties": false,
      "properties": {
        "type": {
          "type": "string",
          "const": "url",
          "description": "Variable kind. One of color, text, number, date, image, url or list."
        },
        "value": {
          "type": "string",
          "pattern": "^(?:https?://|mailto:|tel:)\\S+$",
          "description": "Link target this variable resolves to."
        },
        "required": {
          "type": "boolean",
          "default": true,
          "description": "Whether the variable must be filled. Defaults to true: a variable with no 'value' is unfilled, and an unfilled required variable is an error in a normal deck and expected in a template. Set false for an optional slot: an unfilled optional variable resolves to empty text (inline tokens) or the field that references it is omitted."
        },
        "label": {
          "type": "string",
          "description": "Optional short human label for forms and fill panels."
        },
        "description": {
          "type": "string",
          "description": "Optional prose describing what the variable is for, surfaced by pickers, fill forms and agents."
        },
        "example": {
          "type": "string",
          "pattern": "^(?:https?://|mailto:|tel:)\\S+$",
          "description": "Illustrative link shown in fill forms and used when a template is previewed with examples. Never written to output."
        }
      },
      "description": "A link target (http, https, mailto or tel). Use it as '{{<id>}}' inside a link string or reference it whole as 'var:<id>' in a link field."
    },
    "ListVariable": {
      "type": "object",
      "required": [
        "type"
      ],
      "additionalProperties": false,
      "properties": {
        "type": {
          "type": "string",
          "const": "list",
          "description": "Variable kind. One of color, text, number, date, image, url or list."
        },
        "value": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Entries this variable resolves to."
        },
        "required": {
          "type": "boolean",
          "default": true,
          "description": "Whether the variable must be filled. Defaults to true: a variable with no 'value' is unfilled, and an unfilled required variable is an error in a normal deck and expected in a template. Set false for an optional slot: an unfilled optional variable resolves to empty text (inline tokens) or the field that references it is omitted."
        },
        "label": {
          "type": "string",
          "description": "Optional short human label for forms and fill panels."
        },
        "description": {
          "type": "string",
          "description": "Optional prose describing what the variable is for, surfaced by pickers, fill forms and agents."
        },
        "example": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Illustrative entries shown in fill forms and used when a template is previewed with examples. Never written to output."
        }
      },
      "description": "A list of strings, for bullets and list items. A whole-string array element 'var:<id>' splices every entry into the array in place; a whole field 'var:<id>' becomes the array; '{{<id>}}' joins the entries with ', ' (or the separator after a pipe: '{{<id>|; }}')."
    },
    "BackgroundShortcut": {
      "oneOf": [
        {
          "$ref": "#/$defs/ThemeBackgroundSlot"
        },
        {
          "$ref": "#/$defs/HexColor"
        },
        {
          "$ref": "#/$defs/ImageSource"
        }
      ],
      "description": "String shorthand for a background. Theme slots ('light1', 'light2', 'dark1', 'dark2') are equivalent to { type: 'theme', slot: value }; hex colors are equivalent to { type: 'solid', color: value }; an image source (starting with 'asset:', 'https://', 'data:', './' or '../') is equivalent to { type: 'image', src: value }, a cover image. Any other string is invalid.",
      "examples": [
        "dark1",
        "light2",
        "#ffff00",
        "asset:cover-photo",
        "./images/harbour.jpg"
      ]
    },
    "ImageSource": {
      "type": "string",
      "pattern": "^(asset:|https://|data:|\\./|\\.\\./)",
      "description": "An image source in a string shorthand: an 'asset:<id>' reference, an HTTPS URL, a data URI, or a relative path starting with './' or '../' (resolved against the OPF file location).",
      "examples": [
        "asset:cover-photo",
        "https://cdn.acme.com/backgrounds/cover.jpg",
        "./images/harbour.jpg"
      ]
    },
    "ColorVariant": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "background"
      ],
      "description": "A variant of the deck's single color scheme, as a mapping over its twelve slots (PowerPoint's clrMap): 'background' is the slot the slide background and the role bg1 take, and with it the other roles: light1 maps bg1 = light1, tx1 = dark1, bg2 = light2, tx2 = dark2; dark1 maps bg1 = dark1, tx1 = light1, bg2 = dark2, tx2 = light2; light2 and dark2 make that slot both the background and the alternate surface (light2: bg1 = bg2 = light2, tx1 = dark1, tx2 = dark2; dark2: bg1 = bg2 = dark2, tx1 = light1, tx2 = light2), which is how a slide with that theme background has always been drawn. Text, secondary text, the card surface and every neutral (borders, gridlines, chart axis, code panel) follow the map. The PowerPoint export writes it as the master's clrMap, or a slide's clrMapOvr.",
      "properties": {
        "background": {
          "$ref": "#/$defs/ThemeBackgroundSlot",
          "description": "The scheme slot that is the background (bg1) of the variant."
        },
        "accents": {
          "type": "array",
          "minItems": 6,
          "maxItems": 6,
          "uniqueItems": true,
          "items": {
            "type": "string",
            "enum": [
              "accent1",
              "accent2",
              "accent3",
              "accent4",
              "accent5",
              "accent6"
            ]
          },
          "description": "Optional accent order: a permutation of accent1 to accent6. Entry i is the scheme slot drawn as accent i + 1, so primary, secondary and accent (the first three) and the chart series colors follow it. Default: the scheme's own order.",
          "examples": [
            [
              "accent2",
              "accent1",
              "accent3",
              "accent4",
              "accent5",
              "accent6"
            ]
          ]
        }
      },
      "examples": [
        {
          "background": "dark1"
        },
        {
          "background": "light2",
          "accents": [
            "accent2",
            "accent1",
            "accent3",
            "accent4",
            "accent5",
            "accent6"
          ]
        }
      ]
    },
    "Background": {
      "description": "Background fill applied to slides. Theme backgrounds preserve PowerPoint's color-scheme background choice; other variants represent fixed background fills.",
      "oneOf": [
        {
          "$ref": "#/$defs/ThemeBackground"
        },
        {
          "$ref": "#/$defs/SolidBackground"
        },
        {
          "$ref": "#/$defs/GradientBackground"
        },
        {
          "$ref": "#/$defs/ImageBackground"
        },
        {
          "$ref": "#/$defs/PatternBackground"
        }
      ]
    },
    "ThemeBackground": {
      "type": "object",
      "description": "Theme-controlled PowerPoint slide background. The slot is resolved through the active color scheme and remains theme-aware.",
      "required": [
        "type",
        "slot"
      ],
      "properties": {
        "type": {
          "type": "string",
          "const": "theme",
          "description": "Theme-controlled background fill."
        },
        "slot": {
          "$ref": "#/$defs/ThemeBackgroundSlot"
        }
      }
    },
    "SolidBackground": {
      "type": "object",
      "description": "Fixed solid slide background fill.",
      "required": [
        "type",
        "color"
      ],
      "properties": {
        "type": {
          "type": "string",
          "const": "solid",
          "description": "Fixed solid background fill."
        },
        "color": {
          "$ref": "#/$defs/ColorRef",
          "description": "Fixed solid fill color: a hex string, a color-scheme slot or role name, or a var:<id> variable reference (a ColorRef, resolved against the effective color scheme and the deck variables). Use { type: 'theme', slot: ... } for PowerPoint's four theme-controlled background choices.",
          "examples": [
            "#FFFFFF",
            "#0F172A",
            "#F8FAFC"
          ]
        },
        "opacity": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Background opacity from 0 (fully transparent) to 1 (fully opaque)."
        }
      }
    },
    "GradientBackground": {
      "type": "object",
      "description": "Fixed gradient slide background fill.",
      "required": [
        "type",
        "gradient"
      ],
      "properties": {
        "tone": {
          "type": "string",
          "enum": [
            "dark",
            "light"
          ],
          "description": "Whether the background is dark or light, which picks the color map (dark1 or light1) so text, lines and neutrals read on it. Without a tone a picture or gradient takes the deck's variant, else counts as light."
        },
        "type": {
          "type": "string",
          "const": "gradient",
          "description": "Fixed gradient background fill."
        },
        "gradient": {
          "type": "object",
          "description": "Gradient fill definition.",
          "properties": {
            "angle": {
              "type": "number",
              "description": "Gradient angle in degrees (0 = left-to-right, 90 = top-to-bottom)."
            },
            "stops": {
              "type": "array",
              "minItems": 2,
              "description": "Ordered list of color stops along the gradient. A gradient needs at least two stops.",
              "items": {
                "type": "object",
                "description": "Color stop along the gradient.",
                "required": [
                  "color",
                  "position"
                ],
                "properties": {
                  "color": {
                    "$ref": "#/$defs/ColorRef",
                    "description": "Stop color: a hex string, a color-scheme slot or role name, or a var:<id> variable reference (a ColorRef).",
                    "examples": [
                      "#1E40AF",
                      "#22D3EE"
                    ]
                  },
                  "position": {
                    "type": "number",
                    "minimum": 0,
                    "maximum": 1,
                    "description": "Stop position along the gradient, from 0 (start) to 1 (end)."
                  }
                }
              }
            }
          }
        },
        "opacity": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Background opacity from 0 (fully transparent) to 1 (fully opaque)."
        }
      }
    },
    "ImageBackground": {
      "type": "object",
      "additionalProperties": false,
      "description": "Picture background: the image fills the whole canvas behind everything and never moves content (to push content aside, use an image block with placement). The string shorthand 'asset:x' (or any image source) is { type: 'image', src: 'asset:x' }, a cover image. Paint order: the colour scheme's default slide background, the picture, then the overlay, then furniture and content.",
      "required": [
        "type",
        "src"
      ],
      "properties": {
        "tone": {
          "type": "string",
          "enum": [
            "dark",
            "light"
          ],
          "description": "Whether the background is dark or light, which picks the color map (dark1 or light1) so text, lines and neutrals read on it. Without a tone a picture or gradient takes the deck's variant, else counts as light."
        },
        "type": {
          "type": "string",
          "const": "image",
          "description": "Picture background."
        },
        "src": {
          "type": "string",
          "description": "Source for the background image: an 'asset:<id>' reference, HTTPS URL, data URI, or a relative path resolved against the OPF file location.",
          "examples": [
            "https://cdn.acme.com/backgrounds/cover.jpg",
            "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAA...",
            "./backgrounds/cover.jpg",
            "asset:bg-cover"
          ]
        },
        "alt": {
          "type": "string",
          "description": "Alternative text. A background with alt is meaningful: PowerPoint export draws it as a full-slide picture at the back that carries the text, so screen readers see it. Without alt it is decorative and exports as the native slide background; the alt text of a referenced asset does not count, so a background is decorative unless it says otherwise."
        },
        "fit": {
          "type": "string",
          "enum": [
            "cover",
            "contain",
            "stretch",
            "tile"
          ],
          "description": "How the picture fills the canvas: 'cover' fills it and crops what overflows around focus; 'contain' shows the whole picture centered over the colour scheme's default background; 'stretch' scales it to the canvas exactly; 'tile' repeats it at its own size from the top-left corner. Default 'cover'."
        },
        "focus": {
          "$ref": "#/$defs/ImageFocus",
          "description": "Point of the picture to keep in view when 'cover' crops it. Ignored by the other fits."
        },
        "opacity": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Picture opacity from 0 (fully transparent) to 1 (fully opaque); the overlay keeps its own opacity. Default 1."
        },
        "recolor": {
          "$ref": "#/$defs/ImageRecolor",
          "description": "Grayscale or duotone treatment of the picture's pixels, as on an image block: recolor and opacity apply to the pixels, then the overlay is drawn above."
        },
        "overlay": {
          "$ref": "#/$defs/Overlay",
          "description": "Scrim over the whole picture or a band along one edge (edge, size), beneath furniture and content, for example to keep a title readable over a busy photo."
        }
      },
      "examples": [
        {
          "type": "image",
          "src": "asset:cover-photo"
        },
        {
          "type": "image",
          "src": "./images/harbour.jpg",
          "alt": "Container ships at dawn",
          "focus": {
            "x": 0.5,
            "y": 0.7
          },
          "overlay": {
            "color": "dark1",
            "opacity": 0.4
          }
        }
      ]
    },
    "ImageFocus": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "x",
        "y"
      ],
      "description": "A point of a picture as fractions of its width and height, from the top-left corner. A cover fit centers this point in the frame as far as the picture still covers the frame, so it always stays in view: { x: 0.5, y: 0.5 } (the default) is a center crop, { x: 0, y: 0 } keeps the top-left corner.",
      "properties": {
        "x": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Horizontal position, 0 (left edge) to 1 (right edge)."
        },
        "y": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Vertical position, 0 (top edge) to 1 (bottom edge)."
        }
      },
      "examples": [
        {
          "x": 0.5,
          "y": 0.7
        }
      ]
    },
    "Overlay": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "color",
        "opacity"
      ],
      "description": "Solid scrim over a picture: the whole frame in the frame's shape, or a band along one edge. Shared by image backgrounds and image blocks. Drawn directly above its picture and beneath headings and content; PowerPoint export writes one native shape above the picture.",
      "properties": {
        "color": {
          "$ref": "#/$defs/ColorRef",
          "description": "Overlay fill color: a hex color (eight-digit hex keeps its alpha), a color-scheme slot or role name, or a 'var:<id>' variable reference."
        },
        "opacity": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Overlay fill opacity."
        },
        "edge": {
          "type": "string",
          "enum": [
            "top",
            "bottom",
            "left",
            "right"
          ],
          "description": "Cover only a band along this edge of the frame, for example a caption strip. Backgrounds and rectangle image frames only; on another shape the overlay is not drawn and composition reports unsupported-image-treatment. Omit to cover the whole frame. In a right-to-left deck 'left' and 'right' are the start and end sides."
        },
        "size": {
          "type": "number",
          "minimum": 0.05,
          "maximum": 1,
          "description": "Band share of the frame for an edge overlay. Default 0.3. Ignored without edge."
        }
      },
      "examples": [
        {
          "color": "dark1",
          "opacity": 0.4
        },
        {
          "color": "#000000",
          "opacity": 0.75,
          "edge": "bottom",
          "size": 0.25
        }
      ]
    },
    "ImagePlacement": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "edge"
      ],
      "description": "Bleeds an image block to one edge of the slide: the image takes a band along that edge, edge to edge, and the headings and other content compose in the rest of the slide at the normal padding. Only top-level blocks (slides.N.blocks.I) can be placed, at most one per edge. Template layout regions do not supply image placement; set it on the image block itself. Bands are taken in block order, each spanning the free area left by earlier ones. Placement is the only mechanism that moves content aside; a background never does. A slide whose only body is placed images is composed like a cover: its headings center in the free area. In a right-to-left deck 'left' is the start side, drawn at the right.",
      "properties": {
        "edge": {
          "type": "string",
          "enum": [
            "left",
            "right",
            "top",
            "bottom"
          ],
          "description": "The slide edge the image bleeds to."
        },
        "size": {
          "type": "number",
          "minimum": 0.1,
          "maximum": 0.9,
          "description": "Share of the slide width (left, right) or height (top, bottom) given to the band. Default 0.5."
        },
        "inset": {
          "type": "boolean",
          "description": "Draw the frame inside the slide padding on every side of the band, like a card, instead of edge to edge. Default false."
        }
      },
      "examples": [
        {
          "edge": "left",
          "size": 0.45
        },
        {
          "edge": "right",
          "size": 0.4,
          "inset": true
        }
      ]
    },
    "ImageBorder": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "color",
        "width"
      ],
      "description": "Solid line along the image frame's shape, centered on the outline with a miter join, like a native picture line. A thick dark border on a rounded portrait frame gives a device bezel.",
      "properties": {
        "color": {
          "$ref": "#/$defs/ColorRef",
          "description": "Line color: a hex color, a color-scheme slot or role name, or a 'var:<id>' variable reference."
        },
        "width": {
          "type": "number",
          "minimum": 0,
          "maximum": 64,
          "description": "Line width in reference pixels at a 720-pixel short edge. 0 removes the line."
        }
      }
    },
    "ImageRecolor": {
      "oneOf": [
        {
          "type": "string",
          "const": "grayscale",
          "description": "Replace each pixel with its luminance, exported as native a:grayscl."
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "dark",
            "light"
          ],
          "properties": {
            "dark": {
              "$ref": "#/$defs/ColorRef",
              "description": "Color at luminance 0."
            },
            "light": {
              "$ref": "#/$defs/ColorRef",
              "description": "Color at luminance 1."
            }
          },
          "description": "Duotone: map each pixel's luminance linearly from dark to light, exported as native a:duotone."
        }
      ],
      "description": "Color treatment for the image pixels. Luminance uses Rec. 601 weights (0.299, 0.587, 0.114) on sRGB values."
    },
    "PatternBackground": {
      "type": "object",
      "description": "Fixed pattern slide background fill.",
      "required": [
        "type",
        "pattern"
      ],
      "properties": {
        "type": {
          "type": "string",
          "const": "pattern",
          "description": "Fixed pattern background fill."
        },
        "pattern": {
          "type": "object",
          "description": "Pattern fill definition.",
          "required": [
            "preset"
          ],
          "properties": {
            "preset": {
              "type": "string",
              "description": "Pattern preset or engine-defined pattern id. DrawingML preset names (ECMA-376 ST_PresetPatternVal, for example pct5, ltHorz, wdUpDiag) are portable: PPTX export writes them as native pattern fills and import returns the same name. Engine-defined ids are renderer-specific; the legacy preview id diagStripe remains accepted and exports as wdUpDiag.",
              "examples": [
                "pct5",
                "ltHorz",
                "wdUpDiag"
              ]
            },
            "foregroundColor": {
              "$ref": "#/$defs/ColorRef",
              "description": "Foreground color for the pattern: a hex string, a color-scheme slot or role name, or a var:<id> variable reference (a ColorRef).",
              "examples": [
                "#0F172A"
              ]
            },
            "backgroundColor": {
              "$ref": "#/$defs/ColorRef",
              "description": "Background color behind the pattern: a hex string, a color-scheme slot or role name, or a var:<id> variable reference (a ColorRef).",
              "examples": [
                "#FFFFFF"
              ]
            }
          }
        },
        "opacity": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Background opacity from 0 (fully transparent) to 1 (fully opaque)."
        }
      }
    },
    "OrganizationLogo": {
      "type": "object",
      "description": "An organization's logo in up to four shapes. Each shape is a path or Asset, or { onLight, onDark } for the two backgrounds. A missing shape falls back to full, and full to the first defined of wordmark, stacked and icon; within a shape a missing onLight or onDark uses the other. Shapes are placed with slide-scoped references such as 'var:organization.logo.icon'.",
      "additionalProperties": false,
      "minProperties": 1,
      "properties": {
        "full": {
          "$ref": "#/$defs/LogoSource",
          "description": "The full logo (lockup): mark and name side by side. Drawn on cover and section slides, and placed by 'var:organization.logo'."
        },
        "stacked": {
          "$ref": "#/$defs/LogoSource",
          "description": "The stacked lockup: mark above the name, for portrait or square slots. Placed by 'var:organization.logo.stacked'."
        },
        "icon": {
          "$ref": "#/$defs/LogoSource",
          "description": "The mark or symbol without the name, for tight spaces such as header and footer zones and picture bullets. Placed by 'var:organization.logo.icon'."
        },
        "wordmark": {
          "$ref": "#/$defs/LogoSource",
          "description": "The name set in the brand's lettering, without the mark. Placed by 'var:organization.logo.wordmark'."
        }
      },
      "examples": [
        {
          "full": "./assets/acme-logo.svg",
          "icon": "./assets/acme-mark.svg"
        },
        {
          "full": {
            "onLight": "./assets/acme-logo.svg",
            "onDark": "./assets/acme-logo-white.svg"
          }
        }
      ]
    },
    "LogoSource": {
      "description": "One logo shape: a path or Asset for every background, or { onLight, onDark }. onLight is drawn on light backgrounds (usually dark artwork) and onDark on dark backgrounds (usually light artwork), by each slide's background; a missing one uses the other.",
      "oneOf": [
        {
          "$ref": "#/$defs/Asset"
        },
        {
          "type": "object",
          "additionalProperties": false,
          "minProperties": 1,
          "properties": {
            "onLight": {
              "$ref": "#/$defs/Asset",
              "description": "The logo for light backgrounds, usually dark artwork."
            },
            "onDark": {
              "$ref": "#/$defs/Asset",
              "description": "The logo for dark backgrounds, usually light or white artwork."
            }
          }
        }
      ],
      "examples": [
        "./assets/acme-mark.svg",
        {
          "onLight": "./assets/acme-logo.svg",
          "onDark": "./assets/acme-logo-white.svg"
        }
      ]
    },
    "Watermark": {
      "type": "object",
      "description": "Decorative watermark: an image ('src') or a text stamp ('text'), exactly one of the two, with its opacity. An image is drawn once per slide, contained and centered in a fixed frame (the middle 40% of the slide width and height, from 30% to 70% on each axis). A text watermark is one line of text in the heading font and the theme text color at the given opacity, centered on the slide and rotated 30 degrees counterclockwise (rising to the right), sized to span at most 70% of the slide width and at most 30% of the shorter slide edge in height; it is drawn behind the slide content and above the background. There is no option to move, scale, rotate or tile either form. PPTX export writes one native picture (image) or one native text box (text) per slide with the opacity as alpha, and import restores the watermark. A string or Asset (no opacity) is the image watermark at opacity 0.08. A watermark object needs opacity and exactly one of src and text; use a plain string or Asset for an image at the default opacity. Use design.watermark = false to disable an inherited watermark.",
      "additionalProperties": false,
      "required": [
        "opacity"
      ],
      "oneOf": [
        {
          "required": [
            "src"
          ]
        },
        {
          "required": [
            "text"
          ]
        }
      ],
      "properties": {
        "src": {
          "type": "string",
          "description": "Source for the watermark image: an 'asset:<id>' reference, HTTPS URL, data URI, relative path or local path, as for Asset.src. Exactly one of src and text is set."
        },
        "text": {
          "type": "string",
          "minLength": 1,
          "description": "Text for a text watermark, such as DRAFT or CONFIDENTIAL; line breaks are drawn as spaces. Exactly one of src and text is set.",
          "examples": [
            "DRAFT",
            "CONFIDENTIAL"
          ]
        },
        "opacity": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Watermark opacity from 0 (fully transparent) to 1 (fully opaque)."
        }
      }
    },
    "HeaderFooter": {
      "type": "object",
      "description": "Repeated header or footer content split into left, center, and right zones. Header/footer content is slide furniture, separate from the main slide content payloads.",
      "properties": {
        "left": {
          "$ref": "#/$defs/HeaderFooterItem",
          "description": "Left-aligned header/footer content."
        },
        "center": {
          "$ref": "#/$defs/HeaderFooterItem",
          "description": "Centered header/footer content."
        },
        "right": {
          "$ref": "#/$defs/HeaderFooterItem",
          "description": "Right-aligned header/footer content."
        }
      }
    },
    "HeaderFooterItem": {
      "type": "object",
      "description": "One header/footer zone. Every configured field renders, side by side in one row in the order image, text, socials, date (mirrored in a right-to-left deck), aligned to the zone's edge (left, center or right) and vertically centered on each other; a line break inside text or socials ('\\n') stacks lines within that part. When the parts are wider than the zone their text wraps, and a row that cannot fit even so is reported as overflow. Generated values such as the slide number, the slide count, the section, the organization or the speaker are variables inside text ('{{slide.number}} / {{deck.slideCount}}', '{{organization.name}}'), so one text writes several values in the author's order. An organization logo is image: 'var:organization.logo.icon'. See docs/templates-and-variables.md.",
      "additionalProperties": false,
      "properties": {
        "text": {
          "type": "string",
          "description": "Text rendered in this zone. Variables resolve inside it like any string: deck-wide ones ('{{organization.name}}', '{{speaker.name}}, {{speaker.title}}', '{{customer}}') before composition, and the slide-scoped built-ins '{{slide.number}}', '{{slide.section}}' and '{{deck.slideCount}}' for each slide as it is laid out. Each '{{slide.number}}' is a live slide-number field: PPTX export writes it as a native field when its value fits within one accepted text line, and as static text with a diagnostic otherwise. '{{deck.slideCount}}' is fixed text, because PowerPoint has no slide-count field. Write '\\{{' for literal braces.",
          "examples": [
            "Confidential",
            "Q4 Business Review",
            "{{slide.number}} / {{deck.slideCount}}",
            "{{organization.name}}\n{{slide.section}}"
          ]
        },
        "image": {
          "$ref": "#/$defs/Asset",
          "description": "Image rendered first in this zone's row, such as a logo, partner mark, certification badge, or icon: a path, URL or Asset, or an organization logo reference ('var:organization.logo.icon', 'var:organization.<id>.logo.wordmark'), which resolves for each slide's background (onLight or onDark).",
          "examples": [
            "var:organization.logo.icon",
            "./assets/footer-badge.svg",
            "var:organization.beta.logo"
          ]
        },
        "date": {
          "oneOf": [
            {
              "type": "boolean"
            },
            {
              "type": "string"
            }
          ],
          "description": "true renders the current date: the renderer or exporter must be given an explicit ISO date by its host (core never reads a clock). PPTX export writes a native date field only for a supported dateFormat whose complete value fits within one accepted text line; otherwise it writes static text with a diagnostic. Native PowerPoint refresh and save/reopen compatibility require separate verification. A string is fixed: with dateFormat it must be an ISO YYYY-MM-DD date and is formatted; without dateFormat it is literal text rendered as written.",
          "examples": [
            true,
            "2026-04-23",
            "April 2026"
          ]
        },
        "dateFormat": {
          "type": "string",
          "minLength": 1,
          "description": "Date pattern for date. Tokens: yyyy (2026), yy (26), MMMM (April), MMM (Apr), MM (04), M (4), dd (09), d (9), EEEE (Thursday), EEE (Thu). Text in single quotes and other non-letter characters are literal. Month and weekday names are English, independent of host locale. Defaults to \"M/d/yyyy\" for a current date. PPTX export writes a native current-date field only when its complete value fits within one accepted text line and the pattern matches a PowerPoint en-US date field ('M/d/yyyy'; 'EEEE, MMMM d, yyyy'; 'd MMMM yyyy'; 'MMMM d, yyyy'; 'd-MMM-yy'; 'MMMM yy'; 'MMM-yy'). Other patterns and wrapped fields export as static text with a diagnostic. Full provenance can recover generated-date intent from unchanged supported wrapped dates on OPF reimport; the existing PPTX text remains static.",
          "examples": [
            "MMM d, yyyy",
            "yyyy-MM-dd",
            "MMM yyyy",
            "MMMM d, yyyy"
          ]
        },
        "socials": {
          "type": "boolean",
          "description": "Whether to render the primary organization's social profiles from organization.socials, one line per platform in key order. A handle is formatted through the platform's socialPlatforms record (companyUrlPattern, else profileUrlPattern, else baseUrl, with handlePrefix stripped) and shown as that profile URL without its 'https://' scheme; a value that is already a URL is shown without an 'https://' scheme; an unknown platform key shows the raw value. Exporters link each line to its full URL when one exists. Speaker socials are not rendered by this field."
        }
      }
    },
    "Slide": {
      "type": "object",
      "description": "A single slide. Content can be authored as a full-slide root payload, or inside promoted named region keys such as 'left', 'center+right', and 'top:left'.",
      "additionalProperties": false,
      "properties": {
        "id": {
          "type": "string",
          "description": "Optional stable identifier for the slide within the document. Use when another system needs to reference a slide across edits, comments, generation state, exports, or narrative tooling. Slide order is defined by the slides array, so simple decks may omit this.",
          "examples": [
            "s1",
            "cover",
            "problem-1",
            "ask"
          ]
        },
        "type": {
          "type": "string",
          "enum": [
            "text",
            "list",
            "image",
            "chart",
            "table",
            "video",
            "code",
            "metric",
            "quote",
            "timeline"
          ],
          "description": "Optional full-slide content kind. When omitted, engines infer the kind from root payload fields."
        },
        "beat": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "array",
              "items": {
                "type": "string"
              }
            }
          ],
          "description": "Optional reference to one or more beats of the deck's narrative (each value is the id of a beat in the narrative record that the root 'narrative' resolves to). A single string declares the slide's primary beat; an array declares that one slide covers multiple beats. Declares the slide's role in the story arc; does not constrain ordering or structure. Core validate warns about a beat id the resolved narrative does not define, and reports a beat that no slide references. Slides without a beat are valid; multiple slides may share a beat."
        },
        "layout": {
          "$ref": "#/$defs/CatalogReference",
          "description": "Optional layout: a layouts reference, a bare id ('pillars') or 'name:id' ('acme:hero'), or 'auto'. When omitted or 'auto', the slide is composed with no layout record: engines arrange title, subtitle, tag and content automatically, a slide with no body payload is a cover (vertically centered), and design hints apply; there is no finding. 'auto' is reserved, so no catalog may define a layout of that id, and opf format drops it. A layout is a grid template (layout.schema.json): the slide's content stays flat and binds to the layout's regions by reading order, role and kind, a block may pin itself to a region with 'region', and an empty region collapses. A reference that resolves nowhere is the warning opf/unresolved-reference (and the 'unresolved-reference' diagnostic of resolveSlideContext), the slide composes automatically, and a strict export fails. A layout id of the 0.18 default catalog that 0.19 no longer has is such a reference: 0.19 has no migration path for layouts. A layout never changes what a slide contains, and engines never substitute a different layout.",
          "examples": [
            "cover",
            "pillars",
            "chart-beside",
            "auto",
            "acme:hero"
          ]
        },
        "title": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "array",
              "items": {
                "$ref": "#/$defs/TextRun"
              }
            }
          ],
          "description": "Slide-level title content. A v2 layout renders this in its title heading area, or an implicit heading row when that area is absent. Use a string for plain text or TextRun[] for inline rich text (a colored word, bold, a link, a citation or footnote marker); the heading keeps its size and fitting rules either way, and run colors resolve like body text.",
          "examples": [
            "Quarterly Review",
            "Why Now",
            "Next Steps",
            [
              "Revenue grew ",
              {
                "text": "28%",
                "color": "accent1"
              }
            ]
          ]
        },
        "subtitle": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "array",
              "items": {
                "$ref": "#/$defs/TextRun"
              }
            }
          ],
          "description": "Slide-level subtitle or supporting line. A v2 layout renders this in its subtitle area when present, otherwise in the title heading group. Use a string for plain text or TextRun[] for inline rich text (a colored word, bold, a link, a citation or footnote marker); the heading keeps its size and fitting rules either way, and run colors resolve like body text.",
          "examples": [
            "Prepared for the board",
            "Three signals changed this quarter"
          ]
        },
        "tag": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "array",
              "items": {
                "$ref": "#/$defs/TextRun"
              }
            }
          ],
          "description": "Small slide-level label or badge. A v2 layout renders this before the title in its title heading group; tag is not a separate layout area. Use a string for plain text or TextRun[] for inline rich text (a colored word, bold, a link, a citation or footnote marker); the heading keeps its size and fitting rules either way, and run colors resolve like body text.",
          "examples": [
            "Intro",
            "Confidential",
            "Appendix"
          ]
        },
        "text": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "array",
              "items": {
                "$ref": "#/$defs/TextRun"
              }
            }
          ],
          "description": "Full-slide text payload. Use a string for plain text or TextRun[] for inline rich text. TextRun items may be plain strings or formatted run objects."
        },
        "items": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ListItem"
          },
          "description": "Full-slide structured list payload. Presence of this field infers type 'list'. Entries are strings, TextRun[] or objects with `text`, optional `description` (supporting detail under the entry), `level` and `start`. Use `items` when entries share a shape (features, steps, options, risks) or any entry needs a `description`; use `bullets` for plain talking points. Both draw the same marker, nesting and numbering; they differ in the inferred kind and in `description`, which only `items` accepts. At slide root, multiple content payload kinds with no explicit type, blocks, or regions are accepted as shorthand for layout-agnostic blocks, so `items` next to `text` or `bullets` composes as separate blocks side by side."
        },
        "bullets": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/BulletItem"
          },
          "description": "Full-slide prose bullet payload: short talking points, each standing alone. Presence of this field infers type 'text', so it may sit beside `text` in one payload. Entries are strings, TextRun[] or objects with `text`, `level` and `start`; there is no `description` (use `items` for entries with supporting detail)."
        },
        "numbering": {
          "$ref": "#/$defs/NumberingSpec",
          "description": "Number the full-slide `items` or `bullets` instead of bulleting them. A style name (arabic, roman-upper, roman-lower, alpha-upper, alpha-lower) or a Numbering object applies to every list level; an array gives one entry per level (index = level, the last entry repeats for deeper levels). Counting follows PowerPoint: consecutive entries of one level count up from its start, and an entry of a shallower level restarts the deeper levels. Absent = bullets. Valid only with `items` or `bullets`. Native PowerPoint export writes a:buAutoNum with the matching scheme and startAt; the preview draws the same numbers at the same marker geometry.",
          "examples": [
            "arabic",
            "roman-lower",
            {
              "style": "alpha-upper",
              "start": 3,
              "suffix": "paren"
            },
            [
              "arabic",
              "alpha-lower",
              {
                "style": "roman-lower",
                "suffix": "paren-both"
              }
            ]
          ]
        },
        "image": {
          "$ref": "#/$defs/Asset",
          "description": "Shorthand for one image block: the picture composes as body content, like { type: 'image', image: value }, with the effective design.imageFit. A v2 layout binds it to a compatible body region; a region's bleed setting may extend its outer edges to the slide edge. For fit, focus, treatments or an explicit placement use an image block in blocks; for a full-slide picture behind the content use design.background. Presence of this field infers type 'image'."
        },
        "video": {
          "$ref": "#/$defs/Asset",
          "description": "Full-slide video source. Presence of this field infers type 'video'. Engines do not play video: the preview draws a placeholder (a play badge with the asset's title or source as its caption), and PPTX export draws the same placeholder as native shapes linked to an http(s) source, with no embedded media. Native playback is out of scope (docs/programs/release-readiness)."
        },
        "chart": {
          "$ref": "#/$defs/Chart",
          "description": "Full-slide chart payload. Presence of this field infers type 'chart'."
        },
        "table": {
          "$ref": "#/$defs/Table",
          "description": "Full-slide table payload. Presence of this field infers type 'table'."
        },
        "code": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "$ref": "#/$defs/Code"
            }
          ],
          "description": "Full-slide code payload. A string is shorthand for { \"source\": value }; object form carries optional syntax language and filename metadata."
        },
        "metric": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "number"
            },
            {
              "$ref": "#/$defs/Metric"
            }
          ],
          "description": "Full-slide metric payload. A string or number is shorthand for { \"value\": value }; object form carries optional label, description, unit, delta, trend, and sentiment metadata. Numeric values remain numbers; renderers format them for display. Presence of this field infers type 'metric'."
        },
        "quote": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "$ref": "#/$defs/Quote"
            }
          ],
          "description": "Full-slide quote payload. A string is shorthand for { \"text\": value }; object form carries optional attribution and source metadata. Presence of this field infers type 'quote'."
        },
        "timeline": {
          "$ref": "#/$defs/Timeline",
          "description": "Full-slide timeline payload. An array is shorthand for { \"events\": value }; object form carries optional name and description metadata. Presence of this field infers type 'timeline'."
        },
        "caption": {
          "$ref": "#/$defs/Caption",
          "description": "Caption for the slide's root image, chart, table or video payload. Valid only when the slide root holds exactly one of those payloads."
        },
        "blocks": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ContentPayload"
          },
          "description": "Layout-agnostic content blocks rendered together as a composed payload when exact placement is unspecified. At slide root, multiple content payload kinds with no explicit type, blocks, or regions are accepted as shorthand for equivalent blocks."
        },
        "design": {
          "$ref": "#/$defs/SlideDesign",
          "description": "Slide-level design applied on top of the deck-wide design."
        },
        "left": {
          "$ref": "#/$defs/ContentPayload"
        },
        "center": {
          "$ref": "#/$defs/ContentPayload"
        },
        "right": {
          "$ref": "#/$defs/ContentPayload"
        },
        "left+center": {
          "$ref": "#/$defs/ContentPayload"
        },
        "center+right": {
          "$ref": "#/$defs/ContentPayload"
        },
        "left+center+right": {
          "$ref": "#/$defs/ContentPayload"
        },
        "top": {
          "$ref": "#/$defs/ContentPayload"
        },
        "middle": {
          "$ref": "#/$defs/ContentPayload"
        },
        "bottom": {
          "$ref": "#/$defs/ContentPayload"
        },
        "top+middle": {
          "$ref": "#/$defs/ContentPayload"
        },
        "middle+bottom": {
          "$ref": "#/$defs/ContentPayload"
        },
        "top+middle+bottom": {
          "$ref": "#/$defs/ContentPayload"
        },
        "top:left": {
          "$ref": "#/$defs/ContentPayload"
        },
        "top:center": {
          "$ref": "#/$defs/ContentPayload"
        },
        "top:right": {
          "$ref": "#/$defs/ContentPayload"
        },
        "top:left+center": {
          "$ref": "#/$defs/ContentPayload"
        },
        "top:center+right": {
          "$ref": "#/$defs/ContentPayload"
        },
        "top:left+center+right": {
          "$ref": "#/$defs/ContentPayload"
        },
        "middle:left": {
          "$ref": "#/$defs/ContentPayload"
        },
        "middle:center": {
          "$ref": "#/$defs/ContentPayload"
        },
        "middle:right": {
          "$ref": "#/$defs/ContentPayload"
        },
        "middle:left+center": {
          "$ref": "#/$defs/ContentPayload"
        },
        "middle:center+right": {
          "$ref": "#/$defs/ContentPayload"
        },
        "middle:left+center+right": {
          "$ref": "#/$defs/ContentPayload"
        },
        "bottom:left": {
          "$ref": "#/$defs/ContentPayload"
        },
        "bottom:center": {
          "$ref": "#/$defs/ContentPayload"
        },
        "bottom:right": {
          "$ref": "#/$defs/ContentPayload"
        },
        "bottom:left+center": {
          "$ref": "#/$defs/ContentPayload"
        },
        "bottom:center+right": {
          "$ref": "#/$defs/ContentPayload"
        },
        "bottom:left+center+right": {
          "$ref": "#/$defs/ContentPayload"
        },
        "top+middle:left": {
          "$ref": "#/$defs/ContentPayload"
        },
        "top+middle:center": {
          "$ref": "#/$defs/ContentPayload"
        },
        "top+middle:right": {
          "$ref": "#/$defs/ContentPayload"
        },
        "top+middle:left+center": {
          "$ref": "#/$defs/ContentPayload"
        },
        "top+middle:center+right": {
          "$ref": "#/$defs/ContentPayload"
        },
        "top+middle:left+center+right": {
          "$ref": "#/$defs/ContentPayload"
        },
        "middle+bottom:left": {
          "$ref": "#/$defs/ContentPayload"
        },
        "middle+bottom:center": {
          "$ref": "#/$defs/ContentPayload"
        },
        "middle+bottom:right": {
          "$ref": "#/$defs/ContentPayload"
        },
        "middle+bottom:left+center": {
          "$ref": "#/$defs/ContentPayload"
        },
        "middle+bottom:center+right": {
          "$ref": "#/$defs/ContentPayload"
        },
        "middle+bottom:left+center+right": {
          "$ref": "#/$defs/ContentPayload"
        },
        "top+middle+bottom:left": {
          "$ref": "#/$defs/ContentPayload"
        },
        "top+middle+bottom:center": {
          "$ref": "#/$defs/ContentPayload"
        },
        "top+middle+bottom:right": {
          "$ref": "#/$defs/ContentPayload"
        },
        "top+middle+bottom:left+center": {
          "$ref": "#/$defs/ContentPayload"
        },
        "top+middle+bottom:center+right": {
          "$ref": "#/$defs/ContentPayload"
        },
        "top+middle+bottom:left+center+right": {
          "$ref": "#/$defs/ContentPayload"
        },
        "notes": {
          "type": "string",
          "description": "Speaker notes shown in presenter view.",
          "examples": [
            "Open with the customer story; pause for questions before moving to the architecture slide."
          ]
        },
        "section": {
          "type": "string",
          "description": "PowerPoint-style slide section label. Consecutive slides with the same value belong to the same section in presenter view, outlines, and PowerPoint section-aware exports. Also the slide-scoped built-in variable '{{slide.section}}', for example in a header text.",
          "examples": [
            "Intro",
            "Problem",
            "Solution",
            "Ask",
            "Appendix"
          ]
        },
        "hidden": {
          "type": "boolean",
          "description": "Whether the slide is hidden from the presented sequence. The player skips it, the PPTX export writes it as a hidden slide, and per-slide image and PDF output skips it unless the caller asks to include hidden slides (opf CLI: --include-hidden; the deck-level toSvg: the opt-in skipHidden). A slide named explicitly (opf convert --slides, toSvg with a slide number) is still rendered."
        },
        "composition": {
          "$ref": "#/$defs/Composition"
        },
        "extensions": {
          "type": "object",
          "description": "Custom data passthrough for agent workflows at slide scope; ignored by the engine but preserved across read/write round-trips. Use for review state, generation provenance, or authoring conventions such as { \"authoring\": { \"locked\": true } }."
        }
      }
    },
    "ContentPayload": {
      "type": "object",
      "description": "A content leaf or recursively composed group. A group contains blocks and optional composition; it cannot mix blocks with leaf payload fields. Groups may nest up to 32 levels.",
      "additionalProperties": false,
      "properties": {
        "id": {
          "type": "string",
          "description": "Optional stable identifier for this payload, unique among slide and payload ids in the document. Use when another system needs to address the payload across edits — patch-style agent edits, comments, review state, or generation provenance. Identity survives reordering where array indexes do not.",
          "examples": [
            "kpi-adoption",
            "churn-quote"
          ]
        },
        "extensions": {
          "type": "object",
          "description": "Custom data passthrough for agent workflows at payload scope; ignored by the engine but preserved across read/write round-trips."
        },
        "region": {
          "type": "string",
          "pattern": "^[a-z][a-z0-9-]*$",
          "description": "Pin a root block (slides.N.blocks.I) to a region of the slide's template layout by name (OPF 0.19). The block goes to that region when the region exists, accepts the block's kind and has room; otherwise the pin is ignored with a warning (opf/region-unknown, opf/region-kind or opf/region-full) and the block is placed by its kind. Blocks without a pin are bound by reading order, role and kind. A pin on a nested block, or on a slide without a template layout, has no effect.",
          "examples": [
            "notes",
            "metrics"
          ]
        },
        "type": {
          "type": "string",
          "enum": [
            "text",
            "list",
            "image",
            "chart",
            "table",
            "video",
            "code",
            "metric",
            "quote",
            "timeline",
            "group"
          ],
          "description": "Optional content kind. When omitted, engines infer the kind from the fields present."
        },
        "text": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "array",
              "items": {
                "$ref": "#/$defs/TextRun"
              }
            }
          ],
          "description": "Text payload. Use a string for plain text or TextRun[] for inline rich text. TextRun items may be plain strings or formatted run objects.",
          "examples": [
            "Hello, world",
            [
              "Revenue grew ",
              {
                "text": "42%",
                "bold": true,
                "color": "#16A34A"
              },
              " year over year."
            ]
          ]
        },
        "items": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ListItem"
          },
          "description": "Structured list payload (type 'list'). Each item is either a plain string, a TextRun[] rich text sequence, or a ListItem object with optional `description`. List nesting uses item.level rather than nested content payloads. Use `items` when entries share a shape or any entry needs a `description`; use `bullets` for plain talking points. Both draw the same marker, nesting and numbering. A block or region holds `items` or `bullets`, never both, and `items` cannot sit beside `text`.",
          "examples": [
            [
              "Sub-second agent latency",
              [
                "Drop-in compatible with ",
                {
                  "text": "OpenAI tool-calling",
                  "bold": true
                }
              ],
              {
                "text": "SOC 2 Type II",
                "description": "Security review ready for enterprise procurement."
              }
            ]
          ]
        },
        "bullets": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/BulletItem"
          },
          "description": "Prose bullet payload: short talking points, each standing alone. Presence of this field infers type 'text', so it may sit beside `text` in one payload. Entries have no `description`; use `items` for entries with supporting detail.",
          "examples": [
            [
              "Sub-second agent latency",
              "Drop-in compatible with OpenAI tool-calling",
              "SOC 2 Type II"
            ]
          ]
        },
        "numbering": {
          "$ref": "#/$defs/NumberingSpec",
          "description": "Number the payload's `items` or `bullets` instead of bulleting them. A style name (arabic, roman-upper, roman-lower, alpha-upper, alpha-lower) or a Numbering object applies to every list level; an array gives one entry per level (index = level, the last entry repeats for deeper levels). Counting follows PowerPoint: consecutive entries of one level count up from its start, and an entry of a shallower level restarts the deeper levels. Absent = bullets. Valid only with `items` or `bullets`. Native PowerPoint export writes a:buAutoNum with the matching scheme and startAt; the preview draws the same numbers at the same marker geometry.",
          "examples": [
            "arabic",
            "roman-lower",
            {
              "style": "alpha-upper",
              "start": 3,
              "suffix": "paren"
            },
            [
              "arabic",
              "alpha-lower",
              {
                "style": "roman-lower",
                "suffix": "paren-both"
              }
            ]
          ]
        },
        "columns": {
          "oneOf": [
            {
              "const": "auto"
            },
            {
              "type": "integer",
              "minimum": 1,
              "maximum": 3
            }
          ],
          "description": "Lay the payload's `items` or `bullets` out in columns (OPF 0.19). 'auto' tries 1, 2 then 3 equal columns at the starting text size and uses the first count at which the list fits, as long as a column stays at least a quarter of the slide wide; when none fits, the largest allowed count shrinks towards minFontSize. 1, 2 or 3 fixes the count. Column breaks fall between items (a nested item stays with its parent) and keep the columns as even as possible; numbering continues and reading order runs column by column. A lone list in a layout region with listColumns: 'auto' behaves as 'auto'.",
          "examples": [
            "auto",
            2
          ]
        },
        "image": {
          "$ref": "#/$defs/Asset",
          "description": "Source for an image item.",
          "examples": [
            "https://cdn.acme.com/images/diagram.png",
            "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAusB9V3iWggAAAAASUVORK5CYII=",
            "./images/diagram.png",
            "asset:img-diagram"
          ]
        },
        "fit": {
          "type": "string",
          "enum": [
            "cover",
            "contain",
            "stretch"
          ],
          "description": "Image payloads only. How the picture fills its frame: 'cover' fills it and crops what overflows around focus; 'contain' shows the whole picture, in a frame of its own proportions placed at the region's anchor (top by default); 'stretch' scales it to the frame exactly. Default: the effective design.imageFit, else 'cover' in a layout and 'contain' on a slide with no layout."
        },
        "focus": {
          "$ref": "#/$defs/ImageFocus",
          "description": "Image payloads only. Point of the picture to keep in view when 'cover' crops it. Ignored by the other fits."
        },
        "aspectRatio": {
          "type": "number",
          "exclusiveMinimum": 0,
          "maximum": 10,
          "description": "Image payloads only. Width-to-height ratio of the frame: the frame becomes the largest centered box with this ratio inside the block's region, for example 2.39 for a cinematic letterbox or 0.5 for a phone-shaped frame. shape 'circle' always uses 1."
        },
        "shape": {
          "type": "string",
          "enum": [
            "rectangle",
            "rounded",
            "circle",
            "hexagon"
          ],
          "description": "Image payloads only. Mask applied to the frame, exported as the picture's native preset geometry (rect, roundRect, ellipse, hexagon). 'circle' makes the frame square. Default 'rectangle'."
        },
        "cornerRadius": {
          "type": "number",
          "minimum": 0,
          "maximum": 0.5,
          "description": "Image payloads only. Corner radius for shape 'rounded' as a fraction of the frame's shorter side. Default 0.16667, PowerPoint's roundRect default."
        },
        "border": {
          "$ref": "#/$defs/ImageBorder",
          "description": "Image payloads only. Line along the frame's shape."
        },
        "opacity": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Image payloads only. Picture opacity from 0 to 1, exported as a native alphaModFix. The border and overlay keep their own opacity. Default 1."
        },
        "recolor": {
          "$ref": "#/$defs/ImageRecolor",
          "description": "Image payloads only. Grayscale or duotone treatment of the picture's pixels."
        },
        "overlay": {
          "$ref": "#/$defs/Overlay",
          "description": "Image payloads only. Scrim over the picture in the frame's shape, or a band along one edge of a rectangle frame."
        },
        "placement": {
          "$ref": "#/$defs/ImagePlacement",
          "description": "Image payloads only, and only on a top-level block (slides.N.blocks.I), at most one per edge. Bleeds the image to one slide edge; the headings and the other blocks compose in the rest of the slide."
        },
        "video": {
          "$ref": "#/$defs/Asset",
          "description": "Source for a video item. Engines do not play video: the preview draws a placeholder (a play badge with the asset's title or source as its caption), and PPTX export draws the same placeholder as native shapes linked to an http(s) source, with no embedded media. Native playback is out of scope (docs/programs/release-readiness).",
          "examples": [
            "asset:demo-video",
            "./media/demo.mp4"
          ]
        },
        "chart": {
          "$ref": "#/$defs/Chart",
          "description": "Chart payload. Presence of this field infers type 'chart'."
        },
        "table": {
          "$ref": "#/$defs/Table",
          "description": "Table payload. Presence of this field infers type 'table'."
        },
        "code": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "$ref": "#/$defs/Code"
            }
          ],
          "description": "Code payload. A string is shorthand for { \"source\": value }; object form carries optional syntax language and filename metadata.",
          "examples": [
            "def greet(name: str) -> str:\n    return f\"Hello, {name}!\"",
            {
              "source": "export function greet(name: string) {\n  return `Hello, ${name}`;\n}",
              "language": "ts",
              "filename": "greet.ts"
            }
          ]
        },
        "metric": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "number"
            },
            {
              "$ref": "#/$defs/Metric"
            }
          ],
          "description": "Metric payload. A string or number is shorthand for { \"value\": value }; object form carries optional label, description, unit, delta, trend, and sentiment metadata. Numeric values remain numbers; renderers format them for display.",
          "examples": [
            "98%",
            42,
            {
              "value": "$12.4M",
              "label": "Revenue",
              "description": "Recognized revenue for the quarter.",
              "delta": "+12%",
              "trend": "up"
            }
          ]
        },
        "quote": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "$ref": "#/$defs/Quote"
            }
          ],
          "description": "Quote payload. A string is shorthand for { \"text\": value }; object form carries optional attribution, role, photo and source metadata.",
          "examples": [
            "This changed how our team handles reviews.",
            {
              "text": "This changed how our team handles reviews.",
              "attribution": "VP Operations, Acme Corp",
              "source": "Customer interview, March 2026"
            }
          ]
        },
        "timeline": {
          "$ref": "#/$defs/Timeline",
          "description": "Timeline payload ordered by narrative or chronology.",
          "examples": [
            [
              {
                "when": "2026-01",
                "what": "Pilot",
                "description": "Launch with the first operations team."
              },
              {
                "when": "2026-04",
                "what": "Rollout",
                "description": "Expand to all regions."
              }
            ],
            {
              "name": "Rollout Plan",
              "description": "Major milestones for the regional rollout.",
              "events": [
                {
                  "when": "Q1",
                  "what": "Pilot"
                },
                {
                  "when": "Q2",
                  "what": "Rollout"
                }
              ]
            }
          ]
        },
        "caption": {
          "$ref": "#/$defs/Caption",
          "description": "Caption for an image, chart, table or video payload, composed inside the block's region (below the media by default). Invalid on other payload kinds and on groups."
        },
        "blocks": {
          "type": "array",
          "minItems": 1,
          "items": {
            "$ref": "#/$defs/ContentPayload"
          },
          "description": "Ordered children of a group. Each child is a leaf or another group."
        },
        "composition": {
          "$ref": "#/$defs/Composition",
          "description": "Arrangement within this group. Only minFontSize and overflow inherit from the parent; strict overflow cannot be weakened."
        }
      },
      "allOf": [
        {
          "if": {
            "required": [
              "type"
            ],
            "properties": {
              "type": {
                "const": "list"
              }
            }
          },
          "then": {
            "required": [
              "items"
            ]
          }
        },
        {
          "if": {
            "required": [
              "type"
            ],
            "properties": {
              "type": {
                "const": "image"
              }
            }
          },
          "then": {
            "required": [
              "image"
            ]
          }
        },
        {
          "if": {
            "required": [
              "type"
            ],
            "properties": {
              "type": {
                "const": "chart"
              }
            }
          },
          "then": {
            "required": [
              "chart"
            ]
          }
        },
        {
          "if": {
            "required": [
              "type"
            ],
            "properties": {
              "type": {
                "const": "table"
              }
            }
          },
          "then": {
            "required": [
              "table"
            ]
          }
        },
        {
          "if": {
            "required": [
              "type"
            ],
            "properties": {
              "type": {
                "const": "video"
              }
            }
          },
          "then": {
            "required": [
              "video"
            ]
          }
        },
        {
          "if": {
            "required": [
              "type"
            ],
            "properties": {
              "type": {
                "const": "code"
              }
            }
          },
          "then": {
            "required": [
              "code"
            ]
          }
        },
        {
          "if": {
            "required": [
              "type"
            ],
            "properties": {
              "type": {
                "const": "metric"
              }
            }
          },
          "then": {
            "required": [
              "metric"
            ]
          }
        },
        {
          "if": {
            "required": [
              "type"
            ],
            "properties": {
              "type": {
                "const": "quote"
              }
            }
          },
          "then": {
            "required": [
              "quote"
            ]
          }
        },
        {
          "if": {
            "required": [
              "type"
            ],
            "properties": {
              "type": {
                "const": "timeline"
              }
            }
          },
          "then": {
            "required": [
              "timeline"
            ]
          }
        },
        {
          "if": {
            "required": [
              "type"
            ],
            "properties": {
              "type": {
                "const": "group"
              }
            }
          },
          "then": {
            "required": [
              "blocks"
            ]
          }
        },
        {
          "if": {
            "required": [
              "composition"
            ]
          },
          "then": {
            "required": [
              "blocks"
            ]
          }
        },
        {
          "if": {
            "required": [
              "blocks"
            ]
          },
          "then": {
            "properties": {
              "type": {
                "const": "group"
              }
            },
            "not": {
              "anyOf": [
                {
                  "required": [
                    "text"
                  ]
                },
                {
                  "required": [
                    "items"
                  ]
                },
                {
                  "required": [
                    "bullets"
                  ]
                },
                {
                  "required": [
                    "image"
                  ]
                },
                {
                  "required": [
                    "video"
                  ]
                },
                {
                  "required": [
                    "chart"
                  ]
                },
                {
                  "required": [
                    "table"
                  ]
                },
                {
                  "required": [
                    "code"
                  ]
                },
                {
                  "required": [
                    "metric"
                  ]
                },
                {
                  "required": [
                    "quote"
                  ]
                },
                {
                  "required": [
                    "timeline"
                  ]
                }
              ]
            }
          }
        },
        {
          "if": {
            "required": [
              "columns"
            ]
          },
          "then": {
            "anyOf": [
              {
                "required": [
                  "items"
                ]
              },
              {
                "required": [
                  "bullets"
                ]
              }
            ]
          }
        }
      ]
    },
    "Quote": {
      "type": "object",
      "description": "Quote content with optional attribution metadata. Use 'text' for the quoted text, 'attribution' for the credited person or organization, 'role' for that person's title and organization, 'photo' for their headshot and 'source' for a citation or URL. A string value in a quote field is shorthand for { \"text\": value }.",
      "additionalProperties": false,
      "required": [
        "text"
      ],
      "properties": {
        "text": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "array",
              "items": {
                "$ref": "#/$defs/TextRun"
              }
            }
          ],
          "description": "Quoted text: a string, or TextRun[] for inline rich text (a colored phrase, bold, a link, or a citation or footnote marker). The engine draws the surrounding quotation marks.",
          "examples": [
            "This changed how our team handles reviews.",
            [
              "Cut review time by ",
              {
                "text": "40%",
                "bold": true
              },
              {
                "text": " in a quarter",
                "cite": "acme-case-study"
              }
            ]
          ]
        },
        "attribution": {
          "type": "string",
          "description": "Person or organization credited for the quote. Drawn after the quote text, in the muted text color.",
          "examples": [
            "Priya Raman",
            "Acme Corp"
          ]
        },
        "role": {
          "type": "string",
          "description": "Title and organization of the attributed person. Drawn on its own line under the attribution; without an attribution it stands alone. It does not replace the attribution, so the person's name belongs in 'attribution'.",
          "examples": [
            "VP Operations, Acme",
            "Head of Platform"
          ]
        },
        "photo": {
          "$ref": "#/$defs/Asset",
          "description": "Headshot of the attributed person, drawn as a circle beside the attribution and role lines (on the logical start side: left in a left-to-right deck, right in a right-to-left deck). Give it alt text (validate's opf/missing-alt-text rule checks it). A raster photograph works best; an SVG exports as its PNG raster because the circular mask is not confirmed on SVG pictures in PowerPoint. An unresolved source draws the ordinary image placeholder.",
          "examples": [
            "./assets/priya-raman.jpg",
            {
              "src": "asset:priya-raman",
              "alt": "Priya Raman"
            }
          ]
        },
        "source": {
          "type": "string",
          "description": "Optional quote source, citation, or URL. Follows the attribution and role after ' - '.",
          "examples": [
            "Customer interview, March 2026",
            "https://acme.com/case-study"
          ]
        }
      }
    },
    "Code": {
      "type": "object",
      "description": "Code content with optional rendering metadata. Use 'source' for the code text, 'language' for syntax highlighting, 'filename' when the rendered block should show a file label, and 'highlight' to emphasize lines. A string value in a code field is shorthand for { \"source\": value }.",
      "additionalProperties": false,
      "required": [
        "source"
      ],
      "properties": {
        "source": {
          "type": "string",
          "description": "Source code text to display.",
          "examples": [
            "def greet(name: str) -> str:\n    return f\"Hello, {name}!\""
          ]
        },
        "language": {
          "type": "string",
          "description": "Language identifier used for syntax highlighting.",
          "examples": [
            "python",
            "ts",
            "tsx",
            "rust",
            "go",
            "bash",
            "json",
            "yaml"
          ]
        },
        "filename": {
          "type": "string",
          "description": "Optional file label shown with the code block.",
          "examples": [
            "app.py",
            "components/Button.tsx",
            "terraform/main.tf"
          ]
        },
        "highlight": {
          "type": "array",
          "minItems": 1,
          "items": {
            "oneOf": [
              {
                "type": "integer",
                "minimum": 1
              },
              {
                "type": "array",
                "minItems": 2,
                "maxItems": 2,
                "items": {
                  "type": "integer",
                  "minimum": 1
                }
              }
            ]
          },
          "description": "Source lines to emphasize, 1-based: each entry is a line number or an inclusive [start, end] range, so [3, [5, 7]] marks lines 3 and 5 to 7. Lines are counted by line break in 'source', so a line that wraps stays one line. Engines draw a theme-derived band behind the marked lines and dim the other lines slightly, keeping every line at least 4.5:1 against its background; PPTX export draws one native rectangle behind the line text boxes and import restores the list. A line number past the last line, or a range written end before start, gets a validation warning (code-highlight-out-of-range, code-highlight-range-reversed) and is ignored. When a code block is paginated across slides each page keeps the lines that fall on it, renumbered from 1.",
          "examples": [
            [
              3
            ],
            [
              3,
              [
                5,
                7
              ]
            ],
            [
              [
                2,
                4
              ]
            ]
          ]
        }
      }
    },
    "Metric": {
      "type": "object",
      "description": "Metric content with optional display metadata. Use 'value' for the primary value, 'label' for the metric name, 'description' for supporting context, 'unit' for a suffix/currency marker, 'delta' for change, 'trend' for direction, and 'sentiment' for whether the change is good news. A string or number value in a metric field is shorthand for { \"value\": value }; numeric values remain numbers and are formatted by renderers.",
      "additionalProperties": false,
      "required": [
        "value"
      ],
      "properties": {
        "value": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "number"
            }
          ],
          "description": "Primary metric value.",
          "examples": [
            42,
            "$12.4M",
            "98%"
          ]
        },
        "label": {
          "type": "string",
          "description": "Metric label.",
          "examples": [
            "Revenue",
            "Retention",
            "Latency"
          ]
        },
        "description": {
          "type": "string",
          "description": "Optional supporting context for the metric.",
          "examples": [
            "Recognized revenue for the quarter.",
            "Median API latency across production traffic."
          ]
        },
        "unit": {
          "type": "string",
          "description": "Metric unit, suffix, or currency marker.",
          "examples": [
            "%",
            "ms",
            "$M"
          ]
        },
        "delta": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "number"
            }
          ],
          "description": "Metric change value.",
          "examples": [
            "+12%",
            -4.2
          ]
        },
        "trend": {
          "type": "string",
          "enum": [
            "up",
            "down",
            "flat"
          ],
          "description": "Metric trend direction. The preview and the PowerPoint export draw an arrow beside the trend word that always points the way the trend does (up, down or flat) and colour the arrow, the trend word and the delta text by `sentiment`."
        },
        "sentiment": {
          "type": "string",
          "enum": [
            "positive",
            "negative",
            "neutral"
          ],
          "description": "Whether the change is good news. Positive draws the trend arrow and the trend and delta text in green, negative in red and neutral in the neutral text colour, each kept at 4.5:1 contrast or more against the slide background. When absent the colour follows the trend: up is positive, down is negative and flat is neutral. Set it when the direction is not the verdict, for example positive on a falling churn, cost or latency trend. The arrow always keeps the direction of `trend`. Only the trend arrow and the trend and delta text take the colour, so sentiment has no visible effect on a metric without a trend."
        }
      }
    },
    "Timeline": {
      "description": "Timeline content. An array is shorthand for { \"events\": value }; object form carries optional name and description metadata.",
      "oneOf": [
        {
          "type": "array",
          "items": {
            "$ref": "#/$defs/TimelineEvent"
          },
          "minItems": 1
        },
        {
          "type": "object",
          "additionalProperties": false,
          "required": [
            "events"
          ],
          "properties": {
            "name": {
              "type": "string",
              "description": "Short timeline label.",
              "examples": [
                "Rollout Plan",
                "Migration Path"
              ]
            },
            "description": {
              "type": "string",
              "description": "Optional timeline-level context.",
              "examples": [
                "Major milestones for the regional rollout."
              ]
            },
            "events": {
              "type": "array",
              "items": {
                "$ref": "#/$defs/TimelineEvent"
              },
              "minItems": 1,
              "description": "Timeline events ordered by narrative, sequence, or chronology."
            }
          }
        }
      ]
    },
    "TimelineEvent": {
      "type": "object",
      "description": "A single event inside a timeline content payload.",
      "required": [
        "what"
      ],
      "additionalProperties": false,
      "properties": {
        "when": {
          "type": "string",
          "description": "Event time, date, or sequence label. Use ISO-like values when possible, but human labels are allowed for quarters, eras, and relative milestones.",
          "examples": [
            "2026-01",
            "Q2 2026",
            "Launch week"
          ]
        },
        "what": {
          "type": "string",
          "description": "Short event label.",
          "examples": [
            "Pilot",
            "Rollout",
            "Scale"
          ]
        },
        "description": {
          "type": "string",
          "description": "Optional event detail.",
          "examples": [
            "Launch with the first operations team."
          ]
        },
        "status": {
          "type": "string",
          "enum": [
            "done",
            "current",
            "planned"
          ],
          "description": "Progress of the event, drawn from the deck's own colors by both the SVG renderer and the PPTX exporter. Absent means no status and the event is drawn as a plain filled marker with normal text, which is also how 'done' looks. 'done' is a filled marker in the primary color with normal text. 'current' marks 'we are here': the filled marker is surrounded by a ring and the event label (`what`) is bold. 'planned' is an outlined, hollow marker (primary-color outline over the slide background) with muted secondary text. Text colors keep a 4.5:1 contrast against the slide background. In PPTX the markers are native ellipses (the ring is a second ellipse), and PPTX import restores the status the export recorded. Status describes progress only; schedule health such as at risk or blocked belongs in the event text.",
          "examples": [
            "done",
            "current",
            "planned"
          ]
        }
      }
    },
    "ListItem": {
      "description": "A flat item inside a list. Strings cover the common case, TextRun[] supports inline rich text without an object wrapper, and object form adds description and nesting depth without creating nested slide content payloads.",
      "oneOf": [
        {
          "type": "string"
        },
        {
          "type": "array",
          "items": {
            "$ref": "#/$defs/TextRun"
          }
        },
        {
          "type": "object",
          "required": [
            "text"
          ],
          "additionalProperties": false,
          "properties": {
            "text": {
              "oneOf": [
                {
                  "type": "string"
                },
                {
                  "type": "array",
                  "items": {
                    "$ref": "#/$defs/TextRun"
                  }
                }
              ],
              "description": "Text for the list item. Use a string for plain text or TextRun[] for inline rich text. TextRun items may be plain strings or formatted run objects.",
              "examples": [
                "Improve retention by 12 points",
                [
                  "Improve retention by ",
                  {
                    "text": "12 points",
                    "bold": true
                  }
                ]
              ]
            },
            "description": {
              "oneOf": [
                {
                  "type": "string"
                },
                {
                  "type": "array",
                  "items": {
                    "$ref": "#/$defs/TextRun"
                  }
                }
              ],
              "description": "Optional supporting detail for the list item. Use a string for plain text or TextRun[] for inline rich text.",
              "examples": [
                "Focused on activation and first-value time.",
                [
                  "Focused on ",
                  {
                    "text": "activation",
                    "bold": true
                  },
                  " and first-value time."
                ]
              ]
            },
            "level": {
              "type": "integer",
              "minimum": 0,
              "description": "Zero-based nesting level for the list item."
            },
            "start": {
              "type": "integer",
              "minimum": 1,
              "maximum": 32767,
              "description": "Restart the list's numbering at this number for this item (counted at its level); the entries after it continue from it. Only meaningful when the payload has `numbering`. Paginated continuation pages use it to keep the numbers of the whole list."
            }
          }
        }
      ]
    },
    "BulletItem": {
      "description": "A flat bullet item. Strings cover the common case, TextRun[] supports inline rich text without an object wrapper, and object form adds nesting depth without list-item descriptions.",
      "oneOf": [
        {
          "type": "string"
        },
        {
          "type": "array",
          "items": {
            "$ref": "#/$defs/TextRun"
          }
        },
        {
          "type": "object",
          "required": [
            "text"
          ],
          "additionalProperties": false,
          "properties": {
            "text": {
              "oneOf": [
                {
                  "type": "string"
                },
                {
                  "type": "array",
                  "items": {
                    "$ref": "#/$defs/TextRun"
                  }
                }
              ],
              "description": "Text for the bullet. Use a string for plain text or TextRun[] for inline rich text. TextRun items may be plain strings or formatted run objects.",
              "examples": [
                "Improve retention by 12 points",
                [
                  "Improve retention by ",
                  {
                    "text": "12 points",
                    "bold": true
                  }
                ]
              ]
            },
            "level": {
              "type": "integer",
              "minimum": 0,
              "description": "Zero-based nesting level for the bullet."
            },
            "start": {
              "type": "integer",
              "minimum": 1,
              "maximum": 32767,
              "description": "Restart the list's numbering at this number for this bullet (counted at its level); the entries after it continue from it. Only meaningful when the payload has `numbering`. Paginated continuation pages use it to keep the numbers of the whole list."
            }
          }
        }
      ]
    },
    "NumberingStyle": {
      "type": "string",
      "enum": [
        "arabic",
        "roman-upper",
        "roman-lower",
        "alpha-upper",
        "alpha-lower"
      ],
      "description": "A list number style: 1, 2, 3; I, II, III; i, ii, iii; A, B, C; a, b, c. Alphabetic numbering past 26 repeats the letter as PowerPoint does (aa, bb, cc). Roman numerals stop at 3999; larger values are drawn in arabic with a numbering-adapted diagnostic."
    },
    "Numbering": {
      "type": "object",
      "additionalProperties": false,
      "description": "Numbering of one list level.",
      "properties": {
        "style": {
          "$ref": "#/$defs/NumberingStyle",
          "description": "Number style. Default arabic."
        },
        "start": {
          "type": "integer",
          "minimum": 1,
          "maximum": 32767,
          "description": "First number counted at this level. Default 1. Native PowerPoint accepts 1 to 32767."
        },
        "suffix": {
          "type": "string",
          "enum": [
            "period",
            "paren",
            "paren-both"
          ],
          "description": "Text after the number: period (1.), paren (1)) or paren-both ((1)). Default period."
        }
      }
    },
    "NumberingSpec": {
      "description": "The value of a numbering field: a style name or Numbering object for every level, or an array with one entry per level (at most 9, the native depth).",
      "oneOf": [
        {
          "$ref": "#/$defs/NumberingStyle"
        },
        {
          "$ref": "#/$defs/Numbering"
        },
        {
          "type": "array",
          "minItems": 1,
          "maxItems": 9,
          "items": {
            "oneOf": [
              {
                "$ref": "#/$defs/NumberingStyle"
              },
              {
                "$ref": "#/$defs/Numbering"
              }
            ]
          }
        }
      ]
    },
    "TextRun": {
      "description": "A contiguous run of text. Strings cover unformatted spans; object form adds character formatting.",
      "oneOf": [
        {
          "type": "string"
        },
        {
          "type": "object",
          "required": [
            "text"
          ],
          "properties": {
            "text": {
              "type": "string",
              "description": "Text for this run.",
              "examples": [
                "Hello, ",
                "world"
              ]
            },
            "bold": {
              "type": "boolean",
              "description": "Whether the run is rendered in bold."
            },
            "italic": {
              "type": "boolean",
              "description": "Whether the run is rendered in italic."
            },
            "underline": {
              "type": "boolean",
              "description": "Whether the run is underlined."
            },
            "strikethrough": {
              "type": "boolean",
              "description": "Whether the run is rendered with a strikethrough line."
            },
            "color": {
              "type": "string",
              "description": "Run text color. Documented forms: a hex string ('#RGB', '#RRGGBB', '#RRGGBBAA'), a color-scheme slot or role name resolved through the effective color scheme ('accent2', 'text'), or a 'var:<id>' reference into the top-level variables map. Prefer names over hex so runs survive re-theming. Any other string stays schema-valid so imported decks keep validating: validators warn and renderers fall back to the theme text color.",
              "examples": [
                "#0F172A",
                "accent2",
                "var:risk"
              ]
            },
            "fontSize": {
              "type": "number",
              "exclusiveMinimum": 0,
              "description": "Requested run font size in points."
            },
            "fontFamily": {
              "type": "string",
              "description": "Run font family override. It wins over the code font a run with 'code' takes.",
              "examples": [
                "Inter",
                "Source Serif Pro",
                "JetBrains Mono"
              ]
            },
            "code": {
              "type": "boolean",
              "description": "Whether the run is an inline code span: it is drawn in the design's code font (design.fontScheme.code, else the resolved font scheme's code family, else Roboto Mono), unless the run names its own fontFamily. Only the font changes; there is no background, because a PPTX run cannot have one. Markdown backticks read and write code runs."
            },
            "lang": {
              "type": "string",
              "pattern": "^[A-Za-z]{2,8}(-[A-Za-z0-9]{1,8})*$",
              "description": "BCP-47 language tag of the run, such as 'fr-FR' or 'ja-JP', when it differs from the deck language. It sets the proofing language (PPTX a:rPr lang) and the language the run's script fonts and glyph variants follow (for example the Japanese or the Simplified Chinese face for Han characters); without it the run follows the deck language.",
              "examples": [
                "fr-FR",
                "ja-JP",
                "de"
              ]
            },
            "link": {
              "type": "string",
              "pattern": "^(https?://|mailto:|tel:)\\S+$",
              "description": "URL to link the run text to: an http(s) URL, a 'mailto:' address or a 'tel:' number, without whitespace. The preview draws it as a link and PPTX export writes a native hyperlink for all three; any other scheme is not valid.",
              "examples": [
                "https://acme.com",
                "https://acme.com/case-studies/beta",
                "mailto:hello@acme.com",
                "tel:+15551234567"
              ]
            },
            "superscript": {
              "type": "boolean",
              "description": "Whether the run is rendered as superscript."
            },
            "subscript": {
              "type": "boolean",
              "description": "Whether the run is rendered as subscript."
            },
            "cite": {
              "oneOf": [
                {
                  "type": "string",
                  "minLength": 1
                },
                {
                  "type": "array",
                  "minItems": 1,
                  "items": {
                    "type": "string",
                    "minLength": 1
                  }
                }
              ],
              "description": "One or more ids from the top-level references list that this run cites. Engines draw a superscript marker ('1', or '1,2' for several ids) directly after the run and list '<n> <reference text>' in the slide's footnote area; markers are numbered per deck in order of first use, and the same id keeps its number. An id missing from references is a validation error (cite-unknown-reference). Supported in text, bullets and list item runs, in the slide title, subtitle and tag, and in the quote text.",
              "examples": [
                "gartner-2026",
                [
                  "gartner-2026",
                  "annual-report"
                ]
              ]
            },
            "footnote": {
              "oneOf": [
                {
                  "type": "string",
                  "minLength": 1
                },
                {
                  "type": "array",
                  "minItems": 1,
                  "items": {
                    "$ref": "#/$defs/TextRun"
                  }
                }
              ],
              "description": "An inline note for this run, without a references entry. Engines draw a superscript marker after the run and list the note in the slide's footnote area; every footnote takes a new number in the deck's marker sequence. Supported in text, bullets and list item runs, in the slide title, subtitle and tag, and in the quote text.",
              "examples": [
                "Excludes the discontinued hardware line."
              ]
            }
          }
        }
      ]
    },
    "Caption": {
      "description": "A caption for an image, chart, table or video payload. A string or TextRun[] is the caption text placed below the media; object form adds the position and alignment.",
      "oneOf": [
        {
          "type": "string"
        },
        {
          "type": "array",
          "items": {
            "$ref": "#/$defs/TextRun"
          }
        },
        {
          "type": "object",
          "required": [
            "text"
          ],
          "additionalProperties": false,
          "properties": {
            "text": {
              "oneOf": [
                {
                  "type": "string"
                },
                {
                  "type": "array",
                  "items": {
                    "$ref": "#/$defs/TextRun"
                  }
                }
              ],
              "description": "Caption text: a string or TextRun[] for inline rich text."
            },
            "position": {
              "type": "string",
              "enum": [
                "below",
                "above"
              ],
              "description": "Where the caption band sits inside the block's region: below the media (default) or above it. Core composition reserves the band and shrinks the media by its height."
            },
            "align": {
              "type": "string",
              "enum": [
                "left",
                "center",
                "right"
              ],
              "description": "Horizontal alignment of the caption text within the block. Defaults to left."
            }
          }
        }
      ],
      "examples": [
        "Figure 1. Quarterly revenue by region",
        {
          "text": "Source: internal reporting",
          "position": "above",
          "align": "center"
        }
      ]
    },
    "Reference": {
      "type": "object",
      "description": "A source that runs cite with 'cite'. Cited references are listed in the footnote area of the slides that cite them, numbered per deck in order of first use; referencesSlide() builds an ordinary list slide of them.",
      "additionalProperties": false,
      "required": [
        "id",
        "text"
      ],
      "properties": {
        "id": {
          "type": "string",
          "minLength": 1,
          "description": "Identifier runs cite. Unique within the references list.",
          "examples": [
            "gartner-2026",
            "annual-report"
          ]
        },
        "text": {
          "oneOf": [
            {
              "type": "string"
            },
            {
              "type": "array",
              "items": {
                "$ref": "#/$defs/TextRun"
              }
            }
          ],
          "description": "The reference as it is listed: a string or TextRun[] for inline rich text."
        },
        "url": {
          "type": "string",
          "description": "Optional link for the reference; a references slide links its entry to it.",
          "examples": [
            "https://acme.com/reports/2026"
          ]
        }
      }
    },
    "Chart": {
      "type": "object",
      "description": "Chart content. The chart object keeps chart-specific fields together so slides and regions do not expose loose chart fields. OPF charts are `{ type, data }` where `data` is `{ columns, rows }`: the first column holds the category labels and every further column is one series. There are no `categories`, `series`, `labels` or `datasets` keys (the Chart.js and ECharts shape); write them as columns and rows. Example: `{ \"type\": \"column\", \"data\": { \"columns\": [\"Quarter\", \"Decks\"], \"rows\": [[\"Q1\", 3], [\"Q2\", 8], [\"Q3\", 21]] } }`.",
      "additionalProperties": false,
      "required": [
        "type",
        "data"
      ],
      "properties": {
        "type": {
          "type": "string",
          "enum": [
            "100pct-stacked-area",
            "100pct-stacked-bar",
            "100pct-stacked-column",
            "area",
            "bar",
            "box-and-whisker",
            "column",
            "combo",
            "doughnut",
            "filled-radar",
            "funnel",
            "histogram",
            "line",
            "line-with-markers",
            "pareto",
            "pie",
            "radar",
            "radar-with-markers",
            "scatter",
            "stacked-area",
            "stacked-bar",
            "stacked-column",
            "stacked-line",
            "stacked-line-with-markers",
            "treemap",
            "waterfall",
            "world"
          ],
          "description": "Chart type, an engine vocabulary validated directly (no catalog lookup): the chart types Aspose.Slides officially supports, plus 'combo' (clustered columns with line series, see 'line' and 'secondaryAxis'). Each engine maps a type to its own chart model; labels and picker groups are catalog display metadata.",
          "examples": [
            "column",
            "bar",
            "line",
            "pie",
            "doughnut",
            "area",
            "scatter",
            "radar",
            "waterfall",
            "funnel",
            "treemap",
            "stacked-column",
            "combo"
          ]
        },
        "data": {
          "oneOf": [
            {
              "$ref": "#/$defs/ChartData"
            },
            {
              "$ref": "#/$defs/DatasetRef"
            }
          ],
          "description": "Chart data. Inline data uses a tabular columns/rows shape; renderers convert rows to chart series internally. A DatasetRef ({ \"dataset\": \"<id>\" }) plots a top-level dataset instead. Data from a spreadsheet or file is imported into inline columns and rows, and its origin is recorded in data.source."
        },
        "mapping": {
          "$ref": "#/$defs/ChartMapping",
          "description": "Optional series mapping by column name: which column is the category, which is the X column of a scatter chart, and which columns are plotted, in order. Absent keeps the positional rule (first column the category, then the X column for scatter, every other column a series)."
        },
        "line": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "minItems": 1,
          "uniqueItems": true,
          "description": "Combo charts only (type 'combo'): the plotted series, by column name, that are drawn as lines with markers; every other plotted series is drawn as clustered columns. Absent: the last plotted series is the line. A combo chart keeps at least one column series, so a list that names every series draws the first one as columns. Column series are drawn, exported and listed in the legend first, then the line series on the primary axis, then those on the secondary axis, each in plotted order. A name that is not a column is a 'chart-mapping-unknown-column' error; a column that is not plotted is a 'chart-mapping-adapted' warning. On any other chart type it is ignored with a 'chart-option-adapted' warning.",
          "examples": [
            [
              "Margin"
            ]
          ]
        },
        "secondaryAxis": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "minItems": 1,
          "uniqueItems": true,
          "description": "Combo charts only: line series, by column name, plotted against a secondary value axis at the right of the plot. That axis has its own scale, and its tick labels use the number format of the first secondary series' column (DataColumn.format), for example '0%' for a margin. Absent: every series shares the primary value axis at the left. A name that is not a line series (see 'line') stays on the primary axis with a 'chart-mapping-adapted' warning; an unknown column is a 'chart-mapping-unknown-column' error. On any other chart type it is ignored with a 'chart-option-adapted' warning.",
          "examples": [
            [
              "Margin"
            ]
          ]
        },
        "axisTitles": {
          "$ref": "#/$defs/ChartAxisTitles",
          "description": "Optional axis titles. Absent keeps today's untitled axes. Supported on the chart types that have a category/value (or X/Y) axis pair (column, bar, line, area, scatter, and the histogram, pareto, waterfall and box-and-whisker constructs; the funnel construct takes a category title only; a combo chart also takes 'secondary' when it plots a series on the secondary axis); a title on a type without that axis (pie, doughnut, radar, treemap, map) is dropped with a 'chart-option-adapted' diagnostic by renderers and exporters."
        },
        "legend": {
          "type": "string",
          "enum": [
            "none",
            "top",
            "bottom",
            "left",
            "right"
          ],
          "description": "Optional legend position. 'none' hides the legend. Absent keeps today's behaviour exactly (a legend at the right of multi-series charts and of pie and doughnut charts, none for single-series charts). A named position shows the legend there even for a single-series chart. Of the Office 2016 constructs only box-and-whisker takes a legend; histogram, pareto, waterfall, funnel, treemap and map drop the option with a 'chart-option-adapted' diagnostic."
        },
        "dataLabels": {
          "oneOf": [
            {
              "type": "boolean"
            },
            {
              "$ref": "#/$defs/ChartDataLabels"
            }
          ],
          "description": "Optional data labels. true shows value labels at each type's default position, false (or absent) shows none, which is today's behaviour. Use the object form for the label content, position and separator."
        },
        "alt": {
          "type": "string",
          "description": "Text alternative for the chart: what the data shows (the point and the key numbers), not 'a chart' or 'bar chart'. The preview exposes it as the chart's accessible name (role img with aria-label) and the PowerPoint export writes it as the chart frame's alternative text (descr); import reads it back. An empty string marks the chart decorative, with the same meaning as an empty Asset alt, but it is a reviewed choice that opf/chart-text-alternative still reports as info (a chart almost always carries a message). When absent, validate accepts text beside the chart instead.",
          "examples": [
            "Revenue grew from $12M in Q1 to $18M in Q2, with the steepest rise in the West region."
          ]
        },
        "colors": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/ColorRef"
          },
          "minItems": 1,
          "maxItems": 24,
          "description": "Optional series colors, by position: entry i replaces palette color i, the color of series i (the i-th plotted value column), of slice or category i on a pie, doughnut, treemap or funnel chart, and of the i-th color a histogram, pareto, waterfall or box-and-whisker chart draws with. An entry is any ColorRef: a hex color, a color-scheme slot or role ('accent3', 'secondary') or a 'var:<id>' color variable; a scheme name keeps following the deck if its scheme changes, and is written to PowerPoint as a theme color. Positions past the last entry keep the deck palette (accent1 to accent6, then their tints). A color is kept at 3:1 contrast against the chart panel (a lighter or darker shade is used when it falls short) and 'chart.highlight' wins over it: highlighted marks take the primary color and the rest the muted neutral. A color that cannot be resolved falls back to the palette color for its position. Absent keeps the deck palette exactly.",
          "examples": [
            [
              "accent3",
              "#7B241C"
            ]
          ]
        },
        "highlight": {
          "$ref": "#/$defs/ChartHighlight",
          "description": "Optional emphasis: the series and/or categories that carry the message. The engines draw the highlighted marks in the deck's primary (accent) color and every other mark in a muted neutral derived from the theme (a light grey on a light chart panel, a dim grey on a dark one); there is no color field. A mark is highlighted when its series OR its category is named. Absent keeps today's colors exactly. Supported on column, bar and line charts (series and categories; on a line a category highlight marks that category's points), pie and doughnut charts (categories, one per slice), and area, scatter and radar charts (series); the histogram, pareto, waterfall, funnel, treemap, box-and-whisker, map and combo constructs drop the option with a 'chart-option-adapted' diagnostic, as does a part the type cannot highlight. A name that matches no column or row label is a 'chart-highlight-unknown-name' error."
        }
      }
    },
    "ChartAxisTitles": {
      "type": "object",
      "additionalProperties": false,
      "description": "Titles for the axes of a chart. 'category' is the axis that carries the row labels (the horizontal axis of a column or line chart, the vertical axis of a bar chart, the X axis of a scatter chart); 'value' is the other axis; 'secondary' is the secondary value axis of a combo chart.",
      "properties": {
        "category": {
          "type": "string",
          "description": "Title of the category (X) axis.",
          "examples": [
            "Quarter",
            "Region"
          ]
        },
        "value": {
          "type": "string",
          "description": "Title of the value (Y) axis. On a combo chart, the primary (left) value axis.",
          "examples": [
            "Revenue ($M)",
            "Customers"
          ]
        },
        "secondary": {
          "type": "string",
          "description": "Combo charts only: title of the secondary value axis at the right of the plot, drawn rotated like the primary value axis title. Dropped with a 'chart-option-adapted' diagnostic on any other chart type and on a combo chart without 'secondaryAxis'.",
          "examples": [
            "Margin (%)"
          ]
        }
      }
    },
    "ChartHighlight": {
      "type": "object",
      "additionalProperties": false,
      "minProperties": 1,
      "description": "Which series and categories a chart emphasizes. Names are matched exactly: series by data column name (after any 'fields' selection; a series is a plotted value column), categories by row label (the first column, or mapping.category), as text. A category label shared by several rows highlights each of them.",
      "properties": {
        "series": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "minItems": 1,
          "uniqueItems": true,
          "description": "Series (value columns) to highlight: all marks of each named series. A name that is not a column is a 'chart-highlight-unknown-name' error; a column that is not plotted as a series (the category or X column, or one mapping.series leaves out) highlights nothing and is a 'chart-highlight-adapted' warning.",
          "examples": [
            [
              "Revenue"
            ]
          ]
        },
        "categories": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "minItems": 1,
          "uniqueItems": true,
          "description": "Categories (row labels) to highlight: the marks of each named category (a column or bar of every series, a line's points, a pie or doughnut slice). A label no row has is a 'chart-highlight-unknown-name' error.",
          "examples": [
            [
              "Q3"
            ]
          ]
        }
      },
      "examples": [
        {
          "series": [
            "Revenue"
          ]
        },
        {
          "categories": [
            "Q3"
          ]
        }
      ]
    },
    "ChartDataLabels": {
      "type": "object",
      "additionalProperties": false,
      "description": "Data label settings. A label shows the selected content parts in the fixed order category, value, percent, joined by the separator.",
      "properties": {
        "content": {
          "type": "array",
          "items": {
            "type": "string",
            "enum": [
              "value",
              "percent",
              "category"
            ]
          },
          "minItems": 1,
          "uniqueItems": true,
          "description": "Which parts a label shows. Defaults to ['value']. 'percent' is the share of the total and exists only on pie and doughnut charts; 'category' shows the category name (the X value on a scatter chart). A part a chart type cannot show is dropped with a 'chart-option-adapted' diagnostic."
        },
        "position": {
          "type": "string",
          "enum": [
            "auto",
            "center",
            "inside-end",
            "inside-base",
            "outside-end",
            "above",
            "below",
            "left",
            "right"
          ],
          "description": "Where a label sits relative to its mark. 'auto' (the default) is the type's default: outside-end for clustered columns and bars, pie slices and the histogram, pareto and waterfall constructs; center for stacked columns and bars; above for line and scatter points. Clustered columns and bars and the histogram, pareto and waterfall constructs take center, inside-end, inside-base and outside-end; stacked columns and bars take center, inside-end and inside-base; pie takes center, inside-end and outside-end; line and scatter points take above, below, left, right and center. Area, doughnut and radar charts and the funnel and treemap constructs take only 'auto' (the box-and-whisker and map constructs have no data labels). A combo chart places the labels of its column series like clustered columns and those of its line series like line points; a position only one part takes applies to that part, and the other part keeps its default (outside-end, above). An unsupported position falls back to 'auto' with a 'chart-option-adapted' diagnostic."
        },
        "separator": {
          "type": "string",
          "description": "Text between the parts of a label that shows more than one. Defaults to ', '.",
          "examples": [
            ", ",
            "; "
          ]
        }
      }
    },
    "Table": {
      "type": "object",
      "description": "Table content, inline or dataset-backed. An inline table has 'rows' (required) and optional 'columns'. A dataset-backed table has 'dataset' (required) and optional 'fields', and no 'rows' or 'columns': it takes its headers, rows and column formats from the dataset (per-cell styles need an inline table).",
      "additionalProperties": false,
      "if": {
        "required": [
          "dataset"
        ]
      },
      "then": {
        "properties": {
          "rows": false,
          "columns": false
        }
      },
      "else": {
        "required": [
          "rows"
        ],
        "properties": {
          "fields": false
        }
      },
      "properties": {
        "columns": {
          "type": "array",
          "items": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "$ref": "#/$defs/TextRun"
                }
              },
              {
                "$ref": "#/$defs/StyledTableCell"
              },
              {
                "$ref": "#/$defs/DataColumn"
              },
              {
                "type": "null"
              }
            ]
          },
          "description": "Optional column labels. Labels may be strings, rich runs, styled cell objects or DataColumn objects ({ \"name\", \"format\" }). A header's 'format' (DataColumn or StyledTableCell) is the column's number format; a body cell's own format wins. Null is an empty label or a placeholder covered by a preceding column span.",
          "examples": [
            [
              "Region",
              "Q3 Revenue",
              "Q4 Revenue",
              "YoY %"
            ]
          ]
        },
        "rows": {
          "type": "array",
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/TableCell"
            }
          },
          "description": "Two-dimensional table row data; each row aligns by index with columns when columns are supplied.",
          "examples": [
            [
              [
                "North America",
                12.4,
                18.1,
                "46%"
              ],
              [
                "EMEA",
                8.2,
                11.5,
                "40%"
              ]
            ]
          ]
        },
        "dataset": {
          "$ref": "#/$defs/DatasetId",
          "description": "Id of a top-level dataset that supplies this table's headers, rows and column formats. Excludes 'rows' and 'columns'. An unknown id is a 'dataset-unknown' error."
        },
        "fields": {
          "$ref": "#/$defs/DatasetFields",
          "description": "Dataset tables only: the dataset columns to show, by name and in order. Absent shows every column. An unknown name is a 'dataset-field-unknown' error."
        },
        "alt": {
          "type": "string",
          "description": "Text alternative for the table: what it shows (the point and the key numbers), not 'a table'. The preview exposes it as the table's accessible name (role group with aria-label; the cells stay readable) and the PowerPoint export writes it as the table frame's alternative text (descr); import reads it back. An empty string hides a purely decorative table, with the same meaning as an empty Asset alt. The alt is a summary read before the cells, which stay readable, so it is most useful for a large or dense table; validate does not require one and does not report a missing one.",
          "examples": [
            "North America grew 46% to $18.1M in Q4, ahead of EMEA at 40%."
          ]
        }
      }
    },
    "ChartData": {
      "type": "object",
      "description": "Inline tabular data driving a chart, written as `{ \"columns\": [\"Quarter\", \"Decks\"], \"rows\": [[\"Q1\", 3], [\"Q2\", 8]] }`: one column of labels plus one column per series, not separate `categories` and `series` lists. The first column usually supplies category/x-axis labels; subsequent columns are plotted measures unless 'chart.mapping' or a chart type maps them differently. Value cells are numbers; a string is read only in strict decimal syntax ('12', '-3.5', '1e6'), and anything else ('12%', '$5', '(5)', '1,234') is a gap and a 'chart-value-not-numeric' warning.",
      "additionalProperties": false,
      "required": [
        "columns",
        "rows"
      ],
      "properties": {
        "columns": {
          "type": "array",
          "items": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "$ref": "#/$defs/DataColumn"
              }
            ]
          },
          "minItems": 1,
          "description": "Ordered column labels for the chart data table. A label is a string or a DataColumn ({ \"name\", \"format\" }) whose number format the data labels, value axis and exported workbook use.",
          "examples": [
            [
              "Quarter",
              "Revenue"
            ],
            [
              "Quarter",
              "Revenue",
              "Costs"
            ],
            [
              "Quarter",
              {
                "name": "Revenue",
                "format": "$#,##0.0"
              },
              {
                "name": "Margin",
                "format": "0%"
              }
            ]
          ]
        },
        "rows": {
          "type": "array",
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/ChartDataCell"
            }
          },
          "minItems": 1,
          "description": "Tabular chart rows. Each row aligns by index with columns.",
          "examples": [
            [
              [
                "Q1",
                12
              ],
              [
                "Q2",
                18
              ],
              [
                "Q3",
                24
              ],
              [
                "Q4",
                31
              ]
            ]
          ]
        },
        "source": {
          "$ref": "#/$defs/DataSourceRef",
          "description": "Optional provenance: where this inline data came from. Engines never read, fetch or refresh it; they keep it through editing, export and re-import."
        }
      }
    },
    "DataColumn": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "name"
      ],
      "description": "A named data column with an optional number format. Anywhere a chart or dataset column is a string it may be a DataColumn; the string form is { \"name\": value } with no format. A table column header may also be a DataColumn.",
      "properties": {
        "name": {
          "type": "string",
          "description": "Column label, used as the series name, the table header and the name 'fields' and 'chart.mapping' address.",
          "examples": [
            "Revenue",
            "Margin"
          ]
        },
        "format": {
          "$ref": "#/$defs/NumberFormat",
          "description": "Number format of the column's number values (data labels, value axis, table cells, exported workbook). Absent: the General form."
        }
      },
      "examples": [
        {
          "name": "Revenue",
          "format": "$#,##0.0"
        },
        {
          "name": "Margin",
          "format": "0%"
        }
      ]
    },
    "DataSourceRef": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "src"
      ],
      "description": "Provenance of inline data or a dataset: the file, sheet and range it came from and when. Engines never read, fetch or refresh it; they keep it through editing, export and re-import. Re-import the data to update it.",
      "properties": {
        "src": {
          "type": "string",
          "description": "Where the data came from: an 'asset:<id>' reference, a URL, or a relative or local path.",
          "examples": [
            "./data/revenue.csv",
            "asset:revenue",
            "https://cdn.acme.com/data/revenue.csv"
          ]
        },
        "sheet": {
          "type": "string",
          "description": "Sheet or table name inside a spreadsheet source.",
          "examples": [
            "Sheet1"
          ]
        },
        "range": {
          "type": "string",
          "description": "A1-style range inside a spreadsheet source.",
          "examples": [
            "A1:D8"
          ]
        },
        "fields": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "The source fields the data was taken from, in order.",
          "examples": [
            [
              "Quarter",
              "Revenue"
            ]
          ]
        },
        "retrieved": {
          "type": "string",
          "anyOf": [
            {
              "format": "date"
            },
            {
              "format": "date-time"
            }
          ],
          "description": "When the data was taken from the source: an ISO 8601 date or date-time.",
          "examples": [
            "2026-10-05",
            "2026-10-05T09:30:00Z"
          ]
        },
        "description": {
          "type": "string",
          "description": "Free-form note about the source.",
          "examples": [
            "Finance export, unaudited"
          ]
        }
      },
      "examples": [
        {
          "src": "./data/revenue.csv",
          "retrieved": "2026-10-05"
        }
      ]
    },
    "DatasetId": {
      "type": "string",
      "pattern": "^[a-zA-Z0-9][a-zA-Z0-9._-]*$",
      "description": "Id of an entry in the top-level datasets map (the assets id pattern).",
      "examples": [
        "revenue",
        "pipeline-2026"
      ]
    },
    "DatasetFields": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "minItems": 1,
      "uniqueItems": true,
      "description": "Dataset column names to use, in order, each at most once. Selects and orders the dataset's columns; an unknown name is a 'dataset-field-unknown' error.",
      "examples": [
        [
          "Quarter",
          "Revenue"
        ]
      ]
    },
    "Datasets": {
      "type": "object",
      "description": "Shared data tables keyed by id (the assets id pattern). Charts reference one with 'chart.data': { \"dataset\": \"<id>\" } and tables with 'table': { \"dataset\": \"<id>\" }.",
      "propertyNames": {
        "pattern": "^[a-zA-Z0-9][a-zA-Z0-9._-]*$"
      },
      "additionalProperties": {
        "$ref": "#/$defs/Dataset"
      },
      "examples": [
        {
          "revenue": {
            "title": "Revenue by quarter",
            "columns": [
              "Quarter",
              {
                "name": "Revenue",
                "format": "$#,##0.0"
              },
              "Costs"
            ],
            "rows": [
              [
                "Q1",
                12,
                8
              ],
              [
                "Q2",
                18,
                11
              ],
              [
                "Q3",
                24,
                15
              ]
            ],
            "source": {
              "src": "./data/revenue.csv",
              "retrieved": "2026-10-05"
            }
          }
        }
      ]
    },
    "Dataset": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "columns",
        "rows"
      ],
      "description": "One shared data table: named columns (strings or DataColumn objects with a number format) and rows of scalar cells. Column names are unique ('data-column-duplicate' error). Rich text and styling belong in an inline table.",
      "properties": {
        "title": {
          "type": "string",
          "description": "Human name of the dataset, shown by editors.",
          "examples": [
            "Revenue by quarter"
          ]
        },
        "description": {
          "type": "string",
          "description": "What the dataset holds.",
          "examples": [
            "Quarterly revenue and costs, in $M."
          ]
        },
        "columns": {
          "type": "array",
          "items": {
            "oneOf": [
              {
                "type": "string"
              },
              {
                "$ref": "#/$defs/DataColumn"
              }
            ]
          },
          "minItems": 1,
          "description": "Ordered, uniquely named columns.",
          "examples": [
            [
              "Quarter",
              {
                "name": "Revenue",
                "format": "$#,##0.0"
              },
              "Costs"
            ]
          ]
        },
        "rows": {
          "type": "array",
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/$defs/ChartDataCell"
            }
          },
          "description": "Rows of scalar cells (string, number, boolean, null); each row aligns by index with columns.",
          "examples": [
            [
              [
                "Q1",
                12,
                8
              ],
              [
                "Q2",
                18,
                11
              ]
            ]
          ]
        },
        "source": {
          "$ref": "#/$defs/DataSourceRef",
          "description": "Optional provenance. Engines never read, fetch or refresh it."
        }
      }
    },
    "DatasetRef": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "dataset"
      ],
      "description": "Chart data taken from a top-level dataset. Engines inline it before plotting; 'chart.mapping' names columns after the 'fields' selection.",
      "properties": {
        "dataset": {
          "$ref": "#/$defs/DatasetId",
          "description": "Id of the dataset. An unknown id is a 'dataset-unknown' error."
        },
        "fields": {
          "$ref": "#/$defs/DatasetFields",
          "description": "The dataset columns to use, by name and in order. Absent uses every column."
        }
      },
      "examples": [
        {
          "dataset": "revenue"
        },
        {
          "dataset": "revenue",
          "fields": [
            "Quarter",
            "Revenue"
          ]
        }
      ]
    },
    "ChartMapping": {
      "type": "object",
      "additionalProperties": false,
      "description": "Series mapping by column name (after any 'fields' selection). Mapping only selects and orders columns; pie, doughnut and other single-series constructs still plot one series. An unknown name is a 'chart-mapping-unknown-column' error; a series that repeats the category or X column, and an X column on a chart type without an X axis, are dropped with a 'chart-mapping-adapted' warning.",
      "properties": {
        "category": {
          "type": "string",
          "description": "The label (category) column. Default: the first column.",
          "examples": [
            "Quarter"
          ]
        },
        "x": {
          "type": "string",
          "description": "The X column of an XY (scatter) chart. Default: the second column (the first, when the category is the second column), and only when there are three or more columns: with two, the second column is the one series, plotted against row numbers. An X that leaves no series is plotted as the series with a 'chart-mapping-adapted' warning.",
          "examples": [
            "Spend"
          ]
        },
        "series": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "minItems": 1,
          "description": "The plotted columns, in order. Default: every column that is not the category or the X column.",
          "examples": [
            [
              "Revenue",
              "Costs"
            ]
          ]
        }
      },
      "examples": [
        {
          "category": "Quarter",
          "series": [
            "Costs",
            "Revenue"
          ]
        },
        {
          "category": "Region",
          "x": "Spend",
          "series": [
            "Revenue"
          ]
        }
      ]
    },
    "ChartDataCell": {
      "oneOf": [
        {
          "type": "string"
        },
        {
          "type": "number"
        },
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "description": "A cell in inline chart data."
    },
    "TableCell": {
      "oneOf": [
        {
          "$ref": "#/$defs/TableCellValue"
        },
        {
          "$ref": "#/$defs/StyledTableCell"
        }
      ],
      "description": "A scalar, rich-run array, or styled/spanning cell object. Existing scalar and rich forms remain valid."
    },
    "TableCellValue": {
      "oneOf": [
        {
          "type": "string"
        },
        {
          "type": "number"
        },
        {
          "type": "boolean"
        },
        {
          "type": "null"
        },
        {
          "type": "array",
          "items": {
            "$ref": "#/$defs/TextRun"
          }
        }
      ],
      "description": "A scalar table value or canonical rich text runs, without cell decoration or geometry."
    },
    "StyledTableCell": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "value"
      ],
      "properties": {
        "value": {
          "$ref": "#/$defs/TableCellValue",
          "description": "Editable cell content; styling and spans do not change its scalar type or rich runs."
        },
        "style": {
          "$ref": "#/$defs/TableCellStyle"
        },
        "colSpan": {
          "type": "integer",
          "minimum": 1,
          "description": "Number of grid columns covered, starting at this cell. Covered positions must contain null. Default 1."
        },
        "rowSpan": {
          "type": "integer",
          "minimum": 1,
          "description": "Number of grid rows covered, starting at this cell. Covered positions must contain null. Header cells cannot span into body rows. Default 1."
        },
        "format": {
          "$ref": "#/$defs/NumberFormat",
          "description": "Number format. On a body cell it formats that cell's number value (and wins over the column's format); on a header cell (in 'columns') it is the column's format, the same as a DataColumn header. Strings, booleans, null and rich runs display unchanged."
        }
      },
      "description": "A cell with explicit visual style or merged geometry. Its position remains its array column index; use null placeholders for every covered grid position."
    },
    "TableCellStyle": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "fill": {
          "$ref": "#/$defs/ColorRef",
          "description": "Cell background: a hex color, a color-scheme slot or role name, or a 'var:<id>' variable reference. Eight-digit hex colors include alpha; #00000000 is transparent."
        },
        "color": {
          "$ref": "#/$defs/ColorRef",
          "description": "Default text color, overridden by individual rich run colors. Accepts a hex color, a color-scheme slot or role name, or a 'var:<id>' variable reference."
        },
        "bold": {
          "type": "boolean",
          "description": "Bold cell text. Runs that set their own bold keep it; a number cell stays bold and still uses the cell's or column's number format."
        },
        "align": {
          "type": "string",
          "enum": [
            "left",
            "center",
            "right"
          ],
          "description": "Horizontal text alignment inside the cell."
        },
        "verticalAlign": {
          "type": "string",
          "enum": [
            "top",
            "middle",
            "bottom"
          ],
          "description": "Vertical alignment inside the padded cell box."
        },
        "padding": {
          "$ref": "#/$defs/TableCellPadding"
        },
        "borders": {
          "type": "object",
          "additionalProperties": false,
          "properties": {
            "top": {
              "$ref": "#/$defs/TableCellBorder"
            },
            "right": {
              "$ref": "#/$defs/TableCellBorder"
            },
            "bottom": {
              "$ref": "#/$defs/TableCellBorder"
            },
            "left": {
              "$ref": "#/$defs/TableCellBorder"
            }
          },
          "description": "Independent cell edges. An omitted edge keeps the table's default rule: a line under every row (and over the first row), none between columns. Width 0 removes an edge."
        }
      },
      "description": "Cell appearance. Sizes use reference pixels at a 720-pixel canvas short edge and scale with the slide."
    },
    "TableCellPadding": {
      "type": "object",
      "additionalProperties": false,
      "properties": {
        "top": {
          "type": "number",
          "minimum": 0,
          "maximum": 200
        },
        "right": {
          "type": "number",
          "minimum": 0,
          "maximum": 200
        },
        "bottom": {
          "type": "number",
          "minimum": 0,
          "maximum": 200
        },
        "left": {
          "type": "number",
          "minimum": 0,
          "maximum": 200
        }
      },
      "description": "Text insets in reference pixels. Defaults: top 8, right 10, bottom 4, left 10."
    },
    "TableCellBorder": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "color",
        "width"
      ],
      "properties": {
        "color": {
          "$ref": "#/$defs/ColorRef",
          "description": "Border color: a hex color, a color-scheme slot or role name, or a 'var:<id>' variable reference. Eight-digit hex colors include alpha; #00000000 is transparent."
        },
        "width": {
          "type": "number",
          "minimum": 0,
          "maximum": 32,
          "description": "Border width in reference pixels; 0 removes this edge."
        },
        "dash": {
          "type": "string",
          "enum": [
            "solid",
            "dash",
            "dot"
          ],
          "description": "Default solid."
        }
      },
      "description": "One explicit cell border."
    },
    "Catalogs": {
      "type": "object",
      "description": "The catalog records a document embeds, grouped by the catalog they came from. Each property is a group; inside a group, records are keyed by kind and then by id.\n- 'default': the catalog bare ids come from. It needs a 'source' when it holds records. Omitted: bare ids fall back to the host's default catalog. false: no catalog fallback, so every bare id must be embedded (under 'custom' or 'default').\n- 'custom': the records the document defines itself. It has no source.\n- any other name ('acme'): an extra catalog, identified by its 'source'. The name is the prefix references use ('acme:hero'). Names are lowercase kebab-case; 'default' and 'custom' are reserved.\n\nResolution, for every kind: a bare id resolves in 'custom', then in the records embedded under 'default', then in the catalog the host registered for default.source (the host's default catalog when 'default' is omitted). 'name:id' resolves in that group's records, then in the catalog the host registered for its source. A reference written inside an embedded record (a theme's colorScheme) resolves in that record's own group first. A prefix that names no group is a validation error; a reference that resolves nowhere is the warning opf/unresolved-reference. Engines never fetch a source: hosts register catalogs by their source string, and authoring tools embed every record a document uses when they save it.",
      "properties": {
        "default": {
          "oneOf": [
            {
              "allOf": [
                {
                  "$ref": "#/$defs/CatalogGroup"
                },
                {
                  "if": {
                    "anyOf": [
                      {
                        "required": [
                          "layouts"
                        ]
                      },
                      {
                        "required": [
                          "themes"
                        ]
                      },
                      {
                        "required": [
                          "colorSchemes"
                        ]
                      },
                      {
                        "required": [
                          "fontSchemes"
                        ]
                      },
                      {
                        "required": [
                          "narratives"
                        ]
                      },
                      {
                        "required": [
                          "audiences"
                        ]
                      },
                      {
                        "required": [
                          "purposes"
                        ]
                      },
                      {
                        "required": [
                          "tones"
                        ]
                      }
                    ]
                  },
                  "then": {
                    "required": [
                      "source"
                    ]
                  }
                }
              ]
            },
            {
              "const": false
            }
          ],
          "description": "The catalog bare ids come from: its source and the records of it this document embeds. false turns off the catalog fallback for bare ids.",
          "examples": [
            {
              "source": "https://www.pptx.gallery",
              "layouts": {
                "two-column": {
                  "name": "Two column",
                  "regions": [
                    {
                      "name": "title"
                    },
                    {
                      "direction": "row",
                      "regions": [
                        {
                          "name": "primary",
                          "accepts": [
                            "text"
                          ]
                        },
                        {
                          "name": "secondary",
                          "accepts": [
                            "text"
                          ]
                        }
                      ]
                    }
                  ]
                }
              }
            },
            false
          ]
        },
        "custom": {
          "allOf": [
            {
              "$ref": "#/$defs/CatalogGroup"
            },
            {
              "not": {
                "required": [
                  "source"
                ]
              }
            }
          ],
          "description": "Records the document defines itself, referenced by bare id. Checked first for every bare id. Forking a catalog record copies it here under a new id, so the change of ownership is visible."
        }
      },
      "propertyNames": {
        "pattern": "^[a-z][a-z0-9-]*$",
        "description": "Group name: lowercase kebab-case. 'default' and 'custom' are reserved."
      },
      "additionalProperties": {
        "allOf": [
          {
            "$ref": "#/$defs/CatalogGroup"
          },
          {
            "required": [
              "source"
            ]
          }
        ],
        "description": "A named catalog: its source and the records of it this document embeds. References name it as a prefix ('acme:hero')."
      },
      "examples": [
        {
          "default": {
            "source": "https://www.pptx.gallery",
            "themes": {
              "minimal": {
                "name": "Minimal",
                "colorScheme": "cool-horizon",
                "fontScheme": "aptos"
              }
            }
          },
          "acme": {
            "source": "pkg:@acme/opf-catalog",
            "layouts": {
              "hero": {
                "name": "Hero",
                "regions": [
                  {
                    "name": "title"
                  }
                ]
              }
            }
          },
          "custom": {
            "layouts": {
              "q4-special": {
                "name": "Q4 special",
                "regions": [
                  {
                    "name": "title"
                  },
                  {
                    "name": "chart",
                    "accepts": [
                      "chart"
                    ],
                    "flow": "none"
                  }
                ]
              }
            }
          }
        }
      ]
    },
    "CatalogGroup": {
      "type": "object",
      "additionalProperties": false,
      "description": "One catalog group: the catalog's source and the records of it the document embeds, by kind and then by id.",
      "properties": {
        "source": {
          "$ref": "#/$defs/CatalogSource"
        },
        "layouts": {
          "$ref": "#/$defs/CatalogRecords",
          "description": "Layout records keyed by id, each with the fields of https://openpresentation.org/schema/opf-layout/v2. Referenced from Slide.layout."
        },
        "themes": {
          "$ref": "#/$defs/CatalogRecords",
          "description": "Theme records keyed by id, each with the fields of https://openpresentation.org/schema/opf-theme/v1. Referenced from design.theme."
        },
        "colorSchemes": {
          "$ref": "#/$defs/CatalogRecords",
          "description": "Colour-scheme records keyed by id, each with the fields of https://openpresentation.org/schema/opf-color-scheme/v1. Referenced from design.colorScheme and a theme's colorScheme."
        },
        "fontSchemes": {
          "$ref": "#/$defs/CatalogRecords",
          "description": "Font-scheme records keyed by id, each with the fields of https://openpresentation.org/schema/opf-font-scheme/v1. Referenced from design.fontScheme, a theme's fontScheme and a language's font schemes."
        },
        "narratives": {
          "$ref": "#/$defs/CatalogRecords",
          "description": "Narrative records keyed by id, each with the fields of https://openpresentation.org/schema/opf-narrative/v1. Referenced from narrative."
        },
        "audiences": {
          "$ref": "#/$defs/CatalogRecords",
          "description": "Audience records keyed by id, each with the fields of https://openpresentation.org/schema/opf-audience/v1. Referenced from audience."
        },
        "purposes": {
          "$ref": "#/$defs/CatalogRecords",
          "description": "Purpose records keyed by id, each with the fields of https://openpresentation.org/schema/opf-purpose/v1. Referenced from purpose."
        },
        "tones": {
          "$ref": "#/$defs/CatalogRecords",
          "description": "Tone records keyed by id, each with the fields of https://openpresentation.org/schema/opf-tone/v1. Referenced from tone."
        }
      }
    },
    "CatalogSource": {
      "type": "string",
      "pattern": "^(?:https://[^\\s]+|pkg:[^\\s]+)$",
      "description": "Identity of a catalog: an HTTPS URL ('https://www.pptx.gallery') or a package reference ('pkg:@acme/opf-catalog'). It names the catalog; engines never fetch or install it. A host registers the catalog's records under this exact string, and copying slides between documents matches groups by it.",
      "examples": [
        "https://www.pptx.gallery",
        "pkg:@acme/opf-catalog"
      ]
    },
    "CatalogRecords": {
      "type": "object",
      "description": "Embedded records of one kind, keyed by id. The key is the record's id; an embedded record carries no '$schema', 'id', origin or digest. Catalog display metadata ('x-*' members) is stripped when a record is embedded.",
      "propertyNames": {
        "pattern": "^[a-z][a-z0-9-]*$"
      },
      "additionalProperties": {
        "type": "object",
        "not": {
          "anyOf": [
            {
              "required": [
                "$schema"
              ]
            },
            {
              "required": [
                "id"
              ]
            }
          ]
        },
        "description": "One embedded record: the fields of the kind's companion schema without '$schema' and 'id'."
      }
    },
    "CatalogReference": {
      "type": "string",
      "pattern": "^(?:[a-z][a-z0-9-]*:)?[a-z][a-z0-9-]*$",
      "description": "A content reference: a bare id ('two-column') or 'name:id' ('acme:hero'), where the prefix names a group of 'catalogs'. URLs and 'pkg:' strings are not references; a named catalog group replaces them. See Catalogs for the resolution order.",
      "examples": [
        "two-column",
        "acme:hero",
        "default:minimal",
        "custom:q4-special"
      ]
    },
    "LanguageTag": {
      "type": "string",
      "pattern": "^(?:[A-Za-z]{2,3}|[iIxX])(?:-[A-Za-z0-9]{1,8})*$",
      "description": "A BCP-47 language tag ('en-US', 'ja', 'zh-Hans', 'sr-Latn-ME'), an engine vocabulary. Use 'en-GB' for UK English; 'en-UK' is not a valid region.",
      "examples": [
        "en-US",
        "en-GB",
        "ja",
        "zh-Hans",
        "ar-SA"
      ]
    },
    "Composition": {
      "type": "object",
      "additionalProperties": false,
      "description": "Automatic slide and content-group arrangement. Nested content groups arrange their children independently, inheriting only minFontSize and overflow. Explicit promoted regions retain their positions. A layout defines its grid as one ordered list of regions; its composition supports gap, padding, minFontSize and overflow rather than mode, columns or weights.",
      "properties": {
        "mode": {
          "type": "string",
          "enum": [
            "auto",
            "grid",
            "row",
            "column"
          ],
          "description": "auto chooses a grid from available space and content; grid uses columns; row and column use one horizontal or vertical track."
        },
        "columns": {
          "type": "integer",
          "minimum": 1,
          "maximum": 12,
          "description": "Column count for grid. In auto mode this caps the number of columns."
        },
        "gap": {
          "type": "number",
          "minimum": 0,
          "maximum": 0.1,
          "description": "Space between cells as a fraction of the container short edge (canvas at slide root). Default 0.03333333333333333."
        },
        "padding": {
          "type": "number",
          "minimum": 0,
          "maximum": 0.2,
          "description": "Inset as a fraction of the container short edge. Default 0.08 on a slide, 0 inside a group."
        },
        "weights": {
          "type": "array",
          "minItems": 1,
          "maxItems": 12,
          "items": {
            "type": "number",
            "exclusiveMinimum": 0,
            "maximum": 100
          },
          "description": "Relative track sizes: columns for row/grid/auto, rows for column. Omitted tracks have weight 1; extra weights are ignored."
        },
        "minFontSize": {
          "type": "number",
          "minimum": 8,
          "maximum": 32,
          "description": "Minimum readable text size in reference pixels at a 720-pixel canvas short edge. Default 16. Overflow is diagnosed when text cannot fit at this size."
        },
        "overflow": {
          "type": "string",
          "enum": [
            "warn",
            "error"
          ],
          "description": "warn returns diagnostics for content that does not fit; error rejects layout. Content is never silently removed. Default warn."
        }
      }
    }
  }
}

Definition choices

Values declared by this schema and its nested definitions. Paths ending in [] describe array items; * describes each dictionary entry. Variant paths apply within the named schema branch.

$defs.Audience.seniority · Allowed values
"ic", "manager", "director", "vp", "c-suite", "mixed"
$defs.Audience.technicalFluency · Allowed values
"low", "medium", "high", "mixed"
$defs.Audience.decisionPower · Allowed values
"informational", "advisory", "decision-maker"
$defs.Language.direction · Allowed values
"ltr", "rtl"
$defs.Organization.role · Allowed values
"primary", "partner", "client", "sponsor", "host"
$defs.Socials (property names) · Allowed values
"linkedin", "x", "github", "youtube", "instagram", "facebook", "tiktok", "threads", "mastodon", "bluesky"
$defs.Design.dimensions · Named choices (see schema for other values and constraints)
"16:9", "4:3", "16:10", "1:1", "4:5", "9:16", "letter", "a4", "widescreen", "standard"
$defs.Design.background · Named choices (see schema for other values and constraints)
"light1", "light2", "dark1", "dark2"
$defs.Design.variant · Named choices (see schema for other values and constraints)
"light1", "light2", "dark1", "dark2"
$defs.Design.logo · Named choices (see schema for other values and constraints)
false
$defs.Design.watermark · Named choices (see schema for other values and constraints)
false
$defs.Design.header · Named choices (see schema for other values and constraints)
false
$defs.Design.footer · Named choices (see schema for other values and constraints)
false
$defs.Design.titleAlignment · Allowed values
"left", "center", "right"
$defs.Design.contentAlignment · Allowed values
"left", "center", "right"
$defs.Design.contentDirection · Allowed values
"horizontal", "vertical"
$defs.Design.chartPrimary · Allowed values
"none", "top", "bottom", "left", "right"
$defs.Design.imageFit · Allowed values
"cover", "contain", "stretch"
$defs.Design.listBullet · Allowed values
"character", "image", "none"
$defs.FontScheme.type · Allowed values
"sans-serif", "serif", "monospace"
$defs.FontScheme.app · Allowed values
"powerpoint", "google-slides"
$defs.FontScheme.languageFamily · Allowed values
"latin", "ea", "cs", "eastAsian", "complexScript"
$defs.DimensionPreset · Allowed values
"16:9", "4:3", "16:10", "1:1", "4:5", "9:16", "letter", "a4", "widescreen", "standard"
$defs.Dimensions.preset · Allowed values
"16:9", "4:3", "16:10", "1:1", "4:5", "9:16", "letter", "a4", "widescreen", "standard"
$defs.ThemeBackgroundSlot · Allowed values
"light1", "light2", "dark1", "dark2"
$defs.ColorRef · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
$defs.ColorVariable.type · Allowed values
"color"
$defs.TextVariable.type · Allowed values
"text"
$defs.NumberVariable.type · Allowed values
"number"
$defs.DateVariable.type · Allowed values
"date"
$defs.ImageVariable.type · Allowed values
"image"
$defs.UrlVariable.type · Allowed values
"url"
$defs.ListVariable.type · Allowed values
"list"
$defs.BackgroundShortcut · Named choices (see schema for other values and constraints)
"light1", "light2", "dark1", "dark2"
$defs.ColorVariant.background · Allowed values
"light1", "light2", "dark1", "dark2"
$defs.ColorVariant.accents[] · Allowed values
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6"
$defs.ThemeBackground.type · Allowed values
"theme"
$defs.ThemeBackground.slot · Allowed values
"light1", "light2", "dark1", "dark2"
$defs.SolidBackground.type · Allowed values
"solid"
$defs.SolidBackground.color · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
$defs.GradientBackground.tone · Allowed values
"dark", "light"
$defs.GradientBackground.type · Allowed values
"gradient"
$defs.GradientBackground.gradient.stops[].color · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
$defs.ImageBackground.tone · Allowed values
"dark", "light"
$defs.ImageBackground.type · Allowed values
"image"
$defs.ImageBackground.fit · Allowed values
"cover", "contain", "stretch", "tile"
$defs.ImageBackground.recolor · Named choices (see schema for other values and constraints)
"grayscale"
$defs.Overlay.color · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
$defs.Overlay.edge · Allowed values
"top", "bottom", "left", "right"
$defs.ImagePlacement.edge · Allowed values
"left", "right", "top", "bottom"
$defs.ImageBorder.color · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
$defs.ImageRecolor · Named choices (see schema for other values and constraints)
"grayscale"
$defs.ImageRecolor (oneOf 2).dark · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
$defs.ImageRecolor (oneOf 2).light · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
$defs.PatternBackground.type · Allowed values
"pattern"
$defs.PatternBackground.pattern.foregroundColor · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
$defs.PatternBackground.pattern.backgroundColor · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
$defs.Slide.type · Allowed values
"text", "list", "image", "chart", "table", "video", "code", "metric", "quote", "timeline"
$defs.Slide.numbering · Named choices (see schema for other values and constraints)
"arabic", "roman-upper", "roman-lower", "alpha-upper", "alpha-lower"
$defs.ContentPayload.type · Allowed values
"text", "list", "image", "chart", "table", "video", "code", "metric", "quote", "timeline", "group"
$defs.ContentPayload.numbering · Named choices (see schema for other values and constraints)
"arabic", "roman-upper", "roman-lower", "alpha-upper", "alpha-lower"
$defs.ContentPayload.columns · Named choices (see schema for other values and constraints)
"auto"
$defs.ContentPayload.fit · Allowed values
"cover", "contain", "stretch"
$defs.ContentPayload.shape · Allowed values
"rectangle", "rounded", "circle", "hexagon"
$defs.ContentPayload.recolor · Named choices (see schema for other values and constraints)
"grayscale"
$defs.Metric.trend · Allowed values
"up", "down", "flat"
$defs.Metric.sentiment · Allowed values
"positive", "negative", "neutral"
$defs.TimelineEvent.status · Allowed values
"done", "current", "planned"
$defs.NumberingStyle · Allowed values
"arabic", "roman-upper", "roman-lower", "alpha-upper", "alpha-lower"
$defs.Numbering.style · Allowed values
"arabic", "roman-upper", "roman-lower", "alpha-upper", "alpha-lower"
$defs.Numbering.suffix · Allowed values
"period", "paren", "paren-both"
$defs.NumberingSpec · Named choices (see schema for other values and constraints)
"arabic", "roman-upper", "roman-lower", "alpha-upper", "alpha-lower"
$defs.NumberingSpec (oneOf 3)[] · Named choices (see schema for other values and constraints)
"arabic", "roman-upper", "roman-lower", "alpha-upper", "alpha-lower"
$defs.Caption (oneOf 3).position · Allowed values
"below", "above"
$defs.Caption (oneOf 3).align · Allowed values
"left", "center", "right"
$defs.Chart.type · Allowed values
"100pct-stacked-area", "100pct-stacked-bar", "100pct-stacked-column", "area", "bar", "box-and-whisker", "column", "combo", "doughnut", "filled-radar", "funnel", "histogram", "line", "line-with-markers", "pareto", "pie", "radar", "radar-with-markers", "scatter", "stacked-area", "stacked-bar", "stacked-column", "stacked-line", "stacked-line-with-markers", "treemap", "waterfall", "world"
$defs.Chart.legend · Allowed values
"none", "top", "bottom", "left", "right"
$defs.Chart.colors[] · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
$defs.ChartDataLabels.content[] · Allowed values
"value", "percent", "category"
$defs.ChartDataLabels.position · Allowed values
"auto", "center", "inside-end", "inside-base", "outside-end", "above", "below", "left", "right"
$defs.TableCellStyle.fill · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
$defs.TableCellStyle.color · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
$defs.TableCellStyle.align · Allowed values
"left", "center", "right"
$defs.TableCellStyle.verticalAlign · Allowed values
"top", "middle", "bottom"
$defs.TableCellBorder.color · Named choices (see schema for other values and constraints)
"accent1", "accent2", "accent3", "accent4", "accent5", "accent6", "dark1", "dark2", "light1", "light2", "hyperlink", "followedHyperlink", "primary", "secondary", "accent", "background", "surface", "surfaceAlt", "text", "textSecondary"
$defs.TableCellBorder.dash · Allowed values
"solid", "dash", "dot"
$defs.Catalogs.default · Named choices (see schema for other values and constraints)
false
$defs.Composition.mode · Allowed values
"auto", "grid", "row", "column"
$defs.Composition.overflow · Allowed values
"warn", "error"