@openpresentation/opf 0.10.1 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{catalogs-DoVmvDr7.d.ts → catalogs-atkOF4Vy.d.ts} +2 -2
- package/dist/catalogs.d.ts +2 -2
- package/dist/catalogs.js +1 -1
- package/dist/{chunk-TU7I3KSB.js → chunk-6FU2KICU.js} +306 -306
- package/dist/{chunk-ZIL7MGZU.js → chunk-CHKJ4QHQ.js} +223 -73
- package/dist/{chunk-EWJNRHXA.js → chunk-EQHZ3ZO4.js} +3 -3
- package/dist/{chunk-PQJRDNA6.js → chunk-FTWNWFIV.js} +72 -1
- package/dist/{chunk-FHGJX5QK.js → chunk-FWA5XB45.js} +33 -12
- package/dist/{chunk-D3GQIREP.js → chunk-GN52EE3P.js} +133 -12
- package/dist/composition-Tv9Wm3Oh.d.ts +691 -0
- package/dist/composition.d.ts +1 -676
- package/dist/composition.js +1 -1
- package/dist/docs.js +38 -8
- package/dist/examples.d.ts +1 -1
- package/dist/index.d.ts +65 -4
- package/dist/index.js +204 -6
- package/dist/lint.d.ts +3 -3
- package/dist/lint.js +5 -5
- package/dist/pagination.d.ts +2 -2
- package/dist/pagination.js +5 -5
- package/dist/{presentation-BMTdX6O1.d.ts → presentation-Ct42Mitb.d.ts} +51 -8
- package/dist/repo-readme.js +1 -1
- package/dist/{schemas-BYe5y8-i.d.ts → schemas-CiVmUT2p.d.ts} +6 -0
- package/dist/schemas.d.ts +1 -1
- package/dist/schemas.js +1 -1
- package/dist/spec/catalogs/narratives/board-meeting.json +21 -21
- package/dist/spec/catalogs/narratives/business-narrative.json +8 -8
- package/dist/spec/catalogs/narratives/business-review.json +12 -12
- package/dist/spec/catalogs/narratives/capacity-planning.json +8 -8
- package/dist/spec/catalogs/narratives/challenge-resolution.json +7 -7
- package/dist/spec/catalogs/narratives/classic-story.json +7 -7
- package/dist/spec/catalogs/narratives/company-intro.json +9 -9
- package/dist/spec/catalogs/narratives/conference-talk.json +1 -1
- package/dist/spec/catalogs/narratives/early-startup-pitch.json +12 -12
- package/dist/spec/catalogs/narratives/educate.json +9 -9
- package/dist/spec/catalogs/narratives/employee-review.json +8 -8
- package/dist/spec/catalogs/narratives/failure-analysis.json +10 -10
- package/dist/spec/catalogs/narratives/focus.json +12 -12
- package/dist/spec/catalogs/narratives/golden-circle.json +1 -1
- package/dist/spec/catalogs/narratives/innovation.json +9 -9
- package/dist/spec/catalogs/narratives/justice.json +11 -11
- package/dist/spec/catalogs/narratives/marketing-strategy.json +11 -11
- package/dist/spec/catalogs/narratives/performance-improvement-plan.json +8 -8
- package/dist/spec/catalogs/narratives/performance-review.json +11 -11
- package/dist/spec/catalogs/narratives/persuade.json +7 -7
- package/dist/spec/catalogs/narratives/persuasive-sales.json +8 -8
- package/dist/spec/catalogs/narratives/pitch-deck.json +3 -3
- package/dist/spec/catalogs/narratives/problem-solution.json +2 -2
- package/dist/spec/catalogs/narratives/product-launch.json +10 -10
- package/dist/spec/catalogs/narratives/project-proposal.json +10 -10
- package/dist/spec/catalogs/narratives/qbr.json +3 -3
- package/dist/spec/catalogs/narratives/rags-to-riches.json +7 -7
- package/dist/spec/catalogs/narratives/reveal.json +8 -8
- package/dist/spec/catalogs/narratives/scqa.json +1 -1
- package/dist/spec/catalogs/narratives/status-update.json +6 -6
- package/dist/spec/catalogs/narratives/strategic-advisory.json +7 -7
- package/dist/spec/catalogs/narratives/strategic-narrative.json +1 -1
- package/dist/spec/catalogs/narratives/survey-analysis.json +10 -10
- package/dist/spec/catalogs/narratives/survival-story.json +10 -10
- package/dist/spec/catalogs/narratives/transformation-arc.json +1 -1
- package/dist/spec/catalogs/narratives/trend-analysis.json +7 -7
- package/dist/spec/catalogs/narratives/underdog-victory.json +8 -8
- package/dist/spec/catalogs/narratives/venture-pitch.json +12 -12
- package/dist/spec/catalogs/narratives/weekly-progress.json +10 -10
- package/dist/spec/openapi.yaml +5 -0
- package/dist/spec/schemas/opf.schema.json +83 -12
- package/dist/types.d.ts +3 -3
- package/dist/validator.d.ts +7 -4
- package/dist/validator.js +4 -4
- package/package.json +1 -1
package/dist/docs.js
CHANGED
|
@@ -12,17 +12,23 @@ var docsData = Object.freeze([
|
|
|
12
12
|
"title": "OPF Catalog Schema Reference",
|
|
13
13
|
"markdown": "# OPF Catalog Schema Reference\n\nCatalog records are reusable presets that OPF documents reference by id. This page summarizes every companion schema in `spec/schemas/` except the top-level presentation schema.\n\nOPF documents usually reference these records with string ids such as `design.theme = \"minimal\"`, `tone = \"formal\"`, or `chart.type = \"line\"`. Dense examples may also embed catalog sources or inline records under `catalogs`.\n\n## Audience\n\n- File: `spec/schemas/audience.schema.json`\n- Schema id: `https://openpresentation.org/schema/opf-audience/v1`\n- Type: `object`\n- Required fields: `$schema`, `id`, `name`\n- Purpose: Schema for audience records in the pptx.gallery library. Each record names an audience archetype (e.g. 'executives', 'engineering-team', 'investors') and carries seniority, technical-fluency, decision-power, and attention-budget hints used by AI-driven generation. Audiences are referenced from OPF documents via audience; the engine resolves the reference against catalogs.audiences (inline) catalogs.audiences.source the default catalog at https://www.pptx.gallery/audiences. The audience field...\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `$schema` | yes | `const:\"https://openpresentation.org/schema/opf-audience/v1\"` | Identifies this record as an audience in the openpresentation.org catalog. |\n| `id` | yes | `string` | Stable slug used by OPF documents to reference this audience via audience. Lowercase kebab-case. |\n| `name` | yes | `string` | Human-readable audience name shown in pickers. |\n| `summary` | no | `string` | One-sentence positioning of the audience who they are and what they care about. |\n| `description` | no | `string` | Longer prose describing the audience archetype and how to address them. |\n| `seniority` | no | `enum:ic \\| manager \\| director \\| vp \\| c-suite \\| mixed` | Typical seniority level of the audience. Engines use this as a hint for default depth and pacing. |\n| `technicalFluency` | no | `enum:low \\| medium \\| high \\| mixed` | Typical technical fluency of the audience. AI generation uses this to decide whether to expand or assume technical terminology. |\n| `decisionPower` | no | `enum:informational \\| advisory \\| decision-maker` | Whether the audience is expected to be informed, to advise, or to actually decide. Shapes the strength of the closing ask. |\n| `attentionBudgetMinutes` | no | `number` | Realistic upper bound on this audience's focused attention for a single presentation, in minutes. Used as a hint when comparing against duration and the resolved narrative's durationRange. |\n| `recommendedNarratives` | no | `array<string>` | Soft cross-link: narrative-catalog ids that work well for this audience. Used by picker UIs to suggest narratives once an audience is chosen. Validators warn on unknown ids; never error. |\n| `recommendedTones` | no | `array<string>` | Soft cross-link: tone-catalog ids that work well for this audience. |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search. |\n| `preview` | no | `object` | Visual previews of the record, used by picker UIs and inline rendering. All sub-fields are optional. |\n\n## Catalog Index\n\n- File: `spec/schemas/catalog-index.schema.json`\n- Schema id: `https://openpresentation.org/schema/opf-catalog-index/v1`\n- Type: `object`\n- Required fields: `$schema`, `version`, `description`, `records`\n- Purpose: Generic shape shared by every `spec/catalogs/<kind>/index.json` file in the OPF repo. An index is a lightweight, ordered summary of the full-record JSON files that live alongside it: each entry names the record's stable id, a human-readable name, and the record's filename, plus whatever extra summary fields are useful for picker UIs (e.g. `summary`, `tags`, `bcp47`, `durationRange`). This schema describes the repo-internal catalog index files themselves, not OPF documents or individual catalo...\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `$schema` | yes | `const:\"https://openpresentation.org/schema/opf-catalog-index/v1\"` | |\n| `version` | yes | `string` | Index format version, as a string. |\n| `description` | yes | `string` | Human-readable description of what this catalog kind holds and how entries are ordered. |\n| `records` | yes | `array<ref:IndexRecord>` | Ordered list of lightweight record summaries. Order defines the catalog's canonical/display order; full record data lives in the sibling JSON file named by `file`. |\n\n### Nested Types\n\n#### IndexRecord\n\n- Type: `object`\n- Required fields: `id`, `name`, `file`\n- Purpose: Lightweight summary of one catalog record. Additional per-kind fields (e.g. `summary`, `tags`, `bcp47`, `durationRange`, `group`, `label`) are allowed and vary by catalog kind.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | yes | `string` | Stable identifier, matching the `id` field inside the record file named by `file`. |\n| `name` | yes | `string` | Human-readable name shown in pickers. |\n| `file` | yes | `string` | Filename of the full record, relative to this index file's directory. |\n\n## Chart Type\n\n- File: `spec/schemas/chart-type.schema.json`\n- Schema id: `https://openpresentation.org/schema/opf-chart-type/v1`\n- Type: `object`\n- Required fields: `$schema`, `id`, `name`, `mappings`\n- Purpose: Schema for chart-type records in the pptx.gallery catalog. Each record describes a named chart variant, its Open XML mapping, its series/category cardinality, the column structure of the underlying workbook, and a small sample dataset suitable for previews. Chart types are referenced from OPF chart content payloads; the engine resolves the reference against catalogs.chartTypes (inline) -> catalogs.chartTypes.source -> the default catalog at https://www.pptx.gallery/chart-types.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `$schema` | yes | `const:\"https://openpresentation.org/schema/opf-chart-type/v1\"` | Identifies this record as a chart type in the open presentation catalog. |\n| `id` | yes | `string` | Stable slug used by OPF documents to reference this chart type. Lowercase kebab-case. Chart type ids may start with a digit (e.g., '100pct-stacked-column', '3d-column') to mirror conventional chart naming. |\n| `name` | yes | `string` | Stable display/programmatic name for this chart type. |\n| `label` | no | `string` | Human-readable label shown in chart pickers. |\n| `summary` | no | `string` | One-sentence positioning: when to reach for this chart variant. |\n| `description` | no | `string` | Longer prose describing the chart and ideal use cases. |\n| `mappings` | yes | `ref:ChartTypeMappings` | Canonical and optional renderer-specific mappings used by engines to render this chart type. |\n| `group` | no | `string` | Top-level grouping in the chart picker (column, bar, line, area, pie, radar, etc.). |\n| `groupSort` | no | `integer` | Display ordering hint within the chart group. |\n| `complexity` | no | `enum:simple \\| calculated \\| hierarchical \\| normalized` | Shape of the underlying data: a flat series ('simple'), one with engine-side calculation ('calculated'), parent-child rows ('hierarchical'), or pre-normalized rows ('normalized'). |\n| `series` | no | `integer` | Number of data series this chart type expects. |\n| `categories` | no | `integer` | Number of category labels this chart type expects on the primary axis. |\n| `seriesGroups` | no | `integer` | Number of series groups (axis bands) this chart type uses; >1 for combo or banded charts. |\n| `useSecondaryCategories` | no | `boolean` | Whether the chart type uses a secondary category axis. |\n| `workbookRange` | no | `string` | A1 reference to the source range in the embedded workbook. |\n| `columns` | no | `array<string>` | Column header names of the embedded workbook, in left-to-right order. |\n| `dataColumns` | no | `array<ref:ChartDataColumn>` | Per-column metadata describing the role and position of each column in the workbook source. |\n| `helperColumns` | no | `array<string>` | Optional auxiliary column names used by calculated or banded charts (e.g., 'Excellent', 'Good', 'Fair', 'Poor' for a bullet chart). |\n| `sampleData` | no | `ref:ChartSampleData` | Inline sample dataset for previews and pickers. |\n| `slideNumber` | no | `integer` | Source slide number in the original chart-gallery deck. Carried for traceability. |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search. |\n| `preview` | no | `object` | Visual previews of the record, used by picker UIs and inline rendering. All sub-fields are optional; engines fall back gracefully when previews aren't available. |\n\n### Nested Types\n\n#### ChartTypeMappings\n\n- Type: `object`\n- Required fields: `openxml`\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `openxml` | yes | `ref:OpenXmlChartMapping` | Canonical mapping to Open XML chart structures. |\n| `renderers` | no | `object` | Optional renderer-specific mappings. Keys are renderer ids; values are intentionally opaque to OPF. |\n\n#### OpenXmlChartMapping\n\n- Type: `object`\n- Required fields: none\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `element` | no | `string` | Primary Open XML chart element or extension chart element, such as 'barChart', 'lineChart', 'pieChart', 'treemapChart', or 'waterfallChart'. |\n| `barDir` | no | `enum:bar \\| col` | Bar direction for Open XML barChart mappings. |\n| `grouping` | no | `enum:standard \\| clustered \\| stacked \\| percentStacked` | Open XML chart grouping value when the chart family supports grouping. |\n| `marker` | no | `boolean` | Whether the chart type expects visible data markers. |\n| `radarStyle` | no | `enum:standard \\| marker \\| filled` | Open XML radarStyle value for radarChart mappings. |\n| `scatterStyle` | no | `enum:line \\| lineMarker \\| marker \\| smooth \\| smoothMarker` | Open XML scatterStyle value for scatterChart mappings. |\n| `composition` | no | `enum:single \\| mixed \\| extension` | Whether the chart maps to one standard chart element, multiple combined chart elements, or an Open XML extension chart. |\n| `extension` | no | `string` | Optional Open XML extension namespace or element hint for extension charts. |\n| `series` | no | `array<ref:OpenXmlChartMapping>` | Open XML chart elements used by mixed/composite chart types. |\n| `notes` | no | `string` | Short implementation note for mappings that need renderer interpretation. |\n\n#### ChartDataColumn\n\n- Type: `object`\n- Required fields: `name`, `role`, `type`\n- Purpose: One column of the embedded chart workbook, annotated with its role and grid position.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `name` | yes | `string` | Column header name (e.g. 'Series 1', 'Value', 'Level1', 'Level2'). |\n| `role` | yes | `enum:categoryLabel \\| series \\| helper` | Role this column plays: a category label (axis tick), a series (plotted values), or a helper (calculated/auxiliary). |\n| `type` | yes | `enum:string \\| number` | Cell value type for the column. |\n| `position` | no | `string` | Grid position of the column header in the source workbook, as 'row<N>_col<M>' (zero-indexed). |\n\n#### ChartSampleData\n\n- Type: `object`\n- Required fields: `headers`, `rows`\n- Purpose: Inline sample dataset for previews. Mirrors a small workbook with header row plus data rows.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `headers` | yes | `array<string>` | Header row labels. The first cell typically labels the series column; the rest are category labels. |\n| `rows` | yes | `array<array<string \\| number>>` | Two-dimensional sample data. Each row aligns by index with the headers first cell is the row label, remaining cells are values. |\n\n## Color Scheme\n\n- File: `spec/schemas/color-scheme.schema.json`\n- Schema id: `https://openpresentation.org/schema/opf-color-scheme/v1`\n- Type: `object`\n- Required fields: `$schema`, `id`, `name`\n- Purpose: Schema for color-scheme records in the pptx.gallery library. Each scheme is a named palette with the twelve PowerPoint color slots (six accents, two darks, two lights, plus hyperlink and followed-hyperlink), suitable for being mapped directly into OOXML theme XML. Color schemes are referenced from OPF documents via design.colorScheme or design.colorScheme.id; the engine resolves the reference against catalogs.colorSchemes (inline) -> catalogs.colorSchemes.source -> the default catalog at http...\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `$schema` | yes | `const:\"https://openpresentation.org/schema/opf-color-scheme/v1\"` | Identifies this record as a color scheme in the openpresentation.org catalog. |\n| `id` | yes | `string` | Stable slug used by OPF documents to reference this color scheme. Lowercase kebab-case. |\n| `name` | yes | `string` | Human-readable scheme name shown in pickers. |\n| `summary` | no | `string` | One-sentence positioning of the palette what mood it evokes and where to use it. |\n| `description` | no | `string` | Longer prose describing the palette and its intended use. |\n| `accent1` | no | `string` | Accent 1 color (hex). Mirrors the OOXML accent1 slot. |\n| `accent2` | no | `string` | Accent 2 color (hex). Mirrors the OOXML accent2 slot. |\n| `accent3` | no | `string` | Accent 3 color (hex). Mirrors the OOXML accent3 slot. |\n| `accent4` | no | `string` | Accent 4 color (hex). Mirrors the OOXML accent4 slot. |\n| `accent5` | no | `string` | Accent 5 color (hex). Mirrors the OOXML accent5 slot. |\n| `accent6` | no | `string` | Accent 6 color (hex). Mirrors the OOXML accent6 slot. |\n| `dark1` | no | `string` | Dark 1 color (hex). Typically the deepest neutral; OOXML dark1. |\n| `dark2` | no | `string` | Dark 2 color (hex). Secondary dark; OOXML dark2. |\n| `light1` | no | `string` | Light 1 color (hex). Typically the slide canvas; OOXML lt1. |\n| `light2` | no | `string` | Light 2 color (hex). Secondary light surface; OOXML lt2. |\n| `hyperlink` | no | `string` | Hyperlink color (hex). OOXML hlink. |\n| `followedHyperlink` | no | `string` | Followed-hyperlink color (hex). OOXML folHlink. |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search. |\n| `preview` | no | `object` | Visual previews of the record, used by picker UIs and inline rendering. All sub-fields are optional; engines fall back gracefully when previews aren't available. |\n\n## Font Scheme\n\n- File: `spec/schemas/font-scheme.schema.json`\n- Schema id: `https://openpresentation.org/schema/opf-font-scheme/v1`\n- Type: `object`\n- Required fields: `$schema`, `id`, `name`, `major`, `minor`\n- Purpose: Schema for font-scheme records in the pptx.gallery library. Each scheme pairs a major (heading) and minor (body) font family in the OOXML majorFont/minorFont sense, scoped to a target app (PowerPoint or Google Slides) and a language family (Latin, East Asian, or Complex Script). Font schemes are referenced from OPF documents via design.fontScheme or design.fontScheme.id; the engine resolves the reference against catalogs.fontSchemes (inline) catalogs.fontSchemes.source the default catalog at...\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `$schema` | yes | `const:\"https://openpresentation.org/schema/opf-font-scheme/v1\"` | Identifies this record as a font scheme in the openpresentation.org catalog. |\n| `id` | yes | `string` | Stable slug used by OPF documents to reference this font scheme. Lowercase kebab-case. |\n| `name` | yes | `string` | Human-readable scheme name shown in pickers. |\n| `major` | yes | `string` | Heading (major) font family mirrors the OOXML majorFont entry. |\n| `minor` | yes | `string` | Body (minor) font family mirrors the OOXML minorFont entry. |\n| `type` | no | `enum:sans-serif \\| serif \\| monospace` | High-level typographic class of the scheme. |\n| `app` | no | `enum:PowerPoint \\| Google Slides` | Target application this font pairing is intended for. |\n| `languageFamily` | no | `enum:latin \\| ea \\| cs` | OOXML font-language family this scheme is intended for: 'latin' for Latin-script content, 'ea' for East Asian scripts, 'cs' for Complex Scripts. |\n| `languages` | no | `array<string>` | Optional list of human-readable language names this scheme is curated for. Useful for picker UIs that group fonts by language coverage. |\n| `textSample` | no | `string` | Short specimen string used by picker UIs to preview the scheme. |\n| `summary` | no | `string` | One-sentence positioning of the font pairing. |\n| `description` | no | `string` | Longer prose describing the font scheme and where it shines. |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search. |\n| `preview` | no | `object` | Visual previews of the record, used by picker UIs and inline rendering. All sub-fields are optional; engines fall back gracefully when previews aren't available. |\n\n## Language\n\n- File: `spec/schemas/language.schema.json`\n- Schema id: `https://openpresentation.org/schema/opf-language/v1`\n- Type: `object`\n- Required fields: `$schema`, `id`, `name`, `bcp47`\n- Purpose: Schema for language records in the pptx.gallery library. Each record names a presentation language, carries a BCP-47 language tag, and pairs it with sensible default font schemes for PowerPoint and Google Slides output. Languages are referenced from OPF documents via language; the engine resolves the reference against catalogs.languages (inline) catalogs.languages.source the default catalog at https://www.pptx.gallery/languages. The presentation language field also accepts BCP-47 tags directl...\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `$schema` | yes | `const:\"https://openpresentation.org/schema/opf-language/v1\"` | Identifies this record as a language in the openpresentation.org catalog. |\n| `id` | yes | `string` | Stable slug used by OPF documents to reference this language via language. Lowercase kebab-case. |\n| `name` | yes | `string` | Human-readable language name. |\n| `code` | no | `string` | ISO 639-3 (or 639-2) three-letter language code. Carried for engines that prefer ISO codes. |\n| `bcp47` | yes | `string` | BCP-47 language tag for this record. Use 'en-GB' for UK English; 'en-UK' is not a valid BCP-47 region form. |\n| `direction` | no | `enum:ltr \\| rtl` | Base text direction for the language. |\n| `script` | no | `string` | ISO 15924 script code when the writing system should be explicit. |\n| `fontScheme` | no | `string` | Default font-scheme id for this language when targeting PowerPoint output. Resolves against catalogs.fontSchemes the same way design.fontScheme or design.fontScheme.id does. |\n| `googleFontScheme` | no | `string` | Default font-scheme id for this language when targeting Google Slides output. Resolves against catalogs.fontSchemes the same way design.fontScheme or design.fontScheme.id does. |\n| `summary` | no | `string` | One-sentence note about coverage or font defaults. |\n| `description` | no | `string` | Longer prose describing the language record and any font-pairing rationale. |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search. |\n| `preview` | no | `object` | Visual previews of the record, used by picker UIs and inline rendering. All sub-fields are optional; engines fall back gracefully when previews aren't available. |\n\n## Layout Preview Index\n\n- File: `spec/schemas/layout-preview-index.schema.json`\n- Schema id: `https://openpresentation.org/schema/opf-layout-preview-index/v1`\n- Type: `object`\n- Required fields: `$schema`, `version`, `description`, `records`\n- Purpose: Shape of `spec/previews/layouts/index.json`, the manifest for the vendored slide-archetype preview gallery under `spec/previews/layouts/`. Each record names a preview id, its self-contained HTML file, and the file's exact UTF-8 byte length. These preview ids are an archetype taxonomy (e.g. 'swot-analysis', 'org-chart') distinct from the structural layout catalog at spec/catalogs/layouts/ (e.g. 'title', 'chart-2x') see spec/README.md. This schema describes a repo-internal index file, not an OP...\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `$schema` | yes | `const:\"https://openpresentation.org/schema/opf-layout-preview-index/v1\"` | |\n| `version` | yes | `string` | Index format version, as a string. |\n| `description` | yes | `string` | Human-readable description of the preview gallery and its rendering conventions. |\n| `records` | yes | `array<ref:PreviewRecord>` | One entry per vendored preview HTML file. |\n\n### Nested Types\n\n#### PreviewRecord\n\n- Type: `object`\n- Required fields: `id`, `file`, `bytes`\n- Purpose: Summary of one vendored preview HTML file.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | yes | `string` | Slide-archetype preview id (e.g. 'swot-analysis', 'agenda', 'org-chart'). Does not correspond to a spec/catalogs/layouts/ record id. |\n| `file` | yes | `string` | HTML filename, relative to this index file's directory. |\n| `bytes` | yes | `integer` | Exact UTF-8 byte length of the referenced HTML file's contents. |\n\n## Slide Layout\n\n- File: `spec/schemas/layout.schema.json`\n- Schema id: `https://openpresentation.org/schema/opf-layout/v1`\n- Type: `object`\n- Required fields: `$schema`, `id`, `name`\n- Purpose: Schema for slide-layout records in the pptx.gallery library. Each record describes a semantic slide layout what regions it exposes and what content kinds those regions are intended to hold. Layouts are referenced from OPF documents via Slide.layout; the engine resolves the reference against catalogs.layouts (inline) catalogs.layouts.source the default catalog at https://www.pptx.gallery/layouts. Free-form custom layout names that don't resolve through any catalog fall through to engine-define...\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `$schema` | yes | `const:\"https://openpresentation.org/schema/opf-layout/v1\"` | Identifies this record as a slide layout in the openpresentation.org catalog. |\n| `id` | yes | `string` | Stable slug used by OPF documents to reference this layout via Slide.layout. Lowercase kebab-case. |\n| `name` | yes | `string` | Human-readable layout name shown in layout pickers. |\n| `summary` | no | `string` | One-sentence positioning of the layout when to reach for it. |\n| `description` | no | `string` | Longer prose describing the layout structure and ideal use cases. |\n| `contentType` | no | `enum:Title \\| Text \\| List \\| Image \\| Number \\| Metric \\| Chart \\| Table \\| Code \\| Video \\| Quote \\| Timeline` | Primary kind of content the layout holds. Drives pickers and AI placement decisions. Metric is the canonical numeric/KPI category; Number remains an accepted legacy label. |\n| `contentMultiple` | no | `enum:None \\| 1x \\| 2x \\| 3x \\| 4x \\| 5x \\| 6x` | How many parallel content blocks the layout exposes ('2x' = two-column, '3x' = three-up, etc.). |\n| `contentAlignment` | no | `enum:None \\| Left \\| Center` | Default horizontal alignment of the content area. |\n| `contentBox` | no | `boolean` | Whether the content area is rendered inside a visible box / card. |\n| `contentTypeChartPrimary` | no | `enum:None \\| Top \\| Bottom \\| Left \\| Right` | For chart layouts, where the primary chart sits relative to the rest of the content. |\n| `contentTypeImageFill` | no | `enum:None \\| Crop \\| Fit` | For image layouts, how the image fills its slot. |\n| `contentTypeListBullet` | no | `enum:None \\| Character \\| Image` | For list layouts, how bullets are rendered. |\n| `contentTypeListHeading` | no | `boolean` | For list layouts, whether each list item carries a heading. |\n| `slideTag` | no | `boolean` | Whether the layout includes a small slide-level tag / label region above or near the title. |\n| `slideTitle` | no | `boolean` | Whether the layout includes a slide title region. |\n| `slideSubtitle` | no | `boolean` | Whether the layout includes a slide-level subtitle or supporting-description region. When placeholders is present, this is true exactly when the layout exposes a placeholder with type 'subtitle'. |\n| `slideTitleAlignment` | no | `enum:None \\| Left \\| Center` | Horizontal alignment of the slide title region. |\n| `slideImage` | no | `boolean` | Whether the layout includes a dedicated slide-level image region (separate from any content image). |\n| `slideImageAlignment` | no | `enum:None \\| Top \\| Bottom \\| Left \\| Right \\| Background` | Where the slide-level image sits relative to the content. |\n| `slideLayoutDirection` | no | `enum:None \\| Horizontal \\| Vertical` | Axis along which the layout's primary regions are arranged. |\n| `placeholders` | no | `array<ref:Placeholder>` | Ordered regions the layout exposes. The engine fills 'title', 'subtitle', and 'tag' placeholders from Slide.title, Slide.subtitle, and Slide.tag. Other placeholders are content-kind hints for renderers and pickers. Sl... |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search. |\n| `preview` | no | `object` | Visual previews of the record, used by picker UIs and inline rendering. All sub-fields are optional; engines fall back gracefully when previews aren't available. |\n| `composition` | no | `ref:Composition` | |\n\n### Nested Types\n\n#### Placeholder\n\n- Type: `object`\n- Required fields: `type`\n- Purpose: A single region inside a slide layout. Title, subtitle, and tag placeholders bind to the corresponding Slide fields; other placeholders describe the intended content kind for that region. The array order in the surrounding 'placeholders' field preserves layout region order.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `type` | yes | `enum:title \\| subtitle \\| tag \\| text \\| metric \\| quote \\| timeline \\| list \\| chart \\| picture \\| table \\| media \\| diagram \\| code` | OPF placeholder kind. 'text' and 'list' are flexible textual content regions. 'metric' is a numeric/KPI content region filled by a metric payload, including its optional label, description, unit, delta, and trend. The... |\n\n#### Composition\n\n- Type: `object`\n- Required fields: none\n- Purpose: Portable dynamic composition. Slide fields override the resolved layout. Nested groups arrange their children independently, inheriting only minFontSize and overflow. Explicit promoted regions retain their positions.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `mode` | no | `enum:auto \\| grid \\| row \\| column` | auto chooses a grid from available space and content; grid uses columns; row and column use one horizontal or vertical track. |\n| `columns` | no | `integer` | Column count for grid. In auto mode this caps the number of columns. |\n| `gap` | no | `number` | Space between cells as a fraction of the container short edge (canvas at slide root). Default 0.03333333333333333. |\n| `padding` | no | `number` | Inset as a fraction of the container short edge. Default 0.08 on a slide, 0 inside a group. |\n| `weights` | no | `array<number>` | Relative track sizes: columns for row/grid/auto, rows for column. Omitted tracks have weight 1; extra weights are ignored. |\n| `minFontSize` | no | `number` | 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. |\n| `overflow` | no | `enum:warn \\| error` | warn returns diagnostics for content that does not fit; error rejects layout. Content is never silently removed. Default warn. |\n\n## Narrative Template\n\n- File: `spec/schemas/narrative.schema.json`\n- Schema id: `https://openpresentation.org/schema/opf-narrative/v1`\n- Type: `object`\n- Required fields: `$schema`, `id`, `name`, `beats`\n- Purpose: Schema for narrative template files in the openpresentation.org catalog. Each template describes a named story arc (e.g. 'problem-solution', 'scqa') as an ordered list of beats. Templates are referenced from OPF documents via narrative either as a bare id string (e.g. 'classic-story') or as an inline object whose shape matches this schema (sans '$schema').\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `$schema` | yes | `const:\"https://openpresentation.org/schema/opf-narrative/v1\"` | |\n| `id` | yes | `string` | Stable slug used by OPF documents to reference this template, e.g. 'problem-solution'. Lowercase kebab-case. |\n| `name` | yes | `string` | Human-readable template name, e.g. 'Problem Solution'. |\n| `summary` | no | `string` | One-sentence description of when and why to use this narrative. |\n| `description` | no | `string` | Longer prose describing the narrative arc and ideal use cases. Used by AI-driven generation to seed deck-level direction. |\n| `audienceFit` | no | `array<string>` | Audiences this narrative works well for, e.g. ['executives', 'investors', 'customers']. |\n| `durationRange` | no | `object` | Typical talk-length window this narrative suits. |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search, e.g. ['business', 'pitch', 'internal']. |\n| `preview` | no | `object` | Visual previews of the record, used by picker UIs and inline rendering. All sub-fields are optional; engines fall back gracefully when previews aren't available. |\n| `beats` | yes | `array<ref:Beat>` | Ordered list of beats that make up the narrative arc. |\n\n### Nested Types\n\n#### Beat\n\n- Type: `object`\n- Required fields: `id`, `name`\n- Purpose: A single narrative beat a labeled segment of the story arc with a specific dramatic purpose. Mirrors the NarrativeBeat definition in opf.schema.json so library entries and inline OPF beats are interchangeable.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | yes | `string` | Stable slug used by Slide.beat to reference this beat. Lowercase kebab-case. |\n| `name` | yes | `string` | Human-readable beat name, e.g. 'The Problem'. |\n| `description` | no | `string` | Curator-written prose that explains what this beat should accomplish. |\n| `instructions` | no | `string` | Short author-facing instruction for the beat typically one phrase. Complements 'description' with a concise directive. |\n| `slideCount` | no | `integer` | Optional explicit slide count for this beat. Defaults to 1 when omitted; values >1 are reserved for beats that intentionally span multiple slides. Prefer decomposing a heavy beat into multiple beats over setting a hig... |\n| `slideType` | no | `enum:text \\| list \\| image \\| shape \\| chart \\| table \\| video \\| code \\| metric \\| quote \\| timeline` | Default content kind for the beat's slide. Uses ContentPayload.type names to help engines choose a layout. The legacy shape value is retained for compatibility and requests an image representation; it is not a native... |\n| `layoutHint` | no | `string` | Suggested layout id for the beat's opening slide, e.g. 'section-divider', 'title-slide', 'text-left'. Resolves the same way as Slide.layout against catalogs.layouts and the default catalog at https://www.pptx.gallery/... |\n| `thoughtCues` | no | `array<string>` | Optional speaker or thinking cues attached to the beat. Surfaced in presenter notes. |\n\n## Purpose\n\n- File: `spec/schemas/purpose.schema.json`\n- Schema id: `https://openpresentation.org/schema/opf-purpose/v1`\n- Type: `object`\n- Required fields: `$schema`, `id`, `name`\n- Purpose: Schema for purpose records in the pptx.gallery library. Each record names a presentation objective such as informing, aligning, persuading, driving a decision, or selling. Purposes are referenced from OPF documents via purpose; the engine resolves the reference against catalogs.purposes (inline) catalogs.purposes.source the default catalog at https://www.pptx.gallery/purposes. The purpose field also accepts free-form strings and inline Purpose objects.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `$schema` | yes | `const:\"https://openpresentation.org/schema/opf-purpose/v1\"` | Identifies this record as a purpose in the openpresentation.org catalog. |\n| `id` | yes | `string` | Stable slug used by OPF documents to reference this purpose via purpose. Lowercase kebab-case. |\n| `name` | yes | `string` | Human-readable purpose name shown in pickers. |\n| `summary` | no | `string` | One-sentence positioning of the purpose what this deck is trying to accomplish. |\n| `description` | no | `string` | Longer prose describing when to use this purpose and how it should shape a deck. |\n| `outcome` | no | `string` | Desired audience outcome after the presentation. |\n| `successCriteria` | no | `array<string>` | Observable signals that the deck accomplished this purpose. |\n| `recommendedNarratives` | no | `array<string>` | Soft cross-link: narrative-catalog ids that work well for this purpose. |\n| `recommendedTones` | no | `array<string>` | Soft cross-link: tone-catalog ids that work well for this purpose. |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search. |\n| `preview` | no | `object` | Visual previews of the record, used by picker UIs and inline rendering. All sub-fields are optional. |\n\n## Social Platform\n\n- File: `spec/schemas/social-platform.schema.json`\n- Schema id: `https://openpresentation.org/schema/opf-social-platform/v1`\n- Type: `object`\n- Required fields: `$schema`, `id`, `name`\n- Purpose: Schema for social-platform records in the pptx.gallery library. Each record describes a single social-media platform its base URL, profile-URL pattern, handle prefix, brand color, and themed icons. Records are referenced from OPF documents indirectly: the property keys of any Socials object (Organization.socials, Speaker.socials) match record ids, and renderers use the catalog record to format URLs and pick icons. The engine resolves references against catalogs.socialPlatforms (inline) catalo...\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `$schema` | yes | `const:\"https://openpresentation.org/schema/opf-social-platform/v1\"` | Identifies this record as a social-platform entry in the openpresentation.org catalog. |\n| `id` | yes | `string` | Stable slug used by OPF documents to reference this platform appears as a property key on Socials objects. Lowercase kebab-case. |\n| `name` | yes | `string` | Human-readable platform name shown in pickers and footers. |\n| `summary` | no | `string` | One-sentence positioning of the platform what it's used for and who's on it. |\n| `description` | no | `string` | Longer prose describing the platform and any rendering conventions (e.g., handle prefixes, distributed instances). |\n| `baseUrl` | no | `string` | Canonical base URL of the platform used as the prefix when normalizing handles to full URLs. |\n| `profileUrlPattern` | no | `string` | URL pattern for individual member profiles. Use '{handle}' as the placeholder for the handle (with the prefix already stripped). |\n| `companyUrlPattern` | no | `string` | Optional URL pattern for organization / company pages, when the platform distinguishes them from member profiles. Use '{handle}' as the placeholder. |\n| `handlePrefix` | no | `string` | Conventional prefix character displayed before the handle (e.g. '@' for X / Mastodon / Threads / TikTok). Empty string when no prefix is used. Renderers strip it before substituting into URL patterns. |\n| `handleExample` | no | `string` | Example handle in its conventional rendered form, used by picker UIs and validation hints. |\n| `brandColor` | no | `string` | Brand color (hex) used for branded icon chips, link styling, or section accents. |\n| `icon` | no | `string` | Default icon source. Accepts an HTTPS URL, data URI, relative path, or asset reference. Used as the fallback when a themed (Light/Dark) variant isn't set. |\n| `iconLight` | no | `string` | Light-colored icon variant intended for rendering on dark backgrounds. |\n| `iconDark` | no | `string` | Dark-colored icon variant intended for rendering on light backgrounds. |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search. |\n| `preview` | no | `object` | Visual previews of the record, used by picker UIs and inline rendering. All sub-fields are optional; engines fall back gracefully when previews aren't available. |\n\n## Theme\n\n- File: `spec/schemas/theme.schema.json`\n- Schema id: `https://openpresentation.org/schema/opf-theme/v1`\n- Type: `object`\n- Required fields: `$schema`, `id`, `name`\n- Purpose: Schema for theme records in the pptx.gallery library. Each theme is a small, named bundle that pairs a color scheme, a font scheme, a default theme-controlled background, and a slide size. Themes are referenced from OPF documents via design.theme or design.theme.id; the engine resolves the reference against catalogs.themes (inline) catalogs.themes.source the default catalog at https://www.pptx.gallery/themes. Inline overrides on design.colorScheme / design.fontScheme / design.background / des...\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `$schema` | yes | `const:\"https://openpresentation.org/schema/opf-theme/v1\"` | Identifies this record as a theme in the openpresentation.org catalog. |\n| `id` | yes | `string` | Stable slug used by OPF documents to reference this theme via design.theme. Lowercase kebab-case. |\n| `name` | yes | `string` | Human-readable theme name shown in pickers. |\n| `summary` | no | `string` | One-sentence positioning of the theme when to reach for it. |\n| `description` | no | `string` | Longer prose describing what the theme looks and feels like and the kinds of decks it suits. |\n| `colorScheme` | no | `string` | Catalog reference to the theme's default color scheme resolved against catalogs.colorSchemes the same way design.colorScheme or design.colorScheme.id is. Accepts a bare id, HTTPS URL, or 'pkg:' reference. |\n| `fontScheme` | no | `string` | Catalog reference to the theme's default font scheme resolved against catalogs.fontSchemes the same way design.fontScheme or design.fontScheme.id is. Accepts a bare id, HTTPS URL, or 'pkg:' reference. |\n| `background` | no | `ref:ThemeBackground` | |\n| `dimensions` | no | `enum:16:9 \\| 4:3 \\| 16:10 \\| letter \\| a4 \\| widescreen \\| standard` | Default slide size for this theme. Accepts the same preset values as design.dimensions.preset. |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search. |\n| `preview` | no | `object` | Visual previews of the record, used by picker UIs and inline rendering. All sub-fields are optional; engines fall back gracefully when previews aren't available. |\n\n### Nested Types\n\n#### ThemeBackgroundSlot\n\n- Type: `enum:light1 | light2 | dark1 | dark2`\n- Required fields: none\n- Purpose: 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.\n\n_No named properties._\n\n#### ThemeBackground\n\n- Type: `object`\n- Required fields: `type`, `slot`\n- Purpose: Theme-controlled PowerPoint slide background. The slot is resolved through the active color scheme and remains theme-aware.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `type` | yes | `const:\"theme\"` | Theme-controlled background fill. |\n| `slot` | yes | `ref:ThemeBackgroundSlot` | |\n\n## Tone\n\n- File: `spec/schemas/tone.schema.json`\n- Schema id: `https://openpresentation.org/schema/opf-tone/v1`\n- Type: `object`\n- Required fields: `$schema`, `id`, `name`\n- Purpose: Schema for tone records in the pptx.gallery library. Each record names a presentation tone (e.g. 'formal', 'casual', 'inspirational') and carries voice cues, anti-patterns, and sample phrases that AI-driven generation uses to shape output. Tones are referenced from OPF documents via tone; the engine resolves the reference against catalogs.tones (inline) catalogs.tones.source the default catalog at https://www.pptx.gallery/tones.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `$schema` | yes | `const:\"https://openpresentation.org/schema/opf-tone/v1\"` | Identifies this record as a tone in the openpresentation.org catalog. |\n| `id` | yes | `string` | Stable slug used by OPF documents to reference this tone via tone. Lowercase kebab-case. |\n| `name` | yes | `string` | Human-readable tone name shown in pickers. |\n| `summary` | no | `string` | One-sentence positioning of the tone when to reach for it. |\n| `description` | no | `string` | Longer prose describing the tone and the kinds of decks it suits. |\n| `voiceCues` | no | `array<string>` | Short directives that shape AI generation toward this tone. Phrased as imperatives, e.g. 'use second-person', 'favor short sentences', 'lead with the recommendation'. |\n| `avoid` | no | `array<string>` | Anti-patterns that AI generation should not produce when this tone is active. |\n| `samplePhrases` | no | `array<string>` | Short example phrases that exemplify this tone. Used by picker UIs and as few-shot examples for AI generation. |\n| `recommendedNarratives` | no | `array<string>` | Soft cross-link: narrative-catalog ids this tone pairs well with. Used by picker UIs to suggest narratives once a tone is chosen. Validators warn on unknown ids; never error. |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search. |\n| `preview` | no | `object` | Visual previews of the record, used by picker UIs and inline rendering. All sub-fields are optional. |\n"
|
|
14
14
|
},
|
|
15
|
+
{
|
|
16
|
+
"slug": "compatibility-matrix",
|
|
17
|
+
"file": "docs/compatibility-matrix.md",
|
|
18
|
+
"title": "Compatibility matrix",
|
|
19
|
+
"markdown": "# Compatibility matrix\n\nPublished registry evidence for the coordinated Node 24 toolchain. This matrix\nis the honest supported subset for [the developer quickstart](quickstart.md).\nIt is not universal Office parity and does not describe archived prototypes as\nshipped.\n\nVerify live versions with `npm view <package> version` before treating a\ndated handoff as current. The pin set below matches `release-plan.json` at the\ntime this file was updated.\n\n## Runtime\n\n| Requirement | Status |\n| --- | --- |\n| Node.js | **24.x** on every package below (`engines.node`) |\n| Package managers | npm for published installs; this repo uses pnpm 10.33.2 for core development |\n| Account / model / hosted API | Not required |\n| Operating systems | macOS, Linux, Windows for Node APIs; browser entrypoints are separate |\n\n## Coordinated published packages\n\n| Package | Version | Depends on |\n| --- | --- | --- |\n| `@openpresentation/opf` | 0.11.0 | \u2014 |\n| `@openpresentation/cli` | 0.9.0 | Bundles core 0.11.0; registry metadata has no runtime `dependencies` |\n| `@openpresentation/opf-render` | 0.8.1 | `@openpresentation/opf@^0.10.1` (0.11.x compatible for schema/validation; ColorRef paint needs a renderer release) |\n| `@openpresentation/opf-editor` | 0.7.1 | `@openpresentation/opf@^0.10.1`; peer `@openpresentation/opf-render@^0.8.1` |\n| `@openpresentation/opf-pptx` | 0.8.1 | `@openpresentation/opf@^0.10.1`; peer `@openpresentation/opf-render@^0.8.1` |\n\nInstall that whole set together. Mixing an older renderer or editor with core\n0.11.0 is unsupported for preview/export fidelity until those packages ship\nColorRef resolution.\n\nShared header/footer geometry (`furniture-flow-v2`) shipped in this set (core\ncomposition plus renderer 0.8.x / editor 0.7.x / PPTX 0.8.x consumers). It is\nnot a pending unpublished increment.\n\n## Supported in this set\n\n| Capability | How | Notes |\n| --- | --- | --- |\n| JSON authoring | `*.opf.json` plus CLI `opf create` | Local files only |\n| Bundled examples catalog | `@openpresentation/opf/examples` | **126** decks; the quickstart JSON is a docs fixture, not a 127th catalog entry |\n| Validate | `validatePresentation` / `opf validate` | Schema and semantic checks |\n| Lint | `lintSource` / `opf lint` | Read-only; no network catalog fetch |\n| Offline fonts | `prepareNodeFonts` (`/fonts-node`) | Bundled Roboto pack; hashed files |\n| Composition | `composeSlide` | Includes shared headers/footers |\n| Pagination | `paginatePresentation` / `opf paginate` | Returns mappings; preserves source |\n| Edit + undo | `@openpresentation/opf-editor` `createEditorSession` | JSON Patch undo/redo |\n| JSON Patch CLI | `opf edit` | No persistent CLI undo history |\n| SVG preview | `renderSvg` / `renderSvgDeck` | Local; same options as layout |\n| PNG | `svgToPng` | Node raster of SVG |\n| PDF | `svgToPdf` | **Raster-backed**, not selectable text |\n| Editable PPTX export | `toPptx` | OPF \u2192 PPTX serialization |\n| Agent skills | `opf skills install` | Offline after the CLI is installed |\n| Browser canvas | `@openpresentation/opf-editor/canvas` | Host must supply font bytes |\n\n## Explicitly not shipped\n\n| Topic | Tracker | Do not describe as done |\n| --- | --- | --- |\n| Linux vs Chromium native-width residual at the 0.1px gate | [opf-render#24](https://github.com/OpenPresentation/opf-render/issues/24) | Rounding that fixes Linux but breaks macOS is rejected |\n| Native PowerPoint open/edit/save/reopen, provenance, tabs, notes-master, font embedding | [opf#87](https://github.com/OpenPresentation/opf/issues/87) | Self-import and `toPptx` are not Office acceptance |\n| Public site route-by-route adoption | [opf#88](https://github.com/OpenPresentation/opf/issues/88) | Dependency bumps are not production verification |\n| HarfBuzz / prepared-glyph shaping | Archive branches `codex/archive-shaping-20260915` | Prototypes are preserved, not in npm |\n| Selectable vector PDF | [pdf plan](plans/pdf-export.md) | Follows font reliability |\n| General SVG diagrams / Mermaid | [diagrams plan](plans/diagrams-svg.md) | Embedded SVG \u2260 native editable primitives |\n| Full visual editor / IME / bidi / repair loop | [developer adoption](plans/developer-adoption-20260915.md) | Schema support \u2260 WYSIWYG coverage |\n\nCLI 0.8.1 does not render or export PPTX. Browser `svgToPng` / `svgToPdf` are\nnot available; those are Node APIs.\n\n## Predecessor notes\n\n| Older set | Relationship |\n| --- | --- |\n| core 0.10.0, renderer/PPTX/CLI 0.8.0, editor 0.7.0 | Previous coordinated Node 24 baseline. Lint and furniture landed across 0.10.0/0.8.0 then layout-placeholder fixes in 0.10.1/0.8.1/0.7.1. |\n| Node 20 / 22 | Not valid for these packages |\n\nDo not install sibling `../opf-render` dist folders when following the\nquickstart. Packed and registry consumers must resolve `@openpresentation/*`\nfrom npm.\n"
|
|
20
|
+
},
|
|
15
21
|
{
|
|
16
22
|
"slug": "content-item-design-overrides",
|
|
17
23
|
"file": "docs/content-item-design-overrides.md",
|
|
18
24
|
"title": "Possible Content Payload Design",
|
|
19
|
-
"markdown": '# Possible Content Payload Design\n\nThis is a parking-lot note for design controls intentionally removed from slide content payloads while the v1 content model stabilizes.\n\nCurrent principle: root slide payload fields and promoted region payloads should describe what the slide contains. Layout and rendering decide how it looks. If per-payload styling returns later, it should live in an explicit override surface rather than mixing presentation controls into the base content payload.\n\n## Possible Shape\n\n```jsonc\n{\n "title": "Revenue",\n "left": {\n "text": "Revenue grew 28%",\n "design": {\n "text": {\n "alignment": "center"\n }\n }\n }\n}\n```\n\nOpen question: whether overrides belong inline on each content payload, in `slides[].design`, or in a reusable style catalog keyed by region key or payload `type`.\n\n## Deferred Fields\n\nThese fields were deliberately kept out of `ContentPayload` for now:\n\n| Area | Candidate fields |\n| --- | --- |\n| Placement | `position`, `size`, `zIndex`, `rotation` |\n| Text | `style`, `fontSize`, `fontFamily`, `color`, `alignment`, `lineHeight`, `textTransform`, `verticalAlignment` |\n| Image/media | `fit`, `borderRadius`, `shadow`, `opacity`, `crop`, `focalPoint` |\n| Chart | `chartPreset`, `options`, `legend`, `showValues`, `showGrid`, `stacked`, `xAxis`, `yAxis`, palette overrides |\n| Table | `tableStyle`, `stripedRows`, `compact`, border colors, header colors |\n| Shape | `fill`, `stroke`, `cornerRadius`, `path` |\n| Code | `theme`, `showLineNumbers`, syntax-highlighting theme |\n\n## Decision Criteria\n\nBring these back only when there is a concrete renderer or authoring workflow that needs them. Prefer small, typed override objects over a large flat bag of visual fields on every content payload.\n'
|
|
25
|
+
"markdown": '# Possible Content Payload Design\n\nThis is a parking-lot note for design controls intentionally removed from slide content payloads while the v1 content model stabilizes.\n\nCurrent principle: root slide payload fields and promoted region payloads should describe what the slide contains. Layout and rendering decide how it looks. If per-payload styling returns later, it should live in an explicit override surface rather than mixing presentation controls into the base content payload.\n\n**Standing requirement for any styling surface that does return:** every color field must accept the shared `ColorRef` forms \u2014 literal hex, a color-scheme slot or role name, and a `var:<id>` variable reference \u2014 from its first release, never hex alone. Rich-text runs and styled table cells already follow this (see [`content-payloads.md`](./content-payloads.md) \u2192 "Color references"); the 0.10 styled-cell surface initially shipped hex-only and had to be widened, which is the failure mode this requirement exists to prevent. A styling surface that ships hex-only freezes every styled deck\'s palette outside the design system and breaks re-theming.\n\n## Possible Shape\n\n```jsonc\n{\n "title": "Revenue",\n "left": {\n "text": "Revenue grew 28%",\n "design": {\n "text": {\n "alignment": "center"\n }\n }\n }\n}\n```\n\nOpen question: whether overrides belong inline on each content payload, in `slides[].design`, or in a reusable style catalog keyed by region key or payload `type`.\n\n## Deferred Fields\n\nThese fields were deliberately kept out of `ContentPayload` for now:\n\n| Area | Candidate fields |\n| --- | --- |\n| Placement | `position`, `size`, `zIndex`, `rotation` |\n| Text | `style`, `fontSize`, `fontFamily`, `color`, `alignment`, `lineHeight`, `textTransform`, `verticalAlignment` |\n| Image/media | `fit`, `borderRadius`, `shadow`, `opacity`, `crop`, `focalPoint` |\n| Chart | `chartPreset`, `options`, `legend`, `showValues`, `showGrid`, `stacked`, `xAxis`, `yAxis`, palette overrides |\n| Table | `tableStyle`, `stripedRows`, `compact`, border colors, header colors |\n| Shape | `fill`, `stroke`, `cornerRadius`, `path` |\n| Code | `theme`, `showLineNumbers`, syntax-highlighting theme |\n\n## Decision Criteria\n\nBring these back only when there is a concrete renderer or authoring workflow that needs them. Prefer small, typed override objects over a large flat bag of visual fields on every content payload.\n'
|
|
20
26
|
},
|
|
21
27
|
{
|
|
22
28
|
"slug": "content-payloads",
|
|
23
29
|
"file": "docs/content-payloads.md",
|
|
24
30
|
"title": "Content Payloads",
|
|
25
|
-
"markdown": '# Content Payloads\n\nSlide content lives directly on a slide as a full-slide payload, in layout-agnostic `blocks`, or inside a promoted region key such as `left`, `center+right`, or `top:left`.\n\nThe optional payload `type` can make intent explicit, but OPF should usually infer the content kind from the field present:\n\n| Field | Inferred type | Notes |\n| --- | --- | --- |\n| `text` | `text` | Plain string or `TextRun[]`. |\n| `bullets` | `text` | Simple text bullets, usually `string[]`. |\n| `items` | `list` | Generic list payload, usually `string[]` or `ListItem[]`. |\n| `image` | `image` | Asset string shorthand or `Asset` object with `src` and optional metadata. |\n| `video` | `video` | Asset string shorthand or `Asset` object with `src` and optional metadata. |\n| `chart` | `chart` | Chart object with `type` and tabular `data`. |\n| `table` | `table` | Table object with optional `columns` and required `rows`. |\n| `code` | `code` | String shorthand or `Code` object with `source`, `language`, and `filename`. |\n| `metric` | `metric` | String/number shorthand or `Metric` object with `value`, `label`, `description`, `unit`, `delta`, and `trend`. |\n| `quote` | `quote` | String shorthand or `Quote` object with `text`, `attribution`, and `source`. |\n| `timeline` | `timeline` | Array shorthand or `Timeline` object with `name`, `description`, and `events`. |\n\n## Blocks\n\nUse slide-level `blocks` when a slide contains multiple content payloads, but exact placement should be inferred by the renderer. Blocks may contain a concrete content payload or a nested group with its own `blocks` and optional `composition`. Groups cannot mix child blocks with leaf payload fields. See [dynamic composition](dynamic-composition.md) for nesting and inheritance rules.\n\n```json\n{\n "title": "Customer Feedback Summary",\n "blocks": [\n {\n "table": {\n "columns": ["Theme", "Mentions"],\n "rows": [\n ["Speed", 42],\n ["Ease of use", 31]\n ]\n }\n },\n {\n "quote": {\n "text": "The new workflow cut review time in half.",\n "attribution": "Operations Lead",\n "source": "Customer interview"\n }\n }\n ]\n}\n```\n\nAt slide root only, multiple content payload kinds are accepted as shorthand for the equivalent blocks form when there is no explicit `type`, no `blocks`, and no promoted region keys:\n\n```json\n{\n "title": "Habitat & Territory",\n "text": "Jaguars are strongly associated with presence of water and dense cover.",\n "items": [\n "Primary habitats include dense rainforests, swamps, and seasonally flooded wetlands.",\n "Solitary animals that establish and defend large territories."\n ]\n}\n```\n\nThe same shorthand works for other content kinds:\n\n```json\n{\n "title": "Evidence Snapshot",\n "chart": {\n "type": "line",\n "data": {\n "columns": ["Quarter", "Sightings"],\n "rows": [\n ["Q1", 12],\n ["Q2", 18]\n ]\n }\n },\n "quote": {\n "text": "Jaguar conservation depends on connected habitat.",\n "attribution": "Field researcher"\n }\n}\n```\n\n## Chart\n\nChart-specific fields are grouped under `chart`. Do not put loose chart data directly on a slide or region.\n\n```json\n{\n "title": "Revenue Trend",\n "chart": {\n "type": "line",\n "data": {\n "columns": ["Quarter", "Revenue", "Costs"],\n "rows": [\n ["Q1", 12, 8],\n ["Q2", 18, 11],\n ["Q3", 24, 15]\n ]\n }\n }\n}\n```\n\nInline chart data is tabular by default. Renderers convert `columns` and `rows` into series, axes, legends, and workbook data internally.\n\nAsset-backed data is still table-oriented:\n\n```json\n{\n "chart": {\n "type": "column",\n "data": {\n "src": "asset:revenue-csv",\n "columns": ["Quarter", "Revenue"]\n }\n }\n}\n```\n\n## Table\n\nTable-specific fields are grouped under `table`. Do not put loose `columns` or `rows` directly on a slide or region.\n\n```json\n{\n "title": "Pipeline",\n "table": {\n "columns": ["Stage", "Count", "Value"],\n "rows": [\n ["Qualified", 42, "$1.2M"],\n ["Proposal", 18, "$840K"]\n ]\n }\n}\n```\n\nTable body cells accept strings, numbers, booleans, or `null`. Since core 0.5.0, a cell or column header also accepts the same `TextRun[]` used by rich text:\n\n```json\n{\n "table": {\n "columns": [["Quarter ", {"text": "growth", "bold": true}], "Value"],\n "rows": [\n [["Up ", {"text": "12%", "color": "#008800"}], 12]\n ]\n }\n}\n```\n\nUse core 0.6.0, renderer 0.4.0, editor 0.3.0 and PPTX 0.4.0 together. Core measures run styles when checking overflow and keeps each row intact when paginating. The renderer traces rich cells for the editor\'s existing formatting, typing and undo controls; the exporter emits editable native text runs. PPTX 0.4.0 imports supported native character styles, paragraph defaults, theme fonts/colors, external links and significant whitespace as rich runs. Unstyled body cells remain strings, and cached display text cannot recover original scalar types or live fields. Conditional table styles, merged geometry and cell fills/borders/alignment remain limited; native PowerPoint visual parity is not yet verified.\n\nCore 0.6.0 adds `layoutTable` from `@openpresentation/opf/composition`. It measures scalar and rich cells, keeps short rows compact, and gives wrapped or multiline rows the height they need. When space is constrained it reduces spare row height before shrinking text, and reports overflow when the minimum fitting size cannot fit. Pass the same `scale`, font family, measurement provider and effective `minFontSize` to each consumer. The returned row boxes, cell text boxes and fits are shared by the coordinated SVG and PPTX implementations; rich table cells use uniform line advances to match native cell paragraph spacing. Native viewer fidelity remains a separate verification boundary.\n\n\n## Code\n\nCode-specific fields are grouped under `code`. A string value is shorthand for `code.source`; use object form when syntax highlighting or a file label matters. In object form, `source` is required.\n\n```json\n{\n "title": "Decision Rule",\n "code": {\n "source": "if risk > threshold:\\n escalate(owner)\\nelse:\\n approve(change)",\n "language": "python",\n "filename": "decision.py"\n }\n}\n```\n\n## Metric\n\nMetric-specific fields are grouped under `metric`. A string or number value is shorthand for `metric.value`; numeric values stay numeric and are formatted by renderers at display time. Use object form when labels, descriptions, units, deltas, or trends matter.\n\nThe `number-1x` through `number-6x` layout IDs declare one title placeholder and one through six `metric` placeholders. The IDs retain their existing names; the content kind and payload key are `metric`, not `number` or `text`. For several metrics, use separate `{ "metric": ... }` entries in `blocks`. Choosing a layout does not reinterpret existing text as numeric data.\n\n```json\n{\n "title": "Operating Metric",\n "metric": {\n "value": "42%",\n "label": "Review cycle reduction",\n "description": "Median reduction across customer review workflows.",\n "delta": "+11 pts",\n "trend": "up"\n }\n}\n```\n\n## Quote\n\nQuote-specific fields are grouped under `quote`. A string value is shorthand for `quote.text`; use object form when attribution or citation matters.\n\n```json\n{\n "title": "Customer Proof",\n "quote": {\n "text": "The new workflow made exceptions visible before they became escalations.",\n "attribution": "VP Operations, Acme Corp",\n "source": "Customer interview"\n }\n}\n```\n\n## Timeline\n\nTimeline-specific fields are grouped under `timeline`. An array value is shorthand for `timeline.events`; use object form when the timeline needs a name or description. Timeline events use `when`, `what`, and `description`.\n\n```json\n{\n "title": "Rollout Plan",\n "timeline": {\n "name": "Regional Rollout",\n "description": "Major milestones for the rollout.",\n "events": [\n {\n "when": "Q1",\n "what": "Pilot",\n "description": "Launch with one operations team."\n },\n {\n "when": "Q2",\n "what": "Rollout",\n "description": "Expand to all regions."\n }\n ]\n }\n}\n```\n\n## Regions\n\nRegion keys address a 3\xD73 grid of rows (`top`, `middle`, `bottom`) and columns (`left`, `center`, `right`):\n\n```\n left center right\n +--------------------+--------------------+--------------------+\n top | top:left | top:center | top:right |\n +--------------------+--------------------+--------------------+\n middle | middle:left | middle:center | middle:right |\n +--------------------+--------------------+--------------------+\n bottom | bottom:left | bottom:center | bottom:right |\n +--------------------+--------------------+--------------------+\n```\n\n- A bare column key (`left`) spans all three rows; a bare row key (`top`) spans all three columns.\n- `+` spans adjacent rows or columns: `center+right`, `top+middle`.\n- `row:column` combines the two: `top:left`, `middle+bottom:center+right`.\n- Keys on one slide must not overlap, and regions cannot be mixed with root payload fields.\n\nSpans compose into common slide shapes:\n\n```\n "left" + "center+right" "top" + "middle+bottom"\n (sidebar + main) (headline band + body)\n +----------+------------------+ +-------------------------------+\n | | | | top |\n | | | +-------------------------------+\n | left | center+right | | |\n | | | | middle+bottom |\n | | | | |\n +----------+------------------+ +-------------------------------+\n\n "top" + "middle+bottom:left" + "middle+bottom:center+right"\n (headline band, then sidebar + main)\n +---------------------------------------------+\n | top |\n +---------------+-----------------------------+\n | | |\n | middle+bottom | middle+bottom:center+right |\n | :left | |\n | | |\n +---------------+-----------------------------+\n```\n\nThe same payload objects work inside regions \u2014 here, the sidebar-plus-main shape:\n\n```json\n{\n "title": "Operating Snapshot",\n "left": {\n "table": {\n "columns": ["Metric", "Value"],\n "rows": [\n ["Revenue", "$4.2M"],\n ["Gross margin", "68%"]\n ]\n }\n },\n "center+right": {\n "chart": {\n "type": "line",\n "data": {\n "columns": ["Month", "Revenue"],\n "rows": [\n ["Jan", 3.4],\n ["Feb", 3.8],\n ["Mar", 4.2]\n ]\n }\n }\n }\n}\n```\n'
|
|
31
|
+
"markdown": '# Content Payloads\n\nSlide content lives directly on a slide as a full-slide payload, in layout-agnostic `blocks`, or inside a promoted region key such as `left`, `center+right`, or `top:left`.\n\nThe optional payload `type` can make intent explicit, but OPF should usually infer the content kind from the field present:\n\n| Field | Inferred type | Notes |\n| --- | --- | --- |\n| `text` | `text` | Plain string or `TextRun[]`. |\n| `bullets` | `text` | Simple text bullets, usually `string[]`. |\n| `items` | `list` | Generic list payload, usually `string[]` or `ListItem[]`. |\n| `image` | `image` | Asset string shorthand or `Asset` object with `src` and optional metadata. |\n| `video` | `video` | Asset string shorthand or `Asset` object with `src` and optional metadata. |\n| `chart` | `chart` | Chart object with `type` and tabular `data`. |\n| `table` | `table` | Table object with optional `columns` and required `rows`. |\n| `code` | `code` | String shorthand or `Code` object with `source`, `language`, and `filename`. |\n| `metric` | `metric` | String/number shorthand or `Metric` object with `value`, `label`, `description`, `unit`, `delta`, and `trend`. |\n| `quote` | `quote` | String shorthand or `Quote` object with `text`, `attribution`, and `source`. |\n| `timeline` | `timeline` | Array shorthand or `Timeline` object with `name`, `description`, and `events`. |\n\n## Color references\n\nEvery content color field \u2014 `TextRun.color`, styled table cell `style.fill` and `style.color`, and table cell border `color` \u2014 accepts three forms:\n\n- A literal hex color: `"#0F172A"`, `"#B42318CC"`.\n- A color-scheme slot or role name, resolved through the effective color scheme after design resolution: slots `accent1`\u2013`accent6`, `dark1`, `dark2`, `light1`, `light2`, `hyperlink`, `followedHyperlink`; roles `primary`, `secondary`, `accent`, `background`, `surface`, `text`, `textSecondary`.\n- A variable reference `var:<id>` into the top-level `variables` map.\n\n```json\n{\n "variables": { "risk": "#B42318" },\n "slides": [\n {\n "title": "What Could Go Wrong",\n "items": [\n ["Two regions at ", { "text": "85% utilization", "color": "var:risk", "bold": true }],\n ["Mitigations ship in ", { "text": "November", "color": "accent2" }]\n ]\n }\n ]\n}\n```\n\nPrefer names and variables over literal hex: re-theming the deck updates every named reference, while a hex value stays frozen at authoring time. An unknown `var:` id is a validation warning, never an error; engines fall back to their default text color. The styled table cell and border color fields enforce the three forms at the schema level; run colors additionally accept any string so imported decks keep validating \u2014 unrecognized values warn, and renderers fall back to the theme color. See [`design-resolution.md`](./design-resolution.md) for the resolution rules.\n\n## Blocks\n\nUse slide-level `blocks` when a slide contains multiple content payloads, but exact placement should be inferred by the renderer. Blocks may contain a concrete content payload or a nested group with its own `blocks` and optional `composition`. Groups cannot mix child blocks with leaf payload fields. See [dynamic composition](dynamic-composition.md) for nesting and inheritance rules.\n\n```json\n{\n "title": "Customer Feedback Summary",\n "blocks": [\n {\n "table": {\n "columns": ["Theme", "Mentions"],\n "rows": [\n ["Speed", 42],\n ["Ease of use", 31]\n ]\n }\n },\n {\n "quote": {\n "text": "The new workflow cut review time in half.",\n "attribution": "Operations Lead",\n "source": "Customer interview"\n }\n }\n ]\n}\n```\n\nAt slide root only, multiple content payload kinds are accepted as shorthand for the equivalent blocks form when there is no explicit `type`, no `blocks`, and no promoted region keys:\n\n```json\n{\n "title": "Habitat & Territory",\n "text": "Jaguars are strongly associated with presence of water and dense cover.",\n "items": [\n "Primary habitats include dense rainforests, swamps, and seasonally flooded wetlands.",\n "Solitary animals that establish and defend large territories."\n ]\n}\n```\n\nThe same shorthand works for other content kinds:\n\n```json\n{\n "title": "Evidence Snapshot",\n "chart": {\n "type": "line",\n "data": {\n "columns": ["Quarter", "Sightings"],\n "rows": [\n ["Q1", 12],\n ["Q2", 18]\n ]\n }\n },\n "quote": {\n "text": "Jaguar conservation depends on connected habitat.",\n "attribution": "Field researcher"\n }\n}\n```\n\n## Chart\n\nChart-specific fields are grouped under `chart`. Do not put loose chart data directly on a slide or region.\n\n```json\n{\n "title": "Revenue Trend",\n "chart": {\n "type": "line",\n "data": {\n "columns": ["Quarter", "Revenue", "Costs"],\n "rows": [\n ["Q1", 12, 8],\n ["Q2", 18, 11],\n ["Q3", 24, 15]\n ]\n }\n }\n}\n```\n\nInline chart data is tabular by default. Renderers convert `columns` and `rows` into series, axes, legends, and workbook data internally.\n\nAsset-backed data is still table-oriented:\n\n```json\n{\n "chart": {\n "type": "column",\n "data": {\n "src": "asset:revenue-csv",\n "columns": ["Quarter", "Revenue"]\n }\n }\n}\n```\n\n## Table\n\nTable-specific fields are grouped under `table`. Do not put loose `columns` or `rows` directly on a slide or region.\n\n```json\n{\n "title": "Pipeline",\n "table": {\n "columns": ["Stage", "Count", "Value"],\n "rows": [\n ["Qualified", 42, "$1.2M"],\n ["Proposal", 18, "$840K"]\n ]\n }\n}\n```\n\nTable body cells accept strings, numbers, booleans, or `null`. Since core 0.5.0, a cell or column header also accepts the same `TextRun[]` used by rich text:\n\n```json\n{\n "table": {\n "columns": [["Quarter ", {"text": "growth", "bold": true}], "Value"],\n "rows": [\n [["Up ", {"text": "12%", "color": "#008800"}], 12]\n ]\n }\n}\n```\n\nUse core 0.6.0, renderer 0.4.0, editor 0.3.0 and PPTX 0.4.0 together. Core measures run styles when checking overflow and keeps each row intact when paginating. The renderer traces rich cells for the editor\'s existing formatting, typing and undo controls; the exporter emits editable native text runs. PPTX 0.4.0 imports supported native character styles, paragraph defaults, theme fonts/colors, external links and significant whitespace as rich runs. Unstyled body cells remain strings, and cached display text cannot recover original scalar types or live fields. Conditional table styles, merged geometry and cell fills/borders/alignment remain limited; native PowerPoint visual parity is not yet verified.\n\nCore 0.6.0 adds `layoutTable` from `@openpresentation/opf/composition`. It measures scalar and rich cells, keeps short rows compact, and gives wrapped or multiline rows the height they need. When space is constrained it reduces spare row height before shrinking text, and reports overflow when the minimum fitting size cannot fit. Pass the same `scale`, font family, measurement provider and effective `minFontSize` to each consumer. The returned row boxes, cell text boxes and fits are shared by the coordinated SVG and PPTX implementations; rich table cells use uniform line advances to match native cell paragraph spacing. Native viewer fidelity remains a separate verification boundary.\n\n\n## Code\n\nCode-specific fields are grouped under `code`. A string value is shorthand for `code.source`; use object form when syntax highlighting or a file label matters. In object form, `source` is required.\n\n```json\n{\n "title": "Decision Rule",\n "code": {\n "source": "if risk > threshold:\\n escalate(owner)\\nelse:\\n approve(change)",\n "language": "python",\n "filename": "decision.py"\n }\n}\n```\n\n## Metric\n\nMetric-specific fields are grouped under `metric`. A string or number value is shorthand for `metric.value`; numeric values stay numeric and are formatted by renderers at display time. Use object form when labels, descriptions, units, deltas, or trends matter.\n\nThe `number-1x` through `number-6x` layout IDs declare one title placeholder and one through six `metric` placeholders. The IDs retain their existing names; the content kind and payload key are `metric`, not `number` or `text`. For several metrics, use separate `{ "metric": ... }` entries in `blocks`. Choosing a layout does not reinterpret existing text as numeric data.\n\n```json\n{\n "title": "Operating Metric",\n "metric": {\n "value": "42%",\n "label": "Review cycle reduction",\n "description": "Median reduction across customer review workflows.",\n "delta": "+11 pts",\n "trend": "up"\n }\n}\n```\n\n## Quote\n\nQuote-specific fields are grouped under `quote`. A string value is shorthand for `quote.text`; use object form when attribution or citation matters.\n\n```json\n{\n "title": "Customer Proof",\n "quote": {\n "text": "The new workflow made exceptions visible before they became escalations.",\n "attribution": "VP Operations, Acme Corp",\n "source": "Customer interview"\n }\n}\n```\n\n## Timeline\n\nTimeline-specific fields are grouped under `timeline`. An array value is shorthand for `timeline.events`; use object form when the timeline needs a name or description. Timeline events use `when`, `what`, and `description`.\n\n```json\n{\n "title": "Rollout Plan",\n "timeline": {\n "name": "Regional Rollout",\n "description": "Major milestones for the rollout.",\n "events": [\n {\n "when": "Q1",\n "what": "Pilot",\n "description": "Launch with one operations team."\n },\n {\n "when": "Q2",\n "what": "Rollout",\n "description": "Expand to all regions."\n }\n ]\n }\n}\n```\n\n## Regions\n\nRegion keys address a 3\xD73 grid of rows (`top`, `middle`, `bottom`) and columns (`left`, `center`, `right`):\n\n```\n left center right\n +--------------------+--------------------+--------------------+\n top | top:left | top:center | top:right |\n +--------------------+--------------------+--------------------+\n middle | middle:left | middle:center | middle:right |\n +--------------------+--------------------+--------------------+\n bottom | bottom:left | bottom:center | bottom:right |\n +--------------------+--------------------+--------------------+\n```\n\n- A bare column key (`left`) spans all three rows; a bare row key (`top`) spans all three columns.\n- `+` spans adjacent rows or columns: `center+right`, `top+middle`.\n- `row:column` combines the two: `top:left`, `middle+bottom:center+right`.\n- Keys on one slide must not overlap, and regions cannot be mixed with root payload fields.\n\nSpans compose into common slide shapes:\n\n```\n "left" + "center+right" "top" + "middle+bottom"\n (sidebar + main) (headline band + body)\n +----------+------------------+ +-------------------------------+\n | | | | top |\n | | | +-------------------------------+\n | left | center+right | | |\n | | | | middle+bottom |\n | | | | |\n +----------+------------------+ +-------------------------------+\n\n "top" + "middle+bottom:left" + "middle+bottom:center+right"\n (headline band, then sidebar + main)\n +---------------------------------------------+\n | top |\n +---------------+-----------------------------+\n | | |\n | middle+bottom | middle+bottom:center+right |\n | :left | |\n | | |\n +---------------+-----------------------------+\n```\n\nThe same payload objects work inside regions \u2014 here, the sidebar-plus-main shape:\n\n```json\n{\n "title": "Operating Snapshot",\n "left": {\n "table": {\n "columns": ["Metric", "Value"],\n "rows": [\n ["Revenue", "$4.2M"],\n ["Gross margin", "68%"]\n ]\n }\n },\n "center+right": {\n "chart": {\n "type": "line",\n "data": {\n "columns": ["Month", "Revenue"],\n "rows": [\n ["Jan", 3.4],\n ["Feb", 3.8],\n ["Mar", 4.2]\n ]\n }\n }\n }\n}\n```\n'
|
|
26
32
|
},
|
|
27
33
|
{
|
|
28
34
|
"slug": "data-import",
|
|
@@ -34,7 +40,7 @@ var docsData = Object.freeze([
|
|
|
34
40
|
"slug": "design-resolution",
|
|
35
41
|
"file": "docs/design-resolution.md",
|
|
36
42
|
"title": "Design Resolution",
|
|
37
|
-
"markdown": '# Design Resolution\n\nHow an engine decides the effective design for any given slide. The schema spreads these rules across field descriptions; this page states them once, as an algorithm.\n\n## Precedence\n\nFor every design field independently, the most specific source wins:\n\n```\n wins +--------------------------------------------------------+\n ^ | 1. slide design slides[i].design.* |\n | +--------------------------------------------------------+\n | | 2. deck design design.* on the presentation root |\n | +--------------------------------------------------------+\n | | 3. resolved theme colorScheme, fontScheme, |\n | | background, dimensions from the |\n | | theme record |\n | +--------------------------------------------------------+\n loses | 4. engine defaults e.g. spec/reference/ |\n v | engine-defaults.json |\n +--------------------------------------------------------+\n```\n\n1. **Slide design** \u2014 `slides[].design.*`\n2. **Deck design** \u2014 `design.*` on the presentation root\n3. **Resolved theme** \u2014 defaults carried by the theme record (`colorScheme`, `fontScheme`, `background`, `dimensions`)\n4. **Engine defaults** \u2014 engine configuration such as [`spec/reference/engine-defaults.json`](../spec/reference/engine-defaults.json)\n\nResolution is **per field**, not per object. A slide that sets only `design.contentAlignment` inherits everything else from the deck design; a deck that sets only `design.colorScheme` keeps the theme\'s font scheme and background.\n\nTwo field-level rules complete the picture:\n\n- **Base-plus-overrides within one object.** Wherever a reference object carries an `id` (`Theme`, `ColorScheme`, `FontScheme`), the `id` resolves a catalog record as the base and sibling fields override the resolved record per key. The string shorthand (`"colorScheme": "cool-horizon"`) is equivalent to setting only `id`.\n\n ```\n "colorScheme": { "id": "cool-horizon", "accent1": "#0F4C81" }\n\n catalog record "cool-horizon" sibling fields on the object\n accent1: "#2874A6" <-- replaced -- accent1: "#0F4C81"\n accent2: "#1B4F72" <-- kept\n light1: "#FFFFFF" <-- kept\n |\n v\n effective scheme: accent1 from the override, everything else\n from the record\n ```\n- **Explicit suppression.** `watermark`, `header`, and `footer` accept `false` to switch off an inherited value \u2014 distinct from omitting the field, which inherits.\n\nCatalog lookups inside this chain follow the standard resolution order (inline `catalogs.<kind>.records[]` \u2192 `catalogs.<kind>.source` \u2192 default catalog); see [`how-opf-works.md`](./how-opf-works.md).\n\n## Worked example 1: color scheme through every level\n\n```json\n{\n "design": {\n "theme": "classic",\n "colorScheme": "forest-green"\n },\n "slides": [\n { "title": "Inherits the deck" },\n {\n "title": "Slide override",\n "design": {\n "colorScheme": { "id": "cool-horizon", "accent1": "#0F4C81" }\n }\n }\n ]\n}\n```\n\n- Slide 1: the `classic` theme record supplies its own default color scheme, but the deck design sets `colorScheme` explicitly, so `forest-green` wins (level 2 beats level 3). Fonts, background, and dimensions still come from `classic`.\n- Slide 2: slide design beats deck design (level 1 beats level 2). The `cool-horizon` record resolves as the base, then `accent1` is replaced by `#0F4C81`. All other `cool-horizon` slots survive.\n\nThere is no ambiguity between "override" and "reference": every scheme value *is* a reference, and any sibling fields on the same object are overrides applied after the reference resolves.\n\n## Worked example 2: backgrounds and suppression\n\n```json\n{\n "design": {\n "theme": "dark",\n "background": "light1",\n "footer": {\n "left": { "text": "Acme Corp" },\n "right": { "slideNumber": true }\n }\n },\n "slides": [\n { "title": "Light slide in a dark theme" },\n {\n "title": "Section divider",\n "design": {\n "background": {\n "type": "gradient",\n "gradient": {\n "angle": 90,\n "stops": [\n { "color": "#0B1B2B", "position": 0 },\n { "color": "#123A5F", "position": 1 }\n ]\n }\n },\n "footer": false\n }\n }\n ]\n}\n```\n\n- Slide 1: the deck-level `background: "light1"` overrides the `dark` theme\'s default background. `light1` is a theme slot \u2014 it resolves through the effective color scheme, which itself resolved through the chain above.\n- Slide 2: the gradient replaces the deck background for this slide only, and `footer: false` suppresses the inherited footer rather than inheriting or replacing it.\n\n## Worked example 3: font scheme models\n\n```json\n{\n "design": {\n "fontScheme": {\n "id": "aptos",\n "code": { "family": "JetBrains Mono" }\n }\n }\n}\n```\n\nThe `aptos` record supplies the OOXML pair (`major`/`minor`). The `code` role is an OPF-specific addition with no OOXML slot, so it layers on top without disturbing the pair. When serializing to PowerPoint, engines write `major`/`minor` to `majorFont`/`minorFont` and map abstract roles (`heading`, `body`) onto those slots; roles like `accent` and `code` are renderer concerns. The same slot-versus-role split applies to color schemes: OOXML slots (`accent1`\u2013`accent6`, `dark1/2`, `light1/2`) round-trip directly, abstract roles (`primary`, `text`, `surface`, \u2026) are mapped onto slots by the engine.\n\n## What is *not* part of this chain\n\
|
|
43
|
+
"markdown": '# Design Resolution\n\nHow an engine decides the effective design for any given slide. The schema spreads these rules across field descriptions; this page states them once, as an algorithm.\n\n## Precedence\n\nFor every design field independently, the most specific source wins:\n\n```\n wins +--------------------------------------------------------+\n ^ | 1. slide design slides[i].design.* |\n | +--------------------------------------------------------+\n | | 2. deck design design.* on the presentation root |\n | +--------------------------------------------------------+\n | | 3. resolved theme colorScheme, fontScheme, |\n | | background, dimensions from the |\n | | theme record |\n | +--------------------------------------------------------+\n loses | 4. engine defaults e.g. spec/reference/ |\n v | engine-defaults.json |\n +--------------------------------------------------------+\n```\n\n1. **Slide design** \u2014 `slides[].design.*`\n2. **Deck design** \u2014 `design.*` on the presentation root\n3. **Resolved theme** \u2014 defaults carried by the theme record (`colorScheme`, `fontScheme`, `background`, `dimensions`)\n4. **Engine defaults** \u2014 engine configuration such as [`spec/reference/engine-defaults.json`](../spec/reference/engine-defaults.json)\n\nResolution is **per field**, not per object. A slide that sets only `design.contentAlignment` inherits everything else from the deck design; a deck that sets only `design.colorScheme` keeps the theme\'s font scheme and background.\n\nTwo field-level rules complete the picture:\n\n- **Base-plus-overrides within one object.** Wherever a reference object carries an `id` (`Theme`, `ColorScheme`, `FontScheme`), the `id` resolves a catalog record as the base and sibling fields override the resolved record per key. The string shorthand (`"colorScheme": "cool-horizon"`) is equivalent to setting only `id`.\n\n ```\n "colorScheme": { "id": "cool-horizon", "accent1": "#0F4C81" }\n\n catalog record "cool-horizon" sibling fields on the object\n accent1: "#2874A6" <-- replaced -- accent1: "#0F4C81"\n accent2: "#1B4F72" <-- kept\n light1: "#FFFFFF" <-- kept\n |\n v\n effective scheme: accent1 from the override, everything else\n from the record\n ```\n- **Explicit suppression.** `watermark`, `header`, and `footer` accept `false` to switch off an inherited value \u2014 distinct from omitting the field, which inherits.\n\nCatalog lookups inside this chain follow the standard resolution order (inline `catalogs.<kind>.records[]` \u2192 `catalogs.<kind>.source` \u2192 default catalog); see [`how-opf-works.md`](./how-opf-works.md).\n\n## Worked example 1: color scheme through every level\n\n```json\n{\n "design": {\n "theme": "classic",\n "colorScheme": "forest-green"\n },\n "slides": [\n { "title": "Inherits the deck" },\n {\n "title": "Slide override",\n "design": {\n "colorScheme": { "id": "cool-horizon", "accent1": "#0F4C81" }\n }\n }\n ]\n}\n```\n\n- Slide 1: the `classic` theme record supplies its own default color scheme, but the deck design sets `colorScheme` explicitly, so `forest-green` wins (level 2 beats level 3). Fonts, background, and dimensions still come from `classic`.\n- Slide 2: slide design beats deck design (level 1 beats level 2). The `cool-horizon` record resolves as the base, then `accent1` is replaced by `#0F4C81`. All other `cool-horizon` slots survive.\n\nThere is no ambiguity between "override" and "reference": every scheme value *is* a reference, and any sibling fields on the same object are overrides applied after the reference resolves.\n\n## Worked example 2: backgrounds and suppression\n\n```json\n{\n "design": {\n "theme": "dark",\n "background": "light1",\n "footer": {\n "left": { "text": "Acme Corp" },\n "right": { "slideNumber": true }\n }\n },\n "slides": [\n { "title": "Light slide in a dark theme" },\n {\n "title": "Section divider",\n "design": {\n "background": {\n "type": "gradient",\n "gradient": {\n "angle": 90,\n "stops": [\n { "color": "#0B1B2B", "position": 0 },\n { "color": "#123A5F", "position": 1 }\n ]\n }\n },\n "footer": false\n }\n }\n ]\n}\n```\n\n- Slide 1: the deck-level `background: "light1"` overrides the `dark` theme\'s default background. `light1` is a theme slot \u2014 it resolves through the effective color scheme, which itself resolved through the chain above.\n- Slide 2: the gradient replaces the deck background for this slide only, and `footer: false` suppresses the inherited footer rather than inheriting or replacing it.\n\n## Worked example 3: font scheme models\n\n```json\n{\n "design": {\n "fontScheme": {\n "id": "aptos",\n "code": { "family": "JetBrains Mono" }\n }\n }\n}\n```\n\nThe `aptos` record supplies the OOXML pair (`major`/`minor`). The `code` role is an OPF-specific addition with no OOXML slot, so it layers on top without disturbing the pair. When serializing to PowerPoint, engines write `major`/`minor` to `majorFont`/`minorFont` and map abstract roles (`heading`, `body`) onto those slots; roles like `accent` and `code` are renderer concerns. The same slot-versus-role split applies to color schemes: OOXML slots (`accent1`\u2013`accent6`, `dark1/2`, `light1/2`) round-trip directly, abstract roles (`primary`, `text`, `surface`, \u2026) are mapped onto slots by the engine.\n\n## Color references in content\n\nContent color fields (`TextRun.color`, styled table cell `style.fill` / `style.color`, table cell border `color`) accept references as well as literal hex, and those references resolve through the same chain above:\n\n```\n "color": "accent2" slot name -> effective color scheme slot\n "color": "text" role name -> role-to-slot mapping, then the slot\n "color": "var:risk" variable -> top-level variables map\n "color": "#B42318" literal -> used as-is (frozen at authoring time)\n```\n\n- **Slot names** (`accent1`\u2013`accent6`, `dark1`, `dark2`, `light1`, `light2`, `hyperlink`, `followedHyperlink`) read the named slot from the *effective* color scheme \u2014 the one produced by the slide \u2192 deck \u2192 theme \u2192 engine-default precedence at the top of this page. A slide-level `design.colorScheme` override therefore recolors that slide\'s named runs too.\n- **Role names** (`primary`, `secondary`, `accent`, `background`, `surface`, `text`, `textSecondary`) resolve through the same role handling engines already apply to color schemes: a role defined on the effective scheme is used directly; otherwise the engine maps the role onto a slot exactly as it does when serializing schemes.\n- **Variable references** (`var:<id>`) resolve against the document\'s top-level `variables` map, independent of the scheme. Variables are deck-scoped named colors \u2014 use them for values that have meaning (`var:risk`) or repeat across slides. An unknown id is a validation warning, never an error, and engines fall back to their default text color.\n\nThe styled table cell and border color fields enforce the reference forms at the schema level (a typo like `"acent2"` is a schema error there \u2014 neither hex, a known name, nor a `var:` reference). Run colors stay open strings so imported decks keep validating: an unrecognized run color is a validation warning, and renderers fall back to the theme text color \u2014 the same warn-don\'t-error posture unknown catalog ids get. Unknown `var:` ids are warnings everywhere.\n\n`@openpresentation/opf` exports `resolveColorRef()` with the shared slot, role, variable, and hex rules above so renderers and exporters do not drift. Pass the effective color scheme, optional resolved role colors, the deck `variables` map, and a theme-text `fallback` for unrecognized references.\n\n## What is *not* part of this chain\n\nBeyond the color references above, content payloads carry no design controls in v1 \u2014 `position`, `fontSize` overrides at payload level, and the like were deliberately kept out while the content model stabilizes (see [`content-item-design-overrides.md`](./content-item-design-overrides.md); styled table cells and rich-text runs carry the only per-content styling, and their color fields take the reference forms above). The design system, plus layout hints (`titleAlignment`, `contentBox`, `chartPrimary`, ...) and dynamic composition, is the styling surface of an OPF document.\n'
|
|
38
44
|
},
|
|
39
45
|
{
|
|
40
46
|
"slug": "dynamic-composition",
|
|
@@ -58,7 +64,7 @@ var docsData = Object.freeze([
|
|
|
58
64
|
"slug": "examples",
|
|
59
65
|
"file": "docs/examples.md",
|
|
60
66
|
"title": "OPF Examples Guide",
|
|
61
|
-
"markdown": "# OPF Examples Guide\n\nThe `examples/` directory has
|
|
67
|
+
"markdown": "# OPF Examples Guide\n\nThe `examples/` directory has two shipped layers, plus a docs fixture kept outside the catalog:\n\n- `examples/technical/` contains compact fixtures that isolate one or two schema behaviors.\n- `examples/gallery/` contains scenario-oriented decks that show OPF working across industries, functions, education, government, international, presentation-type, and design/media use cases.\n- The representative deck for [the published-package quickstart](quickstart.md) lives at [`docs/quickstart/developer-quickstart.opf.json`](quickstart/developer-quickstart.opf.json), outside the catalog, so `@openpresentation/opf/examples` stays at the published example count (currently 126 decks); the renderer golden corpus tracks that catalog on its own release cadence.\n- The examples root is kept as an organizing directory rather than a home for standalone OPF files.\n\n## Technical Fixtures\n\nUse `examples/technical/` when you want a small file that exercises a specific schema surface:\n\n- content payloads, rich text, blocks, charts, tables, media, metrics, quotes, and timelines\n- promoted region keys and span combinations\n- asset string/object forms and asset-backed chart data\n- design backgrounds, logo sets, headers, footers, watermarks, and slide-level overrides\n- metadata array forms, language metadata, narrative beats, and catalog overrides\n\n## Gallery Folders\n\n| Folder | What It Demonstrates |\n| --- | --- |\n| `industries/` | Vertical market decks with operating plans, investment briefs, readiness reviews, and launch coordination. |\n| `business-functions/` | Department-specific decks for sales, marketing, product, engineering, finance, HR, legal, security, support, procurement, and strategy. |\n| `education/` | K-12, higher education, research, advising, workforce, advancement, and student services scenarios. |\n| `government/` | Public health, transit, emergency management, utilities, regulators, courts, parks, workforce, tax, and civic engagement decks. |\n| `presentation-types/` | Reusable deck archetypes such as pitches, board updates, QBRs, conference talks, workshops, postmortems, launches, policy briefings, training, and research reports. |\n| `international/` | Region- or language-specific decks, including examples of language object metadata and right-to-left direction. |\n| `design-and-media/` | Decks that emphasize design controls, image/video assets, data storytelling, and self-running orientation patterns. |\n\n## Patterns To Look For\n\n- Technical fixtures that isolate validator and renderer behavior.\n- Sparse gallery documents that use shorthand catalog references and a small slide list.\n- Medium documents with schema ids, metadata, organization and speaker records, design overrides, assets, and richer slide payloads.\n- Dense documents with inline `catalogs` sources and records, promoted region keys, `blocks`, media assets, code payloads, header/footer configuration, logo sets, watermarks, and extensions.\n- Mixed content payloads across text, bullets, lists, image, video, chart, table, code, metric, quote, and timeline slides.\n- Catalog references across narratives, layouts, chart types, themes, color schemes, font schemes, languages, audiences, purposes, tones, and social platforms.\n\n## Validation\n\nRun the example validator after changing any `*.opf.json` file:\n\n```sh\nnode scripts/validate-examples.mjs\n```\n\nThe script walks every OPF document under `examples/` and reports schema or semantic validation issues with file paths.\n"
|
|
62
68
|
},
|
|
63
69
|
{
|
|
64
70
|
"slug": "font-fidelity",
|
|
@@ -66,6 +72,12 @@ var docsData = Object.freeze([
|
|
|
66
72
|
"title": "Measured fonts and reproducible previews",
|
|
67
73
|
"markdown": "# Measured fonts and reproducible previews\n\nFor the starter set and delivery priorities, see the [font roadmap](plans/font-roadmap.md).\n\nThe [Windows reference-font advance study](evidence/shared-metric-native-anchor/font-study-comparison.json) is exploratory source-checkpoint evidence, not an additional compatibility certification. It measures 1,024 cases across regular/bold Calibri, Arial, Times New Roman and Courier New, recording local reference-file versions/hashes and native font-slot names. Disabling optional ligatures and rounding base glyph advances to eighth-point steps predicts 949 observations within 0.02pt; 75 outliers remain, including combining marks, Arabic and Calibri kerning. Office theme tokens and per-glyph fallback are not resolved to exact native files by these name properties. No runtime provider or open-font mapping changes from this hypothesis, and no reference font is redistributed.\n\nThe composition API accepts a `textMeasurement` provider. A provider resolves font faces and returns actual text widths; callers pass the same provider to pagination, editor geometry, SVG rendering, and PPTX export. Without one, the existing deterministic character-width estimate remains available.\n\nRenderer 0.8.0 publishes `prepareNodeFonts` from `/fonts-node`. Its returned `options` combine the same registry measurement, embedded SVG fonts and explicit raster files, with system/bundled fallback disabled for raster calls. Pass these options to pagination, editor geometry, SVG, PPTX and PNG/PDF export. `pack: 'base'` is the default for authored Roboto decks; `pack: 'office'` adds the six Office substitute families and retains metric policy unless visual substitution is explicitly requested. `registry.substitutions` records actual substitutions; the helper does not rewrite the authored document or add native embedding.\n\nRenderer 0.8.0 groups static files by their OpenType preferred family while retaining legacy family names and explicit custom namespaces. `Roboto` requests at 500/600/800 now select the actual Medium/SemiBold/ExtraBold files instead of nearby 400/700 faces. Optional `TextStyle.fontFace` carries the physical legacy family and native bold/italic flags independently of CSS numeric weight: SemiBold/ExtraBold are regular within their legacy families. The converter consumes this metadata; providers without it retain their prior behavior. Nine actual base faces pass metadata/measurement/outline checks and offline Chromium advances on Node 20/24. Seven payload slides cover serialized native selectors, deterministic output and source/reimport. These checks do not establish native Office paint, embedding or broader script coverage; see the [Mac candidate evidence](evidence/mac-font-variants/README.md).\n\nRenderer 0.8.0 uses adjacent SVG spans when no measurement provider is supplied. This closes the visible gaps caused by estimated fragment widths while retaining estimated line breaks and all run text/style/source offsets. Supplied providers and accepted placements still use exact fragment origins. Measured SVG requests geometric precision; accepted outline placements also constrain horizontal advances with `textLength`/`spacingAndGlyphs` to avoid browser quantization drift. This can scale glyphs horizontally while retaining nominal font size and baseline. Width-only providers do not receive that constraint, and constrained widths do not certify raw font-metric equivalence. The compatible editor supports both forms. This is a spacing improvement, not evidence that unmeasured wrapping or glyph coverage is accurate; see [candidate evidence](evidence/mac-rich-flow/README.md).\n\nBoth Node loaders verify exact package versions, 33 font-file hashes and eight license-notice hashes against the immutable `BUNDLED_FONT_MANIFEST` exported from `/fonts-node`. Missing/modified resources reject with actionable errors. Default raster loading now includes all nine base faces instead of omitting Roboto semibold, italic and bold italic. Font files must remain available and unchanged between preparation and raster export. Browser loading, actual glyph coverage, variant naming, rich spacing, and native compatibility remain separate requirements. These APIs are available in [renderer 0.8.0](https://github.com/OpenPresentation/opf-render/releases/tag/opf-render-v0.8.0), published against core 0.10.0 with Node 24. Prepared HarfBuzz shaping and variable-instance work remain separate drafts.\n\nThe renderer's optional font registry uses [Fontkit](https://github.com/foliojs/fontkit) to shape text and measure glyph advances from local font bytes. It does not discover system fonts or fetch fonts. The Node helper loads the renderer's bundled Roboto and Roboto Mono faces:\n\n```js\nimport { loadBundledFontRegistry } from '@openpresentation/opf-render/fonts-node';\nimport { renderSvg, svgToPng } from '@openpresentation/opf-render';\nimport { paginatePresentation } from '@openpresentation/opf/pagination';\nimport { toPptx } from '@openpresentation/opf-pptx';\n\nconst registry = await loadBundledFontRegistry();\nconst options = { textMeasurement: registry.textMeasurement };\n// Use design.fontScheme: 'roboto', or supply the document's actual font files.\nconst { presentation } = paginatePresentation(deck, options);\nconst svg = renderSvg(presentation, {\n ...options,\n embeddedFonts: registry.embeddedFonts,\n});\nconst png = await svgToPng(svg, {\n fontFiles: registry.fontFiles,\n useBundledFonts: false,\n loadSystemFonts: false,\n});\nconst pptx = await toPptx(presentation, options);\n```\n\n`createFontRegistry` from `@openpresentation/opf-render/fonts` accepts `{data: Uint8Array, weight, italic?, family?, postscriptName?, license?}` entries in Node or the browser. Weights are explicit, with 400 as the default. Supply each style that the document uses. Missing font families and unsupported glyphs fail with `OPFFontError`, including the source path where available. Collection fonts require a `postscriptName` selecting one face.\n\nAliases and fallback families are explicit choices:\n\n```js\nconst registry = createFontRegistry(faces, {\n aliases: { Aptos: 'Roboto', 'Aptos Display': 'Roboto' },\n fallbackFamily: 'Roboto',\n});\nconsole.log(registry.substitutions);\nregistry.clearSubstitutions(); // Start a fresh render's diagnostic collection.\n```\n\nAn available exact family takes precedence over aliases. The registry resolves a requested weight to the closest supplied weight, reports the substitution, and makes the resolved style available to rendering. Missing italic/upright styles fail instead of synthesizing an unmeasured style. `strictGlyphs: false` is an explicit escape hatch for hosts with their own glyph-fallback policy; it is unsuitable for fidelity verification.\n\nSVG embeds supplied fonts using data URIs and includes supplied license notices as metadata. The bundled loader carries the fonts' SIL Open Font License notices. For PNG/PDF, pass the same font files to the rasterizer; its native font loader does not depend on browser CSS font loading. In a browser, wait for `document.fonts.ready` before measuring or taking a screenshot. The editor playground loads and embeds bundled fonts and displays substitutions.\n\nCurrent `svgToPdf` output is image-only: each slide is rasterized and embedded as a PNG on a PDF page. Text is not selectable or searchable through PDF text objects, and shapes are not preserved as vectors. The accepted [selectable/vector PDF roadmap](plans/pdf-export.md) adds a separate backend and verification requirement, including permitted font embedding, Unicode extraction and shared placement. Raster PDF will remain an explicit compatibility mode when the verified vector mode becomes the default; no vector mode has shipped yet.\n\n## Office compatibility pack\n\n`loadOfficeFontRegistry` from `@openpresentation/opf-render/fonts-node` supplies regular, bold, italic, and bold italic faces of Carlito, Caladea, Arimo, Tinos, Cousine, and Gelasio, plus the base Roboto pack. Package versions are pinned and each face carries its distribution's license notice. `includeBaseFonts: false` omits Roboto. Loading never installs fonts into the operating system or downloads fonts at render time.\n\n```js\nconst registry = await loadOfficeFontRegistry({\n substitutionPolicy: 'metric', // Default for this loader; no visual fallback.\n});\nregistry.resolveFont({fontFamily: 'Calibri', fontWeight: 400});\n// requestedFamily: Calibri, resolvedFamily: Carlito, compatibility: metric\n```\n\n`createFontRegistry` defaults to `substitutionPolicy: 'none'`. Policies are `none`, `metric`, and `visual`; visual permits both curated tiers. An explicit `fallbackFamily` is a separate, reported `generic` fallback. Aliases are explicit visual substitutions and never establish metric compatibility. `resolveFont` reports exact resolutions as well; `substitutions` only collects changes. Resolution records include requested/resolved weights, italic, source path, and supporting upstream information where available.\n\n| Requested family | Bundled substitute | Current automatic tier |\n| --- | --- | --- |\n| Calibri | Carlito | Metric intent, standard 400/700 styles |\n| Cambria | Caladea | Fontconfig metric mapping; reference-version testing remains necessary |\n| Arial | Arimo | Metric, standard 400/700 styles |\n| Times New Roman | Tinos | Metric, standard 400/700 styles |\n| Courier New | Cousine | Metric, standard 400/700 styles |\n| Georgia | Gelasio | Visual: optional ligatures changed measured widths |\n| Calibri Light | Carlito | Visual: the bundle has no Carlito Light face |\n| Aptos / Aptos Display | Carlito, unless Source Sans 3 is supplied | Visual; no Aptos metric claim |\n\nUpstream evidence: [Carlito](https://github.com/googlefonts/carlito), [Fontconfig mappings](https://chromium.googlesource.com/external/fontconfig/+/refs/heads/main/conf.d/30-metric-aliases.conf), [Arimo](https://github.com/google/fonts/blob/main/ofl/arimo/DESCRIPTION.en_us.html), [Tinos](https://github.com/google/fonts/blob/main/ofl/tinos/DESCRIPTION.en_us.html), [Cousine](https://github.com/google/fonts/blob/main/apache/cousine/DESCRIPTION.en_us.html), and [Gelasio](https://github.com/SorkinType/Gelasio). Metric classification describes compatibility intent within the stated style scope, not universal identical output. Missing matching weights cannot silently qualify for the metric tier.\n\nThe exported `FONT_COMPATIBILITY` list also contains optional visual candidates and CJK families. Listing a candidate does not bundle it or imply complete character coverage. Liberation Sans Narrow is a separate legacy distribution with a different license history; it is not part of this bundle. Wingdings, Webdings, and Symbol require character mapping before substitution; an ordinary fallback fails with `font-encoding-required`. Missing math fonts require an explicit math-aware choice and fail with `math-font-required` instead of falling through to body text.\n\nDrawingML tokens such as `+mn-lt` resolve through the registry's explicit `themeFonts` option before substitution. Supply concrete `majorLatin`, `minorLatin`, and, where used, `majorEastAsia`, `minorEastAsia`, `majorComplexScript`, or `minorComplexScript` families. Missing theme mappings fail. This helper does not yet extract theme font records or embedded fonts from imported PPTX files.\n\n### Measured results and experimental fonts\n\n`node --import ./scripts/register-local-opf.mjs scripts/test-office-fonts.mjs --system` compares the bundle to reference fonts already installed in macOS's Supplemental directory. It does not redistribute reference fonts. The report records source-file hashes and individual shaped widths. Across four samples and four styles, Arimo/Arial, Tinos/Times New Roman, and Cousine/Courier New matched exactly on 48 runs. Gelasio/Georgia differed on ligature-containing runs, with a maximum difference of 2.0125%. Individual basic-Latin advances matched; disabling optional ligatures removed the tested difference. Until feature handling is consistent across outputs, the policy conservatively labels Gelasio approximate. Calibri and Cambria reference fonts were not available for this comparison.\n\n[Akasia](https://codeberg.org/bloudraad/akasia) remains experimental after the [v0.0.2 open-file assessment](evidence/akasia-assessment/README.md). All twelve styles match public upstream advance/kerning/ligature data, but 14 reference codepoints are missing and Black Italic decomposed accents expose a 0.421875px Fontkit/Chromium advance difference at size 32. Both Node runtimes retain the failure. This is not independent Aptos-binary or native Office verification; no mapping or bundled pack changes. `EXPERIMENTAL_FONT_CANDIDATES` records it separately. Aptos Narrow and Display remain outside that evidence.\n\nAn original OPF font project is technically feasible: independently designed or suitably open-licensed glyph outlines can be fitted to target advance widths, placement, vertical metrics, and shaping behavior. A successful font needs a reproducible source build, provenance, style/coverage tests, visual review, and cross-renderer conformance. Matching bounding boxes alone is insufficient: [OpenType horizontal metrics](https://learn.microsoft.com/en-us/typography/opentype/spec/hmtx) and [glyph positioning](https://learn.microsoft.com/en-us/typography/opentype/spec/gpos) jointly control text placement. Universal pixel identity across rasterizers is not the acceptance criterion; measured layout preservation over an explicit test matrix is.\n\n## Verification and remaining work\n\n`pnpm test:fonts` checks that editor and SVG geometry match, every native PPTX text box has the same coordinates and measured line breaks, and export uses the resolved family. It writes artifacts to `artifacts/fonts/`. A real-browser check of the same Roboto run measured 324.032 pixels versus the font engine's 324.170 pixels at 25 pixels, a difference of 0.138 pixels. These are measured tolerances, not a promise of pixel identity.\n\nPPTX currently records the resolved font family; it does not embed font binaries. PowerPoint still needs those fonts installed or may substitute them. Line height remains the shared 1.22 multiplier, rather than a complete ascent/descent model. Rich-text font overrides, mixed-script fallback and bidi layout, specialized payload internals, and native font embedding remain active fidelity work. Passing a width provider does not remove those limits.\n"
|
|
68
74
|
},
|
|
75
|
+
{
|
|
76
|
+
"slug": "format-card",
|
|
77
|
+
"file": "docs/format-card.md",
|
|
78
|
+
"title": "OPF format card",
|
|
79
|
+
"markdown": '# OPF format card\n\nA self-contained authoring reference for agents and humans writing `*.opf.json` documents, sized for pasting into a model\'s context. The canonical contract is the JSON Schema (`https://openpresentation.org/schema/opf/v1`, in [`spec/schemas/opf.schema.json`](../spec/schemas/opf.schema.json)); this card compresses it. Validate with `validatePresentation` from `@openpresentation/opf` or `opf validate <file>`.\n\n## Document shape\n\nA presentation is one JSON object; only `slides` is required.\n\n```json\n{ "name": "Minimal Deck", "slides": [{ "title": "Minimal Deck" }] }\n```\n\nOptional top-level fields, grouped:\n\n- Identity: `name`, `description`, `filename`, `author`, `organization`, `speaker`, `tags`.\n- Intent (used by AI generation): `audience`, `purpose`, `tone`, `language`, `narrative`, `takeaway`, `duration`.\n- Appearance: `design` (`theme`, `colorScheme`, `fontScheme`, `dimensions`, `background`, `logo`, `watermark`, `header`, `footer`, alignment hints), `variables`.\n- Resources: `assets` (registry referenced as `asset:<id>`), `catalogs` (inline records and/or custom sources per kind).\n- Machine state: `extensions` (preserved, never rendered).\n\n## Slides and content\n\nA slide carries `title` / `subtitle` / `tag` / `notes` / `section` / `beat` / `layout` / `id` / `extensions` plus content in one of three shapes \u2014 pick the loosest that says what you mean:\n\n1. **Root payload** \u2014 content-kind fields directly on the slide. The kind is inferred from the field: `text`, `items` (list), `bullets`, `image`, `video`, `chart`, `table`, `code`, `metric`, `quote`, `timeline`. Several kinds at the root are shorthand for `blocks`.\n2. **`blocks`** \u2014 an ordered array of payloads when placement should stay engine-inferred. A block is a leaf payload or a **group**: `{ "type": "group", "blocks": [...], "composition": { ... } }`. Groups nest (hard cap 32; stay \u2264 3 in practice) and cannot mix `blocks` with leaf fields.\n3. **Promoted regions** \u2014 a 3\xD73 grid when position matters. Rows `top|middle|bottom`, columns `left|center|right`, spans with `+`, intersections with `:` \u2014 `"left"`, `"center+right"`, `"top:left"`, `"middle+bottom:center+right"`. Keys must not overlap; regions cannot mix with a root payload.\n\n`composition` (on a slide or group) arranges children: `{ "mode": "auto|grid|row|column", "columns": 1-12, "weights": [..], "gap": 0-0.1, "padding": 0-0.2, "minFontSize": 8-32, "overflow": "warn|error" }`. Weights are relative track sizes; gap/padding are fractions of the canvas short edge. Engines own placement \u2014 there is no x/y.\n\nPayload notes: chart is `{ "type": "<chart-type id>", "data": { "columns": [...], "rows": [...] } }` or `{ "data": { "src": "asset:<id>" } }`; table rows may hold scalars, `TextRun[]`, or styled cells `{ "value", "style": { "fill", "color", "align", "borders", ... }, "colSpan", "rowSpan" }`; `metric`/`quote`/`code` accept string shorthand; list nesting uses `level` on items, not nested payloads.\n\n## Rich text and color references\n\n`text`, list items, bullets, and table cells accept `TextRun[]`: strings or `{ "text", "bold", "italic", "underline", "strikethrough", "color", "fontSize", "fontFamily", "link", "superscript", "subscript" }`.\n\nEvery content color field (`TextRun.color`, table cell `style.fill` / `style.color`, cell border `color`) accepts three forms:\n\n- Literal hex: `"#0F172A"`, `"#B42318CC"`.\n- A color-scheme name, resolved through the effective scheme: slots `accent1`\u2013`accent6`, `dark1`, `dark2`, `light1`, `light2`, `hyperlink`, `followedHyperlink`, or roles `primary`, `secondary`, `accent`, `background`, `surface`, `text`, `textSecondary`.\n- A variable reference `var:<id>` into the top-level map: `"variables": { "risk": "#B42318" }` (or `{ "type": "color", "value": "#B42318", "description": "..." }`).\n\nPrefer names and variables over hex \u2014 they survive re-theming. Unknown `var:` ids warn, never error. The styled cell and border color fields enforce the three forms at the schema level; run colors tolerate any string (unrecognized values warn and renderers fall back to the theme), so imported decks keep validating.\n\n## Ids and extensions\n\n`id` is optional on slides and on any content payload (including groups), unique document-wide. Use ids when something outside the document must address content across edits \u2014 patch edits, comments, review state. `extensions` objects at document, slide, and payload scope carry machine state; engines ignore and preserve them.\n\n## Catalog references\n\nReusable vocabulary lives in catalogs; references are kebab-case ids: `narrative`, `tone`, `purpose`, `audience`, `language`, `design.theme`, `design.colorScheme`, `design.fontScheme`, `Slide.layout`, `Chart.type`, socials keys. Resolution: inline `catalogs.<kind>.records[]` \u2192 `catalogs.<kind>.source` \u2192 bundled default catalog (browsable at https://pptx.gallery). Object form overrides a record per key: `{ "id": "cool-horizon", "accent1": "#0F4C81" }`. Unknown ids warn, never error. `opf bundle <in> <out>` inlines every record a document uses so it needs no catalog lookups beyond itself (remote media and data assets are separate).\n\n## Design in three lines\n\n`design.theme` bundles scheme + fonts + background + dimensions; `design.colorScheme` / `fontScheme` override it; `slides[].design` overrides per slide; resolution is per field, most specific wins. Backgrounds accept slot names (`"light1"`) or hex. `false` suppresses inherited `watermark` / `header` / `footer`.\n\n## Prefer / never\n\nPrefer: string shorthands; bare catalog ids; inference over explicit `type`; regions only when position matters; groups only when `blocks` ordering is not enough; names/`var:` over hex in color fields; `items` for lists (`bullets` only for plain text-style bullets).\n\nNever: loose chart or table fields directly on a slide; region keys mixed with a root payload; overlapping region keys; `blocks` mixed with leaf fields on one payload; duplicate ids; x/y or pixel geometry (it does not exist in OPF).\n\n## Two canonical slides\n\n```json\n{\n "id": "headline",\n "title": "Adoption Doubled",\n "left": { "id": "kpi", "metric": { "value": "2.1x", "label": "Adoption", "trend": "up" } },\n "center+right": { "chart": { "type": "line", "data": { "columns": ["Month", "Teams"], "rows": [["Jan", 12], ["Feb", 18]] } } }\n}\n```\n\n```json\n{\n "id": "risks",\n "title": "What Could Go Wrong",\n "composition": { "mode": "column" },\n "blocks": [\n { "items": [["Two regions at ", { "text": "85% utilization", "color": "var:risk", "bold": true }]] },\n { "quote": { "text": "Exceptions became visible before they became escalations.", "attribution": "VP Operations" } }\n ],\n "extensions": { "authoring": { "locked": true } }\n}\n```\n'
|
|
80
|
+
},
|
|
69
81
|
{
|
|
70
82
|
"slug": "handoff-2026-09-08",
|
|
71
83
|
"file": "docs/handoff-2026-09-08.md",
|
|
@@ -84,6 +96,12 @@ var docsData = Object.freeze([
|
|
|
84
96
|
"title": "OpenPresentation owner handoff \u2014 September 15, 2026",
|
|
85
97
|
"markdown": "# OpenPresentation owner handoff \u2014 September 15, 2026\n\n## Outcome and boundaries\n\nThe published websites demonstrate editable OPF JSON and live slides. Reusable\npackages provide an open local authoring foundation for scoped developer\nintegrations today. This is not full PowerPoint parity or a finished all-feature\npresentation editor.\n\nThe owner requested committed, remotely preserved work, validated merges or\nexplicit roadmap deferral, and a completed PR cleanup. Eleven dependency PRs\nand four shared-furniture PRs were accepted. One Node26-types update was closed\nto retain Node24. Four remaining shaping PRs conclude as docs/evidence only;\ntheir complete runtime prototypes remain on remote archives. No failed font\nimplementation is promoted, no history is force-pushed, and archives must stay.\n\nUse the original PRs listed below for final merge/check receipts. This document\nis committed in core83 before its final checks/merge and does not invent its\nown future merge SHA. Merging a roadmap does not release its archived feature.\n\n## Repositories and environment\n\n| Repository | Default | Responsibility |\n| --- | --- | --- |\n| [OpenPresentation/opf](https://github.com/OpenPresentation/opf) | main | Schemas, catalogs, composition/edit/lint, CLI, six skills and plans |\n| [OpenPresentation/opf-render](https://github.com/OpenPresentation/opf-render) | main | Font preparation, rendering and image/PDF output |\n| [OpenPresentation/opf-editor](https://github.com/OpenPresentation/opf-editor) | main | Reusable editor controls and source-preserving interaction |\n| [OpenPresentation/opf-pptx](https://github.com/OpenPresentation/opf-pptx) | main | Editable PPTX import/export and provenance |\n| [Data-Advantage/openpresentation-site](https://github.com/Data-Advantage/openpresentation-site) | main | Main website/playground |\n| [Data-Advantage/pptx-gallery](https://github.com/Data-Advantage/pptx-gallery) | main | Gallery and embedded editor demo |\n| [Data-Advantage/pptx-dev](https://github.com/Data-Advantage/pptx-dev) | master | Authoring/inspector/tooling website |\n\nUse Node24. Core/site/gallery pin pnpm10.33.2; pptx-dev pins pnpm11.1.3;\nstandalone libraries use npm lockfiles. Read each AGENTS.md, use codex/ branches\nand focused commits/PRs as work proceeds. Gallery requires Conventional Commits\nand its documented coauthor. Read relevant OPF skills for document operations.\n\nLocal clones live under /Users/michael/Source. This handoff is portable:\nGitHub contains archives and committed evidence. Do not depend on temporary\nworktrees, local dependency symlinks, untracked output or this Mac's credentials.\n\n## Published baseline and accepted source\n\nRegistry inspection confirmed @openpresentation/opf **0.10.0**, opf-render\n**0.8.0**, opf-editor **0.7.0**, opf-pptx **0.8.0**, and cli **0.8.0**.\nHome/playground support JSON editing and preview edits in both directions,\ncontextual catalog choices, indentation, paired quotes and other code-editor\nassistance. Shared controls and contextual lint/design contracts are available.\n\nThe CLI supports create, validate, lint, revision-guarded JSON edits, data\nimport, pagination, schema/catalog lookup and skill installation/update/status.\nDo not invent CLI render/export commands: use documented library/UI APIs.\nSchema-property access is not proof of full WYSIWYG interaction coverage.\n\nCore79 (d0c8841), renderer20 (130a2fa), editor17 (cfdeae6) and PPTX34 (c077b7a)\nadd accepted shared header/footer geometry, editing and provenance. Their main\nCI passed, including coordinated packages and Linux/Windows PPTX checks. These\nnew APIs need a new coordinated release. Do not claim they are in the listed\nnpm versions just because main contains them.\n\nKeep release-plan.json and immutable verification references accurate. Never\noverwrite published versions, change snapshots to conceal regressions or count\nsibling-source imports as installed-package checks. Some older docs/skills\nstill call released APIs unreleased: audit them with the developer quickstart.\n\n## Deployment receipts\n\nLatest retained canonical production checks cover **41 workflows**:\n\n| Website | Verified source commit | Workflows |\n| --- | --- | --- |\n| [openpresentation.org](https://www.openpresentation.org) | bb6b006e5fa18f565779781ad347a839fea4ec83 | 26 |\n| [pptx.gallery](https://www.pptx.gallery) | fe395e4e7187cdb85c2b8a4041ef2801fd81f72d | 5 |\n| [pptx.dev](https://www.pptx.dev) | 3b17ff5366f7a556cf02aae320e6baf87fdf3678 | 10 |\n\nDeployment records and browser logs are in\n[PR consolidation evidence](evidence/pr-consolidation-20260915/README.md).\nThey establish exercised flows, not every capability. The Zod4.6.2 preview\nfailure is fixed/merged in pptx-dev37 using explicit record keys/values and\npublic schema identification.\n\n## Preserved unfinished implementation\n\nEvery library repository retains remote branch codex/archive-shaping-20260915:\n\n| Repository / original PR | Complete immutable prototype |\n| --- | --- |\n| [opf83](https://github.com/OpenPresentation/opf/pull/83) | 36ff66b3d62b39d7d27dcda022b7e79e541bd603 |\n| [renderer21](https://github.com/OpenPresentation/opf-render/pull/21) | 343fb84223f4383ffe546157c6989ccc505c0acb |\n| [editor21](https://github.com/OpenPresentation/opf-editor/pull/21) | ae4cc6426b04c7ca428c1b4acacea2e11d99fa84 |\n| [PPTX35](https://github.com/OpenPresentation/opf-pptx/pull/35) | fbe9a73d012dbd51d65a39251e405e488651a70b |\n\nThese contain HarfBuzz shaping, variable/CFF preparation, prepared SVG glyphs,\nrich-source groups, grapheme/caret/selection/navigation work and native rich/tab\nexport experiments, with tests, licenses and evidence. See\n[the deferred implementation plan](plans/deferred-shaping-20260915.md).\nResume from main and port bounded changes; do not merge an archive wholesale.\n\nRenderer Linux still fails the unchanged 0.1px gate: Source Serif SmText Bold\nmeasures 334.06213682353496px versus Chromium334.193115234375px. Rounding fixes\nfive Linux rows but breaks five macOS rows. Some native platform widths differ\nby more than twice the tolerance. Define an honest supported metric/painting\ncontract; offsets, platform guesses and relaxed assertions do not solve it.\nTrack [renderer24](https://github.com/OpenPresentation/opf-render/issues/24).\n\nArchived editor CI separately has a packed-test mismatch: thirteen rich-input\nworkflows pass but the aggregate expects ten. Repair that assertion and rerun\nthe complete packed command when resuming; the archived run is not green.\n\n[Core87](https://github.com/OpenPresentation/opf/issues/87) and the\n[native plan](plans/powerpoint-acceptance.md) retain image opening, current-content\nprovenance after edit/save/reopen, tab tolerances, notes-master ordering and\nphysical font identity/embedding. Browser, serialization and self-import checks\ndo not establish Office acceptance. Windows host recovery is not authorized:\ndo not retry COM or kill Office processes until recovery is confirmed.\nAptos4.40 is restricted; do not use/distribute it without compatible permission.\n\n## Next milestones\n\nFollow [the developer adoption roadmap](plans/developer-adoption-20260915.md).\nFirst release the accepted increment and provide a clean installed example with\ncurrent API/version docs. Then finish public-site integration in\n[core88](https://github.com/OpenPresentation/opf/issues/88), preserving appearance.\nPackage adoption and feature adoption need separate checks.\n\nBroader work: supported multilingual fonts/fallback/IME/bidi and editing;\nnative Office evidence; bounded deterministic layout repair for dense/nested\ncontent; full visual-editor interaction coverage. Current PDF is raster-backed.\nSelectable vector PDF with legal embedding/Unicode extraction and general SVG/\nsemantic Mermaid follow font reliability. See the linked plans for acceptance.\n\nKeep the foundation provider-neutral and useful offline without an account or\nmodel call. Preserve content, whitespace, formatting, reading order, authored\nintent and undo. Bound layout repair and return actionable failure; never delete\ncontent to fit. AI may be optional application wiring, not a required embedded\ndesign agent. The [broad ecosystem objective](plans/ecosystem-objective-2026-09-09.md)\nremains open. The Codex goal was paused, not completed or replaced by this cleanup.\n\n## Audit record\n\n[Final evidence](evidence/final-handoff-20260915/README.md) records registry\nversions, remote archive checks, all seven repository/worktree inventories and\nlatest archived CI failures. Source audit found no uncommitted source, stashes\nor local-only branch commits. A stale untracked dependency symlink was removed\nwithout changing its target. A legacy temporary directory lacking Git metadata\nwas not treated as an active checkout.\n\nThe four concluding PRs restore runtime/tests/locks/CI to validated main, then\nadd docs/evidence. Verify their final diffs and CI and merge them before reporting\nqueue completion. Do not confuse preserved history with newly accepted code.\n"
|
|
86
98
|
},
|
|
99
|
+
{
|
|
100
|
+
"slug": "handoff-2026-09-16",
|
|
101
|
+
"file": "docs/handoff-2026-09-16.md",
|
|
102
|
+
"title": "Handoff \u2014 September 16, 2026",
|
|
103
|
+
"markdown": "# Handoff \u2014 September 16, 2026\n\nContinue as primary owner. Read this file after the\n[15 September handoff](handoff-2026-09-15.md); that checkpoint\u2019s npm versions\nare outdated.\n\n## Merged and released\n\n- Coordinated packages on npm: core **0.10.1**, renderer **0.8.1**, editor **0.7.1**, PPTX **0.8.1**, CLI **0.8.1** (Node 24).\n- Shared header/footer geometry is in those tarballs.\n- Independent developer path: [quickstart](quickstart.md), [compatibility matrix](compatibility-matrix.md), `docs/quickstart/developer-quickstart.opf.json`, `pnpm test:developer-quickstart`. The fixture stays outside `examples/` so the published 126-deck catalog is unchanged.\n\n## Not done\n\n- [Issue 88](https://github.com/OpenPresentation/opf/issues/88): adopt shared features on openpresentation.org, pptx.dev, pptx.gallery and verify canonical production routes.\n- [Issue 87](https://github.com/OpenPresentation/opf/issues/87): native PowerPoint.\n- [Renderer issue 24](https://github.com/OpenPresentation/opf-render/issues/24): native-width residual.\n- Archived shaping implementations remain on `codex/archive-shaping-20260915`; do not merge wholesale or weaken the 0.1px gate.\n- Selectable vector PDF, general SVG/Mermaid, full editor/IME/repair coverage.\n\n## Next\n\n1. Merge and keep the registry quickstart green in CI.\n2. Finish issue 88 on the three sites without changing their appearance.\n3. Leave 24 and 87 explicit. Update this handoff with what is actually deployed.\n"
|
|
104
|
+
},
|
|
87
105
|
{
|
|
88
106
|
"slug": "handoff-mac-owner-2026-09-10",
|
|
89
107
|
"file": "docs/handoff-mac-owner-2026-09-10.md",
|
|
@@ -106,13 +124,13 @@ var docsData = Object.freeze([
|
|
|
106
124
|
"slug": "how-opf-works",
|
|
107
125
|
"file": "docs/how-opf-works.md",
|
|
108
126
|
"title": "How OPF Works",
|
|
109
|
-
"markdown": '# How OPF Works\n\nAn OPF document is one JSON file that answers three questions about a presentation:\n\n- **What does it say?** \u2014 `slides`, with content payloads and assets.\n- **Who is it for and why?** \u2014 `audience`, `purpose`, `tone`, `language`, and `narrative`.\n- **What should it look like?** \u2014 `design`, resolved through themes, color schemes, and font schemes.\n\nThe document records intent; an engine (a renderer, exporter, or editor) turns that intent into pixels or `.pptx` output. OPF deliberately stops at the format boundary: it never embeds OOXML, layout geometry, or renderer-specific state. You \u2014 or your agent \u2014 own the story, the data, and the ask; the format\'s job is to keep all of that readable, diffable, and out of `<p:sp>` tags.\n\n## Anatomy of a document\n\n```\nPresentation\n\u251C\u2500\u2500 identity ...... name, description, organization, speaker, author\n\u251C\u2500\u2500 intent ........ audience, purpose, tone, language, narrative, takeaway, duration\n\u251C\u2500\u2500 content ....... slides[]\n\u2502 \u251C\u2500\u2500 title / subtitle / tag / notes / section / beat / layout\n\u2502 \u2514\u2500\u2500 one content shape:\n\u2502 root payload (a single content kind)\n\u2502 blocks[] (ordered payloads, placement inferred)\n\u2502 region keys (3x3 placement grid)\n\u251C\u2500\u2500 design ........ theme, colorScheme, fontScheme, background, logo, header, footer\n\u251C\u2500\u2500 assets ........ named media sources, referenced as "asset:<id>"\n\u2514\u2500\u2500 catalogs ...... per-kind overrides: inline records and/or custom sources\n```\n\nOnly `slides` is required. The smallest valid document:\n\n```json\n{\n "name": "Minimal OPF Deck",\n "slides": [\n { "title": "Minimal OPF Deck" },\n { "title": "Next Steps", "text": "Use this as a starting point." }\n ]\n}\n```\n\nEverything else in the format is optional and additive.\n\n## Slides and content\n\nA slide carries its content in one of three shapes. Pick the loosest shape that says what you mean \u2014 engines handle placement.\n\n**1. Root payload** \u2014 one content kind directly on the slide. The kind is inferred from the field present (`text`, `items`, `chart`, `table`, `image`, `video`, `code`, `metric`, `quote`, `timeline`); see [`content-payloads.md`](./content-payloads.md) for the full table.\n\n```json\n{\n "title": "Operating Metric",\n "metric": { "value": "42%", "label": "Review cycle reduction", "trend": "up" }\n}\n```\n\nMultiple kinds at the slide root (with no explicit `type`, `blocks`, or regions) are shorthand for the equivalent `blocks`:\n\n```json\n{\n "title": "Habitat",\n "text": "Jaguars are strongly associated with water and dense cover.",\n "items": ["Rainforests and flooded wetlands", "Large defended territories"]\n}\n```\n\n**2. `blocks`** \u2014 an ordered list of payloads when a slide has several pieces of content but placement should stay renderer-inferred:\n\n```json\n{\n "title": "Customer Feedback",\n "blocks": [\n { "table": { "columns": ["Theme", "Mentions"], "rows": [["Speed", 42], ["Ease of use", 31]] } },\n { "quote": { "text": "The new workflow cut review time in half.", "attribution": "Operations Lead" } }\n ]\n}\n```\n\n**3. Promoted region keys** \u2014 a 3\xD73 placement grid when position matters:\n\n```\n left center right\n +--------------------+--------------------+--------------------+\n top | top:left | top:center | top:right |\n +--------------------+--------------------+--------------------+\n middle | middle:left | middle:center | middle:right |\n +--------------------+--------------------+--------------------+\n bottom | bottom:left | bottom:center | bottom:right |\n +--------------------+--------------------+--------------------+\n\n A bare column key ("left") spans all three rows.\n A bare row key ("top") spans all three columns.\n Keys span neighbors with "+" and intersect rows with columns via ":".\n```\n\nThe spans compose into the slide shapes you actually want:\n\n```\n "left" + "center+right" "top" + "middle+bottom"\n (sidebar + main) (headline band + body)\n +----------+------------------+ +-------------------------------+\n | | | | top |\n | | | +-------------------------------+\n | left | center+right | | |\n | | | | middle+bottom |\n | | | | |\n +----------+------------------+ +-------------------------------+\n\n "top" + "middle+bottom:left" + "middle+bottom:center+right"\n (headline band, then sidebar + main)\n +---------------------------------------------+\n | top |\n +---------------+-----------------------------+\n | | |\n | middle+bottom | middle+bottom:center+right |\n | :left | |\n | | |\n +---------------+-----------------------------+\n```\n\nThat last shape in JSON:\n\n```json\n{\n "title": "Adoption Doubled",\n "top": { "text": "Adoption doubled while support load stayed flat." },\n "middle+bottom:left": { "metric": { "value": "2.1x", "label": "Adoption" } },\n "middle+bottom:center+right": {\n "chart": { "type": "line", "data": { "columns": ["Month", "Teams"], "rows": [["Jan", 12], ["Feb", 18]] } }\n }\n}\n```\n\nAnd the two-column shape from the grid above:\n\n```json\n{\n "title": "Operating Snapshot",\n "left": { "table": { "columns": ["Metric", "Value"], "rows": [["Revenue", "$4.2M"]] } },\n "center+right": { "chart": { "type": "line", "data": { "columns": ["Month", "Revenue"], "rows": [["Jan", 3.4]] } } }\n}\n```\n\nRegion keys on one slide must not overlap, and regions cannot be mixed with a root payload. Slide-level strings `title`, `subtitle`, and `tag` sit alongside whichever content shape you use, and render into the matching placeholders of the resolved layout.\n\n## Layouts are hints, not contracts\n\n`Slide.layout` optionally references a record in the `layouts` catalog. The layout\'s placeholders describe what the layout *exposes* (a title slot, chart regions, image treatment) \u2014 they do not constrain what the slide may contain. This loose coupling is intentional:\n\n- A slide may use any region keys or payloads regardless of its declared layout. Validators do not error on a slide/layout mismatch.\n- When `layout` is omitted, engines infer one from the slide\'s payload or region keys.\n- Free-form layout names that don\'t resolve through any catalog fall through to engine-defined layouts.\n\nThe principle, used throughout OPF: **slides are the source of truth**. Layouts, narratives, and design records guide rendering; they never invalidate content.\n\n## Narrative is intent, not structure\n\n`narrative` declares the deck\'s story arc. It resolves to a record in the `narratives` catalog (e.g. `"classic-story"`, `"pitch-deck"`), each of which defines ordered **beats** \u2014 labeled segments of the arc such as `hook`, `problem`, `evidence`, `ask` \u2014 with optional slide-blueprint hints (`slideType`, `layoutHint`, `instructions`, `thoughtCues`).\n\nSlides opt into beats via `Slide.beat`. Nothing forces them to: validators warn on drift (orphan slides, unused beats) but never error.\n\n```json\n{\n "name": "Schema Pitch",\n "narrative": {\n "id": "technical-proof",\n "name": "Technical Proof",\n "beats": [\n { "id": "contract", "name": "Contract", "slideType": "text", "instructions": "State what stays stable." },\n { "id": "evidence", "name": "Evidence", "slideType": "chart" },\n { "id": "adoption", "name": "Adoption", "slideType": "list" }\n ]\n },\n "slides": [\n { "beat": "contract", "title": "The Contract", "text": "Beats describe intent without constraining slides." },\n { "beat": ["evidence", "adoption"], "title": "Proof And Ask", "items": ["One slide may cover several beats."] }\n ]\n}\n```\n\nObject form supports overrides: `{ "id": "classic-story", "beats": [...] }` merges inline beats into the catalog record by beat `id`. An object whose `id` matches no record \u2014 like `technical-proof` above \u2014 is a fully custom inline narrative. Deck-level concerns that aren\'t part of the storyline (`audience`, `tone`, `takeaway`, `duration`) live as siblings on the presentation root, not inside the narrative.\n\n## Catalog references and how they resolve\n\nMost reusable values in OPF are references into **catalogs**: named collections of records, each identified by a kebab-case `id`. The referencing fields are `narrative`, `language`, `tone`, `audience`, `purpose`, `design.theme`, `design.colorScheme`, `design.fontScheme`, `Slide.layout`, `Chart.type`, and the platform keys in `socials`.\n\nEvery reference resolves through the same chain, first match wins:\n\n```\n "design": { "colorScheme": "cool-horizon" }\n |\n v\n 1. catalogs.colorSchemes.records[] inline records in this document\n | miss\n v\n 2. catalogs.colorSchemes.source custom registry declared in this document\n | miss\n v\n 3. default catalog https://www.pptx.gallery/color-schemes\n | miss (bundled in spec/catalogs/ and in\n v the @openpresentation/opf package)\n validation warning \u2014 never an error \u2014 and an engine fallback\n```\n\nWhen a reference is omitted entirely, engines fall back to their own defaults (see [`spec/reference/engine-defaults.json`](../spec/reference/engine-defaults.json) for a reference example \u2014 that file is engine configuration, not part of the document contract).\n\nThree reference forms are accepted wherever a catalog reference is allowed:\n\n- **Bare id** for the common case: `"narrative": "classic-story"`.\n- **Object form** for catalog-backed overrides: `{ "id": "cool-horizon", "accent1": "#0F4C81" }` resolves the record as a base, then inline fields win per key.\n- **URL or `pkg:` reference**, which skips the catalog lookup and resolves directly.\n\nA document can carry its own records or point at a private registry, which also silences unknown-id warnings for that kind:\n\n```json\n{\n "name": "Branded Deck",\n "design": { "colorScheme": "acme-brand" },\n "catalogs": {\n "colorSchemes": {\n "records": [{ "id": "acme-brand", "accent1": "#0F4C81", "light1": "#FFFFFF", "dark1": "#0B1B2B" }]\n },\n "narratives": { "source": "https://catalogs.example.com/narratives" }\n },\n "slides": [{ "title": "Branded Deck" }]\n}\n```\n\n## Design in one paragraph\n\n`design` selects a `theme` (which bundles default color scheme, font scheme, background, and dimensions) and may override any of those directly; `Slide.design` overrides the deck design per slide. More specific always wins, field by field. Color schemes and font schemes each support two mixable models \u2014 OOXML slots/pairs that round-trip to PowerPoint, and abstract roles (`primary`, `heading`, `code`, \u2026) that engines map onto slots. The full precedence chain with worked examples is in [`design-resolution.md`](./design-resolution.md).\n\n## Assets\n\nBinary content lives in the top-level `assets` registry, keyed by id. Content payloads and design fields reference entries with `asset:<id>` strings; asset `src` values accept HTTPS URLs, data URIs, and paths resolved against the OPF file location.\n\n## A complete small deck\n\nEverything above, together \u2014 intent metadata, a catalog-backed narrative with beats, design, an organization and speaker, an asset-backed chart, regions, notes, and sections:\n\n```json\n{\n "$schema": "https://openpresentation.org/schema/opf/v1",\n "name": "Q3 Business Review",\n "description": "Quarterly review for the executive team.",\n "audience": "executives",\n "purpose": "decide",\n "tone": "formal",\n "language": "en-US",\n "narrative": "qbr",\n "takeaway": "Approve the expanded rollout budget.",\n "duration": 20,\n "organization": {\n "id": "acme",\n "name": "Acme Corp",\n "domain": "acme.com",\n "socials": { "linkedin": "acme" }\n },\n "speaker": { "id": "alice", "name": "Alice Chen", "title": "VP Operations", "organizationId": "acme" },\n "design": {\n "theme": "classic",\n "colorScheme": "forest-green",\n "footer": { "left": { "organization": true }, "right": { "slideNumber": true } }\n },\n "assets": {\n "adoption-csv": { "src": "./data/adoption.csv", "alt": "Monthly adoption data" }\n },\n "slides": [\n {\n "layout": "title",\n "beat": "objectives",\n "title": "Q3 Business Review",\n "subtitle": "Operations \u2014 October 2025"\n },\n {\n "beat": "performance-headline",\n "title": "Adoption Doubled",\n "left": { "metric": { "value": "2.1x", "label": "Quarter-over-quarter adoption", "trend": "up" } },\n "center+right": {\n "chart": { "type": "line", "data": { "src": "asset:adoption-csv", "columns": ["Month", "Active Teams"] } }\n },\n "notes": "Pause here; this is the slide the decision hangs on."\n },\n {\n "beat": "risks",\n "section": "Decision",\n "title": "What Could Go Wrong",\n "items": [\n "Capacity: two regions are at 85% utilization.",\n {\n "text": "Churn risk in the legacy tier.",\n "description": "Mitigation: migration incentives ship in November."\n }\n ]\n },\n {\n "beat": "asks",\n "title": "The Ask",\n "text": "Approve $1.2M to expand the rollout to all regions in Q4."\n }\n ]\n}\n```\n\nThe beat ids (`objectives`, `performance-headline`, `risks`, `asks`) come from the `qbr` narrative record; the theme, color scheme, chart type, and layout all resolve through the bundled catalogs. For a fixture that exercises the full surface in one file, see [`examples/technical/full-feature-tour.opf.json`](../examples/technical/full-feature-tour.opf.json).\n\n## Validation philosophy\n\nTwo layers, with a deliberate split:\n\n- **Schema errors** for structural problems: wrong types, overlapping region keys, payloads mixing incompatible content kinds, a region payload missing concrete content.\n- **Warnings** for advisory drift: unknown catalog ids, narrative/slide mismatches. These never make a document invalid.\n\n`validatePresentation` from `@openpresentation/opf` applies both layers locally.\n\n## Where to go next\n\n- [`schema-reference.md`](./schema-reference.md) \u2014 every field of every object in the presentation schema.\n- [`catalog-schema-reference.md`](./catalog-schema-reference.md) \u2014 every field of every catalog record schema.\n- [`content-payloads.md`](./content-payloads.md) \u2014 payload shapes and inference rules with examples.\n- [`design-resolution.md`](./design-resolution.md) \u2014 the design precedence algorithm.\n- [`examples.md`](./examples.md) \u2014 guide to the example decks under `examples/`.\n\nThen write a deck, commit it, revise it, and read the diff. A two-line diff for a two-word change is the whole argument for the format.\n'
|
|
127
|
+
"markdown": '# How OPF Works\n\nAn OPF document is one JSON file that answers three questions about a presentation:\n\n- **What does it say?** \u2014 `slides`, with content payloads and assets.\n- **Who is it for and why?** \u2014 `audience`, `purpose`, `tone`, `language`, and `narrative`.\n- **What should it look like?** \u2014 `design`, resolved through themes, color schemes, and font schemes.\n\nThe document records intent; an engine (a renderer, exporter, or editor) turns that intent into pixels or `.pptx` output. OPF deliberately stops at the format boundary: it never embeds OOXML, layout geometry, or renderer-specific state. You \u2014 or your agent \u2014 own the story, the data, and the ask; the format\'s job is to keep all of that readable, diffable, and out of `<p:sp>` tags.\n\n## Anatomy of a document\n\n```\nPresentation\n\u251C\u2500\u2500 identity ...... name, description, organization, speaker, author\n\u251C\u2500\u2500 intent ........ audience, purpose, tone, language, narrative, takeaway, duration\n\u251C\u2500\u2500 content ....... slides[]\n\u2502 \u251C\u2500\u2500 title / subtitle / tag / notes / section / beat / layout\n\u2502 \u2514\u2500\u2500 one content shape:\n\u2502 root payload (a single content kind)\n\u2502 blocks[] (ordered payloads, placement inferred)\n\u2502 region keys (3x3 placement grid)\n\u251C\u2500\u2500 design ........ theme, colorScheme, fontScheme, background, logo, header, footer\n\u251C\u2500\u2500 variables ..... named colors, referenced from content as "var:<id>"\n\u251C\u2500\u2500 assets ........ named media sources, referenced as "asset:<id>"\n\u2514\u2500\u2500 catalogs ...... per-kind overrides: inline records and/or custom sources\n```\n\nOnly `slides` is required. The smallest valid document:\n\n```json\n{\n "name": "Minimal OPF Deck",\n "slides": [\n { "title": "Minimal OPF Deck" },\n { "title": "Next Steps", "text": "Use this as a starting point." }\n ]\n}\n```\n\nEverything else in the format is optional and additive.\n\n## Slides and content\n\nA slide carries its content in one of three shapes. Pick the loosest shape that says what you mean \u2014 engines handle placement.\n\n**1. Root payload** \u2014 one content kind directly on the slide. The kind is inferred from the field present (`text`, `items`, `chart`, `table`, `image`, `video`, `code`, `metric`, `quote`, `timeline`); see [`content-payloads.md`](./content-payloads.md) for the full table.\n\n```json\n{\n "title": "Operating Metric",\n "metric": { "value": "42%", "label": "Review cycle reduction", "trend": "up" }\n}\n```\n\nMultiple kinds at the slide root (with no explicit `type`, `blocks`, or regions) are shorthand for the equivalent `blocks`:\n\n```json\n{\n "title": "Habitat",\n "text": "Jaguars are strongly associated with water and dense cover.",\n "items": ["Rainforests and flooded wetlands", "Large defended territories"]\n}\n```\n\n**2. `blocks`** \u2014 an ordered list of payloads when a slide has several pieces of content but placement should stay renderer-inferred:\n\n```json\n{\n "title": "Customer Feedback",\n "blocks": [\n { "table": { "columns": ["Theme", "Mentions"], "rows": [["Speed", 42], ["Ease of use", 31]] } },\n { "quote": { "text": "The new workflow cut review time in half.", "attribution": "Operations Lead" } }\n ]\n}\n```\n\n**3. Promoted region keys** \u2014 a 3\xD73 placement grid when position matters:\n\n```\n left center right\n +--------------------+--------------------+--------------------+\n top | top:left | top:center | top:right |\n +--------------------+--------------------+--------------------+\n middle | middle:left | middle:center | middle:right |\n +--------------------+--------------------+--------------------+\n bottom | bottom:left | bottom:center | bottom:right |\n +--------------------+--------------------+--------------------+\n\n A bare column key ("left") spans all three rows.\n A bare row key ("top") spans all three columns.\n Keys span neighbors with "+" and intersect rows with columns via ":".\n```\n\nThe spans compose into the slide shapes you actually want:\n\n```\n "left" + "center+right" "top" + "middle+bottom"\n (sidebar + main) (headline band + body)\n +----------+------------------+ +-------------------------------+\n | | | | top |\n | | | +-------------------------------+\n | left | center+right | | |\n | | | | middle+bottom |\n | | | | |\n +----------+------------------+ +-------------------------------+\n\n "top" + "middle+bottom:left" + "middle+bottom:center+right"\n (headline band, then sidebar + main)\n +---------------------------------------------+\n | top |\n +---------------+-----------------------------+\n | | |\n | middle+bottom | middle+bottom:center+right |\n | :left | |\n | | |\n +---------------+-----------------------------+\n```\n\nThat last shape in JSON:\n\n```json\n{\n "title": "Adoption Doubled",\n "top": { "text": "Adoption doubled while support load stayed flat." },\n "middle+bottom:left": { "metric": { "value": "2.1x", "label": "Adoption" } },\n "middle+bottom:center+right": {\n "chart": { "type": "line", "data": { "columns": ["Month", "Teams"], "rows": [["Jan", 12], ["Feb", 18]] } }\n }\n}\n```\n\nAnd the two-column shape from the grid above:\n\n```json\n{\n "title": "Operating Snapshot",\n "left": { "table": { "columns": ["Metric", "Value"], "rows": [["Revenue", "$4.2M"]] } },\n "center+right": { "chart": { "type": "line", "data": { "columns": ["Month", "Revenue"], "rows": [["Jan", 3.4]] } } }\n}\n```\n\nRegion keys on one slide must not overlap, and regions cannot be mixed with a root payload. Slide-level strings `title`, `subtitle`, and `tag` sit alongside whichever content shape you use, and render into the matching placeholders of the resolved layout.\n\n## Layouts are hints, not contracts\n\n`Slide.layout` optionally references a record in the `layouts` catalog. The layout\'s placeholders describe what the layout *exposes* (a title slot, chart regions, image treatment) \u2014 they do not constrain what the slide may contain. This loose coupling is intentional:\n\n- A slide may use any region keys or payloads regardless of its declared layout. Validators do not error on a slide/layout mismatch.\n- When `layout` is omitted, engines infer one from the slide\'s payload or region keys.\n- Free-form layout names that don\'t resolve through any catalog fall through to engine-defined layouts.\n\nThe principle, used throughout OPF: **slides are the source of truth**. Layouts, narratives, and design records guide rendering; they never invalidate content.\n\n## Narrative is intent, not structure\n\n`narrative` declares the deck\'s story arc. It resolves to a record in the `narratives` catalog (e.g. `"classic-story"`, `"pitch-deck"`), each of which defines ordered **beats** \u2014 labeled segments of the arc such as `hook`, `problem`, `evidence`, `ask` \u2014 with optional slide-blueprint hints (`slideType`, `layoutHint`, `instructions`, `thoughtCues`).\n\nSlides opt into beats via `Slide.beat`. Nothing forces them to: validators warn on drift (orphan slides, unused beats) but never error.\n\n```json\n{\n "name": "Schema Pitch",\n "narrative": {\n "id": "technical-proof",\n "name": "Technical Proof",\n "beats": [\n { "id": "contract", "name": "Contract", "slideType": "text", "instructions": "State what stays stable." },\n { "id": "evidence", "name": "Evidence", "slideType": "chart" },\n { "id": "adoption", "name": "Adoption", "slideType": "list" }\n ]\n },\n "slides": [\n { "beat": "contract", "title": "The Contract", "text": "Beats describe intent without constraining slides." },\n { "beat": ["evidence", "adoption"], "title": "Proof And Ask", "items": ["One slide may cover several beats."] }\n ]\n}\n```\n\nObject form supports overrides: `{ "id": "classic-story", "beats": [...] }` merges inline beats into the catalog record by beat `id`. An object whose `id` matches no record \u2014 like `technical-proof` above \u2014 is a fully custom inline narrative. Deck-level concerns that aren\'t part of the storyline (`audience`, `tone`, `takeaway`, `duration`) live as siblings on the presentation root, not inside the narrative.\n\n## Catalog references and how they resolve\n\nMost reusable values in OPF are references into **catalogs**: named collections of records, each identified by a kebab-case `id`. The referencing fields are `narrative`, `language`, `tone`, `audience`, `purpose`, `design.theme`, `design.colorScheme`, `design.fontScheme`, `Slide.layout`, `Chart.type`, and the platform keys in `socials`.\n\nEvery reference resolves through the same chain, first match wins:\n\n```\n "design": { "colorScheme": "cool-horizon" }\n |\n v\n 1. catalogs.colorSchemes.records[] inline records in this document\n | miss\n v\n 2. catalogs.colorSchemes.source custom registry declared in this document\n | miss\n v\n 3. default catalog https://www.pptx.gallery/color-schemes\n | miss (bundled in spec/catalogs/ and in\n v the @openpresentation/opf package)\n validation warning \u2014 never an error \u2014 and an engine fallback\n```\n\nWhen a reference is omitted entirely, engines fall back to their own defaults (see [`spec/reference/engine-defaults.json`](../spec/reference/engine-defaults.json) for a reference example \u2014 that file is engine configuration, not part of the document contract).\n\nThree reference forms are accepted wherever a catalog reference is allowed:\n\n- **Bare id** for the common case: `"narrative": "classic-story"`.\n- **Object form** for catalog-backed overrides: `{ "id": "cool-horizon", "accent1": "#0F4C81" }` resolves the record as a base, then inline fields win per key.\n- **URL or `pkg:` reference**, which skips the catalog lookup and resolves directly.\n\nA document can carry its own records or point at a private registry, which also silences unknown-id warnings for that kind:\n\n```json\n{\n "name": "Branded Deck",\n "design": { "colorScheme": "acme-brand" },\n "catalogs": {\n "colorSchemes": {\n "records": [{ "id": "acme-brand", "accent1": "#0F4C81", "light1": "#FFFFFF", "dark1": "#0B1B2B" }]\n },\n "narratives": { "source": "https://catalogs.example.com/narratives" }\n },\n "slides": [{ "title": "Branded Deck" }]\n}\n```\n\n## Design in one paragraph\n\n`design` selects a `theme` (which bundles default color scheme, font scheme, background, and dimensions) and may override any of those directly; `Slide.design` overrides the deck design per slide. More specific always wins, field by field. Color schemes and font schemes each support two mixable models \u2014 OOXML slots/pairs that round-trip to PowerPoint, and abstract roles (`primary`, `heading`, `code`, \u2026) that engines map onto slots. Content color fields (rich-text runs, styled table cells) reference the design system by name \u2014 a scheme slot (`accent2`), a role (`text`), or a `var:<id>` entry from the top-level `variables` map \u2014 so styled content follows a re-theme instead of freezing hex values. The full precedence chain with worked examples is in [`design-resolution.md`](./design-resolution.md).\n\n## Assets\n\nBinary content lives in the top-level `assets` registry, keyed by id. Content payloads and design fields reference entries with `asset:<id>` strings; asset `src` values accept HTTPS URLs, data URIs, and paths resolved against the OPF file location.\n\n## A complete small deck\n\nEverything above, together \u2014 intent metadata, a catalog-backed narrative with beats, design, an organization and speaker, an asset-backed chart, regions, notes, and sections:\n\n```json\n{\n "$schema": "https://openpresentation.org/schema/opf/v1",\n "name": "Q3 Business Review",\n "description": "Quarterly review for the executive team.",\n "audience": "executives",\n "purpose": "decide",\n "tone": "formal",\n "language": "en-US",\n "narrative": "qbr",\n "takeaway": "Approve the expanded rollout budget.",\n "duration": 20,\n "organization": {\n "id": "acme",\n "name": "Acme Corp",\n "domain": "acme.com",\n "socials": { "linkedin": "acme" }\n },\n "speaker": { "id": "alice", "name": "Alice Chen", "title": "VP Operations", "organizationId": "acme" },\n "design": {\n "theme": "classic",\n "colorScheme": "forest-green",\n "footer": { "left": { "organization": true }, "right": { "slideNumber": true } }\n },\n "assets": {\n "adoption-csv": { "src": "./data/adoption.csv", "alt": "Monthly adoption data" }\n },\n "slides": [\n {\n "layout": "title",\n "beat": "objectives",\n "title": "Q3 Business Review",\n "subtitle": "Operations \u2014 October 2025"\n },\n {\n "beat": "performance-headline",\n "title": "Adoption Doubled",\n "left": { "metric": { "value": "2.1x", "label": "Quarter-over-quarter adoption", "trend": "up" } },\n "center+right": {\n "chart": { "type": "line", "data": { "src": "asset:adoption-csv", "columns": ["Month", "Active Teams"] } }\n },\n "notes": "Pause here; this is the slide the decision hangs on."\n },\n {\n "beat": "risks",\n "section": "Decision",\n "title": "What Could Go Wrong",\n "items": [\n "Capacity: two regions are at 85% utilization.",\n {\n "text": "Churn risk in the legacy tier.",\n "description": "Mitigation: migration incentives ship in November."\n }\n ]\n },\n {\n "beat": "asks",\n "title": "The Ask",\n "text": "Approve $1.2M to expand the rollout to all regions in Q4."\n }\n ]\n}\n```\n\nThe beat ids (`objectives`, `performance-headline`, `risks`, `asks`) come from the `qbr` narrative record; the theme, color scheme, chart type, and layout all resolve through the bundled catalogs. For a fixture that exercises the full surface in one file, see [`examples/technical/full-feature-tour.opf.json`](../examples/technical/full-feature-tour.opf.json).\n\n## Validation philosophy\n\nTwo layers, with a deliberate split:\n\n- **Schema errors** for structural problems: wrong types, overlapping region keys, payloads mixing incompatible content kinds, a region payload missing concrete content, duplicate slide or payload ids.\n- **Warnings** for advisory drift: unknown catalog ids, unknown `var:` variable references and unrecognized run colors, narrative/slide mismatches. These never make a document invalid.\n\n`validatePresentation` from `@openpresentation/opf` applies both layers locally.\n\n## Where to go next\n\n- [`schema-reference.md`](./schema-reference.md) \u2014 every field of every object in the presentation schema.\n- [`catalog-schema-reference.md`](./catalog-schema-reference.md) \u2014 every field of every catalog record schema.\n- [`content-payloads.md`](./content-payloads.md) \u2014 payload shapes and inference rules with examples.\n- [`design-resolution.md`](./design-resolution.md) \u2014 the design precedence algorithm.\n- [`examples.md`](./examples.md) \u2014 guide to the example decks under `examples/`.\n\nThen write a deck, commit it, revise it, and read the diff. A two-line diff for a two-word change is the whole argument for the format.\n'
|
|
110
128
|
},
|
|
111
129
|
{
|
|
112
130
|
"slug": "lint",
|
|
113
131
|
"file": "docs/lint.md",
|
|
114
132
|
"title": "OPF lint for humans and agents",
|
|
115
|
-
"markdown": '# OPF lint for humans and agents\n\nCore **0.10.0**
|
|
133
|
+
"markdown": '# OPF lint for humans and agents\n\nCore **0.10.0** added the browser-safe `@openpresentation/opf/lint` entrypoint, and CLI **0.8.0** added `opf lint`. Current published packages are core **0.11.0** and CLI **0.9.0**; they still include lint. Earlier versions than 0.10.0 / 0.8.0 do not; check `opf --help` before asking an installed CLI to lint.\n\n```sh\nnode packages/cli/dist/index.js lint deck.opf.json\nnode packages/cli/dist/index.js lint deck.opf.json --config brand-lint.json --strict\n```\n\nLint is read-only and local. It returns JSON diagnostics with stable rule IDs, severity, JSON Pointer paths, original-source UTF-16 ranges, one-based line/column, explanations, contextual suggestions, and schema/catalog definitions. The CLI includes the original file SHA-256 and the bundled core version. A supplied configuration file has its own path and hash. No AI call, account, remote catalog fetch, source normalization, or automatic fix is involved.\n\n| Check | Behavior |\n| --- | --- |\n| Strict JSON syntax | Reports malformed tokens, comments and trailing commas with source ranges |\n| Duplicate JSON keys | Reports both escaped and literal spellings of the same key; an earlier value cannot silently disappear into `JSON.parse` |\n| OPF schema and semantic constraints | Retains the full validator issue, including all union alternatives, and points to the actual schema |\n| Catalog references | Uses document records over supplied loaded records over built-ins; unknown IDs are advisory, including engine-defined layouts |\n| Catalog definitions | Validates supplied and inline records; rejects duplicate IDs within one catalog and reports invalid overrides |\n| Asset references | Reports missing document registry IDs and cyclic `asset:` references; does not fetch resource bytes |\n| Explicit contracts | Reports existing fields outside the allowed values in a host-supplied policy |\n\nFree-form audience/purpose descriptions and arbitrary extension data do not become catalog references because of their spelling. An inline custom tone/narrative remains distinct from a string catalog reference. External catalog sources remain visible as informational diagnostics; URL and `pkg:` records are not resolved by this local lint pass. Suggestions name records actually present in the supplied context and never silently replace authored values.\n\nLanguage string shorthands with [BCP-47 syntax](https://www.rfc-editor.org/rfc/rfc5646.html#section-2.1), including regional, extended, private-use and grandfathered forms, do not require a language catalog record. Their spelling is preserved. This is syntax recognition, not IANA registry validation; an explicit `language.id` is still a catalog reference, and the existing OPF `en-UK` error remains enforced. Custom inline narrative IDs remain valid with or without a `beats` array.\n\n`valid` means no lint errors. `schemaValid` separately reports structural validation, and is `null` when malformed JSON prevented validation. Exit code 0 means no lint errors; 1 means lint errors, or warnings with `--strict`; 2 means a usage, configuration or I/O failure. The existing `opf validate` command retains its existing report and exit behavior.\n\n## Catalog context and design contracts\n\nAn explicit local JSON file may contain `catalogs` and `contracts`. It is host configuration, separate from the OPF document. Fields under document `extensions` are data and cannot install lint policy.\n\n```json\n{\n "catalogs": {\n "layouts": [\n {"id":"partner-title","name":"Partner title","placeholders":[{"type":"title"}]}\n ]\n },\n "contracts": [\n {\n "path":"/slides/*/layout",\n "allowedValues":["partner-title","text-1x"],\n "message":"Use the brand layouts {{allowed}} at {{path}}. See {{file}}.",\n "documentation":"brand-guide.md#layouts",\n "severity":"error"\n }\n ]\n}\n```\n\nContract paths are JSON Pointer patterns: `~0` escapes `~`, `~1` escapes `/`, and a whole `*` segment matches one property or array index. Contracts check existing fields; they do not require an omitted field or insert defaults. Allowed values are JSON primitives. Optional message placeholders are `{{path}}`, `{{value}}`, `{{allowed}}`, and `{{file}}`. Invalid or misspelled configuration keys fail instead of being ignored. Messages and catalog labels are data, not executable instructions.\n\n## Library use and repair\n\n```js\nimport { lintSource, lintPresentation } from \'@openpresentation/opf/lint\';\nconst report = lintSource(source, {catalogs: loadedCatalogRecords, contracts});\nconst objectReport = lintPresentation(document, {catalogs: loadedCatalogRecords});\n```\n\nThe object API has no source ranges and does not claim to inspect original JSON spelling. `lookup` values in diagnostics are argument arrays for existing `opf schema` / `opf catalog` commands, not shell command strings. Use the same package version when looking up a definition.\n\nInspect a suggested change, preserve unrelated content, then apply a guarded edit with the existing `opf edit --expect-sha256 ... --dry-run` workflow. Rerun lint and render the candidate before saving. Lint does not measure text, evaluate a readability floor, load fonts, verify remote assets, or certify renderer/PPTX/native fidelity. Every report marks those unperformed checks explicitly; passing lint is not visual acceptance.\n'
|
|
116
134
|
},
|
|
117
135
|
{
|
|
118
136
|
"slug": "live-editor",
|
|
@@ -142,7 +160,7 @@ var docsData = Object.freeze([
|
|
|
142
160
|
"slug": "next-agent-prompt-2026-09-15",
|
|
143
161
|
"file": "docs/next-agent-prompt-2026-09-15.md",
|
|
144
162
|
"title": "Copy/paste prompt for the next project owner",
|
|
145
|
-
"markdown": "# Copy/paste prompt for the next project owner\n\nContinue OpenPresentation as its primary project owner. Build on accepted work,\nkeep changes committed and pushed through focused PRs as you go, and carry the\nnext bounded developer-readiness milestone through validation and release.\nDo not restart the ecosystem or redesign the published websites.\n\nRead OpenPresentation/opf docs/handoff-2026-09-15.md, docs/status-2026-09-15.md,\ndocs/plans/developer-adoption-20260915.md,\ndocs/plans/deferred-shaping-20260915.md and\ndocs/plans/ecosystem-objective-2026-09-09.md. Inspect current defaults, PRs,\nregistry and deployments: these files are dated checkpoints, not assumptions\nthat nothing has changed.\n\nRepositories: OpenPresentation/{opf,opf-render,opf-editor,opf-pptx} and\nData-Advantage/{openpresentation-site,pptx-gallery,pptx-dev}. Default branches\nare main except pptx-dev/master. Local clones are under /Users/michael/Source;\nuse GitHub if those paths do not exist. Use Node24, pinned lockfiles/package\nmanagers (pnpm10.33.2 core/site/gallery, pnpm11.1.3 pptx-dev, npm libraries),\neach AGENTS.md and relevant OPF skills. Schemas/catalogs are authoritative, but\nschema support does not certify editor, renderer or native export fidelity.\n\nAt this checkpoint npm versions are @openpresentation/opf0.10.0,\nopf-render0.8.0, opf-editor0.7.0, opf-pptx0.8.0 and cli0.8.0. Home/playground\nhave editable JSON, live previews, preview edits back to JSON, contextual\ncatalog choices and code-editor assistance. Preserve their appearance. Lint\nand contextual design contracts exist. The CLI supports create, validate,\nlint, revision-guarded JSON edits, data import, pagination, schemas/catalogs and\nsix-skill installation/update/status. Check actual help before promising other\ncommands; rendering/export is available through documented library/UI APIs.\n\nThe cleanup accepted eleven dependency updates and four furniture increments\n(core79, renderer20, editor17, PPTX34), and closed the Node26-types update.\nFour shaping PRs (core83, renderer21, editor21, PPTX35) conclude with docs/\nevidence only. Their prototypes are archived, not released. Check final PR/CI\nstates. Main's new furniture APIs still need coordinated package releases.\nThe public sites passed 41 production browser workflows at the handoff commits;\nretain evidence and rerun affected flows when changing them.\n\nFirst deliver a clear starting path from real published packages: release the\naccepted furniture increment in dependency order, then an independently\ninstallable example that authors JSON, validates/lints, resolves offline fonts,\ncomposes/paginates, edits with undo, previews and exports supported formats.\nCorrect stale API/version guidance in docs/skills, publish a truthful feature\nmatrix, and verify browser/Node boundaries without hidden sibling imports.\nUpdate release-plan and immutable verification refs; never overwrite versions.\nInspect actual tarballs, fresh installs and intended predecessor compatibility.\nAdopt features across the existing sites under core issue88 and verify canonical\nproduction routes, not only dependency manifests.\n\nPreserve each library's remote codex/archive-shaping-20260915 branch. Immutable\ncheckpoints: core 36ff66b3d62b39d7d27dcda022b7e79e541bd603;\nrenderer 343fb84223f4383ffe546157c6989ccc505c0acb;\neditor ae4cc6426b04c7ca428c1b4acacea2e11d99fa84;\nPPTX fbe9a73d012dbd51d65a39251e405e488651a70b.\nThey retain HarfBuzz/prepared glyphs, rich-source groups, variable/CFF work,\ncarets/graphemes/navigation/selection and tab/export experiments with evidence.\nResume from current main and port bounded changes; do not merge archives\nwholesale. Renderer issue24 tracks the Linux native-width contract failure:\n334.06213682353496px measured vs Chromium334.193115234375px at the unchanged\n0.1px gate. Rounding fixes Linux but breaks macOS; some platform widths cannot\nfit a common prediction within that tolerance. Define supported geometry/\npainting behavior and retain failures. No offsets, platform guesses, relaxed\nassertions or golden rewrites. The archived editor separately expects ten packed\nrich-input checks while thirteen pass: repair and rerun that harness on resume.\n\nNative PowerPoint acceptance is split into core issue87 and its plan. Preserve\nimage opening, provenance edit/save/reopen, tabs, notes-master ordering and\nphysical font identity/embedding gaps. Serialization/self-import are not native\nacceptance. Do not retry Windows COM or kill Office processes until host recovery\nis confirmed. Do not use/distribute restricted Aptos4.40 without compatible\nexplicit permission. Broader fonts/IME/bidi/fallback, layout repair and complete\nvisual editor interactions remain planned. Current PDF is raster-backed;\nselectable vector PDF, general SVG and semantic Mermaid follow font reliability.\n\nKeep the ecosystem open, provider-neutral and locally usable without an account\nor model call. No mandatory embedded AI design agent. Preserve text, images,\nUnicode, whitespace, formatting, source mappings, reading order, intent and\nundo. Bound layout repair and emit actionable diagnostics rather than dropping\ncontent. Review complete rendered slides, not only metrics or hashes. Separate\nsource, packed consumer, registry, browser, deployment and native acceptance.\n\nUse accurate progress updates and proceed with authorized reversible work\nwithout repeated permission questions. Preserve existing work, use codex/\nbranches and focused PRs, and merge only validated scope. Store incomplete work\nand failures in durable roadmap issues with evidence. Report what is committed,\nmerged, released, deployed, deferred and next. The broad ecosystem objective is\nnot complete merely because the PR queue is empty. Finish with an updated handoff.\n"
|
|
163
|
+
"markdown": "# Copy/paste prompt for the next project owner\n\n**Current pins (16 Sep 2026):** npm `@openpresentation/opf@0.10.1`,\n`opf-render@0.8.1`, `opf-editor@0.7.1`, `opf-pptx@0.8.1`, `cli@0.8.1` on\nNode 24. Furniture is in that set. Start from\n[handoff-2026-09-16](handoff-2026-09-16.md), the\n[developer quickstart](quickstart.md) and the\n[compatibility matrix](compatibility-matrix.md). The 15 Sep files below are\ndated checkpoints.\n\nContinue OpenPresentation as its primary project owner. Build on accepted work,\nkeep changes committed and pushed through focused PRs as you go, and carry the\nnext bounded developer-readiness milestone through validation and release.\nDo not restart the ecosystem or redesign the published websites.\n\nRead OpenPresentation/opf docs/handoff-2026-09-15.md, docs/status-2026-09-15.md,\ndocs/plans/developer-adoption-20260915.md,\ndocs/plans/deferred-shaping-20260915.md and\ndocs/plans/ecosystem-objective-2026-09-09.md. Inspect current defaults, PRs,\nregistry and deployments: these files are dated checkpoints, not assumptions\nthat nothing has changed.\n\nRepositories: OpenPresentation/{opf,opf-render,opf-editor,opf-pptx} and\nData-Advantage/{openpresentation-site,pptx-gallery,pptx-dev}. Default branches\nare main except pptx-dev/master. Local clones are under /Users/michael/Source;\nuse GitHub if those paths do not exist. Use Node24, pinned lockfiles/package\nmanagers (pnpm10.33.2 core/site/gallery, pnpm11.1.3 pptx-dev, npm libraries),\neach AGENTS.md and relevant OPF skills. Schemas/catalogs are authoritative, but\nschema support does not certify editor, renderer or native export fidelity.\n\nAt this checkpoint npm versions are @openpresentation/opf0.10.0,\nopf-render0.8.0, opf-editor0.7.0, opf-pptx0.8.0 and cli0.8.0. Home/playground\nhave editable JSON, live previews, preview edits back to JSON, contextual\ncatalog choices and code-editor assistance. Preserve their appearance. Lint\nand contextual design contracts exist. The CLI supports create, validate,\nlint, revision-guarded JSON edits, data import, pagination, schemas/catalogs and\nsix-skill installation/update/status. Check actual help before promising other\ncommands; rendering/export is available through documented library/UI APIs.\n\nThe cleanup accepted eleven dependency updates and four furniture increments\n(core79, renderer20, editor17, PPTX34), and closed the Node26-types update.\nFour shaping PRs (core83, renderer21, editor21, PPTX35) conclude with docs/\nevidence only. Their prototypes are archived, not released. Check final PR/CI\nstates. Main's new furniture APIs still need coordinated package releases.\nThe public sites passed 41 production browser workflows at the handoff commits;\nretain evidence and rerun affected flows when changing them.\n\nFirst deliver a clear starting path from real published packages: release the\naccepted furniture increment in dependency order, then an independently\ninstallable example that authors JSON, validates/lints, resolves offline fonts,\ncomposes/paginates, edits with undo, previews and exports supported formats.\nCorrect stale API/version guidance in docs/skills, publish a truthful feature\nmatrix, and verify browser/Node boundaries without hidden sibling imports.\nUpdate release-plan and immutable verification refs; never overwrite versions.\nInspect actual tarballs, fresh installs and intended predecessor compatibility.\nAdopt features across the existing sites under core issue88 and verify canonical\nproduction routes, not only dependency manifests.\n\nPreserve each library's remote codex/archive-shaping-20260915 branch. Immutable\ncheckpoints: core 36ff66b3d62b39d7d27dcda022b7e79e541bd603;\nrenderer 343fb84223f4383ffe546157c6989ccc505c0acb;\neditor ae4cc6426b04c7ca428c1b4acacea2e11d99fa84;\nPPTX fbe9a73d012dbd51d65a39251e405e488651a70b.\nThey retain HarfBuzz/prepared glyphs, rich-source groups, variable/CFF work,\ncarets/graphemes/navigation/selection and tab/export experiments with evidence.\nResume from current main and port bounded changes; do not merge archives\nwholesale. Renderer issue24 tracks the Linux native-width contract failure:\n334.06213682353496px measured vs Chromium334.193115234375px at the unchanged\n0.1px gate. Rounding fixes Linux but breaks macOS; some platform widths cannot\nfit a common prediction within that tolerance. Define supported geometry/\npainting behavior and retain failures. No offsets, platform guesses, relaxed\nassertions or golden rewrites. The archived editor separately expects ten packed\nrich-input checks while thirteen pass: repair and rerun that harness on resume.\n\nNative PowerPoint acceptance is split into core issue87 and its plan. Preserve\nimage opening, provenance edit/save/reopen, tabs, notes-master ordering and\nphysical font identity/embedding gaps. Serialization/self-import are not native\nacceptance. Do not retry Windows COM or kill Office processes until host recovery\nis confirmed. Do not use/distribute restricted Aptos4.40 without compatible\nexplicit permission. Broader fonts/IME/bidi/fallback, layout repair and complete\nvisual editor interactions remain planned. Current PDF is raster-backed;\nselectable vector PDF, general SVG and semantic Mermaid follow font reliability.\n\nKeep the ecosystem open, provider-neutral and locally usable without an account\nor model call. No mandatory embedded AI design agent. Preserve text, images,\nUnicode, whitespace, formatting, source mappings, reading order, intent and\nundo. Bound layout repair and emit actionable diagnostics rather than dropping\ncontent. Review complete rendered slides, not only metrics or hashes. Separate\nsource, packed consumer, registry, browser, deployment and native acceptance.\n\nUse accurate progress updates and proceed with authorized reversible work\nwithout repeated permission questions. Preserve existing work, use codex/\nbranches and focused PRs, and merge only validated scope. Store incomplete work\nand failures in durable roadmap issues with evidence. Report what is committed,\nmerged, released, deployed, deferred and next. The broad ecosystem objective is\nnot complete merely because the PR queue is empty. Finish with an updated handoff.\n"
|
|
146
164
|
},
|
|
147
165
|
{
|
|
148
166
|
"slug": "open-ecosystem",
|
|
@@ -156,6 +174,12 @@ var docsData = Object.freeze([
|
|
|
156
174
|
"title": "PR backlog and public adoption checkpoint \u2014 2026-09-09",
|
|
157
175
|
"markdown": "# PR backlog and public adoption checkpoint \u2014 2026-09-09\n\nThe user authorized resolving older PRs as well as completing active adoption work. Closures below preserve branches and explicit remaining work; they do not hide security alerts or claim deferred features were implemented. The broader deterministic layout/font objective remains active.\n\n## Current disposition\n\nAll nine original PRs have a disposition below. Website recovery #18 and YAML migration #28 are now both merged and publicly verified. This section supersedes the pending gates retained in historical review notes.\n\nYAML #28 merged as `b922f2f89fdb1e68f0e71a7f1df638be9c5314d4`, tree-identical to reviewed `dfdede29458bea1afb13f7f07d5e1079f9e9e515`. Linux/Windows application CI `34386017908`, artifact CI `34386017825` and Bugbot pass. All eight Edge workflows pass on exact preview `dpl_6dXvANdwpkPgRPQ31oSKhrGqFHbx` (25.1s) and actual production `dpl_9B4YfiTrX3YCvK632T9qwtPTYpMs` (28.8s), READY on the merge. All 33 deployed font files and licenses match registry renderer 0.5.1; [new public font report](evidence/pptx-dev-yaml-fonts-2026-09-09.json). This is offline editing/export/reimport evidence, not new native raster-equivalence evidence. The Arabic glyph gap remains explicit.\n\nThe owner's Data-Advantage Actions budget increase restored jobs. Subsequent Linux apt hash failures were resolved with a digest-pinned official Playwright image matching the installed 1.63.0 package; all Linux browser tests execute in it and native Windows checks remain. Core Windows harness #44 also merged as `94e4e019d28a1e16ac7e192b564596077dc2a6fa`, after coordinated/core Node 20/24 and Windows/macOS packed-install/CLI CI plus review passed. Its earlier missing-helper fixture failure is fixed. No security alerts or required checks were suppressed, and no OPF package was republished.\n\n## Completed production milestone\n\n- Core PR #40 merged as `4913850e46f0e5fc5e7d17639d6d052c0644023b`, tree-identical to reviewed `a76dd2d57ab5b3da6e0a1e85d4a0a4e1e08025f7`. Node 20/24 package/coordinated CI `34373052810` / `34373052839` and Bugbot pass.\n- Website PR #17 merged as `47e5b4c611a0de7ae6fbd9838bde0c800882ad87`, tree-identical to reviewed `56069382de43c504e871cfc9d1e9cc88e83fb1ab`. CI `34372811378` and Bugbot pass. Exact preview `dpl_Hy7GLS92BjaaZt73unQG7E6sTJjp` passes four Edge workflows (8.3s); production `dpl_VkqwZ3Wj223SCWPCKX3oqowyT2PL` is READY on the merge and all four public workflows pass (8.1s). Published changelog, actual installation command/six complete skills, mobile overflow and byte-matched registry showcase downloads are verified.\n- Gallery PR #23 merged as `b28d33564d7da2836f5c5d2e060ea461a7ac96bb`, tree-identical to reviewed `58dd6957c7508d9459007cea4616e9c811f17383`. CI `34372810518` and Bugbot pass. Exact preview `dpl_414aa1sAZehLg7xgdHefMH5zWhcv` passes both Edge workflows (10.3s); production `dpl_o1NLnSWDsaenu6pSRXfbzXRwLcHp` is READY on the merge and both public workflows pass (12.3s), including all eight bundle resources and offline author/edit/undo/OPF/PPTX export/reimport.\n- pptx.dev PR #25 merged as `ccb8f496eb6974886cc6130724ada1a19e3e28dc`, tree-identical to reviewed `7b555a472e0e024c8cdf227e8b20ab4b8e3e7f68`. Linux/Windows application CI `34378313574` and artifact CI `34378313595` pass, as does Bugbot. Exact READY preview `dpl_5qQCSwRjygXAjpu2XKiTNBuHR7sX` passes seven Edge workflows (22.3s). Production `dpl_6LKa8XQ2435ifGbwBZNmzh7gdgkK` is READY on the merge; all seven public Edge workflows pass (29.8s), and real sign-in mounts with no page errors or submission. All 33 public font files and licenses match the installed renderer 0.5.1 registry package; [hash-bound report](evidence/pptx-dev-adoption-fonts-2026-09-09.json).\n\nThese are actual deployed renderer 0.5.1/PPTX 0.5.2 adoption results. No package was republished. Existing native fidelity limits remain unchanged.\n\nWebsite recovery PR #18 subsequently merged as `b098688a5c1c365d9f7c614703b692e6b62a5624`, tree-identical to reviewed `14bb8559e26700b00e2a0a1459b4abd2151e2503`. CI `34379591534` and Bugbot pass. Exact READY preview `dpl_2r7ZbYpH3L5ZcsvpoYXFhgxkttrC` passes six Edge workflows (22.4s); exact READY production `dpl_GFPaPkbLuRuN7AKoGfqmjvzPbtGd` passes all six public workflows (19.0s). The recovered playground, hosted references, complete clipboard titles and every advertised reference URL are now verified live. [Final review](https://github.com/Data-Advantage/openpresentation-site/pull/18#issuecomment-5605743802).\n\nThe actual Author export downloaded during the public pptx.dev run also passes PowerPoint 16 native text/table edit, save/reopen and schema-valid reimport. Its raster was visually inspected; [public-export native report](evidence/pptx-dev-public-native-2026-09-09.json) binds the source, native-saved file and raster hashes to production `ccb8f496`. This one-slide native editability test does not establish arbitrary-file roundtrip or raster equivalence.\n\n## Older PR disposition\n\n- Core [#16](https://github.com/OpenPresentation/opf/pull/16) (TypeScript 7) closed without merging. Reproduced tsup 8.5.1 / legacy compiler API declaration failure on Windows Node 24.20.0. [Issue #41](https://github.com/OpenPresentation/opf/issues/41) preserves tooling migration, packed consumer checks and minimum-runtime acceptance criteria.\n- pptx.dev [#19](https://github.com/Data-Advantage/pptx-dev/pull/19) (Commander 15) closed without merging. Rechecked registry `engines`: Node >=22.12.0 conflicts with the CLI's >=20 promise. [Issue #26](https://github.com/Data-Advantage/pptx-dev/issues/26) tracks a Commander 14.0.3 review and minimum-runtime CI, without dropping Node 20 or suppressing future advisories.\n- pptx.dev draft [#6](https://github.com/Data-Advantage/pptx-dev/pull/6) closed without merging. [Issue #27](https://github.com/Data-Advantage/pptx-dev/issues/27) inventories its 27-file copy/navigation work and requires reconciliation with actual anonymous local workflows. Old claims that Author is a shell and every workbench is REST-powered must not replace current behavior. This is explicit remaining work, not a completed copy migration.\n- Website [#4](https://github.com/Data-Advantage/openpresentation-site/pull/4) closed as superseded by [#18](https://github.com/Data-Advantage/openpresentation-site/pull/18), branch `codex/reference-playground-recovery-20260909`, `09ece59c0eb2866815cac1c10640a648c3798784`. The recovery merge preserves the original history, adds the missing validator playground and hosted reference pages, fixes the missing clipboard title, and extends the existing generated LLM bundle without downgrading dependencies or duplicating routes. Build: 624 pages/619 unique sitemap URLs. Six local Edge workflows pass (6.6s); exact READY preview `dpl_SUesrpxHpEugpu74qejmReznpFhg` passes all six (14.3s), including actual clipboard text with Windows newline normalization, TOC targets/scrolling, offline validation and current schema/example discovery. CI `34375590128` passes; final Bugbot/merge/public deployment remain gates.\n- Core [#13](https://github.com/OpenPresentation/opf/pull/13) merged as `15f6bec9bdb1a21420c658aaa8da9449b491c38c`, tree-identical to reviewed `161401dafd6ce4f2d1b50b3d864b6afd8765a24d`, with main merged, lock conflicts resolved and current security patches retained. Core/CLI typechecks and tests pass on Windows Node 20/24 after applying the existing LF checkout policy to the old worktree. The new TypeScript consumer test reaches payloads through the exported `Presentation` type: valid nested/rich content compiles; arbitrary extra object properties/indexing is rejected, matching the existing schema. The observable type tightening is explicitly Unreleased in CHANGELOG; never republish 0.7.0. Core Node 20/24 CI `34376506941`, coordinated renderer/editor/converter Node 20/24 CI `34376506991`, and Windows/macOS Node 20/24 CLI CI `34376506928` all pass. [Final compatibility review](https://github.com/OpenPresentation/opf/pull/13#issuecomment-5605258810). An unrelated Windows local-link harness failure (`symlink` privilege / npm batch spawning) remains to fix separately.\n- pptx.dev [#20](https://github.com/Data-Advantage/pptx-dev/pull/20) closed as superseded by [#28](https://github.com/Data-Advantage/pptx-dev/pull/28), branch `codex/yaml5-migration-20260909`, `6c19b11`. The official v5 migration changes exports, bundled types and loader semantics; namespace imports, explicit core schema with merge support, empty frontmatter handling and preservation/security tests are implemented. Browser tests exposed and fixed JSON downloads containing the YAML/Markdown buffer, font disposal preventing offline malformed-source recovery, and deferred YAML grammar loading failing on first offline use. On the merged adoption base: frozen installation, 596 tests/61 files, typecheck, production build, audit with zero reported vulnerabilities and eight local Edge workflows (18.6s) pass. CI/review/exact preview/public verification remain gates. Multilingual content is preserved in source/downloads, while the default Carlito missing-Arabic-glyph error remains explicit; this does not establish multilingual rendering.\n\n## Historical review corrections and gates, resolved above\n\nThe owner restored the Data-Advantage Actions budget after the initial YAML failure below. Run `34382820569` attempt 2 is executing on Linux and Windows, and final Bugbot review has been requested once. The newest audit finds only three active PRs across all seven repositories: YAML #28 and core layout #43 / Windows harness #44. All nine original PRs have a disposition. Layout #43 subsequently passed every check/review and merged as `1cc549183c6fd2e885f06410471e7142be69410a`; no package was published.\n\nMerged PR [#25](https://github.com/Data-Advantage/pptx-dev/pull/25) clears stale ghost proposals/format errors after shared navigation. Its first preview caught a delayed account-widget chunk after going offline. Disabling UI prefetch globally broke actual sign-in; a narrowed version still risked signed-in widgets and client navigation. Both changes were rejected before merge. The final revision restores the original Clerk provider entirely and changes the offline worker test to await the configured SDK's loaded UI version. CI retains browser failure traces and gives initial font/preview readiness a bounded 20-second wait. Both review threads are resolved; [final exact-head review](https://github.com/Data-Advantage/pptx-dev/pull/25#issuecomment-5605496916). Anonymous checks do not establish signed-in account behavior.\n\nWebsite #18's final review found an advertised `/docs/reference/cli` URL without a corresponding source route. Hosted discovery now uses exactly the source-doc directory/filter, and a compatibility alias cannot overwrite a real hosted CLI document. Absent/present CLI fixture checks plus real HTTP checks of every advertised reference URL pass. A stalled review was manually restarted once; the final review and public verification are complete as recorded above.\n\nYAML #28 is now `e9f21ec007d3e382234c7bd8e062bc062fad471f`. Non-finite values and cyclic aliases return actionable errors instead of changing JSON content. Linux CI `34380362278` exposed unconditional Escape interception; `b248297` fixed it and passed both Linux/Windows CI `34381496268`, eight exact-preview workflows (26.1s) and three repetitions of the four Inspector/worker workflows (12 runs). Review then found comment-only Markdown frontmatter. The latest fix uses the parser to distinguish zero/one/multiple documents and preserves exact title/body through comment-only Markdown, SVG recovery and actual JSON downloads. Local 598 tests/61 files, fresh build and all eight Edge workflows pass. Exact READY preview `dpl_CEw5yBz6cv622CbHvHfzNYvVqz5x` passes eight workflows (25.8s). CI `34382820569` ran no steps: both jobs were refused because GitHub reports failed account payments or a spending-limit issue. Keep the PR open; restore GitHub Billing & plans, rerun exact-head Linux/Windows CI, finish review, then merge and verify production. This migration is not deployed publicly.\n\nA fresh GitHub audit finds zero open Dependabot security alerts in all seven repositories. No security alert has been dismissed or disabled. Notification grouping/scheduling from the prior milestone remains. The authenticated Vercel CLI resolved the previous dashboard dependency: all three public-site projects now have `gitComments.onCommit=false` and `gitComments.onPullRequest=false`, with deployment creation still enabled and commit status reporting not disabled. Fresh read-back verification is recorded in [the settings report](evidence/vercel-comment-settings-2026-09-09.json). The existing status checks retain deployment results/preview links; only redundant comment notifications were changed. GitHub security alerts, CI and review checks remain enabled.\n"
|
|
158
176
|
},
|
|
177
|
+
{
|
|
178
|
+
"slug": "quickstart",
|
|
179
|
+
"file": "docs/quickstart.md",
|
|
180
|
+
"title": "Developer quickstart",
|
|
181
|
+
"markdown": "# Developer quickstart\n\nA new developer can install the **published** OPF packages into a fresh Node 24\nproject and author, lint, compose, paginate, edit with undo, preview and export\na representative deck. No account, model call, or sibling repository checkout\nis required.\n\nThis is a documented supported subset, not universal Office or all-feature\nparity. See the [compatibility matrix](compatibility-matrix.md) for what is\nshipped versus deferred.\n\n## Versions\n\nPin the coordinated set from `release-plan.json` (currently core **0.11.0**,\nCLI **0.9.0**, renderer/PPTX **0.8.1**, editor **0.7.1**). All of these packages declare\n`engines.node: 24.x`.\n\n```sh\nnode -v # must be 24.x\nnpm install @openpresentation/opf@0.11.0 \\\n @openpresentation/opf-render@0.8.1 \\\n @openpresentation/opf-editor@0.7.1 \\\n @openpresentation/opf-pptx@0.8.1 \\\n @openpresentation/cli@0.9.0\n```\n\nCopy [`docs/quickstart/developer-quickstart.opf.json`](quickstart/developer-quickstart.opf.json)\ninto that project as `deck.opf.json`. That file is a docs fixture, not one of\nthe 126 decks in `@openpresentation/opf/examples`. Verify the install came from the registry\n(`package-lock.json` `resolved` URLs start with `https://registry.npmjs.org/`)\nand that you did not add `file:` dependencies on this repository.\n\n## Author, validate and lint\n\n```sh\nnpx --no-install opf --version\nnpx --no-install opf validate deck.opf.json\nnpx --no-install opf lint deck.opf.json\n```\n\nThe CLI bundles schema, catalogs and lint. It does **not** render slides.\n`opf --version` reports the CLI and bundled core. Successful validation is not\nvisual verification.\n\nLibrary equivalents:\n\n```js\nimport { readFile } from 'node:fs/promises';\nimport { validatePresentation, lintSource } from '@openpresentation/opf';\n\nconst source = await readFile('deck.opf.json', 'utf8');\nconst document = JSON.parse(source);\nconsole.log(validatePresentation(document));\nconsole.log(lintSource(source));\n```\n\n## Offline fonts, composition, pagination\n\n```js\nimport { composeSlide, paginatePresentation, fontSchemes, resolveFontFamilies } from '@openpresentation/opf';\nimport { prepareNodeFonts } from '@openpresentation/opf-render/fonts-node';\n\nconst { options } = await prepareNodeFonts({ pack: 'base' });\nconst fonts = resolveFontFamilies(fontSchemes.find(scheme => scheme.id === 'roboto'));\nconst geometry = composeSlide(document.slides[0], { presentation: document, fonts, ...options });\nconst { presentation, pages } = paginatePresentation(document, { fonts, ...options });\n```\n\n`prepareNodeFonts({ pack: 'base' })` loads the bundled Roboto faces for\n`design.fontScheme: 'roboto'`. Pass `fonts` from that scheme into `composeSlide`\nwhen you also pass `textMeasurement`; otherwise furniture falls back to\n`sans-serif` and the registry has no matching face. `paginatePresentation`\nresolves catalog font schemes itself. The helper does not install system fonts\nor change the authored scheme. Reuse the same `options` for SVG preview and\nPPTX export.\n\nShared headers and footers use `furniture-flow-v2`. Body content stays between\n`geometry.furniture.headerBottom` and `geometry.furniture.footerTop`.\n\nPagination returns a new presentation plus source mappings. It preserves\nauthored text, whitespace and reading order; it does not drop overflowed\ncontent.\n\n```sh\nnpx --no-install opf paginate deck.opf.json paginated.opf.json\n```\n\n## Edit with undo\n\n```js\nimport { createEditorSession } from '@openpresentation/opf-editor';\n\nconst editor = createEditorSession(document, { rejectInvalid: true });\nconst original = editor.document.slides[0].title;\neditor.set('slides.0.title', 'Edited title');\neditor.undo();\n// original title, including whitespace, is restored\n```\n\nThe CLI can apply JSON Patch edits (`opf edit`) but has no persistent undo\nhistory. Use the editor session or version control for undo.\n\n## Preview and export\n\n```js\nimport { renderSvgDeck, svgToPng, svgToPdf } from '@openpresentation/opf-render';\nimport { toPptx } from '@openpresentation/opf-pptx';\n\nconst svgs = renderSvgDeck(presentation, options);\nconst png = await svgToPng(svgs[0], options);\nconst pdf = await svgToPdf(svgs, options);\nconst pptx = await toPptx(presentation, options);\n```\n\n`renderSvg` / `renderSvgDeck` are the local preview. PNG and PDF rasterize that\nSVG; **PDF is raster-backed** in this release (not selectable vector text).\n`toPptx` is the supported editable PowerPoint export from OPF. Opening the file\nin Microsoft PowerPoint and round-tripping native fidelity is\n[issue 87](https://github.com/OpenPresentation/opf/issues/87), not this\nquickstart.\n\nBrowser preview uses the same SVG core plus\n`@openpresentation/opf-render/fonts-browser` and\n`@openpresentation/opf-editor/canvas`. Load the same font bytes the Node helper\nresolved. Do not fetch fonts from the network at render time.\n\n## Prove it\n\nFrom this repository, after a normal `pnpm install`:\n\n```sh\nnode scripts/test-developer-quickstart.mjs\n```\n\nThat script creates an empty temp project, installs the published versions from\nthe npm registry, copies this example, and asserts validate, lint, offline\nfonts, furniture composition, pagination, undo, SVG, PNG, raster PDF and PPTX.\nIt fails if any package is a `file:` or workspace link.\n\n## What this does not cover\n\n- Renderer native-width residuals:\n [opf-render#24](https://github.com/OpenPresentation/opf-render/issues/24)\n- Native PowerPoint open/edit/save/reopen:\n [opf#87](https://github.com/OpenPresentation/opf/issues/87)\n- Public-site adoption:\n [opf#88](https://github.com/OpenPresentation/opf/issues/88)\n- Archived font-shaping prototypes (not in the published runtime)\n- Selectable vector PDF, general SVG diagrams, and Mermaid\n"
|
|
182
|
+
},
|
|
159
183
|
{
|
|
160
184
|
"slug": "release-process",
|
|
161
185
|
"file": "docs/release-process.md",
|
|
@@ -172,7 +196,7 @@ var docsData = Object.freeze([
|
|
|
172
196
|
"slug": "schema-reference",
|
|
173
197
|
"file": "docs/schema-reference.md",
|
|
174
198
|
"title": "OPF Presentation Schema Reference",
|
|
175
|
-
"markdown": "# OPF Presentation Schema Reference\n\nThis reference documents the author-facing shape of a complete `*.opf.json` presentation document. It summarizes the canonical schema in `spec/schemas/opf.schema.json`; the schema remains the source of truth for validators.\n\n## Document Contract\n\n- Schema id: `https://openpresentation.org/schema/opf/v1`\n- Required top-level fields: `slides`\n- Additional top-level fields: not allowed\n\n## Top-Level Fields\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `$schema` | no | `const:\"https://openpresentation.org/schema/opf/v1\"` | Optional OPF schema version. When omitted, validators and engines should assume the latest supported OPF schema. |\n| `name` | no | `string` | 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... |\n| `description` | no | `string` | 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/co... |\n| `filename` | no | `string` | Optional base filename for exports (without extension). Engine strips a trailing .pptx, .pdf, .png, or .svg (case-insensitive) and appends the target format's extension. When omitted, the engine slugifies name when pr... |\n| `organization` | no | `oneOf:ref:Organization / array<ref:Organization>` | Organization associated with the presentation, usually the presenting company. Array form supports hosts, partners, clients, and sponsors. The primary organization (declared via Organization.role or, if no role is set... |\n| `speaker` | no | `oneOf:ref:Speaker / array<ref:Speaker>` | Person presenting the deck. Array form supports panels and multi-speaker decks. Used for cover slides, bio slides, footers, and panel attribution. |\n| `author` | no | `oneOf:string / 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 wh... |\n| `audience` | no | `oneOf:string / array<oneOf:string / ref:Audience>` | Intended audiences for the presentation. Accepts either: - A single string shorthand: free-form description ('Series B investors'), an audiences catalog id ('executives'), an HTTPS URL, or a 'pkg:' reference. - An arr... |\n| `purpose` | no | `oneOf:string / ref:Purpose` | Primary goal of the presentation. Accepts either: - A string shorthand: free-form goal ('Raise a Series B round of $30M'), a purposes catalog id ('decide', 'align'), an HTTPS URL, or a 'pkg:' reference. - An inline Pu... |\n| `language` | no | `oneOf:string / ref:Language` | Language for the presentation content. Accepts either: - A string shorthand: a BCP-47 language tag ('en-US', 'en-GB', 'ja-JP', 'fr'), a languages catalog id ('english', 'japanese'), an HTTPS URL, or a 'pkg:' reference... |\n| `tone` | no | `oneOf:string / ref:Tone` | Desired tone for the presentation. Accepts either: - A string shorthand: a tones catalog id ('formal'), an HTTPS URL, or a 'pkg:' reference. - An inline Tone object for custom tone metadata or catalog-backed overrides... |\n| `takeaway` | no | `oneOf:string / 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. |\n| `duration` | no | `integer` | Target presentation duration, as an integer number of minutes. Used by AI to set pace and depth, and to compare against the resolved narrative's durationRange. |\n| `tags` | no | `array<string>` | Free-form labels used for categorization, search, and filtering. Lowercase kebab-case is recommended for consistency across a deck library. |\n| `design` | no | `ref: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. |\n| `narrative` | no | `oneOf:string / ref:Narrative` | Structured storyline describing the deck's arc and beats. Resolves to the 'id' of a 'narratives' catalog record. Accepts two forms: - String shorthand for the common case: 'narrative = \"classic-story\"'. Accepts a bare... |\n| `slides` | yes | `array<ref:Slide>` | Ordered array of slides that make up the presentation. |\n| `assets` | no | `ref:Assets` | Optional reusable asset registry for images, data files, videos, documents, fonts, and other resources referenced elsewhere in the deck via 'asset:<id>' strings. |\n| `catalogs` | no | `ref:Catalogs` | Optional per-kind catalog overrides. Each kind may declare a non-default 'source' and/or inline 'records' that override or supplement the default catalog at https://www.pptx.gallery/<kind>. References elsewhere in the... |\n| `extensions` | no | `object` | Custom data passthrough for agent workflows; ignored by the engine but preserved across read/write round-trips. |\n\n## Object And Type Reference\n\n### Assets\n\n- Type: `object`\n- Required fields: none\n- Purpose: 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.\n\n_No named properties._\n\n\n### Asset\n\n- Type: `oneOf:string / object`\n- Required fields: none\n- Purpose: 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, mediaType, or format matters.\n\n_No named properties._\n\n\n### Audience\n\n- Type: `anyOf:schema / schema`\n- Required fields: none\n- Purpose: Inline audience metadata for the presentation. Use 'id' to reference an audiences catalog record and override selected fields, or use 'name' for a custom inline audience.\n- Conditional requirement: `id` or `name`\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | no | `string` | Optional audiences catalog id to resolve before applying inline overrides. |\n| `name` | no | `string` | Human-readable audience name shown in pickers. |\n| `summary` | no | `string` | One-sentence positioning of the audience. |\n| `description` | no | `string` | Longer prose describing the audience and how to address them. |\n| `seniority` | no | `enum:ic \\| manager \\| director \\| vp \\| c-suite \\| mixed` | Typical seniority level of the audience. |\n| `technicalFluency` | no | `enum:low \\| medium \\| high \\| mixed` | Typical technical fluency of the audience. |\n| `decisionPower` | no | `enum:informational \\| advisory \\| decision-maker` | Whether the audience is expected to be informed, advise, or decide. |\n| `attentionBudgetMinutes` | no | `number` | Realistic upper bound on focused attention for a single presentation, in minutes. |\n| `recommendedNarratives` | no | `array<string>` | Soft cross-link: narrative-catalog ids that work well for this audience. |\n| `recommendedTones` | no | `array<string>` | Soft cross-link: tone-catalog ids that work well for this audience. |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search. |\n\n\n### Purpose\n\n- Type: `anyOf:schema / schema`\n- Required fields: none\n- Purpose: Inline purpose metadata for the presentation. Use 'id' to reference a purposes catalog record and override selected fields, or use 'name' for a custom inline purpose.\n- Conditional requirement: `id` or `name`\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | no | `string` | Optional purposes catalog id to resolve before applying inline overrides. |\n| `name` | no | `string` | Human-readable purpose name shown in pickers. |\n| `summary` | no | `string` | One-sentence positioning of the purpose. |\n| `description` | no | `string` | Longer prose describing when to use this purpose and how it should shape a deck. |\n| `outcome` | no | `string` | Desired audience outcome after the presentation. |\n| `successCriteria` | no | `array<string>` | Observable signals that the deck accomplished this purpose. |\n| `recommendedNarratives` | no | `array<string>` | Soft cross-link: narrative-catalog ids that work well for this purpose. |\n| `recommendedTones` | no | `array<string>` | Soft cross-link: tone-catalog ids that work well for this purpose. |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search. |\n\n\n### Language\n\n- Type: `anyOf:schema / schema`\n- Required fields: none\n- Purpose: Inline language metadata for the presentation. Use 'id' to reference a languages catalog record and override selected fields, or use 'bcp47' for a custom language tag without a catalog record.\n- Conditional requirement: `id` or `bcp47`\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | no | `string` | Optional languages catalog id to resolve before applying inline overrides. |\n| `name` | no | `string` | Human-readable language name. |\n| `bcp47` | no | `string` | 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. |\n| `code` | no | `string` | ISO 639-3 or 639-2 language code carried for engines that prefer ISO codes. |\n| `direction` | no | `enum:ltr \\| rtl` | Base text direction for the language. |\n| `script` | no | `string` | ISO 15924 script code when the writing system should be explicit. |\n| `fontScheme` | no | `string` | Default font-scheme id for this language when targeting PowerPoint output. |\n| `googleFontScheme` | no | `string` | Default font-scheme id for this language when targeting Google Slides output. |\n| `summary` | no | `string` | One-sentence note about coverage or font defaults. |\n| `description` | no | `string` | Longer prose describing the language record and any font-pairing rationale. |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search. |\n\n\n### Tone\n\n- Type: `anyOf:schema / schema`\n- Required fields: none\n- Purpose: Inline tone metadata for the presentation. Use 'id' to reference a tones catalog record and override selected fields, or use 'name' for a custom inline tone.\n- Conditional requirement: `id` or `name`\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | no | `string` | Optional tones catalog id to resolve before applying inline overrides. |\n| `name` | no | `string` | Human-readable tone name shown in pickers. |\n| `summary` | no | `string` | One-sentence positioning of the tone. |\n| `description` | no | `string` | Longer prose describing the tone and the kinds of decks it suits. |\n| `voiceCues` | no | `array<string>` | Short directives that shape AI generation toward this tone. |\n| `avoid` | no | `array<string>` | Anti-patterns that AI generation should not produce when this tone is active. |\n| `samplePhrases` | no | `array<string>` | Short example phrases that exemplify this tone. |\n| `recommendedNarratives` | no | `array<string>` | Soft cross-link: narrative-catalog ids this tone pairs well with. |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search. |\n\n\n### Organization\n\n- Type: `object`\n- Required fields: `id`, `name`\n- Purpose: An organization associated with the presentation typically the presenting company, but also hosts, partners, clients, or sponsors. Surfaced on cover slides, footers, and brand bars; the primary organization's logo is the default deck logo unless overridden by design.logo.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | yes | `string` | Stable identifier for the organization, used to reference it from Speaker.organizationId. Must be unique within the deck. |\n| `name` | yes | `string` | Display name shown on slides. |\n| `legalName` | no | `string` | Optional legal entity name when it differs from the display name. |\n| `logo` | no | `ref:Asset` | Source for the organization's logo image. Accepts an HTTPS URL, data URI, relative path (resolved against the OPF file location), local path, or 'asset:<id>' reference. Common formats are SVG (preferred for vector log... |\n| `domain` | no | `string` | Bare internet domain for the organization. Used for footers, contact slides, and engine-driven asset lookups (e.g., favicon-based brand defaults). |\n| `email` | no | `string` | General contact email for the organization. Used on contact slides and footer attribution. |\n| `phone` | no | `string` | Main contact phone number for the organization. E.164 format is recommended. |\n| `tagline` | no | `string` | Short tagline rendered alongside the organization name on cover slides. |\n| `role` | no | `enum:primary \\| partner \\| client \\| sponsor \\| host` | Role of the organization relative to the presentation. When omitted, the single organization or first organization in array form is treated as primary. |\n| `socials` | no | `ref:Socials` | Optional social media handles or URLs for the organization. |\n\n\n### Speaker\n\n- Type: `object`\n- Required fields: `id`, `name`\n- Purpose: A person presenting the deck. Used for cover slides, bio/intro slides, footer attribution, and panel formats with multiple presenters.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | yes | `string` | Stable identifier for the speaker, used for cross-references within the deck. Must be unique within the deck. |\n| `name` | yes | `string` | Display name. |\n| `title` | no | `string` | Role or title. Often paired with the speaker's organization on cover slides. |\n| `photo` | no | `ref:Asset` | 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 appropr... |\n| `email` | no | `string` | Contact email, used on contact slides or footer attribution when appropriate. |\n| `phone` | no | `string` | Contact phone number for the speaker. E.164 format is recommended. |\n| `bio` | no | `string` | Short biographical paragraph for bio or 'about the speaker' slides. |\n| `organizationId` | no | `string` | Reference to an Organization.id in organization. Lets a speaker be attributed to their org in panel or multi-org decks without repeating organization details. |\n| `socials` | no | `ref:Socials` | Optional social media handles or URLs for the speaker. |\n\n\n### Socials\n\n- Type: `object`\n- Required fields: none\n- Purpose: Social media handles or URLs, keyed by platform id from the 'socialPlatforms' catalog. Each value is a string either a full URL or a platform handle (e.g., '@acme'). The catalog record for each platform carries the URL pattern, handle prefix, brand color, and themed icons used by renderers. Keys resolve to the 'id' of a 'socialPlatforms' catalog record. Resolution order: inline catalogs.socialPlatforms.records[] catalogs.socialPlatforms.source default catalog at https://www.pptx.gallery/socia...\n\n_No named properties._\n\n\n### Narrative\n\n- Type: `object`\n- Required fields: none\n- Purpose: Structured storyline used by AI to shape generated content. Mirrors the OPF Narrative Template record at https://openpresentation.org/schema/opf-narrative/v1 (sans '$schema'), so a library record and an inline narrative are interchangeable. Narrative declares the deck's intended story arc; slides may opt into beats via Slide.beat. The narrative does not constrain slide structure validators warn on drift (orphan slides, unused beats) but never error. Slides are the source of truth; narrative i...\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | no | `string` | Stable slug identifying this narrative. When it matches a record in the resolved 'narratives' catalog, the catalog record's beats and metadata seed this narrative; inline fields override per-key. When it doesn't match... |\n| `name` | no | `string` | Human-readable narrative name. |\n| `summary` | no | `string` | One-sentence description of when and why to use this narrative. |\n| `description` | no | `string` | Longer prose describing the narrative arc and ideal use cases. Used by AI-driven generation to seed deck-level direction. |\n| `audienceFit` | no | `array<string>` | Audiences this narrative works well for. Free-form strings or 'audiences' catalog ids. |\n| `durationRange` | no | `object` | Typical talk-length window this narrative suits. Compared by validators against duration. |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search. |\n| `preview` | no | `object` | Visual previews of the narrative, used by picker UIs and inline rendering. All sub-fields are optional. |\n| `beats` | no | `array<ref:NarrativeBeat>` | Ordered list of beats that make up the narrative arc. When 'id' matches a catalog record, beats here override or extend matching catalog beats by their own 'id'. Beat IDs must be unique within the narrative. |\n\n\n### NarrativeBeat\n\n- Type: `object`\n- Required fields: `id`, `name`\n- Purpose: A single narrative beat a labeled segment of the story arc with a specific dramatic purpose (e.g. 'hook', 'problem', 'evidence', 'ask'). Slides reference beats via Slide.beat. Beats may also carry slide-blueprint hints (slideType, layoutHint, thoughtCues, instructions) that guide the assigned slide. Mirrors the Beat definition in narrative.schema.json (https://openpresentation.org/schema/opf-narrative/v1) so library entries and inline OPF beats are interchangeable.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | yes | `string` | Stable slug used by Slide.beat to reference this beat. Lowercase kebab-case. |\n| `name` | yes | `string` | Human-readable beat name. |\n| `description` | no | `string` | Curator-written prose that explains what this beat should accomplish. |\n| `instructions` | no | `string` | Short author-facing instruction for the beat typically one phrase. Complements 'description' with a concise directive. |\n| `slideCount` | no | `integer` | Optional explicit slide count for this beat. Defaults to 1 when omitted; values >1 are reserved for beats that intentionally span multiple slides. Prefer decomposing a heavy beat into multiple beats over setting a hig... |\n| `slideType` | no | `enum:text \\| list \\| image \\| chart \\| table \\| video \\| code \\| metric \\| quote \\| timeline` | Default content kind for the beat's slide. Mirrors ContentPayload.type and helps engines choose a sensible layout when only the beat is specified. |\n| `layoutHint` | no | `string` | Suggested layout id for the beat's opening slide. Resolves the same way as Slide.layout against catalogs.layouts and the default catalog at https://www.pptx.gallery/layouts. |\n| `thoughtCues` | no | `array<string>` | Optional speaker or thinking cues attached to the beat. Surfaced in presenter notes. |\n\n\n### Design\n\n- Type: `object`\n- Required fields: none\n- Purpose: Visual design system applied to the presentation; individual slides may override fields via Slide.design.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `theme` | no | `oneOf:string / ref:Theme` | Theme for the deck. Accepts two forms: - String shorthand: 'design.theme = \"minimal\"'. Bare id, HTTPS URL, or 'pkg:' reference resolved as the 'id' of a 'themes' catalog record. - Object form: a Theme with an optional... |\n| `colorScheme` | no | `oneOf:string / ref:ColorScheme` | Color scheme for the presentation. Accepts two forms: - String shorthand: 'design.colorScheme = \"cool-horizon\"'. Bare id, HTTPS URL, or 'pkg:' reference resolved as the 'id' of a 'colorSchemes' catalog record. - Objec... |\n| `fontScheme` | no | `oneOf:string / ref:FontScheme` | Font scheme for heading, body, accent, and code text. Accepts two forms: - String shorthand: 'design.fontScheme = \"aptos\"'. Bare id, HTTPS URL, or 'pkg:' reference resolved as the 'id' of a 'fontSchemes' catalog recor... |\n| `dimensions` | no | `oneOf:ref:DimensionPreset / ref:Dimensions` | Slide dimensions and aspect ratio. String shorthand such as 'widescreen' is equivalent to { preset: 'widescreen' }. |\n| `background` | no | `oneOf:ref:BackgroundShortcut / ref:Background` | Default slide background applied across the deck unless overridden on a slide. String shorthand accepts theme slots ('light1', 'light2', 'dark1', 'dark2') or hex colors; object forms support theme, solid, gradient, im... |\n| `logo` | no | `oneOf:ref:Asset / ref:LogoSet` | Deck logo assets used by layouts, covers, section dividers, headers, and footers. A string is the default logo source; object form provides light/dark, stacked, icon, and wordmark variants. When omitted, the renderer... |\n| `watermark` | no | `oneOf:const:false / ref:Asset / ref:Watermark` | Optional decorative watermark applied across slides. Use false to suppress an inherited watermark in slide-level design; a string is equivalent to { src: value }. |\n| `header` | no | `oneOf:const:false / ref:HeaderFooter` | Repeated header furniture rendered outside the main slide content. Use false to suppress an inherited header. |\n| `footer` | no | `oneOf:const:false / ref:HeaderFooter` | Repeated footer furniture rendered outside the main slide content. Use false to suppress an inherited footer. |\n| `titleAlignment` | no | `enum:left \\| center \\| right` | Default horizontal alignment for title placeholders in resolved layouts. |\n| `contentAlignment` | no | `enum:left \\| center \\| right` | Default horizontal alignment for body/content regions in resolved layouts. |\n| `contentBox` | no | `boolean` | Whether body/content regions are rendered inside a visible card or surface. |\n| `slideImage` | no | `oneOf:ref:Asset / object` | Optional slide-level image treatment used by layouts that support a decorative or editorial image separate from content images. |\n| `contentDirection` | no | `enum:horizontal \\| vertical` | Axis along which parallel body/content regions are arranged. |\n| `chartPrimary` | no | `enum:none \\| top \\| bottom \\| left \\| right` | For chart layouts, where the primary chart sits relative to supporting content. 'none' means chart regions have equal weight. |\n| `imageFill` | no | `enum:crop \\| fit` | How picture placeholders fill their allocated region. |\n| `listBullet` | no | `enum:character \\| image` | Default bullet rendering style for list layouts. |\n\n\n### Theme\n\n- Type: `object`\n- Required fields: none\n- Purpose: Theme bundle used by the design system. In design.theme, 'id' resolves a themes catalog record as the base; any sibling fields override the resolved theme. The string shorthand on design.theme is equivalent to setting only 'id'.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | no | `string` | Theme reference. Resolves to the 'id' of a 'themes' catalog record. Accepts a bare id (lowercase kebab-case, e.g. 'minimal'), an HTTPS URL pointing at a record file, or a 'pkg:' reference. Field overrides on the surro... |\n| `name` | no | `string` | Human-readable theme name shown in pickers. |\n| `summary` | no | `string` | One-sentence positioning of the theme - when to reach for it. |\n| `description` | no | `string` | Longer prose describing what the theme looks and feels like and the kinds of decks it suits. |\n| `colorScheme` | no | `oneOf:string / ref:ColorScheme` | Default color scheme for this theme. A string resolves against catalogs.colorSchemes; an object may provide an 'id' base reference plus overrides. |\n| `fontScheme` | no | `oneOf:string / ref:FontScheme` | Default font scheme for this theme. A string resolves against catalogs.fontSchemes; an object may provide an 'id' base reference plus overrides. |\n| `background` | no | `oneOf:ref:BackgroundShortcut / ref:Background` | Default background for this theme. String shorthand accepts theme slots ('light1', 'light2', 'dark1', 'dark2') or hex colors. |\n| `dimensions` | no | `oneOf:ref:DimensionPreset / ref:Dimensions` | Default slide size for this theme. A string preset is equivalent to { preset: value }. |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search. |\n\n\n### ColorScheme\n\n- Type: `object`\n- Required fields: none\n- Purpose: Color palette used by the design system. 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. Two parallel models are supported and may be mixed: - OOXML slots - the 12-slot PowerPoint theme model that round-trips directly to OOXML. Use these for full control over the palette as Power...\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | no | `string` | Color scheme reference. Resolves to the 'id' of a 'colorSchemes' catalog record. Accepts a bare id (lowercase kebab-case, e.g. 'cool-horizon'), an HTTPS URL pointing at a record file, or a 'pkg:' reference. Slot and r... |\n| `accent1` | no | `string` | Accent 1 color (hex). Mirrors the OOXML accent1 slot. |\n| `accent2` | no | `string` | Accent 2 color (hex). Mirrors the OOXML accent2 slot. |\n| `accent3` | no | `string` | Accent 3 color (hex). Mirrors the OOXML accent3 slot. |\n| `accent4` | no | `string` | Accent 4 color (hex). Mirrors the OOXML accent4 slot. |\n| `accent5` | no | `string` | Accent 5 color (hex). Mirrors the OOXML accent5 slot. |\n| `accent6` | no | `string` | Accent 6 color (hex). Mirrors the OOXML accent6 slot. |\n| `dark1` | no | `string` | Dark 1 color (hex). Typically the deepest neutral; OOXML dark1. |\n| `dark2` | no | `string` | Dark 2 color (hex). Secondary dark; OOXML dark2. |\n| `light1` | no | `string` | Light 1 color (hex). Typically the slide canvas; OOXML lt1. |\n| `light2` | no | `string` | Light 2 color (hex). Secondary light surface; OOXML lt2. |\n| `hyperlink` | no | `string` | Hyperlink color (hex). OOXML hlink. |\n| `followedHyperlink` | no | `string` | Followed-hyperlink color (hex). OOXML folHlink. |\n| `primary` | no | `string` | Abstract role: primary brand color (hex). The engine maps this onto an OOXML accent slot when serializing. |\n| `secondary` | no | `string` | Abstract role: secondary brand color (hex). |\n| `accent` | no | `string` | Abstract role: accent color used for highlights and emphasis (hex). |\n| `background` | no | `string` | Abstract role: default slide background color (hex). The engine maps this to one of light1 / light2 / dark1 / dark2 when serializing. |\n| `surface` | no | `string` | Abstract role: color for elevated surfaces such as cards and panels (hex). |\n| `text` | no | `string` | Abstract role: primary body text color (hex). |\n| `textSecondary` | no | `string` | Abstract role: secondary or muted text color used for captions and supporting copy (hex). |\n| `custom` | no | `object` | Map of custom named colors for advanced or theme-specific use. |\n\n\n### FontScheme\n\n- Type: `object`\n- Required fields: none\n- Purpose: 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. Two parallel models are supported and may be mixed: - OOXML pairs (major, minor) - heading and body family names that round-trip directly to PowerPoint majorFont/minorFont entries. - Abstract roles...\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | no | `string` | Font scheme reference. Resolves to the 'id' of a 'fontSchemes' catalog record. Accepts a bare id (lowercase kebab-case, e.g. 'aptos'), an HTTPS URL pointing at a record file, or a 'pkg:' reference. Field overrides on... |\n| `major` | no | `string` | Heading (major) font family mirrors the OOXML majorFont entry. Pairs with 'minor'. |\n| `minor` | no | `string` | Body (minor) font family mirrors the OOXML minorFont entry. Pairs with 'major'. |\n| `type` | no | `enum:sans-serif \\| serif \\| monospace` | High-level typographic class of the scheme. |\n| `app` | no | `enum:PowerPoint \\| Google Slides` | Target application this font pairing is intended for. |\n| `languageFamily` | no | `enum:latin \\| ea \\| cs` | OOXML font-language family this scheme is intended for: 'latin' for Latin-script content, 'ea' for East Asian scripts, 'cs' for Complex Scripts. |\n| `heading` | no | `ref:Font` | Abstract role: font used for slide titles and headings. Maps onto the OOXML major slot when serializing. |\n| `body` | no | `ref:Font` | Abstract role: font used for body copy. Maps onto the OOXML minor slot when serializing. |\n| `accent` | no | `ref:Font` | Abstract role: font used for accent text such as quotes or callouts. No direct OOXML slot. |\n| `code` | no | `ref:Font` | Abstract role: monospaced font used for code blocks. No direct OOXML slot. |\n\n\n### Font\n\n- Type: `object`\n- Required fields: `family`\n- Purpose: Specification for a single font role.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `family` | yes | `string` | Font family name. |\n| `weight` | no | `number` | Numeric font weight (e.g., 400 for regular, 700 for bold). |\n| `style` | no | `enum:normal \\| italic` | Font style. |\n| `letterSpacing` | no | `number` | Letter spacing (tracking) in ems. |\n\n\n### DimensionPreset\n\n- Type: `enum:16:9 | 4:3 | 16:10 | letter | a4 | widescreen | standard`\n- Required fields: none\n- Purpose: Named dimension preset; chooses both aspect ratio and physical size. 'widescreen' is an alias for 16:9 in PowerPoint widescreen size; 'standard' is an alias for 4:3 in PowerPoint standard size.\n\n_No named properties._\n\n\n### Dimensions\n\n- Type: `object`\n- Required fields: none\n- Purpose: Slide dimensions; either pick a preset or specify custom inches.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `preset` | no | `ref:DimensionPreset` | |\n| `widthInches` | no | `number` | Custom slide width in inches; overrides the preset width when provided. |\n| `heightInches` | no | `number` | Custom slide height in inches; overrides the preset height when provided. |\n\n\n### ThemeBackgroundSlot\n\n- Type: `enum:light1 | light2 | dark1 | dark2`\n- Required fields: none\n- Purpose: 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.\n\n_No named properties._\n\n\n### HexColor\n\n- Type: `string`\n- Required fields: none\n- Purpose: Hex color shorthand accepted by selected string fields.\n\n_No named properties._\n\n\n### BackgroundShortcut\n\n- Type: `oneOf:ref:ThemeBackgroundSlot / ref:HexColor`\n- Required fields: none\n- Purpose: 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 }.\n\n_No named properties._\n\n\n### Background\n\n- Type: `oneOf:ref:ThemeBackground / ref:SolidBackground / ref:GradientBackground / ref:ImageBackground / ref:PatternBackground`\n- Required fields: none\n- Purpose: Background fill applied to slides. Theme backgrounds preserve PowerPoint's color-scheme background choice; other variants represent fixed background fills.\n\n_No named properties._\n\n\n### ThemeBackground\n\n- Type: `object`\n- Required fields: `type`, `slot`\n- Purpose: Theme-controlled PowerPoint slide background. The slot is resolved through the active color scheme and remains theme-aware.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `type` | yes | `const:\"theme\"` | Theme-controlled background fill. |\n| `slot` | yes | `ref:ThemeBackgroundSlot` | |\n\n\n### SolidBackground\n\n- Type: `object`\n- Required fields: `type`, `color`\n- Purpose: Fixed solid slide background fill.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `type` | yes | `const:\"solid\"` | Fixed solid background fill. |\n| `color` | yes | `string` | Fixed solid fill color, usually a hex string. Use { type: 'theme', slot: ... } for PowerPoint's four theme-controlled background choices. |\n| `opacity` | no | `number` | Background opacity from 0 (fully transparent) to 1 (fully opaque). |\n\n\n### GradientBackground\n\n- Type: `object`\n- Required fields: `type`, `gradient`\n- Purpose: Fixed gradient slide background fill.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `type` | yes | `const:\"gradient\"` | Fixed gradient background fill. |\n| `gradient` | yes | `object` | Gradient fill definition. |\n| `opacity` | no | `number` | Background opacity from 0 (fully transparent) to 1 (fully opaque). |\n\n\n### ImageBackground\n\n- Type: `object`\n- Required fields: `type`, `image`\n- Purpose: Fixed image slide background fill.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `type` | yes | `const:\"image\"` | Fixed image background fill. |\n| `image` | yes | `object` | Image fill definition. |\n| `opacity` | no | `number` | Background opacity from 0 (fully transparent) to 1 (fully opaque). |\n\n\n### PatternBackground\n\n- Type: `object`\n- Required fields: `type`, `pattern`\n- Purpose: Fixed pattern slide background fill.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `type` | yes | `const:\"pattern\"` | Fixed pattern background fill. |\n| `pattern` | yes | `object` | Pattern fill definition. |\n| `opacity` | no | `number` | Background opacity from 0 (fully transparent) to 1 (fully opaque). |\n\n\n### LogoSet\n\n- Type: `object`\n- Required fields: none\n- Purpose: Deck logo variants surfaced by layouts, covers, section dividers, headers, and footers. Organization identity lives in organization; this object only controls visual rendering assets. Renderer convention: on dark backgrounds prefer the 'light' variant, on light backgrounds prefer the 'dark' variant, and in square/vertical slots prefer the stacked family when present.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `default` | no | `ref:Asset` | Default full-lockup logo. Used as fallback when no more specific variant is set. |\n| `light` | no | `ref:Asset` | Light-colored full-lockup logo intended for rendering on dark backgrounds. |\n| `dark` | no | `ref:Asset` | Dark-colored full-lockup logo intended for rendering on light backgrounds. |\n| `stacked` | no | `ref:Asset` | Stacked vertical logo lockup, suited to portrait or square brand-mark slots. |\n| `stackedLight` | no | `ref:Asset` | Light-colored stacked logo variant intended for rendering on dark backgrounds. |\n| `stackedDark` | no | `ref:Asset` | Dark-colored stacked logo variant intended for rendering on light backgrounds. |\n| `icon` | no | `ref:Asset` | Default icon, mark, or symbol without wordmark. Useful for tight spaces such as footers, badges, and slide-corner marks. |\n| `iconLight` | no | `ref:Asset` | Light-colored icon variant intended for rendering on dark backgrounds. |\n| `iconDark` | no | `ref:Asset` | Dark-colored icon variant intended for rendering on light backgrounds. |\n| `wordmark` | no | `ref:Asset` | Default wordmark: the organization name set in branded typography, without icon. |\n| `wordmarkLight` | no | `ref:Asset` | Light-colored wordmark variant intended for rendering on dark backgrounds. |\n| `wordmarkDark` | no | `ref:Asset` | Dark-colored wordmark variant intended for rendering on light backgrounds. |\n\n\n### Watermark\n\n- Type: `object`\n- Required fields: `opacity`\n- Purpose: Decorative watermark image and rendering options. Use design.watermark = false to disable an inherited watermark.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `src` | no | `string` | Source for the watermark image. |\n| `opacity` | yes | `number` | Watermark opacity from 0 (fully transparent) to 1 (fully opaque). |\n\n\n### HeaderFooter\n\n- Type: `object`\n- Required fields: none\n- Purpose: 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.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `left` | no | `ref:HeaderFooterItem` | Left-aligned header/footer content. |\n| `center` | no | `ref:HeaderFooterItem` | Centered header/footer content. |\n| `right` | no | `ref:HeaderFooterItem` | Right-aligned header/footer content. |\n\n\n### HeaderFooterItem\n\n- Type: `object`\n- Required fields: none\n- Purpose: One header/footer zone. Fields may be combined when the renderer supports it; otherwise renderers should prefer image, then text-like generated content.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `text` | no | `string` | Literal text rendered in this zone. |\n| `image` | no | `ref:Asset` | Generic image rendered in this zone, such as a logo, partner mark, certification badge, or icon. |\n| `slideNumber` | no | `boolean` | Whether to render the current slide number in this zone. |\n| `date` | no | `oneOf:boolean / string` | Whether to render the presentation date, or a literal date string to render. |\n| `organization` | no | `boolean` | Whether to render the primary organization name from organization. |\n| `section` | no | `boolean` | Whether to render the current slide section label. |\n\n\n### Slide\n\n- Type: `object`\n- Required fields: none\n- Purpose: 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'.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | no | `string` | 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 s... |\n| `type` | no | `enum:text \\| list \\| image \\| chart \\| table \\| video \\| code \\| metric \\| quote \\| timeline` | Optional full-slide content kind. When omitted, engines infer the kind from root payload fields. |\n| `beat` | no | `oneOf:string / array<string>` | Optional reference to one or more narrative beats (each value matches an id from narrative.beats or the resolved template). A single string declares the slide's primary beat; an array declares that one slide covers mu... |\n| `layout` | no | `string` | Optional slide layout reference. Resolves to the 'id' of a 'layouts' catalog record. When omitted, engines infer a layout from the slide's root payload or promoted region keys. Accepts a bare id (lowercase kebab-case,... |\n| `title` | no | `string` | Slide-level title content. When the resolved layout exposes a 'title' placeholder, the engine renders this value there. |\n| `subtitle` | no | `string` | Slide-level subtitle or supporting line. When the resolved layout exposes a 'subtitle' placeholder, the engine renders this value there. |\n| `tag` | no | `string` | Small slide-level label or badge. When the resolved layout exposes a 'tag' placeholder, the engine renders this value there. |\n| `text` | no | `oneOf:string / array<ref:TextRun>` | 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. |\n| `items` | no | `array<ref:ListItem>` | Full-slide generic list payload. Presence of this field infers type 'list'. At slide root, multiple content payload kinds with no explicit type, blocks, or regions are accepted as shorthand for layout-agnostic blocks. |\n| `bullets` | no | `array<ref:BulletItem>` | Full-slide text-style bullet payload. Presence of this field infers type 'text'. |\n| `image` | no | `ref:Asset` | Full-slide image source. Presence of this field infers type 'image'. |\n| `video` | no | `ref:Asset` | Full-slide video source. Presence of this field infers type 'video'. |\n| `chart` | no | `ref:Chart` | Full-slide chart payload. Presence of this field infers type 'chart'. |\n| `table` | no | `ref:Table` | Full-slide table payload. Presence of this field infers type 'table'. |\n| `code` | no | `oneOf:string / ref:Code` | Full-slide code payload. A string is shorthand for { \"source\": value }; object form carries optional syntax language and filename metadata. |\n| `metric` | no | `oneOf:string / number / ref:Metric` | Full-slide metric payload. A string or number is shorthand for { \"value\": value }; object form carries optional label, description, unit, delta, and trend metadata. Numeric values remain numbers; renderers format them... |\n| `quote` | no | `oneOf:string / ref:Quote` | 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'. |\n| `timeline` | no | `ref:Timeline` | 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'. |\n| `blocks` | no | `array<ref:ContentPayload>` | 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 short... |\n| `design` | no | `ref:Design` | Slide-level design applied on top of the deck-wide design. |\n| `left` | no | `ref:ContentPayload` | |\n| `center` | no | `ref:ContentPayload` | |\n| `right` | no | `ref:ContentPayload` | |\n| `left+center` | no | `ref:ContentPayload` | |\n| `center+right` | no | `ref:ContentPayload` | |\n| `left+center+right` | no | `ref:ContentPayload` | |\n| `top` | no | `ref:ContentPayload` | |\n| `middle` | no | `ref:ContentPayload` | |\n| `bottom` | no | `ref:ContentPayload` | |\n| `top+middle` | no | `ref:ContentPayload` | |\n| `middle+bottom` | no | `ref:ContentPayload` | |\n| `top+middle+bottom` | no | `ref:ContentPayload` | |\n| `top:left` | no | `ref:ContentPayload` | |\n| `top:center` | no | `ref:ContentPayload` | |\n| `top:right` | no | `ref:ContentPayload` | |\n| `top:left+center` | no | `ref:ContentPayload` | |\n| `top:center+right` | no | `ref:ContentPayload` | |\n| `top:left+center+right` | no | `ref:ContentPayload` | |\n| `middle:left` | no | `ref:ContentPayload` | |\n| `middle:center` | no | `ref:ContentPayload` | |\n| `middle:right` | no | `ref:ContentPayload` | |\n| `middle:left+center` | no | `ref:ContentPayload` | |\n| `middle:center+right` | no | `ref:ContentPayload` | |\n| `middle:left+center+right` | no | `ref:ContentPayload` | |\n| `bottom:left` | no | `ref:ContentPayload` | |\n| `bottom:center` | no | `ref:ContentPayload` | |\n| `bottom:right` | no | `ref:ContentPayload` | |\n| `bottom:left+center` | no | `ref:ContentPayload` | |\n| `bottom:center+right` | no | `ref:ContentPayload` | |\n| `bottom:left+center+right` | no | `ref:ContentPayload` | |\n| `top+middle:left` | no | `ref:ContentPayload` | |\n| `top+middle:center` | no | `ref:ContentPayload` | |\n| `top+middle:right` | no | `ref:ContentPayload` | |\n| `top+middle:left+center` | no | `ref:ContentPayload` | |\n| `top+middle:center+right` | no | `ref:ContentPayload` | |\n| `top+middle:left+center+right` | no | `ref:ContentPayload` | |\n| `middle+bottom:left` | no | `ref:ContentPayload` | |\n| `middle+bottom:center` | no | `ref:ContentPayload` | |\n| `middle+bottom:right` | no | `ref:ContentPayload` | |\n| `middle+bottom:left+center` | no | `ref:ContentPayload` | |\n| `middle+bottom:center+right` | no | `ref:ContentPayload` | |\n| `middle+bottom:left+center+right` | no | `ref:ContentPayload` | |\n| `top+middle+bottom:left` | no | `ref:ContentPayload` | |\n| `top+middle+bottom:center` | no | `ref:ContentPayload` | |\n| `top+middle+bottom:right` | no | `ref:ContentPayload` | |\n| `top+middle+bottom:left+center` | no | `ref:ContentPayload` | |\n| `top+middle+bottom:center+right` | no | `ref:ContentPayload` | |\n| `top+middle+bottom:left+center+right` | no | `ref:ContentPayload` | |\n| `notes` | no | `string` | Speaker notes shown in presenter view. |\n| `section` | no | `string` | 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. |\n| `hidden` | no | `boolean` | Whether the slide is hidden from the presented sequence. |\n| `composition` | no | `ref:Composition` | |\n\n\n### ContentPayload\n\n- Type: `allOf:schema + schema + schema + schema + schema + schema + schema + schema + schema + schema + schema + schema`\n- Required fields: none\n- Purpose: 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.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `type` | no | `enum:text \\| list \\| image \\| chart \\| table \\| video \\| code \\| metric \\| quote \\| timeline \\| group` | Optional content kind. When omitted, engines infer the kind from the fields present. |\n| `text` | no | `oneOf:string / array<ref:TextRun>` | Text payload. Use a string for plain text or TextRun[] for inline rich text. TextRun items may be plain strings or formatted run objects. |\n| `items` | no | `array<ref:ListItem>` | Generic list payload. Each item is either a plain string, a TextRun[] rich text sequence, or a ListItem object. List nesting uses item.level rather than nested content payloads. |\n| `bullets` | no | `array<ref:BulletItem>` | Text-style bullet payload. Presence of this field infers type 'text'. |\n| `image` | no | `ref:Asset` | Source for an image item. |\n| `video` | no | `ref:Asset` | Source for a video item. |\n| `chart` | no | `ref:Chart` | Chart payload. Presence of this field infers type 'chart'. |\n| `table` | no | `ref:Table` | Table payload. Presence of this field infers type 'table'. |\n| `code` | no | `oneOf:string / ref:Code` | Code payload. A string is shorthand for { \"source\": value }; object form carries optional syntax language and filename metadata. |\n| `metric` | no | `oneOf:string / number / ref:Metric` | Metric payload. A string or number is shorthand for { \"value\": value }; object form carries optional label, description, unit, delta, and trend metadata. Numeric values remain numbers; renderers format them for display. |\n| `quote` | no | `oneOf:string / ref:Quote` | Quote payload. A string is shorthand for { \"text\": value }; object form carries optional attribution and source metadata. |\n| `timeline` | no | `ref:Timeline` | Timeline payload ordered by narrative or chronology. |\n| `blocks` | no | `array<ref:ContentPayload>` | Ordered children of a group. Each child is a leaf or another group. |\n| `composition` | no | `ref:Composition` | Arrangement within this group. Only minFontSize and overflow inherit from the parent; strict overflow cannot be weakened. |\n\n\n### Quote\n\n- Type: `object`\n- Required fields: `text`\n- Purpose: Quote content with optional attribution metadata. Use 'text' for the quoted text, 'attribution' for the credited person or organization, and 'source' for a citation or URL. A string value in a quote field is shorthand for { \"text\": value }.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `text` | yes | `string` | Quoted text. |\n| `attribution` | no | `string` | Person or organization credited for the quote. |\n| `source` | no | `string` | Optional quote source, citation, or URL. |\n\n\n### Code\n\n- Type: `object`\n- Required fields: `source`\n- Purpose: Code content with optional rendering metadata. Use 'source' for the code text, 'language' for syntax highlighting, and 'filename' when the rendered block should show a file label. A string value in a code field is shorthand for { \"source\": value }.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `source` | yes | `string` | Source code text to display. |\n| `language` | no | `string` | Language identifier used for syntax highlighting. |\n| `filename` | no | `string` | Optional file label shown with the code block. |\n\n\n### Metric\n\n- Type: `object`\n- Required fields: `value`\n- Purpose: 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, and 'trend' for direction. A string or number value in a metric field is shorthand for { \"value\": value }; numeric values remain numbers and are formatted by renderers.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `value` | yes | `oneOf:string / number` | Primary metric value. |\n| `label` | no | `string` | Metric label. |\n| `description` | no | `string` | Optional supporting context for the metric. |\n| `unit` | no | `string` | Metric unit, suffix, or currency marker. |\n| `delta` | no | `oneOf:string / number` | Metric change value. |\n| `trend` | no | `enum:up \\| down \\| flat` | Metric trend direction. |\n\n\n### Timeline\n\n- Type: `oneOf:array<ref:TimelineEvent> / object`\n- Required fields: none\n- Purpose: Timeline content. An array is shorthand for { \"events\": value }; object form carries optional name and description metadata.\n\n_No named properties._\n\n\n### TimelineEvent\n\n- Type: `object`\n- Required fields: `what`\n- Purpose: A single event inside a timeline content payload.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `when` | no | `string` | Event time, date, or sequence label. Use ISO-like values when possible, but human labels are allowed for quarters, eras, and relative milestones. |\n| `what` | yes | `string` | Short event label. |\n| `description` | no | `string` | Optional event detail. |\n\n\n### ListItem\n\n- Type: `oneOf:string / array<ref:TextRun> / object`\n- Required fields: none\n- Purpose: 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.\n\n_No named properties._\n\n\n### BulletItem\n\n- Type: `oneOf:string / array<ref:TextRun> / object`\n- Required fields: none\n- Purpose: 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.\n\n_No named properties._\n\n\n### TextRun\n\n- Type: `oneOf:string / object`\n- Required fields: none\n- Purpose: A contiguous run of text. Strings cover unformatted spans; object form adds character formatting.\n\n_No named properties._\n\n\n### Chart\n\n- Type: `object`\n- Required fields: `type`, `data`\n- Purpose: Chart content. The chart object keeps chart-specific fields together so slides and regions do not expose loose chart fields.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `type` | yes | `string` | Chart type id. Resolves to the id of a chartTypes catalog record; renderers map that record through mappings.openxml and any renderer-specific mapping they understand. |\n| `data` | yes | `oneOf:ref:ChartData / ref:ChartDataSource` | Chart data. Inline data uses a tabular columns/rows shape; renderers convert rows to chart series internally. |\n\n\n### Table\n\n- Type: `object`\n- Required fields: `rows`\n- Purpose: Table content. Columns are optional; rows are the only required field.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `columns` | no | `array<oneOf:string / array<ref:TextRun> / ref:StyledTableCell / null>` | Optional column labels. Labels may be strings, rich runs or styled cell objects. Null is an empty label or a placeholder covered by a preceding column span. |\n| `rows` | yes | `array<array<ref:TableCell>>` | Two-dimensional table row data; each row aligns by index with columns when columns are supplied. |\n\n\n### ChartData\n\n- Type: `object`\n- Required fields: `columns`, `rows`\n- Purpose: Inline tabular data driving a chart. The first column usually supplies category/x-axis labels; subsequent columns are plotted measures unless a chart type or renderer maps them differently.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `columns` | yes | `array<string>` | Ordered column labels for the chart data table. |\n| `rows` | yes | `array<array<ref:ChartDataCell>>` | Tabular chart rows. Each row aligns by index with columns. |\n\n\n### ChartDataSource\n\n- Type: `object`\n- Required fields: `src`\n- Purpose: Chart data sourced from an asset reference, URL, data URI, relative path, or local path such as CSV, TSV, JSON, or XLSX. The source is interpreted as a table; optional columns select or order fields from that table.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `src` | yes | `string` | Data source. Use 'asset:<id>' to reference the top-level assets registry, or provide an HTTPS URL, data URI, relative path, or local filesystem path. |\n| `sheet` | no | `string` | Optional sheet name or table name for spreadsheet-like assets. |\n| `range` | no | `string` | Optional A1-style range or engine-defined range selector for spreadsheet-like assets. |\n| `columns` | no | `array<string>` | Optional ordered columns or fields to read from the source. When omitted, renderers may use the source's own header row or schema. |\n\n\n### ChartDataCell\n\n- Type: `oneOf:string / number / boolean / null`\n- Required fields: none\n- Purpose: A cell in inline chart data.\n\n_No named properties._\n\n\n### TableCell\n\n- Type: `oneOf:ref:TableCellValue / ref:StyledTableCell`\n- Required fields: none\n- Purpose: A scalar, rich-run array, or styled/spanning cell object. Existing scalar and rich forms remain valid.\n\n_No named properties._\n\n\n### TableCellValue\n\n- Type: `oneOf:string / number / boolean / null / array<ref:TextRun>`\n- Required fields: none\n- Purpose: A scalar table value or canonical rich text runs, without cell decoration or geometry.\n\n_No named properties._\n\n\n### StyledTableCell\n\n- Type: `object`\n- Required fields: `value`\n- Purpose: A cell with explicit visual style or merged geometry. Its position remains its array column index; use null placeholders for every covered grid position.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `value` | yes | `ref:TableCellValue` | Editable cell content; styling and spans do not change its scalar type or rich runs. |\n| `style` | no | `ref:TableCellStyle` | |\n| `colSpan` | no | `integer` | Number of grid columns covered, starting at this cell. Covered positions must contain null. Default 1. |\n| `rowSpan` | no | `integer` | Number of grid rows covered, starting at this cell. Covered positions must contain null. Header cells cannot span into body rows. Default 1. |\n\n\n### TableCellStyle\n\n- Type: `object`\n- Required fields: none\n- Purpose: Cell appearance. Sizes use reference pixels at a 720-pixel canvas short edge and scale with the slide.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `fill` | no | `string` | Explicit RGB or RGBA color. Eight-digit colors include alpha; #00000000 is transparent. |\n| `color` | no | `string` | Default text color, overridden by individual rich run colors. |\n| `align` | no | `enum:left \\| center \\| right` | Horizontal text alignment inside the cell. |\n| `verticalAlign` | no | `enum:top \\| middle \\| bottom` | Vertical alignment inside the padded cell box. |\n| `padding` | no | `ref:TableCellPadding` | |\n| `borders` | no | `object` | Independent cell edges. Omitted edges retain the table theme border; width 0 removes an edge. |\n\n\n### TableCellPadding\n\n- Type: `object`\n- Required fields: none\n- Purpose: Text insets in reference pixels. Defaults: top 8, right 10, bottom 4, left 10.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `top` | no | `number` | |\n| `right` | no | `number` | |\n| `bottom` | no | `number` | |\n| `left` | no | `number` | |\n\n\n### TableCellBorder\n\n- Type: `object`\n- Required fields: `color`, `width`\n- Purpose: One explicit cell border.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `color` | yes | `string` | Explicit RGB or RGBA color. Eight-digit colors include alpha; #00000000 is transparent. |\n| `width` | yes | `number` | Border width in reference pixels; 0 removes this edge. |\n| `dash` | no | `enum:solid \\| dash \\| dot` | Default solid. |\n\n\n### Catalogs\n\n- Type: `object`\n- Required fields: none\n- Purpose: Catalog overrides for the in-document references. Every property is optional. The default catalog for a kind lives at https://www.pptx.gallery/<kind> (e.g. https://www.pptx.gallery/narratives, https://www.pptx.gallery/themes). For each kind, declaring a 'source' replaces the default registry and/or 'records' adds inline records that take precedence over anything fetched from a source. Resolution order for any reference (e.g. narrative, design.theme): inline catalogs.<kind>.records[] catalogs....\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `narratives` | no | `ref:CatalogEntry` | Catalog of narrative templates. Records validate against https://openpresentation.org/schema/opf-narrative/v1. Default source: https://www.pptx.gallery/narratives. |\n| `themes` | no | `ref:CatalogEntry` | Catalog of themes. Records validate against https://openpresentation.org/schema/opf-theme/v1. Default source: https://www.pptx.gallery/themes. |\n| `colorSchemes` | no | `ref:CatalogEntry` | Catalog of color schemes. Records validate against https://openpresentation.org/schema/opf-color-scheme/v1. Default source: https://www.pptx.gallery/color-schemes. |\n| `fontSchemes` | no | `ref:CatalogEntry` | Catalog of font schemes. Records validate against https://openpresentation.org/schema/opf-font-scheme/v1. Default source: https://www.pptx.gallery/font-schemes. |\n| `languages` | no | `ref:CatalogEntry` | Catalog of languages. Records validate against https://openpresentation.org/schema/opf-language/v1. Default source: https://www.pptx.gallery/languages. |\n| `layouts` | no | `ref:CatalogEntry` | Catalog of slide layouts. Records validate against https://openpresentation.org/schema/opf-layout/v1. Default source: https://www.pptx.gallery/layouts. |\n| `chartTypes` | no | `ref:CatalogEntry` | Catalog of chart types. Records validate against https://openpresentation.org/schema/opf-chart-type/v1. Default source: https://www.pptx.gallery/chart-types. |\n| `tones` | no | `ref:CatalogEntry` | Catalog of presentation tones. Records validate against https://openpresentation.org/schema/opf-tone/v1. Default source: https://www.pptx.gallery/tones. Referenced from tone. |\n| `purposes` | no | `ref:CatalogEntry` | Catalog of presentation purposes. Records validate against https://openpresentation.org/schema/opf-purpose/v1. Default source: https://www.pptx.gallery/purposes. Referenced from purpose. |\n| `audiences` | no | `ref:CatalogEntry` | Catalog of presentation audiences. Records validate against https://openpresentation.org/schema/opf-audience/v1. Default source: https://www.pptx.gallery/audiences. Referenced from audience. |\n| `socialPlatforms` | no | `ref:CatalogEntry` | Catalog of social-media platforms. Records validate against https://openpresentation.org/schema/opf-social-platform/v1. Default source: https://www.pptx.gallery/social-platforms. Referenced via the property keys of an... |\n\n\n### CatalogEntry\n\n- Type: `object`\n- Required fields: none\n- Purpose: A catalog override for one record kind. 'source' replaces the default registry; 'records' adds inline records that take precedence over anything fetched from a source. Either or both may be provided; both omitted means the kind uses its default catalog.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `source` | no | `oneOf:ref:CatalogSource / array<ref:CatalogSource>` | Single source or an ordered search path of sources. When omitted, the engine falls back to https://www.pptx.gallery/<kind>. |\n| `records` | no | `array<object>` | Inline catalog records embedded in this OPF document. Each record validates against the kind's companion schema (e.g. https://openpresentation.org/schema/opf-narrative/v1 for narratives). Inline records win over anyth... |\n\n\n### CatalogSource\n\n- Type: `string`\n- Required fields: none\n- Purpose: Catalog source location. Accepts: - A bare URL pointing at a catalog directory (e.g. 'https://acme.com/decks/narratives'); record ids resolve to '<base>/<id>.json'. - A URL pointing at an index file (e.g. 'https://acme.com/decks/narratives/index.json'); records are resolved relative to the index file's directory and the index entries describe what's available. - A package reference of the form 'pkg:<package>[/<subpath>]'; resolved through a locally-installed package on the engine's package path.\n\n_No named properties._\n\n\n### Composition\n\n- Type: `object`\n- Required fields: none\n- Purpose: Portable dynamic composition. Slide fields override the resolved layout. Nested groups arrange their children independently, inheriting only minFontSize and overflow. Explicit promoted regions retain their positions.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `mode` | no | `enum:auto \\| grid \\| row \\| column` | auto chooses a grid from available space and content; grid uses columns; row and column use one horizontal or vertical track. |\n| `columns` | no | `integer` | Column count for grid. In auto mode this caps the number of columns. |\n| `gap` | no | `number` | Space between cells as a fraction of the container short edge (canvas at slide root). Default 0.03333333333333333. |\n| `padding` | no | `number` | Inset as a fraction of the container short edge. Default 0.08 on a slide, 0 inside a group. |\n| `weights` | no | `array<number>` | Relative track sizes: columns for row/grid/auto, rows for column. Omitted tracks have weight 1; extra weights are ignored. |\n| `minFontSize` | no | `number` | 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. |\n| `overflow` | no | `enum:warn \\| error` | warn returns diagnostics for content that does not fit; error rejects layout. Content is never silently removed. Default warn. |\n"
|
|
199
|
+
"markdown": "# OPF Presentation Schema Reference\n\nThis reference documents the author-facing shape of a complete `*.opf.json` presentation document. It summarizes the canonical schema in `spec/schemas/opf.schema.json`; the schema remains the source of truth for validators.\n\n## Document Contract\n\n- Schema id: `https://openpresentation.org/schema/opf/v1`\n- Required top-level fields: `slides`\n- Additional top-level fields: not allowed\n\n## Top-Level Fields\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `$schema` | no | `const:\"https://openpresentation.org/schema/opf/v1\"` | Optional OPF schema version. When omitted, validators and engines should assume the latest supported OPF schema. |\n| `name` | no | `string` | 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... |\n| `description` | no | `string` | 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/co... |\n| `filename` | no | `string` | Optional base filename for exports (without extension). Engine strips a trailing .pptx, .pdf, .png, or .svg (case-insensitive) and appends the target format's extension. When omitted, the engine slugifies name when pr... |\n| `organization` | no | `oneOf:ref:Organization / array<ref:Organization>` | Organization associated with the presentation, usually the presenting company. Array form supports hosts, partners, clients, and sponsors. The primary organization (declared via Organization.role or, if no role is set... |\n| `speaker` | no | `oneOf:ref:Speaker / array<ref:Speaker>` | Person presenting the deck. Array form supports panels and multi-speaker decks. Used for cover slides, bio slides, footers, and panel attribution. |\n| `author` | no | `oneOf:string / 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 wh... |\n| `audience` | no | `oneOf:string / array<oneOf:string / ref:Audience>` | Intended audiences for the presentation. Accepts either: - A single string shorthand: free-form description ('Series B investors'), an audiences catalog id ('executives'), an HTTPS URL, or a 'pkg:' reference. - An arr... |\n| `purpose` | no | `oneOf:string / ref:Purpose` | Primary goal of the presentation. Accepts either: - A string shorthand: free-form goal ('Raise a Series B round of $30M'), a purposes catalog id ('decide', 'align'), an HTTPS URL, or a 'pkg:' reference. - An inline Pu... |\n| `language` | no | `oneOf:string / ref:Language` | Language for the presentation content. Accepts either: - A string shorthand: a BCP-47 language tag ('en-US', 'en-GB', 'ja-JP', 'fr'), a languages catalog id ('english', 'japanese'), an HTTPS URL, or a 'pkg:' reference... |\n| `tone` | no | `oneOf:string / ref:Tone` | Desired tone for the presentation. Accepts either: - A string shorthand: a tones catalog id ('formal'), an HTTPS URL, or a 'pkg:' reference. - An inline Tone object for custom tone metadata or catalog-backed overrides... |\n| `takeaway` | no | `oneOf:string / 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. |\n| `duration` | no | `integer` | Target presentation duration, as an integer number of minutes. Used by AI to set pace and depth, and to compare against the resolved narrative's durationRange. |\n| `tags` | no | `array<string>` | Free-form labels used for categorization, search, and filtering. Lowercase kebab-case is recommended for consistency across a deck library. |\n| `design` | no | `ref: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. |\n| `variables` | no | `ref:Variables` | Optional named color variables for values the deck uses in more than one place or wants to name for intent (e.g. a risk red, a brand highlight). Content color fields reference entries as 'var:<id>' strings. Variables... |\n| `narrative` | no | `oneOf:string / ref:Narrative` | Structured storyline describing the deck's arc and beats. Resolves to the 'id' of a 'narratives' catalog record. Accepts two forms: - String shorthand for the common case: 'narrative = \"classic-story\"'. Accepts a bare... |\n| `slides` | yes | `array<ref:Slide>` | Ordered array of slides that make up the presentation. |\n| `assets` | no | `ref:Assets` | Optional reusable asset registry for images, data files, videos, documents, fonts, and other resources referenced elsewhere in the deck via 'asset:<id>' strings. |\n| `catalogs` | no | `ref:Catalogs` | Optional per-kind catalog overrides. Each kind may declare a non-default 'source' and/or inline 'records' that override or supplement the default catalog at https://www.pptx.gallery/<kind>. References elsewhere in the... |\n| `extensions` | no | `object` | Custom data passthrough for agent workflows; ignored by the engine but preserved across read/write round-trips. |\n\n## Object And Type Reference\n\n### Assets\n\n- Type: `object`\n- Required fields: none\n- Purpose: 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.\n\n_No named properties._\n\n\n### Asset\n\n- Type: `oneOf:string / object`\n- Required fields: none\n- Purpose: 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, mediaType, or format matters.\n\n_No named properties._\n\n\n### Audience\n\n- Type: `anyOf:schema / schema`\n- Required fields: none\n- Purpose: Inline audience metadata for the presentation. Use 'id' to reference an audiences catalog record and override selected fields, or use 'name' for a custom inline audience.\n- Conditional requirement: `id` or `name`\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | no | `string` | Optional audiences catalog id to resolve before applying inline overrides. |\n| `name` | no | `string` | Human-readable audience name shown in pickers. |\n| `summary` | no | `string` | One-sentence positioning of the audience. |\n| `description` | no | `string` | Longer prose describing the audience and how to address them. |\n| `seniority` | no | `enum:ic \\| manager \\| director \\| vp \\| c-suite \\| mixed` | Typical seniority level of the audience. |\n| `technicalFluency` | no | `enum:low \\| medium \\| high \\| mixed` | Typical technical fluency of the audience. |\n| `decisionPower` | no | `enum:informational \\| advisory \\| decision-maker` | Whether the audience is expected to be informed, advise, or decide. |\n| `attentionBudgetMinutes` | no | `number` | Realistic upper bound on focused attention for a single presentation, in minutes. |\n| `recommendedNarratives` | no | `array<string>` | Soft cross-link: narrative-catalog ids that work well for this audience. |\n| `recommendedTones` | no | `array<string>` | Soft cross-link: tone-catalog ids that work well for this audience. |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search. |\n\n\n### Purpose\n\n- Type: `anyOf:schema / schema`\n- Required fields: none\n- Purpose: Inline purpose metadata for the presentation. Use 'id' to reference a purposes catalog record and override selected fields, or use 'name' for a custom inline purpose.\n- Conditional requirement: `id` or `name`\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | no | `string` | Optional purposes catalog id to resolve before applying inline overrides. |\n| `name` | no | `string` | Human-readable purpose name shown in pickers. |\n| `summary` | no | `string` | One-sentence positioning of the purpose. |\n| `description` | no | `string` | Longer prose describing when to use this purpose and how it should shape a deck. |\n| `outcome` | no | `string` | Desired audience outcome after the presentation. |\n| `successCriteria` | no | `array<string>` | Observable signals that the deck accomplished this purpose. |\n| `recommendedNarratives` | no | `array<string>` | Soft cross-link: narrative-catalog ids that work well for this purpose. |\n| `recommendedTones` | no | `array<string>` | Soft cross-link: tone-catalog ids that work well for this purpose. |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search. |\n\n\n### Language\n\n- Type: `anyOf:schema / schema`\n- Required fields: none\n- Purpose: Inline language metadata for the presentation. Use 'id' to reference a languages catalog record and override selected fields, or use 'bcp47' for a custom language tag without a catalog record.\n- Conditional requirement: `id` or `bcp47`\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | no | `string` | Optional languages catalog id to resolve before applying inline overrides. |\n| `name` | no | `string` | Human-readable language name. |\n| `bcp47` | no | `string` | 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. |\n| `code` | no | `string` | ISO 639-3 or 639-2 language code carried for engines that prefer ISO codes. |\n| `direction` | no | `enum:ltr \\| rtl` | Base text direction for the language. |\n| `script` | no | `string` | ISO 15924 script code when the writing system should be explicit. |\n| `fontScheme` | no | `string` | Default font-scheme id for this language when targeting PowerPoint output. |\n| `googleFontScheme` | no | `string` | Default font-scheme id for this language when targeting Google Slides output. |\n| `summary` | no | `string` | One-sentence note about coverage or font defaults. |\n| `description` | no | `string` | Longer prose describing the language record and any font-pairing rationale. |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search. |\n\n\n### Tone\n\n- Type: `anyOf:schema / schema`\n- Required fields: none\n- Purpose: Inline tone metadata for the presentation. Use 'id' to reference a tones catalog record and override selected fields, or use 'name' for a custom inline tone.\n- Conditional requirement: `id` or `name`\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | no | `string` | Optional tones catalog id to resolve before applying inline overrides. |\n| `name` | no | `string` | Human-readable tone name shown in pickers. |\n| `summary` | no | `string` | One-sentence positioning of the tone. |\n| `description` | no | `string` | Longer prose describing the tone and the kinds of decks it suits. |\n| `voiceCues` | no | `array<string>` | Short directives that shape AI generation toward this tone. |\n| `avoid` | no | `array<string>` | Anti-patterns that AI generation should not produce when this tone is active. |\n| `samplePhrases` | no | `array<string>` | Short example phrases that exemplify this tone. |\n| `recommendedNarratives` | no | `array<string>` | Soft cross-link: narrative-catalog ids this tone pairs well with. |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search. |\n\n\n### Organization\n\n- Type: `object`\n- Required fields: `id`, `name`\n- Purpose: An organization associated with the presentation typically the presenting company, but also hosts, partners, clients, or sponsors. Surfaced on cover slides, footers, and brand bars; the primary organization's logo is the default deck logo unless overridden by design.logo.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | yes | `string` | Stable identifier for the organization, used to reference it from Speaker.organizationId. Must be unique within the deck. |\n| `name` | yes | `string` | Display name shown on slides. |\n| `legalName` | no | `string` | Optional legal entity name when it differs from the display name. |\n| `logo` | no | `ref:Asset` | Source for the organization's logo image. Accepts an HTTPS URL, data URI, relative path (resolved against the OPF file location), local path, or 'asset:<id>' reference. Common formats are SVG (preferred for vector log... |\n| `domain` | no | `string` | Bare internet domain for the organization. Used for footers, contact slides, and engine-driven asset lookups (e.g., favicon-based brand defaults). |\n| `email` | no | `string` | General contact email for the organization. Used on contact slides and footer attribution. |\n| `phone` | no | `string` | Main contact phone number for the organization. E.164 format is recommended. |\n| `tagline` | no | `string` | Short tagline rendered alongside the organization name on cover slides. |\n| `role` | no | `enum:primary \\| partner \\| client \\| sponsor \\| host` | Role of the organization relative to the presentation. When omitted, the single organization or first organization in array form is treated as primary. |\n| `socials` | no | `ref:Socials` | Optional social media handles or URLs for the organization. |\n\n\n### Speaker\n\n- Type: `object`\n- Required fields: `id`, `name`\n- Purpose: A person presenting the deck. Used for cover slides, bio/intro slides, footer attribution, and panel formats with multiple presenters.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | yes | `string` | Stable identifier for the speaker, used for cross-references within the deck. Must be unique within the deck. |\n| `name` | yes | `string` | Display name. |\n| `title` | no | `string` | Role or title. Often paired with the speaker's organization on cover slides. |\n| `photo` | no | `ref:Asset` | 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 appropr... |\n| `email` | no | `string` | Contact email, used on contact slides or footer attribution when appropriate. |\n| `phone` | no | `string` | Contact phone number for the speaker. E.164 format is recommended. |\n| `bio` | no | `string` | Short biographical paragraph for bio or 'about the speaker' slides. |\n| `organizationId` | no | `string` | Reference to an Organization.id in organization. Lets a speaker be attributed to their org in panel or multi-org decks without repeating organization details. |\n| `socials` | no | `ref:Socials` | Optional social media handles or URLs for the speaker. |\n\n\n### Socials\n\n- Type: `object`\n- Required fields: none\n- Purpose: Social media handles or URLs, keyed by platform id from the 'socialPlatforms' catalog. Each value is a string either a full URL or a platform handle (e.g., '@acme'). The catalog record for each platform carries the URL pattern, handle prefix, brand color, and themed icons used by renderers. Keys resolve to the 'id' of a 'socialPlatforms' catalog record. Resolution order: inline catalogs.socialPlatforms.records[] catalogs.socialPlatforms.source default catalog at https://www.pptx.gallery/socia...\n\n_No named properties._\n\n\n### Narrative\n\n- Type: `object`\n- Required fields: none\n- Purpose: Structured storyline used by AI to shape generated content. Mirrors the OPF Narrative Template record at https://openpresentation.org/schema/opf-narrative/v1 (sans '$schema'), so a library record and an inline narrative are interchangeable. Narrative declares the deck's intended story arc; slides may opt into beats via Slide.beat. The narrative does not constrain slide structure validators warn on drift (orphan slides, unused beats) but never error. Slides are the source of truth; narrative i...\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | no | `string` | Stable slug identifying this narrative. When it matches a record in the resolved 'narratives' catalog, the catalog record's beats and metadata seed this narrative; inline fields override per-key. When it doesn't match... |\n| `name` | no | `string` | Human-readable narrative name. |\n| `summary` | no | `string` | One-sentence description of when and why to use this narrative. |\n| `description` | no | `string` | Longer prose describing the narrative arc and ideal use cases. Used by AI-driven generation to seed deck-level direction. |\n| `audienceFit` | no | `array<string>` | Audiences this narrative works well for. Free-form strings or 'audiences' catalog ids. |\n| `durationRange` | no | `object` | Typical talk-length window this narrative suits. Compared by validators against duration. |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search. |\n| `preview` | no | `object` | Visual previews of the narrative, used by picker UIs and inline rendering. All sub-fields are optional. |\n| `beats` | no | `array<ref:NarrativeBeat>` | Ordered list of beats that make up the narrative arc. When 'id' matches a catalog record, beats here override or extend matching catalog beats by their own 'id'. Beat IDs must be unique within the narrative. |\n\n\n### NarrativeBeat\n\n- Type: `object`\n- Required fields: `id`, `name`\n- Purpose: A single narrative beat a labeled segment of the story arc with a specific dramatic purpose (e.g. 'hook', 'problem', 'evidence', 'ask'). Slides reference beats via Slide.beat. Beats may also carry slide-blueprint hints (slideType, layoutHint, thoughtCues, instructions) that guide the assigned slide. Mirrors the Beat definition in narrative.schema.json (https://openpresentation.org/schema/opf-narrative/v1) so library entries and inline OPF beats are interchangeable.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | yes | `string` | Stable slug used by Slide.beat to reference this beat. Lowercase kebab-case. |\n| `name` | yes | `string` | Human-readable beat name. |\n| `description` | no | `string` | Curator-written prose that explains what this beat should accomplish. |\n| `instructions` | no | `string` | Short author-facing instruction for the beat typically one phrase. Complements 'description' with a concise directive. |\n| `slideCount` | no | `integer` | Optional explicit slide count for this beat. Defaults to 1 when omitted; values >1 are reserved for beats that intentionally span multiple slides. Prefer decomposing a heavy beat into multiple beats over setting a hig... |\n| `slideType` | no | `enum:text \\| list \\| image \\| chart \\| table \\| video \\| code \\| metric \\| quote \\| timeline` | Default content kind for the beat's slide. Mirrors ContentPayload.type and helps engines choose a sensible layout when only the beat is specified. |\n| `layoutHint` | no | `string` | Suggested layout id for the beat's opening slide. Resolves the same way as Slide.layout against catalogs.layouts and the default catalog at https://www.pptx.gallery/layouts. |\n| `thoughtCues` | no | `array<string>` | Optional speaker or thinking cues attached to the beat. Surfaced in presenter notes. |\n\n\n### Design\n\n- Type: `object`\n- Required fields: none\n- Purpose: Visual design system applied to the presentation; individual slides may override fields via Slide.design.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `theme` | no | `oneOf:string / ref:Theme` | Theme for the deck. Accepts two forms: - String shorthand: 'design.theme = \"minimal\"'. Bare id, HTTPS URL, or 'pkg:' reference resolved as the 'id' of a 'themes' catalog record. - Object form: a Theme with an optional... |\n| `colorScheme` | no | `oneOf:string / ref:ColorScheme` | Color scheme for the presentation. Accepts two forms: - String shorthand: 'design.colorScheme = \"cool-horizon\"'. Bare id, HTTPS URL, or 'pkg:' reference resolved as the 'id' of a 'colorSchemes' catalog record. - Objec... |\n| `fontScheme` | no | `oneOf:string / ref:FontScheme` | Font scheme for heading, body, accent, and code text. Accepts two forms: - String shorthand: 'design.fontScheme = \"aptos\"'. Bare id, HTTPS URL, or 'pkg:' reference resolved as the 'id' of a 'fontSchemes' catalog recor... |\n| `dimensions` | no | `oneOf:ref:DimensionPreset / ref:Dimensions` | Slide dimensions and aspect ratio. String shorthand such as 'widescreen' is equivalent to { preset: 'widescreen' }. |\n| `background` | no | `oneOf:ref:BackgroundShortcut / ref:Background` | Default slide background applied across the deck unless overridden on a slide. String shorthand accepts theme slots ('light1', 'light2', 'dark1', 'dark2') or hex colors; object forms support theme, solid, gradient, im... |\n| `logo` | no | `oneOf:ref:Asset / ref:LogoSet` | Deck logo assets used by layouts, covers, section dividers, headers, and footers. A string is the default logo source; object form provides light/dark, stacked, icon, and wordmark variants. When omitted, the renderer... |\n| `watermark` | no | `oneOf:const:false / ref:Asset / ref:Watermark` | Optional decorative watermark applied across slides. Use false to suppress an inherited watermark in slide-level design; a string is equivalent to { src: value }. |\n| `header` | no | `oneOf:const:false / ref:HeaderFooter` | Repeated header furniture rendered outside the main slide content. Use false to suppress an inherited header. |\n| `footer` | no | `oneOf:const:false / ref:HeaderFooter` | Repeated footer furniture rendered outside the main slide content. Use false to suppress an inherited footer. |\n| `titleAlignment` | no | `enum:left \\| center \\| right` | Default horizontal alignment for title placeholders in resolved layouts. |\n| `contentAlignment` | no | `enum:left \\| center \\| right` | Default horizontal alignment for body/content regions in resolved layouts. |\n| `contentBox` | no | `boolean` | Whether body/content regions are rendered inside a visible card or surface. |\n| `slideImage` | no | `oneOf:ref:Asset / object` | Optional slide-level image treatment used by layouts that support a decorative or editorial image separate from content images. |\n| `contentDirection` | no | `enum:horizontal \\| vertical` | Axis along which parallel body/content regions are arranged. |\n| `chartPrimary` | no | `enum:none \\| top \\| bottom \\| left \\| right` | For chart layouts, where the primary chart sits relative to supporting content. 'none' means chart regions have equal weight. |\n| `imageFill` | no | `enum:crop \\| fit` | How picture placeholders fill their allocated region. |\n| `listBullet` | no | `enum:character \\| image` | Default bullet rendering style for list layouts. |\n\n\n### Theme\n\n- Type: `object`\n- Required fields: none\n- Purpose: Theme bundle used by the design system. In design.theme, 'id' resolves a themes catalog record as the base; any sibling fields override the resolved theme. The string shorthand on design.theme is equivalent to setting only 'id'.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | no | `string` | Theme reference. Resolves to the 'id' of a 'themes' catalog record. Accepts a bare id (lowercase kebab-case, e.g. 'minimal'), an HTTPS URL pointing at a record file, or a 'pkg:' reference. Field overrides on the surro... |\n| `name` | no | `string` | Human-readable theme name shown in pickers. |\n| `summary` | no | `string` | One-sentence positioning of the theme - when to reach for it. |\n| `description` | no | `string` | Longer prose describing what the theme looks and feels like and the kinds of decks it suits. |\n| `colorScheme` | no | `oneOf:string / ref:ColorScheme` | Default color scheme for this theme. A string resolves against catalogs.colorSchemes; an object may provide an 'id' base reference plus overrides. |\n| `fontScheme` | no | `oneOf:string / ref:FontScheme` | Default font scheme for this theme. A string resolves against catalogs.fontSchemes; an object may provide an 'id' base reference plus overrides. |\n| `background` | no | `oneOf:ref:BackgroundShortcut / ref:Background` | Default background for this theme. String shorthand accepts theme slots ('light1', 'light2', 'dark1', 'dark2') or hex colors. |\n| `dimensions` | no | `oneOf:ref:DimensionPreset / ref:Dimensions` | Default slide size for this theme. A string preset is equivalent to { preset: value }. |\n| `tags` | no | `array<string>` | Free-form labels for filtering and search. |\n\n\n### ColorScheme\n\n- Type: `object`\n- Required fields: none\n- Purpose: Color palette used by the design system. 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. Two parallel models are supported and may be mixed: - OOXML slots - the 12-slot PowerPoint theme model that round-trips directly to OOXML. Use these for full control over the palette as Power...\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | no | `string` | Color scheme reference. Resolves to the 'id' of a 'colorSchemes' catalog record. Accepts a bare id (lowercase kebab-case, e.g. 'cool-horizon'), an HTTPS URL pointing at a record file, or a 'pkg:' reference. Slot and r... |\n| `accent1` | no | `string` | Accent 1 color (hex). Mirrors the OOXML accent1 slot. |\n| `accent2` | no | `string` | Accent 2 color (hex). Mirrors the OOXML accent2 slot. |\n| `accent3` | no | `string` | Accent 3 color (hex). Mirrors the OOXML accent3 slot. |\n| `accent4` | no | `string` | Accent 4 color (hex). Mirrors the OOXML accent4 slot. |\n| `accent5` | no | `string` | Accent 5 color (hex). Mirrors the OOXML accent5 slot. |\n| `accent6` | no | `string` | Accent 6 color (hex). Mirrors the OOXML accent6 slot. |\n| `dark1` | no | `string` | Dark 1 color (hex). Typically the deepest neutral; OOXML dark1. |\n| `dark2` | no | `string` | Dark 2 color (hex). Secondary dark; OOXML dark2. |\n| `light1` | no | `string` | Light 1 color (hex). Typically the slide canvas; OOXML lt1. |\n| `light2` | no | `string` | Light 2 color (hex). Secondary light surface; OOXML lt2. |\n| `hyperlink` | no | `string` | Hyperlink color (hex). OOXML hlink. |\n| `followedHyperlink` | no | `string` | Followed-hyperlink color (hex). OOXML folHlink. |\n| `primary` | no | `string` | Abstract role: primary brand color (hex). The engine maps this onto an OOXML accent slot when serializing. |\n| `secondary` | no | `string` | Abstract role: secondary brand color (hex). |\n| `accent` | no | `string` | Abstract role: accent color used for highlights and emphasis (hex). |\n| `background` | no | `string` | Abstract role: default slide background color (hex). The engine maps this to one of light1 / light2 / dark1 / dark2 when serializing. |\n| `surface` | no | `string` | Abstract role: color for elevated surfaces such as cards and panels (hex). |\n| `text` | no | `string` | Abstract role: primary body text color (hex). |\n| `textSecondary` | no | `string` | Abstract role: secondary or muted text color used for captions and supporting copy (hex). |\n| `custom` | no | `object` | Map of custom named colors for advanced or theme-specific use. |\n\n\n### FontScheme\n\n- Type: `object`\n- Required fields: none\n- Purpose: 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. Two parallel models are supported and may be mixed: - OOXML pairs (major, minor) - heading and body family names that round-trip directly to PowerPoint majorFont/minorFont entries. - Abstract roles...\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | no | `string` | Font scheme reference. Resolves to the 'id' of a 'fontSchemes' catalog record. Accepts a bare id (lowercase kebab-case, e.g. 'aptos'), an HTTPS URL pointing at a record file, or a 'pkg:' reference. Field overrides on... |\n| `major` | no | `string` | Heading (major) font family mirrors the OOXML majorFont entry. Pairs with 'minor'. |\n| `minor` | no | `string` | Body (minor) font family mirrors the OOXML minorFont entry. Pairs with 'major'. |\n| `type` | no | `enum:sans-serif \\| serif \\| monospace` | High-level typographic class of the scheme. |\n| `app` | no | `enum:PowerPoint \\| Google Slides` | Target application this font pairing is intended for. |\n| `languageFamily` | no | `enum:latin \\| ea \\| cs` | OOXML font-language family this scheme is intended for: 'latin' for Latin-script content, 'ea' for East Asian scripts, 'cs' for Complex Scripts. |\n| `heading` | no | `ref:Font` | Abstract role: font used for slide titles and headings. Maps onto the OOXML major slot when serializing. |\n| `body` | no | `ref:Font` | Abstract role: font used for body copy. Maps onto the OOXML minor slot when serializing. |\n| `accent` | no | `ref:Font` | Abstract role: font used for accent text such as quotes or callouts. No direct OOXML slot. |\n| `code` | no | `ref:Font` | Abstract role: monospaced font used for code blocks. No direct OOXML slot. |\n\n\n### Font\n\n- Type: `object`\n- Required fields: `family`\n- Purpose: Specification for a single font role.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `family` | yes | `string` | Font family name. |\n| `weight` | no | `number` | Numeric font weight (e.g., 400 for regular, 700 for bold). |\n| `style` | no | `enum:normal \\| italic` | Font style. |\n| `letterSpacing` | no | `number` | Letter spacing (tracking) in ems. |\n\n\n### DimensionPreset\n\n- Type: `enum:16:9 | 4:3 | 16:10 | letter | a4 | widescreen | standard`\n- Required fields: none\n- Purpose: Named dimension preset; chooses both aspect ratio and physical size. 'widescreen' is an alias for 16:9 in PowerPoint widescreen size; 'standard' is an alias for 4:3 in PowerPoint standard size.\n\n_No named properties._\n\n\n### Dimensions\n\n- Type: `object`\n- Required fields: none\n- Purpose: Slide dimensions; either pick a preset or specify custom inches.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `preset` | no | `ref:DimensionPreset` | |\n| `widthInches` | no | `number` | Custom slide width in inches; overrides the preset width when provided. |\n| `heightInches` | no | `number` | Custom slide height in inches; overrides the preset height when provided. |\n\n\n### ThemeBackgroundSlot\n\n- Type: `enum:light1 | light2 | dark1 | dark2`\n- Required fields: none\n- Purpose: 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.\n\n_No named properties._\n\n\n### HexColor\n\n- Type: `string`\n- Required fields: none\n- Purpose: Hex color shorthand accepted by selected string fields.\n\n_No named properties._\n\n\n### ColorRef\n\n- Type: `anyOf:ref:HexColor / enum:accent1 | accent2 | accent3 | accent4 | accent5 | accent6 | dark1 | dark2 | light1 | light2 | hyperlink | followedHyperlink | primary | secondary | accent | background | surface | text | textSecondary / string`\n- Required fields: none\n- Purpose: A color value or reference, enforced on styled table cell fill and text colors and on cell border colors. Three forms: - Literal hex: '#RGB', '#RRGGBB', or '#RRGGBBAA'. - 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', 'text', 'textSecondary'). Roles resolve through th...\n\n_No named properties._\n\n\n### Variables\n\n- Type: `object`\n- Required fields: none\n- Purpose: Named color variables, keyed by stable kebab-case id. Content color fields reference entries as 'var:<id>' strings. Each value is a hex string shorthand or a Variable object.\n\n_No named properties._\n\n\n### Variable\n\n- Type: `oneOf:ref:HexColor / object`\n- Required fields: none\n- Purpose: A single named variable. A hex string is shorthand for { \"type\": \"color\", \"value\": value }.\n\n_No named properties._\n\n\n### BackgroundShortcut\n\n- Type: `oneOf:ref:ThemeBackgroundSlot / ref:HexColor`\n- Required fields: none\n- Purpose: 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 }.\n\n_No named properties._\n\n\n### Background\n\n- Type: `oneOf:ref:ThemeBackground / ref:SolidBackground / ref:GradientBackground / ref:ImageBackground / ref:PatternBackground`\n- Required fields: none\n- Purpose: Background fill applied to slides. Theme backgrounds preserve PowerPoint's color-scheme background choice; other variants represent fixed background fills.\n\n_No named properties._\n\n\n### ThemeBackground\n\n- Type: `object`\n- Required fields: `type`, `slot`\n- Purpose: Theme-controlled PowerPoint slide background. The slot is resolved through the active color scheme and remains theme-aware.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `type` | yes | `const:\"theme\"` | Theme-controlled background fill. |\n| `slot` | yes | `ref:ThemeBackgroundSlot` | |\n\n\n### SolidBackground\n\n- Type: `object`\n- Required fields: `type`, `color`\n- Purpose: Fixed solid slide background fill.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `type` | yes | `const:\"solid\"` | Fixed solid background fill. |\n| `color` | yes | `string` | Fixed solid fill color, usually a hex string. Use { type: 'theme', slot: ... } for PowerPoint's four theme-controlled background choices. |\n| `opacity` | no | `number` | Background opacity from 0 (fully transparent) to 1 (fully opaque). |\n\n\n### GradientBackground\n\n- Type: `object`\n- Required fields: `type`, `gradient`\n- Purpose: Fixed gradient slide background fill.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `type` | yes | `const:\"gradient\"` | Fixed gradient background fill. |\n| `gradient` | yes | `object` | Gradient fill definition. |\n| `opacity` | no | `number` | Background opacity from 0 (fully transparent) to 1 (fully opaque). |\n\n\n### ImageBackground\n\n- Type: `object`\n- Required fields: `type`, `image`\n- Purpose: Fixed image slide background fill.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `type` | yes | `const:\"image\"` | Fixed image background fill. |\n| `image` | yes | `object` | Image fill definition. |\n| `opacity` | no | `number` | Background opacity from 0 (fully transparent) to 1 (fully opaque). |\n\n\n### PatternBackground\n\n- Type: `object`\n- Required fields: `type`, `pattern`\n- Purpose: Fixed pattern slide background fill.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `type` | yes | `const:\"pattern\"` | Fixed pattern background fill. |\n| `pattern` | yes | `object` | Pattern fill definition. |\n| `opacity` | no | `number` | Background opacity from 0 (fully transparent) to 1 (fully opaque). |\n\n\n### LogoSet\n\n- Type: `object`\n- Required fields: none\n- Purpose: Deck logo variants surfaced by layouts, covers, section dividers, headers, and footers. Organization identity lives in organization; this object only controls visual rendering assets. Renderer convention: on dark backgrounds prefer the 'light' variant, on light backgrounds prefer the 'dark' variant, and in square/vertical slots prefer the stacked family when present.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `default` | no | `ref:Asset` | Default full-lockup logo. Used as fallback when no more specific variant is set. |\n| `light` | no | `ref:Asset` | Light-colored full-lockup logo intended for rendering on dark backgrounds. |\n| `dark` | no | `ref:Asset` | Dark-colored full-lockup logo intended for rendering on light backgrounds. |\n| `stacked` | no | `ref:Asset` | Stacked vertical logo lockup, suited to portrait or square brand-mark slots. |\n| `stackedLight` | no | `ref:Asset` | Light-colored stacked logo variant intended for rendering on dark backgrounds. |\n| `stackedDark` | no | `ref:Asset` | Dark-colored stacked logo variant intended for rendering on light backgrounds. |\n| `icon` | no | `ref:Asset` | Default icon, mark, or symbol without wordmark. Useful for tight spaces such as footers, badges, and slide-corner marks. |\n| `iconLight` | no | `ref:Asset` | Light-colored icon variant intended for rendering on dark backgrounds. |\n| `iconDark` | no | `ref:Asset` | Dark-colored icon variant intended for rendering on light backgrounds. |\n| `wordmark` | no | `ref:Asset` | Default wordmark: the organization name set in branded typography, without icon. |\n| `wordmarkLight` | no | `ref:Asset` | Light-colored wordmark variant intended for rendering on dark backgrounds. |\n| `wordmarkDark` | no | `ref:Asset` | Dark-colored wordmark variant intended for rendering on light backgrounds. |\n\n\n### Watermark\n\n- Type: `object`\n- Required fields: `opacity`\n- Purpose: Decorative watermark image and rendering options. Use design.watermark = false to disable an inherited watermark.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `src` | no | `string` | Source for the watermark image. |\n| `opacity` | yes | `number` | Watermark opacity from 0 (fully transparent) to 1 (fully opaque). |\n\n\n### HeaderFooter\n\n- Type: `object`\n- Required fields: none\n- Purpose: 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.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `left` | no | `ref:HeaderFooterItem` | Left-aligned header/footer content. |\n| `center` | no | `ref:HeaderFooterItem` | Centered header/footer content. |\n| `right` | no | `ref:HeaderFooterItem` | Right-aligned header/footer content. |\n\n\n### HeaderFooterItem\n\n- Type: `object`\n- Required fields: none\n- Purpose: One header/footer zone. Fields may be combined when the renderer supports it; otherwise renderers should prefer image, then text-like generated content.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `text` | no | `string` | Literal text rendered in this zone. |\n| `image` | no | `ref:Asset` | Generic image rendered in this zone, such as a logo, partner mark, certification badge, or icon. |\n| `slideNumber` | no | `boolean` | Whether to render the current slide number in this zone. |\n| `date` | no | `oneOf:boolean / string` | Whether to render the presentation date, or a literal date string to render. |\n| `organization` | no | `boolean` | Whether to render the primary organization name from organization. |\n| `section` | no | `boolean` | Whether to render the current slide section label. |\n\n\n### Slide\n\n- Type: `object`\n- Required fields: none\n- Purpose: 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'.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | no | `string` | 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 s... |\n| `type` | no | `enum:text \\| list \\| image \\| chart \\| table \\| video \\| code \\| metric \\| quote \\| timeline` | Optional full-slide content kind. When omitted, engines infer the kind from root payload fields. |\n| `beat` | no | `oneOf:string / array<string>` | Optional reference to one or more narrative beats (each value matches an id from narrative.beats or the resolved template). A single string declares the slide's primary beat; an array declares that one slide covers mu... |\n| `layout` | no | `string` | Optional slide layout reference. Resolves to the 'id' of a 'layouts' catalog record. When omitted, engines infer a layout from the slide's root payload or promoted region keys. Accepts a bare id (lowercase kebab-case,... |\n| `title` | no | `string` | Slide-level title content. When the resolved layout exposes a 'title' placeholder, the engine renders this value there. |\n| `subtitle` | no | `string` | Slide-level subtitle or supporting line. When the resolved layout exposes a 'subtitle' placeholder, the engine renders this value there. |\n| `tag` | no | `string` | Small slide-level label or badge. When the resolved layout exposes a 'tag' placeholder, the engine renders this value there. |\n| `text` | no | `oneOf:string / array<ref:TextRun>` | 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. |\n| `items` | no | `array<ref:ListItem>` | Full-slide generic list payload. Presence of this field infers type 'list'. At slide root, multiple content payload kinds with no explicit type, blocks, or regions are accepted as shorthand for layout-agnostic blocks. |\n| `bullets` | no | `array<ref:BulletItem>` | Full-slide text-style bullet payload. Presence of this field infers type 'text'. |\n| `image` | no | `ref:Asset` | Full-slide image source. Presence of this field infers type 'image'. |\n| `video` | no | `ref:Asset` | Full-slide video source. Presence of this field infers type 'video'. |\n| `chart` | no | `ref:Chart` | Full-slide chart payload. Presence of this field infers type 'chart'. |\n| `table` | no | `ref:Table` | Full-slide table payload. Presence of this field infers type 'table'. |\n| `code` | no | `oneOf:string / ref:Code` | Full-slide code payload. A string is shorthand for { \"source\": value }; object form carries optional syntax language and filename metadata. |\n| `metric` | no | `oneOf:string / number / ref:Metric` | Full-slide metric payload. A string or number is shorthand for { \"value\": value }; object form carries optional label, description, unit, delta, and trend metadata. Numeric values remain numbers; renderers format them... |\n| `quote` | no | `oneOf:string / ref:Quote` | 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'. |\n| `timeline` | no | `ref:Timeline` | 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'. |\n| `blocks` | no | `array<ref:ContentPayload>` | 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 short... |\n| `design` | no | `ref:Design` | Slide-level design applied on top of the deck-wide design. |\n| `left` | no | `ref:ContentPayload` | |\n| `center` | no | `ref:ContentPayload` | |\n| `right` | no | `ref:ContentPayload` | |\n| `left+center` | no | `ref:ContentPayload` | |\n| `center+right` | no | `ref:ContentPayload` | |\n| `left+center+right` | no | `ref:ContentPayload` | |\n| `top` | no | `ref:ContentPayload` | |\n| `middle` | no | `ref:ContentPayload` | |\n| `bottom` | no | `ref:ContentPayload` | |\n| `top+middle` | no | `ref:ContentPayload` | |\n| `middle+bottom` | no | `ref:ContentPayload` | |\n| `top+middle+bottom` | no | `ref:ContentPayload` | |\n| `top:left` | no | `ref:ContentPayload` | |\n| `top:center` | no | `ref:ContentPayload` | |\n| `top:right` | no | `ref:ContentPayload` | |\n| `top:left+center` | no | `ref:ContentPayload` | |\n| `top:center+right` | no | `ref:ContentPayload` | |\n| `top:left+center+right` | no | `ref:ContentPayload` | |\n| `middle:left` | no | `ref:ContentPayload` | |\n| `middle:center` | no | `ref:ContentPayload` | |\n| `middle:right` | no | `ref:ContentPayload` | |\n| `middle:left+center` | no | `ref:ContentPayload` | |\n| `middle:center+right` | no | `ref:ContentPayload` | |\n| `middle:left+center+right` | no | `ref:ContentPayload` | |\n| `bottom:left` | no | `ref:ContentPayload` | |\n| `bottom:center` | no | `ref:ContentPayload` | |\n| `bottom:right` | no | `ref:ContentPayload` | |\n| `bottom:left+center` | no | `ref:ContentPayload` | |\n| `bottom:center+right` | no | `ref:ContentPayload` | |\n| `bottom:left+center+right` | no | `ref:ContentPayload` | |\n| `top+middle:left` | no | `ref:ContentPayload` | |\n| `top+middle:center` | no | `ref:ContentPayload` | |\n| `top+middle:right` | no | `ref:ContentPayload` | |\n| `top+middle:left+center` | no | `ref:ContentPayload` | |\n| `top+middle:center+right` | no | `ref:ContentPayload` | |\n| `top+middle:left+center+right` | no | `ref:ContentPayload` | |\n| `middle+bottom:left` | no | `ref:ContentPayload` | |\n| `middle+bottom:center` | no | `ref:ContentPayload` | |\n| `middle+bottom:right` | no | `ref:ContentPayload` | |\n| `middle+bottom:left+center` | no | `ref:ContentPayload` | |\n| `middle+bottom:center+right` | no | `ref:ContentPayload` | |\n| `middle+bottom:left+center+right` | no | `ref:ContentPayload` | |\n| `top+middle+bottom:left` | no | `ref:ContentPayload` | |\n| `top+middle+bottom:center` | no | `ref:ContentPayload` | |\n| `top+middle+bottom:right` | no | `ref:ContentPayload` | |\n| `top+middle+bottom:left+center` | no | `ref:ContentPayload` | |\n| `top+middle+bottom:center+right` | no | `ref:ContentPayload` | |\n| `top+middle+bottom:left+center+right` | no | `ref:ContentPayload` | |\n| `notes` | no | `string` | Speaker notes shown in presenter view. |\n| `section` | no | `string` | 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. |\n| `hidden` | no | `boolean` | Whether the slide is hidden from the presented sequence. |\n| `composition` | no | `ref:Composition` | |\n| `extensions` | no | `object` | 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... |\n\n\n### ContentPayload\n\n- Type: `allOf:schema + schema + schema + schema + schema + schema + schema + schema + schema + schema + schema + schema`\n- Required fields: none\n- Purpose: 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.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `id` | no | `string` | 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 ge... |\n| `extensions` | no | `object` | Custom data passthrough for agent workflows at payload scope; ignored by the engine but preserved across read/write round-trips. |\n| `type` | no | `enum:text \\| list \\| image \\| chart \\| table \\| video \\| code \\| metric \\| quote \\| timeline \\| group` | Optional content kind. When omitted, engines infer the kind from the fields present. |\n| `text` | no | `oneOf:string / array<ref:TextRun>` | Text payload. Use a string for plain text or TextRun[] for inline rich text. TextRun items may be plain strings or formatted run objects. |\n| `items` | no | `array<ref:ListItem>` | Generic list payload. Each item is either a plain string, a TextRun[] rich text sequence, or a ListItem object. List nesting uses item.level rather than nested content payloads. |\n| `bullets` | no | `array<ref:BulletItem>` | Text-style bullet payload. Presence of this field infers type 'text'. |\n| `image` | no | `ref:Asset` | Source for an image item. |\n| `video` | no | `ref:Asset` | Source for a video item. |\n| `chart` | no | `ref:Chart` | Chart payload. Presence of this field infers type 'chart'. |\n| `table` | no | `ref:Table` | Table payload. Presence of this field infers type 'table'. |\n| `code` | no | `oneOf:string / ref:Code` | Code payload. A string is shorthand for { \"source\": value }; object form carries optional syntax language and filename metadata. |\n| `metric` | no | `oneOf:string / number / ref:Metric` | Metric payload. A string or number is shorthand for { \"value\": value }; object form carries optional label, description, unit, delta, and trend metadata. Numeric values remain numbers; renderers format them for display. |\n| `quote` | no | `oneOf:string / ref:Quote` | Quote payload. A string is shorthand for { \"text\": value }; object form carries optional attribution and source metadata. |\n| `timeline` | no | `ref:Timeline` | Timeline payload ordered by narrative or chronology. |\n| `blocks` | no | `array<ref:ContentPayload>` | Ordered children of a group. Each child is a leaf or another group. |\n| `composition` | no | `ref:Composition` | Arrangement within this group. Only minFontSize and overflow inherit from the parent; strict overflow cannot be weakened. |\n\n\n### Quote\n\n- Type: `object`\n- Required fields: `text`\n- Purpose: Quote content with optional attribution metadata. Use 'text' for the quoted text, 'attribution' for the credited person or organization, and 'source' for a citation or URL. A string value in a quote field is shorthand for { \"text\": value }.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `text` | yes | `string` | Quoted text. |\n| `attribution` | no | `string` | Person or organization credited for the quote. |\n| `source` | no | `string` | Optional quote source, citation, or URL. |\n\n\n### Code\n\n- Type: `object`\n- Required fields: `source`\n- Purpose: Code content with optional rendering metadata. Use 'source' for the code text, 'language' for syntax highlighting, and 'filename' when the rendered block should show a file label. A string value in a code field is shorthand for { \"source\": value }.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `source` | yes | `string` | Source code text to display. |\n| `language` | no | `string` | Language identifier used for syntax highlighting. |\n| `filename` | no | `string` | Optional file label shown with the code block. |\n\n\n### Metric\n\n- Type: `object`\n- Required fields: `value`\n- Purpose: 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, and 'trend' for direction. A string or number value in a metric field is shorthand for { \"value\": value }; numeric values remain numbers and are formatted by renderers.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `value` | yes | `oneOf:string / number` | Primary metric value. |\n| `label` | no | `string` | Metric label. |\n| `description` | no | `string` | Optional supporting context for the metric. |\n| `unit` | no | `string` | Metric unit, suffix, or currency marker. |\n| `delta` | no | `oneOf:string / number` | Metric change value. |\n| `trend` | no | `enum:up \\| down \\| flat` | Metric trend direction. |\n\n\n### Timeline\n\n- Type: `oneOf:array<ref:TimelineEvent> / object`\n- Required fields: none\n- Purpose: Timeline content. An array is shorthand for { \"events\": value }; object form carries optional name and description metadata.\n\n_No named properties._\n\n\n### TimelineEvent\n\n- Type: `object`\n- Required fields: `what`\n- Purpose: A single event inside a timeline content payload.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `when` | no | `string` | Event time, date, or sequence label. Use ISO-like values when possible, but human labels are allowed for quarters, eras, and relative milestones. |\n| `what` | yes | `string` | Short event label. |\n| `description` | no | `string` | Optional event detail. |\n\n\n### ListItem\n\n- Type: `oneOf:string / array<ref:TextRun> / object`\n- Required fields: none\n- Purpose: 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.\n\n_No named properties._\n\n\n### BulletItem\n\n- Type: `oneOf:string / array<ref:TextRun> / object`\n- Required fields: none\n- Purpose: 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.\n\n_No named properties._\n\n\n### TextRun\n\n- Type: `oneOf:string / object`\n- Required fields: none\n- Purpose: A contiguous run of text. Strings cover unformatted spans; object form adds character formatting.\n\n_No named properties._\n\n\n### Chart\n\n- Type: `object`\n- Required fields: `type`, `data`\n- Purpose: Chart content. The chart object keeps chart-specific fields together so slides and regions do not expose loose chart fields.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `type` | yes | `string` | Chart type id. Resolves to the id of a chartTypes catalog record; renderers map that record through mappings.openxml and any renderer-specific mapping they understand. |\n| `data` | yes | `oneOf:ref:ChartData / ref:ChartDataSource` | Chart data. Inline data uses a tabular columns/rows shape; renderers convert rows to chart series internally. |\n\n\n### Table\n\n- Type: `object`\n- Required fields: `rows`\n- Purpose: Table content. Columns are optional; rows are the only required field.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `columns` | no | `array<oneOf:string / array<ref:TextRun> / ref:StyledTableCell / null>` | Optional column labels. Labels may be strings, rich runs or styled cell objects. Null is an empty label or a placeholder covered by a preceding column span. |\n| `rows` | yes | `array<array<ref:TableCell>>` | Two-dimensional table row data; each row aligns by index with columns when columns are supplied. |\n\n\n### ChartData\n\n- Type: `object`\n- Required fields: `columns`, `rows`\n- Purpose: Inline tabular data driving a chart. The first column usually supplies category/x-axis labels; subsequent columns are plotted measures unless a chart type or renderer maps them differently.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `columns` | yes | `array<string>` | Ordered column labels for the chart data table. |\n| `rows` | yes | `array<array<ref:ChartDataCell>>` | Tabular chart rows. Each row aligns by index with columns. |\n\n\n### ChartDataSource\n\n- Type: `object`\n- Required fields: `src`\n- Purpose: Chart data sourced from an asset reference, URL, data URI, relative path, or local path such as CSV, TSV, JSON, or XLSX. The source is interpreted as a table; optional columns select or order fields from that table.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `src` | yes | `string` | Data source. Use 'asset:<id>' to reference the top-level assets registry, or provide an HTTPS URL, data URI, relative path, or local filesystem path. |\n| `sheet` | no | `string` | Optional sheet name or table name for spreadsheet-like assets. |\n| `range` | no | `string` | Optional A1-style range or engine-defined range selector for spreadsheet-like assets. |\n| `columns` | no | `array<string>` | Optional ordered columns or fields to read from the source. When omitted, renderers may use the source's own header row or schema. |\n\n\n### ChartDataCell\n\n- Type: `oneOf:string / number / boolean / null`\n- Required fields: none\n- Purpose: A cell in inline chart data.\n\n_No named properties._\n\n\n### TableCell\n\n- Type: `oneOf:ref:TableCellValue / ref:StyledTableCell`\n- Required fields: none\n- Purpose: A scalar, rich-run array, or styled/spanning cell object. Existing scalar and rich forms remain valid.\n\n_No named properties._\n\n\n### TableCellValue\n\n- Type: `oneOf:string / number / boolean / null / array<ref:TextRun>`\n- Required fields: none\n- Purpose: A scalar table value or canonical rich text runs, without cell decoration or geometry.\n\n_No named properties._\n\n\n### StyledTableCell\n\n- Type: `object`\n- Required fields: `value`\n- Purpose: A cell with explicit visual style or merged geometry. Its position remains its array column index; use null placeholders for every covered grid position.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `value` | yes | `ref:TableCellValue` | Editable cell content; styling and spans do not change its scalar type or rich runs. |\n| `style` | no | `ref:TableCellStyle` | |\n| `colSpan` | no | `integer` | Number of grid columns covered, starting at this cell. Covered positions must contain null. Default 1. |\n| `rowSpan` | no | `integer` | Number of grid rows covered, starting at this cell. Covered positions must contain null. Header cells cannot span into body rows. Default 1. |\n\n\n### TableCellStyle\n\n- Type: `object`\n- Required fields: none\n- Purpose: Cell appearance. Sizes use reference pixels at a 720-pixel canvas short edge and scale with the slide.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `fill` | no | `ref:ColorRef` | 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. |\n| `color` | no | `ref:ColorRef` | 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. |\n| `align` | no | `enum:left \\| center \\| right` | Horizontal text alignment inside the cell. |\n| `verticalAlign` | no | `enum:top \\| middle \\| bottom` | Vertical alignment inside the padded cell box. |\n| `padding` | no | `ref:TableCellPadding` | |\n| `borders` | no | `object` | Independent cell edges. Omitted edges retain the table theme border; width 0 removes an edge. |\n\n\n### TableCellPadding\n\n- Type: `object`\n- Required fields: none\n- Purpose: Text insets in reference pixels. Defaults: top 8, right 10, bottom 4, left 10.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `top` | no | `number` | |\n| `right` | no | `number` | |\n| `bottom` | no | `number` | |\n| `left` | no | `number` | |\n\n\n### TableCellBorder\n\n- Type: `object`\n- Required fields: `color`, `width`\n- Purpose: One explicit cell border.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `color` | yes | `ref:ColorRef` | 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. |\n| `width` | yes | `number` | Border width in reference pixels; 0 removes this edge. |\n| `dash` | no | `enum:solid \\| dash \\| dot` | Default solid. |\n\n\n### Catalogs\n\n- Type: `object`\n- Required fields: none\n- Purpose: Catalog overrides for the in-document references. Every property is optional. The default catalog for a kind lives at https://www.pptx.gallery/<kind> (e.g. https://www.pptx.gallery/narratives, https://www.pptx.gallery/themes). For each kind, declaring a 'source' replaces the default registry and/or 'records' adds inline records that take precedence over anything fetched from a source. Resolution order for any reference (e.g. narrative, design.theme): inline catalogs.<kind>.records[] catalogs....\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `narratives` | no | `ref:CatalogEntry` | Catalog of narrative templates. Records validate against https://openpresentation.org/schema/opf-narrative/v1. Default source: https://www.pptx.gallery/narratives. |\n| `themes` | no | `ref:CatalogEntry` | Catalog of themes. Records validate against https://openpresentation.org/schema/opf-theme/v1. Default source: https://www.pptx.gallery/themes. |\n| `colorSchemes` | no | `ref:CatalogEntry` | Catalog of color schemes. Records validate against https://openpresentation.org/schema/opf-color-scheme/v1. Default source: https://www.pptx.gallery/color-schemes. |\n| `fontSchemes` | no | `ref:CatalogEntry` | Catalog of font schemes. Records validate against https://openpresentation.org/schema/opf-font-scheme/v1. Default source: https://www.pptx.gallery/font-schemes. |\n| `languages` | no | `ref:CatalogEntry` | Catalog of languages. Records validate against https://openpresentation.org/schema/opf-language/v1. Default source: https://www.pptx.gallery/languages. |\n| `layouts` | no | `ref:CatalogEntry` | Catalog of slide layouts. Records validate against https://openpresentation.org/schema/opf-layout/v1. Default source: https://www.pptx.gallery/layouts. |\n| `chartTypes` | no | `ref:CatalogEntry` | Catalog of chart types. Records validate against https://openpresentation.org/schema/opf-chart-type/v1. Default source: https://www.pptx.gallery/chart-types. |\n| `tones` | no | `ref:CatalogEntry` | Catalog of presentation tones. Records validate against https://openpresentation.org/schema/opf-tone/v1. Default source: https://www.pptx.gallery/tones. Referenced from tone. |\n| `purposes` | no | `ref:CatalogEntry` | Catalog of presentation purposes. Records validate against https://openpresentation.org/schema/opf-purpose/v1. Default source: https://www.pptx.gallery/purposes. Referenced from purpose. |\n| `audiences` | no | `ref:CatalogEntry` | Catalog of presentation audiences. Records validate against https://openpresentation.org/schema/opf-audience/v1. Default source: https://www.pptx.gallery/audiences. Referenced from audience. |\n| `socialPlatforms` | no | `ref:CatalogEntry` | Catalog of social-media platforms. Records validate against https://openpresentation.org/schema/opf-social-platform/v1. Default source: https://www.pptx.gallery/social-platforms. Referenced via the property keys of an... |\n\n\n### CatalogEntry\n\n- Type: `object`\n- Required fields: none\n- Purpose: A catalog override for one record kind. 'source' replaces the default registry; 'records' adds inline records that take precedence over anything fetched from a source. Either or both may be provided; both omitted means the kind uses its default catalog.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `source` | no | `oneOf:ref:CatalogSource / array<ref:CatalogSource>` | Single source or an ordered search path of sources. When omitted, the engine falls back to https://www.pptx.gallery/<kind>. |\n| `records` | no | `array<object>` | Inline catalog records embedded in this OPF document. Each record validates against the kind's companion schema (e.g. https://openpresentation.org/schema/opf-narrative/v1 for narratives). Inline records win over anyth... |\n\n\n### CatalogSource\n\n- Type: `string`\n- Required fields: none\n- Purpose: Catalog source location. Accepts: - A bare URL pointing at a catalog directory (e.g. 'https://acme.com/decks/narratives'); record ids resolve to '<base>/<id>.json'. - A URL pointing at an index file (e.g. 'https://acme.com/decks/narratives/index.json'); records are resolved relative to the index file's directory and the index entries describe what's available. - A package reference of the form 'pkg:<package>[/<subpath>]'; resolved through a locally-installed package on the engine's package path.\n\n_No named properties._\n\n\n### Composition\n\n- Type: `object`\n- Required fields: none\n- Purpose: Portable dynamic composition. Slide fields override the resolved layout. Nested groups arrange their children independently, inheriting only minFontSize and overflow. Explicit promoted regions retain their positions.\n\n| Field | Required | Type | Notes |\n| --- | --- | --- | --- |\n| `mode` | no | `enum:auto \\| grid \\| row \\| column` | auto chooses a grid from available space and content; grid uses columns; row and column use one horizontal or vertical track. |\n| `columns` | no | `integer` | Column count for grid. In auto mode this caps the number of columns. |\n| `gap` | no | `number` | Space between cells as a fraction of the container short edge (canvas at slide root). Default 0.03333333333333333. |\n| `padding` | no | `number` | Inset as a fraction of the container short edge. Default 0.08 on a slide, 0 inside a group. |\n| `weights` | no | `array<number>` | Relative track sizes: columns for row/grid/auto, rows for column. Omitted tracks have weight 1; extra weights are ignored. |\n| `minFontSize` | no | `number` | 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. |\n| `overflow` | no | `enum:warn \\| error` | warn returns diagnostics for content that does not fit; error rejects layout. Content is never silently removed. Default warn. |\n"
|
|
176
200
|
},
|
|
177
201
|
{
|
|
178
202
|
"slug": "security-2026-09-09",
|
|
@@ -186,6 +210,12 @@ var docsData = Object.freeze([
|
|
|
186
210
|
"title": "OpenPresentation status \u2014 September 15, 2026",
|
|
187
211
|
"markdown": "# OpenPresentation status \u2014 September 15, 2026\n\nThe public JSON/slide demo and reusable authoring foundation are available.\nShared headers/footers are validated on main. Four unfinished shaping prototypes\nare preserved on remote archive branches and tracked in the roadmap; their\noriginal PRs conclude with documentation/evidence changes only.\n\nRead the [current handoff](handoff-2026-09-15.md),\n[next-agent prompt](next-agent-prompt-2026-09-15.md) and\n[developer adoption roadmap](plans/developer-adoption-20260915.md).\nEarlier dated checkpoints are historical evidence, not current release claims.\n\n| Area | Current state |\n| --- | --- |\n| Public demo | Home/playground support editable OPF JSON, live preview, preview edits back to JSON, contextual catalog choices and normal code-editor assistance. Appearance is preserved. |\n| Published packages | Core0.10.0, renderer0.8.0, editor0.7.0, PPTX0.8.0 and CLI0.8.0 were confirmed in the registry. This final cleanup publishes no additional versions. |\n| Developer foundation | Schemas/catalogs, six agent skills, contextual lint/contracts, source-preserving edits/undo, composition/pagination, preview and supported exports exist. Feature and platform limits apply. |\n| Shared headers/footers | Core79, renderer20, editor17 and PPTX34 are merged with passing main CI. This increment needs new coordinated versions and consumer adoption. |\n| Font shaping/prepared editing | Core83, renderer21, editor21 and PPTX35 retain complete prototypes on archive branches. Final PR diffs contain roadmap/evidence only. Linux native-width failures and an editor packed-test assertion remain recorded, not waived. |\n| Native PowerPoint | Acceptance is separately tracked in core issue87. Serialization and self-import do not certify Office. |\n| Production checks | Latest retained deployed checks passed 26 main-site, five gallery and ten pptx.dev workflows. See the handoff for commits/evidence. |\n\nThe original twenty-PR queue comprises eleven accepted dependency updates,\nfour accepted furniture increments, four roadmap-only conclusions and one\nclosed Node26-types update because the ecosystem targets Node24. Check the\nlinked PR states for final merge/check receipts; merging a roadmap does not\nrelease its archived prototype.\n\nNext: release the accepted increment, provide one independently installable\ndeveloper example with current API/version docs, and adopt shared behavior\nacross the public sites. Broader font/IME/bidi coverage, native Office evidence,\nlayout repair and full visual-editor coverage remain roadmap work. Selectable\nvector PDF and general SVG/Mermaid follow font reliability.\n"
|
|
188
212
|
},
|
|
213
|
+
{
|
|
214
|
+
"slug": "status-2026-09-16",
|
|
215
|
+
"file": "docs/status-2026-09-16.md",
|
|
216
|
+
"title": "OpenPresentation status \u2014 September 16, 2026",
|
|
217
|
+
"markdown": "# OpenPresentation status \u2014 September 16, 2026\n\nTreat [status-2026-09-15](status-2026-09-15.md) as the previous checkpoint.\nLive npm is **newer** than that file: core 0.10.1, renderer/PPTX/CLI 0.8.1,\neditor 0.7.1, all Node 24.\n\n| Area | Current state |\n| --- | --- |\n| Published packages | `@openpresentation/opf@0.10.1`, `opf-render@0.8.1`, `opf-editor@0.7.1`, `opf-pptx@0.8.1`, `cli@0.8.1` |\n| Shared headers/footers | In that published set (`furniture-flow-v2`) |\n| Developer starting path | [Quickstart](quickstart.md) plus [compatibility matrix](compatibility-matrix.md). Prove with `pnpm test:developer-quickstart` (fresh registry install). Fixture: `docs/quickstart/developer-quickstart.opf.json`, not the 126-deck examples catalog. |\n| Public-site adoption | Still [issue 88](https://github.com/OpenPresentation/opf/issues/88). Not claimed done by this docs PR. |\n| Renderer native widths | Still [opf-render#24](https://github.com/OpenPresentation/opf-render/issues/24) |\n| Native PowerPoint | Still [issue 87](https://github.com/OpenPresentation/opf/issues/87) |\n| Archived shaping | Remote `codex/archive-shaping-20260915` branches; not in npm |\n\nPDF remains raster-backed. The CLI does not render. An empty PR queue does not\nfinish the ecosystem objective.\n"
|
|
218
|
+
},
|
|
189
219
|
{
|
|
190
220
|
"slug": "table-text-colors",
|
|
191
221
|
"file": "docs/table-text-colors.md",
|