@openpresentation/opf 0.26.10 → 0.28.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/README.md +6 -0
- package/dist/browser.js +20 -17
- package/dist/{catalog-refs-BSfGELpt.d.ts → catalog-refs-kAefsZWT.d.ts} +2 -1
- package/dist/{catalog-schemas-DoxA2BgY.d.ts → catalog-schemas-CC1d_h8s.d.ts} +3 -2
- package/dist/{chart-data-BnNqgnC-.d.ts → chart-data-Ci9s_NDN.d.ts} +2 -1
- package/dist/{chunk-XRMV2GMB.js → chunk-2CUCYENF.js} +758 -232
- package/dist/chunk-43JWUIGF.js +8 -0
- package/dist/{chunk-F4HFDP6I.js → chunk-5Q4IYLMW.js} +31 -15
- package/dist/{chunk-GIWNHRTX.js → chunk-BQUWRXTR.js} +4 -4
- package/dist/chunk-CR72ZJ6W.js +236 -0
- package/dist/{chunk-L52N5FZZ.js → chunk-F6DCEGB3.js} +6 -6
- package/dist/chunk-GM7WFPGG.js +10 -0
- package/dist/chunk-JBARNYFR.js +23 -0
- package/dist/{chunk-EQ6S5SEZ.js → chunk-KELC4K62.js} +1 -1
- package/dist/{chunk-77KL2PMM.js → chunk-KXKN3W5Z.js} +3 -3
- package/dist/{chunk-D25BNPTW.js → chunk-LLEXM7TQ.js} +4 -4
- package/dist/{chunk-3S2XVDPN.js → chunk-MTFK7QEY.js} +6 -6
- package/dist/{chunk-TKQ2VFV5.js → chunk-N77N4AOD.js} +1 -1
- package/dist/{chunk-NVT2YDVC.js → chunk-OAIAFXMS.js} +2 -2
- package/dist/{chunk-PHP45MO7.js → chunk-P6PKYJTS.js} +1 -1
- package/dist/{chunk-H7XMO36O.js → chunk-PCU4XGKV.js} +5 -5
- package/dist/{chunk-Y4TZCE7R.js → chunk-SEZ4EPW6.js} +2 -2
- package/dist/{chunk-Y25DYRME.js → chunk-TNUTRV6E.js} +1 -1
- package/dist/{chunk-G5WJMJV3.js → chunk-UOHWG4OS.js} +1 -1
- package/dist/{chunk-A54NGT2K.js → chunk-VGGPAMP7.js} +2 -2
- package/dist/{chunk-IVPA6NG6.js → chunk-WPKCWQ6W.js} +494 -120
- package/dist/{chunk-VZBFQLCA.js → chunk-XZ23FORL.js} +6 -6
- package/dist/chunk-ZROVYWGU.js +1 -0
- package/dist/{composition-DIftf6iP.d.ts → composition-C-hd_Ci3.d.ts} +134 -14
- package/dist/composition.d.ts +3 -3
- package/dist/composition.js +2 -1
- package/dist/conversion-XJTDWQ5W.js +24 -0
- package/dist/{conversion-ChmGA8Ul.d.ts → conversion-hbZeS5kD.d.ts} +8 -7
- package/dist/convert.d.ts +6 -5
- package/dist/convert.js +9 -7
- package/dist/data.d.ts +4 -3
- package/dist/data.js +3 -2
- package/dist/{deck-report-5vwMGcQz.d.ts → deck-report-DQMsvyBI.d.ts} +5 -4
- package/dist/deck.d.ts +9 -8
- package/dist/deck.js +13 -11
- package/dist/diff.d.ts +3 -2
- package/dist/diff.js +6 -4
- package/dist/docs.d.ts +2 -1
- package/dist/docs.js +33 -19
- package/dist/examples.d.ts +3 -2
- package/dist/examples.js +92 -50
- package/dist/{explain-JSuESV-Y.d.ts → explain-iZeNOUc6.d.ts} +2 -1
- package/dist/font-policy.d.ts +2 -1
- package/dist/font-policy.js +1 -0
- package/dist/format.d.ts +2 -1
- package/dist/format.js +3 -2
- package/dist/ids.d.ts +114 -0
- package/dist/ids.js +6 -0
- package/dist/index.d.ts +40 -16
- package/dist/index.js +24 -21
- package/dist/markdown.d.ts +8 -7
- package/dist/markdown.js +10 -8
- package/dist/node-engine.d.ts +33 -10
- package/dist/node-engine.js +37 -28
- package/dist/{pagination-D_kJe4jH.d.ts → pagination-DyAKYpXu.d.ts} +4 -3
- package/dist/pagination.d.ts +4 -4
- package/dist/pagination.js +6 -4
- package/dist/patch.d.ts +89 -4
- package/dist/patch.js +5 -3
- package/dist/precompiled.d.ts +2 -0
- package/dist/precompiled.js +7 -0
- package/dist/{presentation-Bwo8Ko6D.d.ts → presentation-8jLSTFqL.d.ts} +11 -11
- package/dist/repo-readme.js +3 -1
- package/dist/schema-engine-ajv.js +37 -0
- package/dist/schema-engine-precompiled.js +3 -0
- package/dist/schema.d.ts +4 -3
- package/dist/schema.js +5 -3
- package/dist/schemas.d.ts +2 -1
- package/dist/schemas.js +2 -1
- package/dist/source.d.ts +5 -4
- package/dist/source.js +12 -10
- package/dist/spec/README.md +1 -1
- package/dist/spec/schemas/audience.schema.json +1 -0
- package/dist/spec/schemas/catalog-index.schema.json +1 -0
- package/dist/spec/schemas/catalog-manifest.schema.json +1 -0
- package/dist/spec/schemas/chart-type.schema.json +1 -0
- package/dist/spec/schemas/color-scheme.schema.json +1 -0
- package/dist/spec/schemas/finding.schema.json +1 -0
- package/dist/spec/schemas/font-scheme.schema.json +1 -0
- package/dist/spec/schemas/language.schema.json +1 -0
- package/dist/spec/schemas/layout-preview-index.schema.json +1 -0
- package/dist/spec/schemas/layout.schema.json +8 -6
- package/dist/spec/schemas/narrative.schema.json +1 -0
- package/dist/spec/schemas/opf.schema.json +9 -8
- package/dist/spec/schemas/purpose.schema.json +1 -0
- package/dist/spec/schemas/social-platform.schema.json +1 -0
- package/dist/spec/schemas/theme.schema.json +3 -1
- package/dist/spec/schemas/tone.schema.json +1 -0
- package/dist/spec-files.d.ts +2 -1
- package/dist/spec-files.js +1 -0
- package/dist/symbol-font-encodings.d.ts +2 -1
- package/dist/symbol-font-encodings.js +2 -0
- package/dist/types.d.ts +9 -9
- package/dist/{validation-types-3ARvTsB0.d.ts → validation-types-mNmfcY9A.d.ts} +4 -3
- package/dist/validator.d.ts +8 -8
- package/dist/validator.js +5 -3
- package/dist/yaml.d.ts +8 -7
- package/dist/yaml.js +9 -7
- package/package.json +30 -9
- package/dist/conversion-IVKCKMCN.js +0 -21
|
@@ -500,7 +500,7 @@ type ContentPayload = {
|
|
|
500
500
|
mediaType?: string;
|
|
501
501
|
});
|
|
502
502
|
/**
|
|
503
|
-
* Image payloads only. How the picture fills its frame: 'cover' fills it and crops what overflows around focus; 'contain' shows the whole picture
|
|
503
|
+
* Image payloads only. How the picture fills its frame: 'cover' fills it and crops what overflows around focus; 'contain' shows the whole picture, in a frame of its own proportions placed at the region's anchor (top by default); 'stretch' scales it to the frame exactly. Default: the effective design.imageFit, else 'cover' in a layout and 'contain' on a slide with no layout.
|
|
504
504
|
*/
|
|
505
505
|
fit?: ("cover" | "contain" | "stretch");
|
|
506
506
|
focus?: ImageFocus1;
|
|
@@ -1202,7 +1202,7 @@ interface Design {
|
|
|
1202
1202
|
*/
|
|
1203
1203
|
titleAlignment?: ("left" | "center" | "right");
|
|
1204
1204
|
/**
|
|
1205
|
-
* Default horizontal alignment for body/content regions in resolved layouts. Effective value: the slide's design, then the deck's design, then the theme's design.contentAlignment, then the layout record's design.contentAlignment, then the engine default. The tag follows titleAlignment (and a
|
|
1205
|
+
* Default horizontal alignment for body/content regions in resolved layouts. Effective value: the slide's design, then the deck's design, then the theme's design.contentAlignment, then the layout record's design.contentAlignment, then the engine default. The tag follows titleAlignment (and so does a subtitle in the title area, as on a cover) unless the slide's own design sets contentAlignment.
|
|
1206
1206
|
*/
|
|
1207
1207
|
contentAlignment?: ("left" | "center" | "right");
|
|
1208
1208
|
/**
|
|
@@ -1218,13 +1218,13 @@ interface Design {
|
|
|
1218
1218
|
*/
|
|
1219
1219
|
chartPrimary?: ("none" | "top" | "bottom" | "left" | "right");
|
|
1220
1220
|
/**
|
|
1221
|
-
* Default fit of image blocks (and Slide.image) that set no fit of their own: 'cover' fills the frame and crops what overflows around the block's focus, 'contain' shows the whole picture centered
|
|
1221
|
+
* Default fit of image blocks (and Slide.image) that set no fit of their own: 'cover' fills the frame and crops what overflows around the block's focus, 'contain' shows the whole picture in a frame of its own proportions, centered across and placed down the cell by the region's anchor (top by default), 'stretch' scales it to the frame exactly. Effective value: the slide's design, then the deck's design, then the theme's design.imageFit, then the layout record's design.imageFit, then 'cover'; a slide composed with no layout shows its pictures whole ('contain') instead. Backgrounds set their own fit.
|
|
1222
1222
|
*/
|
|
1223
1223
|
imageFit?: ("cover" | "contain" | "stretch");
|
|
1224
1224
|
/**
|
|
1225
|
-
* Marker style for items and bullets lists. Effective value: the slide's design, then the deck's design, then the theme's design.listBullet, then the layout record's design.listBullet, then 'character'. 'character' (the default) draws the glyph marker. 'image' draws the primary organization's icon logo (or the organization and shape design.logo names; the onDark value on dark backgrounds) as a picture bullet: a square with side 0.65 times the marker's font size whose bottom sits on the marker baseline, so list geometry does not change. Without a logo the glyph is drawn and the engine reports unresolved-content at this field.
|
|
1225
|
+
* Marker style for items and bullets lists. Effective value: the slide's design, then the deck's design, then the theme's design.listBullet, then the layout record's design.listBullet, then 'character'. 'character' (the default) draws the glyph marker. 'image' draws the primary organization's icon logo (or the organization and shape design.logo names; the onDark value on dark backgrounds) as a picture bullet: a square with side 0.65 times the marker's font size whose bottom sits on the marker baseline, so list geometry does not change. Without a logo the glyph is drawn and the engine reports unresolved-content at this field. 'none' draws no marker and no hanging indent, so each entry's text (and its description) starts at the left edge of the list: use it for label-and-description lists such as pillars, team members and questions with answers. Nested levels keep their indent. A list that sets numbering still draws its numbers.
|
|
1226
1226
|
*/
|
|
1227
|
-
listBullet?: ("character" | "image");
|
|
1227
|
+
listBullet?: ("character" | "image" | "none");
|
|
1228
1228
|
/**
|
|
1229
1229
|
* Draw the slide's template layout mirrored (OPF 0.19): each row's cells and the column sizes reversed, so a 'beside' layout puts its picture, chart or table at the end. Logical: a right-to-left deck mirrors on top. Binding and reading order do not change. Effective value: the slide's design, then the deck's design, then the layout record's design.mirror, then false. Slides without a template layout ignore it.
|
|
1230
1230
|
*/
|
|
@@ -2393,7 +2393,7 @@ interface Chart {
|
|
|
2393
2393
|
highlight?: ChartHighlight;
|
|
2394
2394
|
}
|
|
2395
2395
|
/**
|
|
2396
|
-
* Inline tabular data driving a chart. The first column usually supplies category/x-axis labels; subsequent columns are plotted measures unless 'chart.mapping' or a chart type maps them differently. Value cells are numbers; a string is read only in strict decimal syntax ('12', '-3.5', '1e6'), and anything else ('12%', '$5', '(5)', '1,234') is a gap and a 'chart-value-not-numeric' warning.
|
|
2396
|
+
* Inline tabular data driving a chart, written as `{ "columns": ["Quarter", "Decks"], "rows": [["Q1", 3], ["Q2", 8]] }`: one column of labels plus one column per series, not separate `categories` and `series` lists. The first column usually supplies category/x-axis labels; subsequent columns are plotted measures unless 'chart.mapping' or a chart type maps them differently. Value cells are numbers; a string is read only in strict decimal syntax ('12', '-3.5', '1e6'), and anything else ('12%', '$5', '(5)', '1,234') is a gap and a 'chart-value-not-numeric' warning.
|
|
2397
2397
|
*
|
|
2398
2398
|
* This interface was referenced by `Presentation`'s JSON-Schema
|
|
2399
2399
|
* via the `definition` "ChartData".
|
|
@@ -2634,7 +2634,7 @@ interface TableCellStyle {
|
|
|
2634
2634
|
verticalAlign?: ("top" | "middle" | "bottom");
|
|
2635
2635
|
padding?: TableCellPadding;
|
|
2636
2636
|
/**
|
|
2637
|
-
* Independent cell edges.
|
|
2637
|
+
* Independent cell edges. An omitted edge keeps the table's default rule: a line under every row (and over the first row), none between columns. Width 0 removes an edge.
|
|
2638
2638
|
*/
|
|
2639
2639
|
borders?: {
|
|
2640
2640
|
top?: TableCellBorder;
|
|
@@ -3049,7 +3049,7 @@ interface Design1 {
|
|
|
3049
3049
|
*/
|
|
3050
3050
|
titleAlignment?: ("left" | "center" | "right");
|
|
3051
3051
|
/**
|
|
3052
|
-
* Default horizontal alignment for body/content regions in resolved layouts. Effective value: the slide's design, then the deck's design, then the theme's design.contentAlignment, then the layout record's design.contentAlignment, then the engine default. The tag follows titleAlignment (and a
|
|
3052
|
+
* Default horizontal alignment for body/content regions in resolved layouts. Effective value: the slide's design, then the deck's design, then the theme's design.contentAlignment, then the layout record's design.contentAlignment, then the engine default. The tag follows titleAlignment (and so does a subtitle in the title area, as on a cover) unless the slide's own design sets contentAlignment.
|
|
3053
3053
|
*/
|
|
3054
3054
|
contentAlignment?: ("left" | "center" | "right");
|
|
3055
3055
|
/**
|
|
@@ -3065,13 +3065,13 @@ interface Design1 {
|
|
|
3065
3065
|
*/
|
|
3066
3066
|
chartPrimary?: ("none" | "top" | "bottom" | "left" | "right");
|
|
3067
3067
|
/**
|
|
3068
|
-
* Default fit of image blocks (and Slide.image) that set no fit of their own: 'cover' fills the frame and crops what overflows around the block's focus, 'contain' shows the whole picture centered
|
|
3068
|
+
* Default fit of image blocks (and Slide.image) that set no fit of their own: 'cover' fills the frame and crops what overflows around the block's focus, 'contain' shows the whole picture in a frame of its own proportions, centered across and placed down the cell by the region's anchor (top by default), 'stretch' scales it to the frame exactly. Effective value: the slide's design, then the deck's design, then the theme's design.imageFit, then the layout record's design.imageFit, then 'cover'; a slide composed with no layout shows its pictures whole ('contain') instead. Backgrounds set their own fit.
|
|
3069
3069
|
*/
|
|
3070
3070
|
imageFit?: ("cover" | "contain" | "stretch");
|
|
3071
3071
|
/**
|
|
3072
|
-
* Marker style for items and bullets lists. Effective value: the slide's design, then the deck's design, then the theme's design.listBullet, then the layout record's design.listBullet, then 'character'. 'character' (the default) draws the glyph marker. 'image' draws the primary organization's icon logo (or the organization and shape design.logo names; the onDark value on dark backgrounds) as a picture bullet: a square with side 0.65 times the marker's font size whose bottom sits on the marker baseline, so list geometry does not change. Without a logo the glyph is drawn and the engine reports unresolved-content at this field.
|
|
3072
|
+
* Marker style for items and bullets lists. Effective value: the slide's design, then the deck's design, then the theme's design.listBullet, then the layout record's design.listBullet, then 'character'. 'character' (the default) draws the glyph marker. 'image' draws the primary organization's icon logo (or the organization and shape design.logo names; the onDark value on dark backgrounds) as a picture bullet: a square with side 0.65 times the marker's font size whose bottom sits on the marker baseline, so list geometry does not change. Without a logo the glyph is drawn and the engine reports unresolved-content at this field. 'none' draws no marker and no hanging indent, so each entry's text (and its description) starts at the left edge of the list: use it for label-and-description lists such as pillars, team members and questions with answers. Nested levels keep their indent. A list that sets numbering still draws its numbers.
|
|
3073
3073
|
*/
|
|
3074
|
-
listBullet?: ("character" | "image");
|
|
3074
|
+
listBullet?: ("character" | "image" | "none");
|
|
3075
3075
|
/**
|
|
3076
3076
|
* Draw the slide's template layout mirrored (OPF 0.19): each row's cells and the column sizes reversed, so a 'beside' layout puts its picture, chart or table at the end. Logical: a right-to-left deck mirrors on top. Binding and reading order do not change. Effective value: the slide's design, then the deck's design, then the layout record's design.mirror, then false. Slides without a template layout ignore it.
|
|
3077
3077
|
*/
|
package/dist/repo-readme.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import './chunk-GM7WFPGG.js';
|
|
2
|
+
|
|
1
3
|
// src/generated/repo-readme.ts
|
|
2
|
-
var repoReadmeRaw = '# Open Presentation Format (OPF)\n\n[](https://www.npmjs.com/package/@openpresentation/opf)\n[](https://www.npmjs.com/package/@openpresentation/opf)\n[](./LICENSE)\n[](https://github.com/OpenPresentation/opf/actions/workflows/ci.yml)\n[](https://github.com/OpenPresentation/opf/actions/workflows/nightly.yml)\n\nPublic npm package: [`@openpresentation/opf`](https://www.npmjs.com/package/@openpresentation/opf) (`npm install @openpresentation/opf`).\n\nOpen Presentation Format is the portable, human-readable JSON document format for slide decks.\n\nThis repository is the canonical home for the OPF **spec**, **JSON Schemas**, **catalog presets**, examples, generated developer types, local validation tooling, and integration docs for the render/edit/convert toolkit. OpenPresentation publishes open-source code and documentation only; it does not provide hosted APIs, hosted rendering functions, queues, storage, authentication, jobs, previews, SLAs, telemetry, or managed infrastructure.\n\nFor AI agents, use the [OPF skill set](docs/agent-skills.md) for authoring, layout, presets, editing, export, and schema inspection.\n\nPublished CLI 0.18.0 installs all six skills into your project with `npx @openpresentation/cli@0.18.0 skills install`. It uses local copies, preserves existing instructions and refuses to overwrite customized skills. See the [installation and update guide](docs/agent-skills.md) for personal or agent-specific targets and source development.\n\nFor a fresh Node 24 project that installs **published** packages (not this\ncheckout), follow the [developer quickstart](docs/quickstart.md) and the\n[compatibility matrix](docs/compatibility-matrix.md).\n\nFor LLM authoring, start with [the authoring guide](docs/llm-authoring.md), [dynamic composition](docs/dynamic-composition.md), and [local ecosystem verification](docs/ecosystem-development.md).\n\n## File naming\n\nOpen Presentation Format documents are JSON files. Use `*.opf.json` for complete OPF presentation documents, for example `board-review.opf.json` or `deck.opf.json`.\n\nAvoid using bare `*.opf` for OPF JSON. The `.opf` extension is already used by other document and project formats, while `.opf.json` keeps the OPF identity and still makes the underlying JSON format clear to editors, validators, agents, and version-control tooling.\n\n## Naming and reuse\n\nThe format name is **Open Presentation Format**. The schemas, catalogs, packages, and local tooling in this repository are free and open source under the MIT license, so third-party tools may read, write, validate, render, convert, and describe support for Open Presentation Format without adopting any product-specific branding.\n\n## Why OPF\n\n`.pptx` is a zipped bundle of XML. Humans can\'t diff it, LLMs can\'t read or write it reliably, and git can\'t track it meaningfully. Every change looks like a binary blob.\n\nOPF is plain JSON. A human can open it in an editor. A model can read and write it without guessing at schema-by-example. Decks live in git like the rest of your work.\n\nThat\'s the shift that lets LLMs actually *author* decks. When the format stops fighting them, models can do the work that matters \u2014 narrative structure, persuasive framing, data analysis, chart recommendations, ruthless revision passes \u2014 instead of wrestling with `<p:sp>` tags.\n\nAnd they don\'t start from a blank canvas. [pptx.gallery](https://pptx.gallery) is the human-browsable reference for OPF catalog presets: layouts, themes, color schemes, font schemes, chart types, narratives, audiences, purposes, tones, languages, and social platforms.\n\n## Start in three steps\n\n1. **Install the coordinated published packages** on Node 24. See [the developer quickstart](docs/quickstart.md) for the currently recorded registry pin set: core, renderer, PPTX, editor, CLI and Gallery, all at the shared version 0.26.1. The default catalog is supplied by `@openpresentation/gallery@0.26.1`; see the [compatibility matrix](docs/compatibility-matrix.md) for feature and native limits.\n2. **Author, validate, paginate, preview and export.** New to OPF? Run the [first deck](docs/first-deck/README.md) end to end first. Copy [`docs/quickstart/developer-quickstart.opf.json`](./docs/quickstart/developer-quickstart.opf.json) and run the commands in that guide. From code, `convert("deck.opf.md", "deck.pdf")` of `@openpresentation/opf` is the simple path to a PDF, PNG, SVG or PPTX file. `validate` / `opf validate` is one local checker for format, references, accessibility, layout and content ([guide](docs/validate.md)), not visual verification.\n3. **Know the limits.** PPTX export writes one text box per wrapped line, so text edited in PowerPoint or Keynote does not reflow (see [rich text](docs/rich-text.md)) unless you opt in to `--body-text native` (opf-pptx and CLI 0.22.0 or later), and fonts are named, not embedded. The [compatibility matrix](docs/compatibility-matrix.md) lists shipped APIs versus renderer issue 24, native PowerPoint issue 87, and other deferred work. Browse presets at [pptx.gallery](https://pptx.gallery).\n\nYour deck can live in git from the first commit. After installing dependencies and supplying referenced assets, these commands run locally without a model provider, account or hosted OPF API.\n\n## JavaScript and TypeScript\n\nThe canonical JavaScript/TypeScript package is published at [`packages/javascript`](./packages/javascript) as [`@openpresentation/opf`](https://www.npmjs.com/package/@openpresentation/opf). The schema is pre-stable (0.x \u2014 expect breaking changes between minor versions until 1.0). Its responsibility is local and format-level only:\n\n- export the canonical schemas from [`spec/`](./spec)\n- register the pptx.gallery catalog of [`@openpresentation/gallery`](./packages/gallery) (a dependency, released with core at the same version) as the Node defaults, as the CLI does; a browser host registers it itself\n- export a typed raw spec file manifest for package-addressable `spec/` content\n- generate TypeScript types, with `Presentation` as the top-level type\n- validate OPF JSON and catalog records locally\n\nIn Node (and Bun and Deno) its root also reads and writes files (`convert`, `open`, `save`) and draws them through the optional engines below; in a browser or a worker the same import is a browser-safe build with the same names, where those three reject with `node-only`. Every other entry runs in a browser. It does not generate content with AI, fetch remote catalogs, call hosted APIs, or provide managed services. Render/edit/convert packages live in this repository as separate MIT packages that depend on `@openpresentation/opf`. The format package also exposes pure composition geometry so those packages share layout behavior.\n\n## Toolkit libraries\n\nOPF is six packages. **Core** (`@openpresentation/opf`) is the format and its API: it reads and writes the text formats (JSON, YAML, Markdown) and validates, and in Node reads and writes files, through the same import. **The gallery** (`@openpresentation/gallery`) is the pptx.gallery catalog of layouts, themes, colour and font schemes and the other records, released with the other packages; core depends on it and registers it in Node. **The CLI** (`@openpresentation/cli`) is the `opf` command. **Render** (`opf-render`), **PPTX** (`opf-pptx`) and **the editor** (`opf-editor`) are the engines: drawing, PowerPoint and editing, installed as needed. All six live in this repository (`packages/`) and are released together at one version. See [ecosystem development](docs/ecosystem-development.md) for local builds and verification, and [dynamic composition](docs/dynamic-composition.md) for portable layout rules.\n\n| Package | Role | Boundary |\n|---|---|---|\n| [`packages/javascript`](./packages/javascript) (`@openpresentation/opf`) | Core: format, schemas, validation, composition | The format and its API; reads and writes files in Node and draws through the optional engines |\n| [`packages/gallery`](./packages/gallery) (`@openpresentation/gallery`) | The pptx.gallery catalog | Catalog records only, no runtime dependency; records are authored by pull request here, and a changed drawing or a removed record needs a minor release |\n| [`packages/cli`](./packages/cli) (`@openpresentation/cli`) | `opf` command | Runs core\'s Node engine: reads and writes files and calls the engines below as optional peers |\n| [`packages/render`](./packages/render) (`@openpresentation/opf-render`) | OPF to SVG/PNG/PDF | Local and embeddable rendering library |\n| [`packages/editor`](./packages/editor) (`@openpresentation/opf-editor`) | WYSIWYG bindings/components | Headless editor primitives plus optional UI components |\n| [`packages/pptx`](./packages/pptx) (`@openpresentation/opf-pptx`) | OPF to PPTX and PPTX to OPF | Pure local import/export library for browser and server use where supported |\n\nThese packages provide OSS primitives only. Downstream applications own hosting, auth, storage, collaboration, queues, previews, analytics, support, and workflow UX.\n\n## Usage\n\nInstall from npm:\n\n```sh\npnpm add @openpresentation/opf\n# or: npm install @openpresentation/opf\n```\n\nTo work on the packages, clone this repo and build the workspace (all six packages are in `packages/`; see [CONTRIBUTING](./CONTRIBUTING.md)):\n\n```sh\npnpm install\npnpm build\n```\n\nUse the format package from JavaScript or TypeScript:\n\n```ts\nimport { presentation, validate } from "@openpresentation/opf";\nimport { gallery } from "@openpresentation/gallery";\n\nimport type { Presentation } from "@openpresentation/opf";\n\nconst deck: Presentation = {\n name: "Quarterly Review",\n slides: [{ title: "Quarterly Review", items: ["Revenue", "Product", "Hiring"] }],\n};\n\nconst report = validate(deck);\nconsole.log(report.valid); // no finding has severity "error"\nconsole.log(report.findings); // every finding: rule id, severity, category, JSON Pointer path, message, fixes\n// Core ships no catalog records; in Node, validate registers the gallery when a call names no catalogs, and a host may name its own.\nconsole.log(validate({ ...deck, design: { theme: "classic" } }, { catalogs: [gallery] }).valid);\nconsole.log(Object.keys(gallery.audiences).length);\n```\n\nConvert, open and save files in Node with `@openpresentation/opf`, the same import a browser uses (the engines `@openpresentation/opf-render` and `@openpresentation/opf-pptx` are optional peers, installed as needed; see [OPF files in Node](docs/node.md)):\n\n```ts\nimport * as opf from "@openpresentation/opf";\n\nawait opf.convert("deck.opf.md", "deck.pdf");\nconst deck = await opf.open("deck.opf.md");\ndeck.slides.push({ title: "Q4" });\nawait opf.save(deck, "deck.opf.md");\nconst { files } = await opf.convert(deck, { format: "pptx" }); // bytes, nothing written\n```\n\nUse focused imports when you only need one surface:\n\n```ts\nimport { presentation } from "@openpresentation/opf/schemas";\nimport { specFileEntries } from "@openpresentation/opf/spec-files";\nimport { validate } from "@openpresentation/opf/validator";\nimport type { Presentation } from "@openpresentation/opf/types";\n```\n\nUse raw JSON when an engine or resolver needs package-addressable files:\n\n```ts\nimport presentationSchema from "@openpresentation/opf/spec/schemas/opf.schema.json" with {\n type: "json",\n};\n```\n\nUse the [installable OPF CLI](./packages/cli/README.md) to create, validate, and edit files locally:\n\n```sh\npnpm --filter @openpresentation/cli build\nnode packages/cli/dist/index.js create deck.opf.json --title "Decision brief"\nnode packages/cli/dist/index.js validate deck.opf.json\nnode packages/cli/dist/index.js edit deck.opf.json --patch changes.json --in-place\n```\n\nSee [CSV and JSON data import](./docs/data-import.md) for editable tables and charts in the editor, CLI, and package API, and [content conversions](./docs/conversions.md) for the pure converters (`@openpresentation/opf/convert`) that change a block\'s kind, nest list items, restructure a slide and split or merge slides, and [Markdown and outlines](./docs/markdown.md) for the deterministic Markdown dialect (`@openpresentation/opf/markdown`, `opf convert deck.md deck.opf.json`) that reads and writes a whole deck as text.\n\n[OPF as YAML](./docs/yaml.md) describes the strict YAML form of a deck (`@openpresentation/opf/yaml`, `opf convert deck.opf.json deck.opf.yaml`, `.opf.yaml` files in every command, editor autocomplete); JSON stays the canonical form. A deck can equally be a Markdown file, `deck.opf.md`: every command reads and writes it (see [Markdown decks in every command](./docs/markdown.md#markdown-decks-in-every-command)), and `parse` / `stringify` read and write a deck in JSON, YAML or Markdown with one call.\n\nSee [Templates and variables](./docs/templates-and-variables.md) for fillable OPF templates: typed variables, `{{id}}` tokens, `opf fill` and `resolveVariables`.\n\n## Layout\n\n| Path | Contents |\n|---|---|\n| [`spec/schemas/opf.schema.json`](./spec/schemas/opf.schema.json) | Canonical JSON Schema for top-level OPF `Presentation` documents. |\n| [`docs/how-opf-works.md`](./docs/how-opf-works.md) | Conceptual introduction: the document model, content shapes, catalog resolution, and the validation philosophy. Start here. |\n| [`docs/slide-design-principles.md`](./docs/slide-design-principles.md) | Timeless principles for slide layout, typography, spacing, visual balance, and reviewing layout defaults. |\n| [`docs/design-resolution.md`](./docs/design-resolution.md) | The design precedence algorithm (slide design \u2192 deck design \u2192 resolved theme \u2192 engine defaults) with worked examples. |\n| [`docs/schema-reference.md`](./docs/schema-reference.md) | Author-facing reference for top-level OPF fields and every presentation schema `$defs` object/type. |\n| [`docs/slide-sizes.md`](./docs/slide-sizes.md) | OPF\'s slide-size presets in inches, points and EMU, how they compare with PowerPoint\'s presets, and what PPTX export and import do with them. |\n| [`docs/catalog-schema-reference.md`](./docs/catalog-schema-reference.md) | Author-facing reference for every companion catalog schema. |\n| [`docs/content-payloads.md`](./docs/content-payloads.md) | Author-facing notes for slide and region content payloads, including chart and table object shapes. |\n| [`docs/footnotes-citations-captions.md`](./docs/footnotes-citations-captions.md) | Citations (`cite`), inline footnotes, the deck `references` list, captions on images, charts, tables and videos, and how every engine draws them. |\n| [`docs/examples.md`](./docs/examples.md) | Guide to the expanded scenario-oriented examples under `examples/gallery/`. |\n| [`docs/live-editor.md`](./docs/live-editor.md) | Browser canvas, live OPF editing, font loading, published packages, and current fidelity limits. |\n| [`docs/release-process.md`](./docs/release-process.md) | Maintainer runbook for the one-click release: gate, tag, trusted npm publishing of all six packages, verification, GitHub release notes, and the site bumps. |\n| [`spec/schemas/*.schema.json`](./spec/schemas) | Companion schemas for catalog records and sub-objects. |\n| [`packages/gallery`](./packages/gallery) (`@openpresentation/gallery`) | The default catalog and layout previews, released with the other packages. |\n| [`spec/openapi.yaml`](./spec/openapi.yaml) | Optional reference OpenAPI contract for downstream services that choose to expose OPF over HTTP. OpenPresentation does not host this API. |\n| [`examples/technical/`](./examples/technical) | Focused OPF fixtures for validator, renderer, catalog-resolution, design, content-payload, and region behavior. |\n| [`examples/gallery/`](./examples/gallery) | Broader OPF example decks organized by industry, function, education, government, presentation type, international, and design/media scenarios. |\n| [`packages/javascript/`](./packages/javascript) | Public pre-stable source for `@openpresentation/opf`. |\n| [`packages/cli/`](./packages/cli) | Installable local CLI for creating, validating, editing, and inspecting OPF. |\n| [`legacy/`](./legacy) | Tombstone for service-specific clients, CLIs, tool integrations, and workflows removed from the OpenPresentation OSS repo. |\n\n## OpenPresentation Boundary\n\nOpenPresentation defines the format, bundled presets, local validation, examples, docs, and planned local render/edit/convert libraries. It does not provide hosted functions or managed product surfaces.\n\nFuture non-JavaScript OPF packages should follow the same local-first boundary: Python and Go packages should expose schemas, types/models, catalogs, validation, and package-addressable assets. Future toolkit packages should expose embeddable library APIs with no required network calls, hosted callbacks, hidden telemetry, or managed infrastructure assumptions.\n\nThe published JavaScript package copies package-addressable OPF schemas, catalogs, reference assets, and the optional reference `spec/openapi.yaml` from `spec/`. It intentionally remains `@openpresentation/opf` instead of introducing a separate `@openpresentation/opf-spec` package so downstream imports can advance by semver-pinning one canonical package.\n\n## License\n\nMIT. See [LICENSE](./LICENSE).\n';
|
|
4
|
+
var repoReadmeRaw = '<p align="center">\n <picture>\n <source media="(prefers-color-scheme: dark)" srcset="docs/brand/opf-logo-dark.svg">\n <img src="docs/brand/opf-logo.svg" alt="Open Presentation Format" width="64" height="64">\n </picture>\n</p>\n\n# Open Presentation Format (OPF)\n\n[](https://www.npmjs.com/package/@openpresentation/opf)\n[](https://www.npmjs.com/package/@openpresentation/opf)\n[](./LICENSE)\n[](https://github.com/OpenPresentation/opf/actions/workflows/ci.yml)\n[](https://github.com/OpenPresentation/opf/actions/workflows/nightly.yml)\n\nPublic npm package: [`@openpresentation/opf`](https://www.npmjs.com/package/@openpresentation/opf) (`npm install @openpresentation/opf`).\n\nOpen Presentation Format is the portable, human-readable JSON document format for slide decks.\n\nThis repository is the canonical home for the OPF **spec**, **JSON Schemas**, **catalog presets**, examples, generated developer types, local validation tooling, and integration docs for the render/edit/convert toolkit. OpenPresentation publishes open-source code and documentation only; it does not provide hosted APIs, hosted rendering functions, queues, storage, authentication, jobs, previews, SLAs, telemetry, or managed infrastructure.\n\nFor AI agents, use the [OPF skill set](docs/agent-skills.md) for authoring, layout, presets, editing, export, and schema inspection.\n\nPublished CLI 0.18.0 installs all six skills into your project with `npx @openpresentation/cli@0.18.0 skills install`. It uses local copies, preserves existing instructions and refuses to overwrite customized skills. See the [installation and update guide](docs/agent-skills.md) for personal or agent-specific targets and source development.\n\nFor a fresh Node 24 project that installs **published** packages (not this\ncheckout), follow the [developer quickstart](docs/quickstart.md) and the\n[compatibility matrix](docs/compatibility-matrix.md).\n\nFor LLM authoring, start with [the authoring guide](docs/llm-authoring.md), [dynamic composition](docs/dynamic-composition.md), and [local ecosystem verification](docs/ecosystem-development.md).\n\n## File naming\n\nOpen Presentation Format documents are JSON files. Use `*.opf.json` for complete OPF presentation documents, for example `board-review.opf.json` or `deck.opf.json`.\n\nAvoid using bare `*.opf` for OPF JSON. The `.opf` extension is already used by other document and project formats, while `.opf.json` keeps the OPF identity and still makes the underlying JSON format clear to editors, validators, agents, and version-control tooling.\n\n## Naming and reuse\n\nThe format name is **Open Presentation Format**. The schemas, catalogs, packages, and local tooling in this repository are free and open source under the MIT license, so third-party tools may read, write, validate, render, convert, and describe support for Open Presentation Format without adopting any product-specific branding.\n\n## Why OPF\n\n`.pptx` is a zipped bundle of XML. Humans can\'t diff it, LLMs can\'t read or write it reliably, and git can\'t track it meaningfully. Every change looks like a binary blob.\n\nOPF is plain JSON. A human can open it in an editor. A model can read and write it without guessing at schema-by-example. Decks live in git like the rest of your work.\n\nThat\'s the shift that lets LLMs actually *author* decks. When the format stops fighting them, models can do the work that matters \u2014 narrative structure, persuasive framing, data analysis, chart recommendations, ruthless revision passes \u2014 instead of wrestling with `<p:sp>` tags.\n\nAnd they don\'t start from a blank canvas. [pptx.gallery](https://pptx.gallery) is the human-browsable reference for OPF catalog presets: layouts, themes, color schemes, font schemes, chart types, narratives, audiences, purposes, tones, languages, and social platforms.\n\n## Start in three steps\n\n1. **Install the coordinated published packages** on Node 24. See [the developer quickstart](docs/quickstart.md) for the currently recorded registry pin set: core, renderer, PPTX, editor, CLI and Gallery, all at the shared version 0.26.1. The default catalog is supplied by `@openpresentation/gallery@0.26.1`; see the [compatibility matrix](docs/compatibility-matrix.md) for feature and native limits.\n2. **Author, validate, paginate, preview and export.** New to OPF? Run the [first deck](docs/first-deck/README.md) end to end first. Copy [`docs/quickstart/developer-quickstart.opf.json`](./docs/quickstart/developer-quickstart.opf.json) and run the commands in that guide. From code, `convert("deck.opf.md", "deck.pdf")` of `@openpresentation/opf` is the simple path to a PDF, PNG, SVG or PPTX file. `validate` / `opf validate` is one local checker for format, references, accessibility, layout and content ([guide](docs/validate.md)), not visual verification.\n3. **Know the limits.** PPTX export writes one text box per wrapped line, so text edited in PowerPoint or Keynote does not reflow (see [rich text](docs/rich-text.md)) unless you opt in to `--body-text native` (opf-pptx and CLI 0.22.0 or later), and fonts are named, not embedded. The [compatibility matrix](docs/compatibility-matrix.md) lists shipped APIs versus renderer issue 24, native PowerPoint issue 87, and other deferred work. Browse presets at [pptx.gallery](https://pptx.gallery).\n\nYour deck can live in git from the first commit. After installing dependencies and supplying referenced assets, these commands run locally without a model provider, account or hosted OPF API.\n\n## JavaScript and TypeScript\n\nThe canonical JavaScript/TypeScript package is published at [`packages/javascript`](./packages/javascript) as [`@openpresentation/opf`](https://www.npmjs.com/package/@openpresentation/opf). The schema is pre-stable (0.x \u2014 expect breaking changes between minor versions until 1.0). Its responsibility is local and format-level only:\n\n- export the canonical schemas from [`spec/`](./spec)\n- register the pptx.gallery catalog of [`@openpresentation/gallery`](./packages/gallery) (a dependency, released with core at the same version) as the Node defaults, as the CLI does; a browser host registers it itself\n- export a typed raw spec file manifest for package-addressable `spec/` content\n- generate TypeScript types, with `Presentation` as the top-level type\n- validate OPF JSON and catalog records locally\n\nIn Node (and Bun and Deno) its root also reads and writes files (`convert`, `open`, `save`) and draws them through the optional engines below; in a browser or a worker the same import is a browser-safe build with the same names, where those three reject with `node-only`. Every other entry runs in a browser. It does not generate content with AI, fetch remote catalogs, call hosted APIs, or provide managed services. Render/edit/convert packages live in this repository as separate MIT packages that depend on `@openpresentation/opf`. The format package also exposes pure composition geometry so those packages share layout behavior.\n\n## Toolkit libraries\n\nOPF is seven packages. **Core** (`@openpresentation/opf`) is the format and its API: it reads and writes the text formats (JSON, YAML, Markdown) and validates, and in Node reads and writes files, through the same import. **The gallery** (`@openpresentation/gallery`) is the pptx.gallery catalog of layouts, themes, colour and font schemes and the other records, released with the other packages; core depends on it and registers it in Node. **The CLI** (`@openpresentation/cli`) is the `opf` command. **The MCP server** (`@openpresentation/mcp`, `npx -y @openpresentation/mcp`) lets an MCP-native agent learn OPF (docs, schemas, catalog, examples and skills as resources) and validate and convert decks. **Render** (`opf-render`), **PPTX** (`opf-pptx`) and **the editor** (`opf-editor`) are the engines: drawing, PowerPoint and editing, installed as needed. All seven live in this repository (`packages/`) and are released together at one version. See [ecosystem development](docs/ecosystem-development.md) for local builds and verification, and [dynamic composition](docs/dynamic-composition.md) for portable layout rules.\n\n| Package | Role | Boundary |\n|---|---|---|\n| [`packages/javascript`](./packages/javascript) (`@openpresentation/opf`) | Core: format, schemas, validation, composition | The format and its API; reads and writes files in Node and draws through the optional engines |\n| [`packages/gallery`](./packages/gallery) (`@openpresentation/gallery`) | The pptx.gallery catalog | Catalog records only, no runtime dependency; records are authored by pull request here, and a changed drawing or a removed record needs a minor release |\n| [`packages/cli`](./packages/cli) (`@openpresentation/cli`) | `opf` command | Runs core\'s Node engine: reads and writes files and calls the engines below as optional peers |\n| [`packages/render`](./packages/render) (`@openpresentation/opf-render`) | OPF to SVG/PNG/PDF | Local and embeddable rendering library |\n| [`packages/editor`](./packages/editor) (`@openpresentation/opf-editor`) | WYSIWYG bindings/components | Headless editor primitives plus optional UI components |\n| [`packages/pptx`](./packages/pptx) (`@openpresentation/opf-pptx`) | OPF to PPTX and PPTX to OPF | Pure local import/export library for browser and server use where supported |\n\nThese packages provide OSS primitives only. Downstream applications own hosting, auth, storage, collaboration, queues, previews, analytics, support, and workflow UX.\n\n## Usage\n\nInstall from npm:\n\n```sh\npnpm add @openpresentation/opf\n# or: npm install @openpresentation/opf\n```\n\nTo work on the packages, clone this repo and build the workspace (all seven packages are in `packages/`; see [CONTRIBUTING](./CONTRIBUTING.md)):\n\n```sh\npnpm install\npnpm build\n```\n\nUse the format package from JavaScript or TypeScript:\n\n```ts\nimport { presentation, validate } from "@openpresentation/opf";\nimport { gallery } from "@openpresentation/gallery";\n\nimport type { Presentation } from "@openpresentation/opf";\n\nconst deck: Presentation = {\n name: "Quarterly Review",\n slides: [{ title: "Quarterly Review", items: ["Revenue", "Product", "Hiring"] }],\n};\n\nconst report = validate(deck);\nconsole.log(report.valid); // no finding has severity "error"\nconsole.log(report.findings); // every finding: rule id, severity, category, JSON Pointer path, message, fixes\n// Core ships no catalog records; in Node, validate registers the gallery when a call names no catalogs, and a host may name its own.\nconsole.log(validate({ ...deck, design: { theme: "classic" } }, { catalogs: [gallery] }).valid);\nconsole.log(Object.keys(gallery.audiences).length);\n```\n\nConvert, open and save files in Node with `@openpresentation/opf`, the same import a browser uses (the engines `@openpresentation/opf-render` and `@openpresentation/opf-pptx` are optional peers, installed as needed; see [OPF files in Node](docs/node.md)):\n\n```ts\nimport * as opf from "@openpresentation/opf";\n\nawait opf.convert("deck.opf.md", "deck.pdf");\nconst deck = await opf.open("deck.opf.md");\ndeck.slides.push({ title: "Q4" });\nawait opf.save(deck, "deck.opf.md");\nconst { files } = await opf.convert(deck, { format: "pptx" }); // bytes, nothing written\n```\n\nUse focused imports when you only need one surface:\n\n```ts\nimport { presentation } from "@openpresentation/opf/schemas";\nimport { specFileEntries } from "@openpresentation/opf/spec-files";\nimport { validate } from "@openpresentation/opf/validator";\nimport type { Presentation } from "@openpresentation/opf/types";\n```\n\nUse raw JSON when an engine or resolver needs package-addressable files:\n\n```ts\nimport presentationSchema from "@openpresentation/opf/spec/schemas/opf.schema.json" with {\n type: "json",\n};\n```\n\nUse the [installable OPF CLI](./packages/cli/README.md) to create, validate, and edit files locally:\n\n```sh\npnpm --filter @openpresentation/cli build\nnode packages/cli/dist/index.js create deck.opf.json --title "Decision brief"\nnode packages/cli/dist/index.js validate deck.opf.json\nnode packages/cli/dist/index.js edit deck.opf.json --patch changes.json --in-place\n```\n\nSee [CSV and JSON data import](./docs/data-import.md) for editable tables and charts in the editor, CLI, and package API, and [content conversions](./docs/conversions.md) for the pure converters (`@openpresentation/opf/convert`) that change a block\'s kind, nest list items, restructure a slide and split or merge slides, and [Markdown and outlines](./docs/markdown.md) for the deterministic Markdown dialect (`@openpresentation/opf/markdown`, `opf convert deck.md deck.opf.json`) that reads and writes a whole deck as text.\n\n[OPF as YAML](./docs/yaml.md) describes the strict YAML form of a deck (`@openpresentation/opf/yaml`, `opf convert deck.opf.json deck.opf.yaml`, `.opf.yaml` files in every command, editor autocomplete); JSON stays the canonical form. A deck can equally be a Markdown file, `deck.opf.md`: every command reads and writes it (see [Markdown decks in every command](./docs/markdown.md#markdown-decks-in-every-command)), and `parse` / `stringify` read and write a deck in JSON, YAML or Markdown with one call.\n\nSee [Templates and variables](./docs/templates-and-variables.md) for fillable OPF templates: typed variables, `{{id}}` tokens, `opf fill` and `resolveVariables`.\n\n## Layout\n\n| Path | Contents |\n|---|---|\n| [`spec/schemas/opf.schema.json`](./spec/schemas/opf.schema.json) | Canonical JSON Schema for top-level OPF `Presentation` documents. |\n| [`docs/how-opf-works.md`](./docs/how-opf-works.md) | Conceptual introduction: the document model, content shapes, catalog resolution, and the validation philosophy. Start here. |\n| [`docs/slide-design-principles.md`](./docs/slide-design-principles.md) | Timeless principles for slide layout, typography, spacing, visual balance, and reviewing layout defaults. |\n| [`docs/design-resolution.md`](./docs/design-resolution.md) | The design precedence algorithm (slide design \u2192 deck design \u2192 resolved theme \u2192 engine defaults) with worked examples. |\n| [`docs/schema-reference.md`](./docs/schema-reference.md) | Author-facing reference for top-level OPF fields and every presentation schema `$defs` object/type. |\n| [`docs/slide-sizes.md`](./docs/slide-sizes.md) | OPF\'s slide-size presets in inches, points and EMU, how they compare with PowerPoint\'s presets, and what PPTX export and import do with them. |\n| [`docs/catalog-schema-reference.md`](./docs/catalog-schema-reference.md) | Author-facing reference for every companion catalog schema. |\n| [`docs/content-payloads.md`](./docs/content-payloads.md) | Author-facing notes for slide and region content payloads, including chart and table object shapes. |\n| [`docs/footnotes-citations-captions.md`](./docs/footnotes-citations-captions.md) | Citations (`cite`), inline footnotes, the deck `references` list, captions on images, charts, tables and videos, and how every engine draws them. |\n| [`docs/examples.md`](./docs/examples.md) | Guide to the expanded scenario-oriented examples under `examples/gallery/`. |\n| [`docs/live-editor.md`](./docs/live-editor.md) | Browser canvas, live OPF editing, font loading, published packages, and current fidelity limits. |\n| [`docs/release-process.md`](./docs/release-process.md) | Maintainer runbook for the one-click release: gate, tag, trusted npm publishing of all seven packages, verification, GitHub release notes, and the site bumps. |\n| [`spec/schemas/*.schema.json`](./spec/schemas) | Companion schemas for catalog records and sub-objects. |\n| [`packages/gallery`](./packages/gallery) (`@openpresentation/gallery`) | The default catalog and layout previews, released with the other packages. |\n| [`spec/openapi.yaml`](./spec/openapi.yaml) | Optional reference OpenAPI contract for downstream services that choose to expose OPF over HTTP. OpenPresentation does not host this API. |\n| [`examples/technical/`](./examples/technical) | Focused OPF fixtures for validator, renderer, catalog-resolution, design, content-payload, and region behavior. |\n| [`examples/gallery/`](./examples/gallery) | Broader OPF example decks organized by industry, function, education, government, presentation type, international, and design/media scenarios. |\n| [`packages/javascript/`](./packages/javascript) | Public pre-stable source for `@openpresentation/opf`. |\n| [`packages/cli/`](./packages/cli) | Installable local CLI for creating, validating, editing, and inspecting OPF. |\n| [`legacy/`](./legacy) | Tombstone for service-specific clients, CLIs, tool integrations, and workflows removed from the OpenPresentation OSS repo. |\n\n## OpenPresentation Boundary\n\nOpenPresentation defines the format, bundled presets, local validation, examples, docs, and planned local render/edit/convert libraries. It does not provide hosted functions or managed product surfaces.\n\nFuture non-JavaScript OPF packages should follow the same local-first boundary: Python and Go packages should expose schemas, types/models, catalogs, validation, and package-addressable assets. Future toolkit packages should expose embeddable library APIs with no required network calls, hosted callbacks, hidden telemetry, or managed infrastructure assumptions.\n\nThe published JavaScript package copies package-addressable OPF schemas, catalogs, reference assets, and the optional reference `spec/openapi.yaml` from `spec/`. It intentionally remains `@openpresentation/opf` instead of introducing a separate `@openpresentation/opf-spec` package so downstream imports can advance by semver-pinning one canonical package.\n\n## License\n\nMIT. See [LICENSE](./LICENSE).\n';
|
|
3
5
|
|
|
4
6
|
// src/repo-readme.ts
|
|
5
7
|
var repoReadme = repoReadmeRaw;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { installedSchemaEngine } from './chunk-43JWUIGF.js';
|
|
2
|
+
import { qualifyBranch } from './chunk-JBARNYFR.js';
|
|
3
|
+
import { schemas } from './chunk-5Q4IYLMW.js';
|
|
4
|
+
import './chunk-GM7WFPGG.js';
|
|
5
|
+
import Ajv2020 from 'ajv/dist/2020.js';
|
|
6
|
+
import addFormats from 'ajv-formats';
|
|
7
|
+
|
|
8
|
+
var ajv;
|
|
9
|
+
var branches = /* @__PURE__ */ new WeakMap();
|
|
10
|
+
function getAjv() {
|
|
11
|
+
if (ajv) return ajv;
|
|
12
|
+
const instance = new Ajv2020({ allErrors: true, verbose: true, strict: false, allowUnionTypes: true });
|
|
13
|
+
addFormats(instance);
|
|
14
|
+
for (const schema of Object.values(schemas)) instance.addSchema(schema);
|
|
15
|
+
ajv = instance;
|
|
16
|
+
return instance;
|
|
17
|
+
}
|
|
18
|
+
var engine = {
|
|
19
|
+
root(name) {
|
|
20
|
+
const schema = schemas[name];
|
|
21
|
+
return getAjv().getSchema(schema.$id) ?? getAjv().compile(schema);
|
|
22
|
+
},
|
|
23
|
+
definition(name, definition) {
|
|
24
|
+
return getAjv().getSchema(`${schemas[name].$id}#/$defs/${definition}`);
|
|
25
|
+
},
|
|
26
|
+
branch(branch, rootId) {
|
|
27
|
+
let validate = branches.get(branch);
|
|
28
|
+
if (!validate) {
|
|
29
|
+
validate = getAjv().compile(qualifyBranch(branch, rootId));
|
|
30
|
+
branches.set(branch, validate);
|
|
31
|
+
}
|
|
32
|
+
return validate;
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
var schemaEngine = () => installedSchemaEngine() ?? engine;
|
|
36
|
+
|
|
37
|
+
export { schemaEngine };
|
package/dist/schema.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { C as CatalogRecordKind } from './catalog-schemas-
|
|
1
|
+
import { C as CatalogRecordKind } from './catalog-schemas-CC1d_h8s.js';
|
|
2
2
|
import { SchemaName } from './schemas.js';
|
|
3
|
-
import './catalog-refs-
|
|
3
|
+
import './catalog-refs-kAefsZWT.js';
|
|
4
4
|
import './json-BFSdESOE.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -162,4 +162,5 @@ declare function describeField(path: OpfPath, document?: unknown): FieldInfo;
|
|
|
162
162
|
*/
|
|
163
163
|
declare function catalogKindAt(path: OpfPath, document?: unknown): CatalogRecordKind | undefined;
|
|
164
164
|
|
|
165
|
-
export { COMMON_KEYS, CatalogRecordKind,
|
|
165
|
+
export { COMMON_KEYS, CatalogRecordKind, UNRANKED_PRIORITY, activeSchema, catalogKindAt, createSchemaValue, describeField, isPromotedRegionKey, listSchemaFields, resolveSchema, schemaAtPath, schemaCatalogKinds, schemaLabel, schemaType, schemaVariants, splitOpfPath };
|
|
166
|
+
export type { EnumValue, FieldChild, FieldInfo, JsonSchema, OpfPath, SchemaField, SchemaNodeKey, SchemaRoot, VariantInfo };
|
package/dist/schema.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
export { COMMON_KEYS, UNRANKED_PRIORITY, activeSchema, catalogKindAt, createSchemaValue, describeField, isPromotedRegionKey, listSchemaFields, resolveSchema, schemaAtPath, schemaCatalogKinds, schemaLabel, schemaType, schemaVariants, splitOpfPath } from './chunk-
|
|
2
|
-
import './chunk-
|
|
3
|
-
import './chunk-
|
|
1
|
+
export { COMMON_KEYS, UNRANKED_PRIORITY, activeSchema, catalogKindAt, createSchemaValue, describeField, isPromotedRegionKey, listSchemaFields, resolveSchema, schemaAtPath, schemaCatalogKinds, schemaLabel, schemaType, schemaVariants, splitOpfPath } from './chunk-WPKCWQ6W.js';
|
|
2
|
+
import './chunk-JBARNYFR.js';
|
|
3
|
+
import './chunk-5Q4IYLMW.js';
|
|
4
|
+
import './chunk-2CUCYENF.js';
|
|
5
|
+
import './chunk-GM7WFPGG.js';
|
package/dist/schemas.d.ts
CHANGED
|
@@ -293,4 +293,5 @@ interface SchemaEntry {
|
|
|
293
293
|
}
|
|
294
294
|
declare const schemaEntries: readonly SchemaEntry[];
|
|
295
295
|
|
|
296
|
-
export {
|
|
296
|
+
export { audience, chartType, colorScheme, fontScheme, language, layout, narrative, presentation, purpose, schemaEntries, schemaNames, schemas, socialPlatform, theme, tone };
|
|
297
|
+
export type { SchemaEntry, SchemaName };
|
package/dist/schemas.js
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export { audience, chartType, colorScheme, fontScheme, language, layout, narrative, presentation, purpose, schemaEntries, schemaNames, schemas, socialPlatform, theme, tone } from './chunk-
|
|
1
|
+
export { audience, chartType, colorScheme, fontScheme, language, layout, narrative, presentation, purpose, schemaEntries, schemaNames, schemas, socialPlatform, theme, tone } from './chunk-5Q4IYLMW.js';
|
|
2
|
+
import './chunk-GM7WFPGG.js';
|
package/dist/source.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { F as FindingTextContext, a as FindingText } from './explain-
|
|
3
|
-
export { R as RuleExplanation, d as distance, e as explain, n as nearest, s as pointerSegments } from './explain-
|
|
1
|
+
import { FindingLocation, Finding } from './index.js';
|
|
2
|
+
import { F as FindingTextContext, a as FindingText } from './explain-iZeNOUc6.js';
|
|
3
|
+
export { R as RuleExplanation, d as distance, e as explain, n as nearest, s as pointerSegments } from './explain-iZeNOUc6.js';
|
|
4
4
|
|
|
5
5
|
/** Keys of `<!-- slide: ... -->`. */
|
|
6
6
|
declare const SLIDE_OPTION_KEYS: readonly ["id", "type", "layout", "section", "tag", "hidden", "beat"];
|
|
@@ -273,4 +273,5 @@ interface AnalyzeYamlOptions {
|
|
|
273
273
|
*/
|
|
274
274
|
declare function analyzeYamlSyntax(text: string, options?: AnalyzeYamlOptions): YamlSyntaxProblem[];
|
|
275
275
|
|
|
276
|
-
export {
|
|
276
|
+
export { BLOCK_AS_VALUES, BLOCK_OPTION_KEYS, FENCE_ATTRIBUTES, FENCE_KINDS, FindingText, FindingTextContext, LINE_KEYWORDS, METRIC_KEYS, PATTERN_PHRASES, SLIDE_OPTION_KEYS, SPAN_FLAGS, SPAN_VALUES, analyzeJsonSyntax, analyzeYamlSyntax, applyTextEdits, describeFinding, locate, pathAt, scanMarkdown, starterValue };
|
|
277
|
+
export type { AnalyzeOptions, AnalyzeYamlOptions, LocateOptions, LocatePart, MarkdownCommentScan, MarkdownFenceScan, MarkdownFrontMatter, MarkdownNotesScan, MarkdownScan, MarkdownSlideScan, PathAtResult, PatternPhrase, ScanMarkdownOptions, ScanRange, SourceFormat, SyntaxFix, SyntaxProblem, SyntaxProblemCode, TextEdit, TextRange, YamlProblemCode, YamlSyntaxProblem };
|
package/dist/source.js
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
export { explain } from './chunk-
|
|
2
|
-
import { readMarkdown, frontMatter, splitSegments, isOutline, NOTES, fenceStart, fenceClose, COMMENT } from './chunk-
|
|
3
|
-
import './chunk-
|
|
4
|
-
import { splitLines } from './chunk-
|
|
5
|
-
export { analyzeYamlSyntax } from './chunk-
|
|
6
|
-
import './chunk-
|
|
7
|
-
import { rememberByText, SLIDE_OPTION_KEYS, FENCE_KINDS, createLocator, parsePointer } from './chunk-
|
|
8
|
-
export { BLOCK_AS_VALUES, BLOCK_OPTION_KEYS, FENCE_ATTRIBUTES, FENCE_KINDS, LINE_KEYWORDS, METRIC_KEYS, PATTERN_PHRASES, SLIDE_OPTION_KEYS, SPAN_FLAGS, SPAN_VALUES, analyzeJsonSyntax, applyTextEdits, describeFinding, distance, nearest, segmentsOf as pointerSegments, starterValue } from './chunk-
|
|
9
|
-
import './chunk-
|
|
10
|
-
import './chunk-
|
|
1
|
+
export { explain } from './chunk-UOHWG4OS.js';
|
|
2
|
+
import { readMarkdown, frontMatter, splitSegments, isOutline, NOTES, fenceStart, fenceClose, COMMENT } from './chunk-PCU4XGKV.js';
|
|
3
|
+
import './chunk-P6PKYJTS.js';
|
|
4
|
+
import { splitLines } from './chunk-SEZ4EPW6.js';
|
|
5
|
+
export { analyzeYamlSyntax } from './chunk-SEZ4EPW6.js';
|
|
6
|
+
import './chunk-TNUTRV6E.js';
|
|
7
|
+
import { rememberByText, SLIDE_OPTION_KEYS, FENCE_KINDS, createLocator, parsePointer } from './chunk-WPKCWQ6W.js';
|
|
8
|
+
export { BLOCK_AS_VALUES, BLOCK_OPTION_KEYS, FENCE_ATTRIBUTES, FENCE_KINDS, LINE_KEYWORDS, METRIC_KEYS, PATTERN_PHRASES, SLIDE_OPTION_KEYS, SPAN_FLAGS, SPAN_VALUES, analyzeJsonSyntax, applyTextEdits, describeFinding, distance, nearest, segmentsOf as pointerSegments, starterValue } from './chunk-WPKCWQ6W.js';
|
|
9
|
+
import './chunk-JBARNYFR.js';
|
|
10
|
+
import './chunk-5Q4IYLMW.js';
|
|
11
|
+
import './chunk-2CUCYENF.js';
|
|
12
|
+
import './chunk-GM7WFPGG.js';
|
|
11
13
|
import { findNodeAtOffset, getNodePath, parseTree } from 'jsonc-parser';
|
|
12
14
|
import { parseDocument, isMap, isSeq, isScalar, isAlias } from 'yaml';
|
|
13
15
|
|
package/dist/spec/README.md
CHANGED
|
@@ -17,7 +17,7 @@ New to the format? Read [`docs/how-opf-works.md`](../docs/how-opf-works.md) firs
|
|
|
17
17
|
|
|
18
18
|
## Layout templates and previews
|
|
19
19
|
|
|
20
|
-
The gallery package's `catalog/layouts/` contains the
|
|
20
|
+
The gallery package's `catalog/layouts/` contains the 30 v2 intent templates that `Slide.layout` resolves against. They are ordered lists of regions with content rules, nested for two dimensions; examples include `cover`, `text`, `chart` and `two-column`.
|
|
21
21
|
|
|
22
22
|
`previews/layouts/` contains one self-contained SVG preview for each template, keyed by the same layout id. Its version-2 index names the SVG filename and exact UTF-8 byte length. Picker thumbnails therefore show the template the slide will use.
|
|
23
23
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://openpresentation.org/schema/opf-audience/v1",
|
|
4
|
+
"$comment": "The v1 in the $id is the pre-1.0 line, not a frozen contract: this schema may change in any 0.x minor release. The release that produced this copy is the version of the @openpresentation/opf package it came from (opf --version; opf schemas lists it next to each id). See docs/schema-versioning.md.",
|
|
4
5
|
"title": "Audience",
|
|
5
6
|
"description": "Schema for audience records. Each record names an audience archetype (e.g. 'executive', 'engineering-team', 'investor') and carries seniority, technical-fluency, decision-power, and attention-budget hints used by AI-driven generation. Documents reference an audience from 'audience', which also accepts free-form text.\n\nA document references a record as a bare id or 'name:id' and resolves it in its own catalogs groups first, then in the catalog the host registered for the group's source; engines never fetch a catalog. A published record file carries '$schema' and 'id'; the copy a document embeds under catalogs.<group>.<kind>.<id> carries neither (the key is the id) and no 'x-*' display metadata.",
|
|
6
7
|
"type": "object",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://openpresentation.org/schema/opf-catalog-index/v1",
|
|
4
|
+
"$comment": "The v1 in the $id is the pre-1.0 line, not a frozen contract: this schema may change in any 0.x minor release. The release that produced this copy is the version of the @openpresentation/opf package it came from (opf --version; opf schemas lists it next to each id). See docs/schema-versioning.md.",
|
|
4
5
|
"title": "Catalog Index",
|
|
5
6
|
"description": "Generic shape shared by every `<kind>/index.json` file of the @openpresentation/gallery package (packages/gallery/catalog in the OPF repo) and by the default-catalog index that pptx.gallery publishes at `https://www.pptx.gallery/<kind>/index.json` (the gallery package is a pinned snapshot of that catalog; see docs/default-catalog.md). 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`, `duration`). This schema describes catalog index files themselves, not OPF documents or individual catalog records — it is not part of the OPF document contract and is intentionally excluded from the package's published/typed schema surface.",
|
|
6
7
|
"type": "object",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://openpresentation.org/schema/opf-catalog-manifest/v1",
|
|
4
|
+
"$comment": "The v1 in the $id is the pre-1.0 line, not a frozen contract: this schema may change in any 0.x minor release. The release that produced this copy is the version of the @openpresentation/opf package it came from (opf --version; opf schemas lists it next to each id). See docs/schema-versioning.md.",
|
|
4
5
|
"title": "Catalog Snapshot Manifest",
|
|
5
6
|
"description": "Shape of the `manifest.json` of the @openpresentation/gallery package (packages/gallery/catalog/manifest.json), which pins the snapshot of the default OPF catalog published by pptx.gallery. It records the gallery commit the snapshot came from and, per kind, how the snapshot relates to the published catalog plus a content hash of the bundled records. Written by scripts/sync-gallery-catalog.mjs and checked by scripts/check-spec-integrity.mjs; see docs/default-catalog.md. This schema describes a repo-internal file, not an OPF document or a catalog record; it is intentionally excluded from the package's published/typed schema surface.",
|
|
6
7
|
"type": "object",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://openpresentation.org/schema/opf-chart-type/v1",
|
|
4
|
+
"$comment": "The v1 in the $id is the pre-1.0 line, not a frozen contract: this schema may change in any 0.x minor release. The release that produced this copy is the version of the @openpresentation/opf package it came from (opf --version; opf schemas lists it next to each id). See docs/schema-versioning.md.",
|
|
4
5
|
"title": "Chart Type",
|
|
5
6
|
"description": "Schema for chart-type records: display metadata for chart pickers (name, group, expected series, complexity) and the Open XML mapping a picker can describe. One record per chart type that Aspose.Slides officially supports (see mappings.renderers[\"aspose-slides\"].chartType), plus the column-and-line combination 'combo'. A document's chart.type is an engine vocabulary validated directly; engines never look a chart-type record up. pptx.gallery publishes these records and @openpresentation/gallery ships them as catalogDisplay.chartTypes.",
|
|
6
7
|
"type": "object",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://openpresentation.org/schema/opf-color-scheme/v1",
|
|
4
|
+
"$comment": "The v1 in the $id is the pre-1.0 line, not a frozen contract: this schema may change in any 0.x minor release. The release that produced this copy is the version of the @openpresentation/opf package it came from (opf --version; opf schemas lists it next to each id). See docs/schema-versioning.md.",
|
|
4
5
|
"title": "Color Scheme",
|
|
5
6
|
"description": "Schema for color-scheme records. 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. Documents reference a scheme from design.colorScheme (or design.colorScheme.id) and from a theme's colorScheme; slot overrides on design.colorScheme take precedence over the resolved scheme.\n\nThe slot fields here mirror the inline-override fields on the in-document ColorScheme type (in opf.schema.json), so records and inline OPF overrides are interchangeable.\n\nA document references a record as a bare id or 'name:id' and resolves it in its own catalogs groups first, then in the catalog the host registered for the group's source; engines never fetch a catalog. A published record file carries '$schema' and 'id'; the copy a document embeds under catalogs.<group>.<kind>.<id> carries neither (the key is the id) and no 'x-*' display metadata.",
|
|
6
7
|
"type": "object",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://openpresentation.org/schema/opf-finding/v1",
|
|
4
|
+
"$comment": "The v1 in the $id is the pre-1.0 line, not a frozen contract: this schema may change in any 0.x minor release. The release that produced this copy is the version of the @openpresentation/opf package it came from (opf --version; opf schemas lists it next to each id). See docs/schema-versioning.md.",
|
|
4
5
|
"title": "Validation results",
|
|
5
6
|
"description": "Errors, warnings and suggested fixes.",
|
|
6
7
|
"type": "object",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://openpresentation.org/schema/opf-font-scheme/v1",
|
|
4
|
+
"$comment": "The v1 in the $id is the pre-1.0 line, not a frozen contract: this schema may change in any 0.x minor release. The release that produced this copy is the version of the @openpresentation/opf package it came from (opf --version; opf schemas lists it next to each id). See docs/schema-versioning.md.",
|
|
4
5
|
"title": "Font Scheme",
|
|
5
6
|
"description": "Schema for font-scheme records. 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). Documents reference a scheme from design.fontScheme (or design.fontScheme.id), from a theme's fontScheme and from a language's fontScheme / googleFontScheme. Role overrides on design.fontScheme (heading, body, accent, code), each a font family name, take precedence over the resolved scheme.\n\nA document references a record as a bare id or 'name:id' and resolves it in its own catalogs groups first, then in the catalog the host registered for the group's source; engines never fetch a catalog. A published record file carries '$schema' and 'id'; the copy a document embeds under catalogs.<group>.<kind>.<id> carries neither (the key is the id) and no 'x-*' display metadata.",
|
|
6
7
|
"type": "object",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://openpresentation.org/schema/opf-language/v1",
|
|
4
|
+
"$comment": "The v1 in the $id is the pre-1.0 line, not a frozen contract: this schema may change in any 0.x minor release. The release that produced this copy is the version of the @openpresentation/opf package it came from (opf --version; opf schemas lists it next to each id). See docs/schema-versioning.md.",
|
|
4
5
|
"title": "Language",
|
|
5
6
|
"description": "Schema for language records: display metadata for the language pickers of authoring tools (name, ISO code, the default font schemes a picker suggests). The document's 'language' is an engine vocabulary, a BCP-47 tag validated directly; engines never look a language record up, and their script, direction, OOXML tag and default script fonts come from spec/reference/engine-vocabularies.json. pptx.gallery publishes these records and @openpresentation/gallery ships them as catalogDisplay.languages.",
|
|
6
7
|
"type": "object",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://openpresentation.org/schema/opf-layout-preview-index/v1",
|
|
4
|
+
"$comment": "The v1 in the $id is the pre-1.0 line, not a frozen contract: this schema may change in any 0.x minor release. The release that produced this copy is the version of the @openpresentation/opf package it came from (opf --version; opf schemas lists it next to each id). See docs/schema-versioning.md.",
|
|
4
5
|
"title": "Layout Preview Index",
|
|
5
6
|
"description": "Shape of previews/layouts/index.json in @openpresentation/gallery 2: one self-contained SVG preview per v2 intent layout, keyed by the matching catalog layout id. Each record names its SVG file and exact UTF-8 byte length. The gallery package owns the files; this checkout materializes ignored copies under packages/gallery/previews/layouts/. This internal index schema is excluded from the package's published/typed schema surface.",
|
|
6
7
|
"type": "object",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://openpresentation.org/schema/opf-layout/v2",
|
|
4
|
+
"$comment": "The v2 in the $id marks the pre-1.0 line of this schema, not a frozen contract: it may change in any 0.x minor release. The release that produced this copy is the version of the @openpresentation/opf package it came from (opf --version; opf schemas lists it next to each id). See docs/schema-versioning.md.",
|
|
4
5
|
"title": "Slide Layout",
|
|
5
6
|
"description": "Schema for slide-layout records. A layout is one ordered list of regions, declared once, in reading order: 'direction' says whether the record's 'regions' sit side by side (row) or are stacked (column), and each region says which content kinds it takes and how several blocks share it. A split is an entry that nests a second list the other way, which is how a layout gets two dimensions. 'title' and 'subtitle' are reserved heading regions. Engines compile the list into a grid of tracks (the guillotine partition it describes). Slide content stays flat: engines bind a slide's blocks to the regions by reading order, role and kind (bindRegions in @openpresentation/opf), a block may pin itself to a region with 'region', and an empty region collapses into a neighbour. Built-in and custom layouts are records of this one schema; a custom layout is embedded under catalogs.custom.layouts or shipped in a catalog. Documents reference a layout from Slide.layout; a slide without a layout, with layout 'auto', or whose layout resolves nowhere composes automatically.\n\nA document references a record as a bare id or 'name:id' and resolves it in its own catalogs groups first, then in the catalog the host registered for the group's source; engines never fetch a catalog. A published record file carries '$schema' and 'id'; the copy a document embeds under catalogs.<group>.<kind>.<id> carries neither (the key is the id) and no 'x-*' display metadata.",
|
|
6
7
|
"type": "object",
|
|
@@ -77,7 +78,7 @@
|
|
|
77
78
|
"middle",
|
|
78
79
|
"bottom"
|
|
79
80
|
],
|
|
80
|
-
"description": "Vertical position of the content of every body region when it is shorter than the region. A split's 'anchor' replaces it for the regions under that split, and a region's own 'anchor' replaces both. Only 'anchor' is inherited, and only by body regions: the heading regions 'title' and 'subtitle' never take it, and the other region rules stay per region. Default 'top'."
|
|
81
|
+
"description": "Vertical position of the content of every body region when it is shorter than the region. A split's 'anchor' replaces it for the regions under that split, and a region's own 'anchor' replaces both. Only 'anchor' is inherited, and only by body regions: the heading regions 'title' and 'subtitle' never take it, and the other region rules stay per region. One exception places the whole slide: when the record is a column and every entry of its 'regions' list is sized 'auto' (heading regions included), the record has no numeric row to hold the leftover height, so its 'anchor' places the whole stack, title and subtitle included, in the content box's leftover height: 'middle' centres it, 'bottom' sits it at the foot, 'top' (default) starts it at the top as before. A record with any numeric entry, a row record and an anchor on a split keep the rule above. Default 'top'."
|
|
81
82
|
},
|
|
82
83
|
"regions": {
|
|
83
84
|
"type": "array",
|
|
@@ -220,7 +221,7 @@
|
|
|
220
221
|
"const": "auto"
|
|
221
222
|
}
|
|
222
223
|
],
|
|
223
|
-
"description": "The region's or split's share along its parent's direction: a number above 0 and up to 100 that siblings share in proportion (the gap is taken out first), default 1; or 'auto', the length the content needs at the starting text size (
|
|
224
|
+
"description": "The region's or split's share along its parent's direction: a number above 0 and up to 100 that siblings share in proportion (the gap is taken out first), default 1; or 'auto', the length the content needs at the starting text size (up to the space the heading rows and the content of the numeric rows leave; auto rows that do not all fit shrink together, each giving up the same fraction of what it can give up above its content's length at the minimum font size; a split sized auto is as tall as its tallest content, and every row of a column split sized auto is auto too; auto regions with no content take no space). 'auto' is allowed only on an entry of a column; in a row it is the validate finding opf/layout-template. When every entry of a column record is 'auto', the record's 'anchor' places the whole stack. The default for a heading region is 'auto' in a column and 1 in a row.",
|
|
224
225
|
"examples": [
|
|
225
226
|
1,
|
|
226
227
|
2,
|
|
@@ -362,7 +363,7 @@
|
|
|
362
363
|
"column",
|
|
363
364
|
"auto"
|
|
364
365
|
],
|
|
365
|
-
"description": "How several blocks share the region: 'none' one block fills it; 'grid' by count (1 fills, 2 side by side, 3 in a row, 4 as 2 x 2, 5 as 3 + 2, 6 as 3 x 2, 7 to 12 in four columns; rows and columns swap in a portrait region; a short last row is centred); 'column' stacked
|
|
366
|
+
"description": "How several blocks share the region: 'none' one block fills it; 'grid' by count (1 fills, 2 side by side, 3 in a row, 4 as 2 x 2, 5 as 3 + 2, 6 as 3 x 2, 7 to 12 in four columns; rows and columns swap in a portrait region; a short last row is centred); 'column' stacked at the heights the blocks need, one gap apart, and placed by the region's anchor (charts, pictures, tables, timelines and videos take what the measured blocks leave; blocks that do not fit share the region, each giving up the same fraction of what it can give up above its height at the minimum font size); 'auto' a grid when every block is short and a column when any block is long (more than 6 estimated lines in its grid cell at the starting size). design.contentDirection turns every flowing region into one row or one column. Default 'auto'."
|
|
366
367
|
},
|
|
367
368
|
"max": {
|
|
368
369
|
"type": "integer",
|
|
@@ -392,7 +393,7 @@
|
|
|
392
393
|
"middle",
|
|
393
394
|
"bottom"
|
|
394
395
|
],
|
|
395
|
-
"description": "Vertical position of the region's content when it is shorter than the region. Replaces the 'anchor' of the record and of the splits around it. Default: the nearest of those that sets one, else 'top'."
|
|
396
|
+
"description": "Vertical position of the region's content when it is shorter than the region. Replaces the 'anchor' of the record and of the splits around it. Default: the nearest of those that sets one, else 'top'. A picture shown whole (fit 'contain') and a video, whose 16:9 frame is the largest that fits the cell, sit at the anchor inside the cell."
|
|
396
397
|
},
|
|
397
398
|
"empty": {
|
|
398
399
|
"type": "string",
|
|
@@ -466,9 +467,10 @@
|
|
|
466
467
|
"type": "string",
|
|
467
468
|
"enum": [
|
|
468
469
|
"character",
|
|
469
|
-
"image"
|
|
470
|
+
"image",
|
|
471
|
+
"none"
|
|
470
472
|
],
|
|
471
|
-
"description": "Marker style of lists: 'character' draws the glyph, 'image' draws the deck's icon logo as a picture bullet."
|
|
473
|
+
"description": "Marker style of lists: 'character' draws the glyph, 'image' draws the deck's icon logo as a picture bullet, 'none' draws no marker and no hanging indent (label-and-description lists)."
|
|
472
474
|
},
|
|
473
475
|
"mirror": {
|
|
474
476
|
"type": "boolean",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://openpresentation.org/schema/opf-narrative/v1",
|
|
4
|
+
"$comment": "The v1 in the $id is the pre-1.0 line, not a frozen contract: this schema may change in any 0.x minor release. The release that produced this copy is the version of the @openpresentation/opf package it came from (opf --version; opf schemas lists it next to each id). See docs/schema-versioning.md.",
|
|
4
5
|
"title": "Narrative Template",
|
|
5
6
|
"description": "Schema for narrative records. A narrative is a plan: a named story arc (e.g. 'problem-solution', 'scqa') as an ordered list of beats, each saying what its slide must do. A document points at one with the string 'narrative' and links its slides to beats with 'slides[].beat'; a narrative the document defines itself is a record in catalogs.custom.narratives. Core validate warns about a 'slides[].beat' id the resolved narrative does not define (opf/unknown-beat) and about a root 'duration' outside this record's 'duration' range (opf/duration-outside-narrative), and reports a beat no slide references (opf/unused-beat).\n\nA document references a record as a bare id or 'name:id' and resolves it in its own catalogs groups first, then in the catalog the host registered for the group's source; engines never fetch a catalog. A published record file carries '$schema' and 'id'; the copy a document embeds under catalogs.<group>.<kind>.<id> carries neither (the key is the id) and no 'x-*' display metadata.",
|
|
6
7
|
"type": "object",
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"$id": "https://openpresentation.org/schema/opf/v1",
|
|
4
|
+
"$comment": "The v1 in the $id is the pre-1.0 line, not a frozen contract: this schema may change in any 0.x minor release. The release that produced this copy is the version of the @openpresentation/opf package it came from (opf --version; opf schemas lists it next to each id). See docs/schema-versioning.md.",
|
|
4
5
|
"title": "Presentation",
|
|
5
6
|
"description": "Open-source JSON format for describing PowerPoint presentations. Agents describe narratives, content, audience, reusable assets, and design — the engine handles OOXML complexity.\n\nContent references (Slide.layout, design.theme, design.colorScheme / design.colorScheme.id, design.fontScheme / design.fontScheme.id, narrative, audience, purpose and tone, and the colorScheme / fontScheme a theme record names) point at catalog records. Each is a bare 'id' or a 'name:id' whose prefix names a group in 'catalogs'. A bare id resolves in catalogs.custom, then in the records embedded under catalogs.default, then in the catalog the host registered for catalogs.default.source (or the host's default catalog when 'default' is omitted); 'name:id' resolves in catalogs.<name>, then in the catalog the host registered for its source. A reference that resolves nowhere is the warning opf/unresolved-reference, and the slide uses automatic composition or the engine default. Engines never fetch a catalog: a saved document embeds every record it uses, and hosts register any other catalog by its source string. See docs/default-catalog.md.\n\nchart.type, the language tag and the keys of Organization.socials / Speaker.socials are engine vocabularies, validated directly with no catalog lookup. When a document names no theme, colour scheme or font scheme, every engine uses the same small engine defaults (spec/reference/engine-defaults.json). Asset references use 'asset:<id>' strings that point into the top-level assets registry, and content color fields (rich-text runs, styled table cells) accept hex values, color-scheme slot/role names, or 'var:<id>' references into the top-level variables map.",
|
|
6
7
|
"type": "object",
|
|
@@ -748,7 +749,7 @@
|
|
|
748
749
|
"contentAlignment": {
|
|
749
750
|
"type": "string",
|
|
750
751
|
"enum": ["left", "center", "right"],
|
|
751
|
-
"description": "Default horizontal alignment for body/content regions in resolved layouts. Effective value: the slide's design, then the deck's design, then the theme's design.contentAlignment, then the layout record's design.contentAlignment, then the engine default. The tag follows titleAlignment (and a
|
|
752
|
+
"description": "Default horizontal alignment for body/content regions in resolved layouts. Effective value: the slide's design, then the deck's design, then the theme's design.contentAlignment, then the layout record's design.contentAlignment, then the engine default. The tag follows titleAlignment (and so does a subtitle in the title area, as on a cover) unless the slide's own design sets contentAlignment."
|
|
752
753
|
},
|
|
753
754
|
"contentBox": {
|
|
754
755
|
"type": "boolean",
|
|
@@ -767,12 +768,12 @@
|
|
|
767
768
|
"imageFit": {
|
|
768
769
|
"type": "string",
|
|
769
770
|
"enum": ["cover", "contain", "stretch"],
|
|
770
|
-
"description": "Default fit of image blocks (and Slide.image) that set no fit of their own: 'cover' fills the frame and crops what overflows around the block's focus, 'contain' shows the whole picture centered
|
|
771
|
+
"description": "Default fit of image blocks (and Slide.image) that set no fit of their own: 'cover' fills the frame and crops what overflows around the block's focus, 'contain' shows the whole picture in a frame of its own proportions, centered across and placed down the cell by the region's anchor (top by default), 'stretch' scales it to the frame exactly. Effective value: the slide's design, then the deck's design, then the theme's design.imageFit, then the layout record's design.imageFit, then 'cover'; a slide composed with no layout shows its pictures whole ('contain') instead. Backgrounds set their own fit."
|
|
771
772
|
},
|
|
772
773
|
"listBullet": {
|
|
773
774
|
"type": "string",
|
|
774
|
-
"enum": ["character", "image"],
|
|
775
|
-
"description": "Marker style for items and bullets lists. Effective value: the slide's design, then the deck's design, then the theme's design.listBullet, then the layout record's design.listBullet, then 'character'. 'character' (the default) draws the glyph marker. 'image' draws the primary organization's icon logo (or the organization and shape design.logo names; the onDark value on dark backgrounds) as a picture bullet: a square with side 0.65 times the marker's font size whose bottom sits on the marker baseline, so list geometry does not change. Without a logo the glyph is drawn and the engine reports unresolved-content at this field."
|
|
775
|
+
"enum": ["character", "image", "none"],
|
|
776
|
+
"description": "Marker style for items and bullets lists. Effective value: the slide's design, then the deck's design, then the theme's design.listBullet, then the layout record's design.listBullet, then 'character'. 'character' (the default) draws the glyph marker. 'image' draws the primary organization's icon logo (or the organization and shape design.logo names; the onDark value on dark backgrounds) as a picture bullet: a square with side 0.65 times the marker's font size whose bottom sits on the marker baseline, so list geometry does not change. Without a logo the glyph is drawn and the engine reports unresolved-content at this field. 'none' draws no marker and no hanging indent, so each entry's text (and its description) starts at the left edge of the list: use it for label-and-description lists such as pillars, team members and questions with answers. Nested levels keep their indent. A list that sets numbering still draws its numbers."
|
|
776
777
|
},
|
|
777
778
|
"mirror": {
|
|
778
779
|
"type": "boolean",
|
|
@@ -2316,7 +2317,7 @@
|
|
|
2316
2317
|
"fit": {
|
|
2317
2318
|
"type": "string",
|
|
2318
2319
|
"enum": ["cover", "contain", "stretch"],
|
|
2319
|
-
"description": "Image payloads only. How the picture fills its frame: 'cover' fills it and crops what overflows around focus; 'contain' shows the whole picture
|
|
2320
|
+
"description": "Image payloads only. How the picture fills its frame: 'cover' fills it and crops what overflows around focus; 'contain' shows the whole picture, in a frame of its own proportions placed at the region's anchor (top by default); 'stretch' scales it to the frame exactly. Default: the effective design.imageFit, else 'cover' in a layout and 'contain' on a slide with no layout."
|
|
2320
2321
|
},
|
|
2321
2322
|
"focus": {
|
|
2322
2323
|
"$ref": "#/$defs/ImageFocus",
|
|
@@ -3157,7 +3158,7 @@
|
|
|
3157
3158
|
},
|
|
3158
3159
|
"Chart": {
|
|
3159
3160
|
"type": "object",
|
|
3160
|
-
"description": "Chart content. The chart object keeps chart-specific fields together so slides and regions do not expose loose chart fields.",
|
|
3161
|
+
"description": "Chart content. The chart object keeps chart-specific fields together so slides and regions do not expose loose chart fields. OPF charts are `{ type, data }` where `data` is `{ columns, rows }`: the first column holds the category labels and every further column is one series. There are no `categories`, `series`, `labels` or `datasets` keys (the Chart.js and ECharts shape); write them as columns and rows. Example: `{ \"type\": \"column\", \"data\": { \"columns\": [\"Quarter\", \"Decks\"], \"rows\": [[\"Q1\", 3], [\"Q2\", 8], [\"Q3\", 21]] } }`.",
|
|
3161
3162
|
"additionalProperties": false,
|
|
3162
3163
|
"required": ["type", "data"],
|
|
3163
3164
|
"properties": {
|
|
@@ -3390,7 +3391,7 @@
|
|
|
3390
3391
|
},
|
|
3391
3392
|
"ChartData": {
|
|
3392
3393
|
"type": "object",
|
|
3393
|
-
"description": "Inline tabular data driving a chart. The first column usually supplies category/x-axis labels; subsequent columns are plotted measures unless 'chart.mapping' or a chart type maps them differently. Value cells are numbers; a string is read only in strict decimal syntax ('12', '-3.5', '1e6'), and anything else ('12%', '$5', '(5)', '1,234') is a gap and a 'chart-value-not-numeric' warning.",
|
|
3394
|
+
"description": "Inline tabular data driving a chart, written as `{ \"columns\": [\"Quarter\", \"Decks\"], \"rows\": [[\"Q1\", 3], [\"Q2\", 8]] }`: one column of labels plus one column per series, not separate `categories` and `series` lists. The first column usually supplies category/x-axis labels; subsequent columns are plotted measures unless 'chart.mapping' or a chart type maps them differently. Value cells are numbers; a string is read only in strict decimal syntax ('12', '-3.5', '1e6'), and anything else ('12%', '$5', '(5)', '1,234') is a gap and a 'chart-value-not-numeric' warning.",
|
|
3394
3395
|
"additionalProperties": false,
|
|
3395
3396
|
"required": ["columns", "rows"],
|
|
3396
3397
|
"properties": {
|
|
@@ -3724,7 +3725,7 @@
|
|
|
3724
3725
|
"$ref": "#/$defs/TableCellBorder"
|
|
3725
3726
|
}
|
|
3726
3727
|
},
|
|
3727
|
-
"description": "Independent cell edges.
|
|
3728
|
+
"description": "Independent cell edges. An omitted edge keeps the table's default rule: a line under every row (and over the first row), none between columns. Width 0 removes an edge."
|
|
3728
3729
|
}
|
|
3729
3730
|
},
|
|
3730
3731
|
"description": "Cell appearance. Sizes use reference pixels at a 720-pixel canvas short edge and scale with the slide."
|