Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,16 @@

### Added

- Added [`docs/how-opf-works.md`](./docs/how-opf-works.md), a conceptual introduction to the format: the document model, the three content shapes, layouts-as-hints, narrative beats, catalog resolution, and the validation philosophy.
- Added [`docs/design-resolution.md`](./docs/design-resolution.md), an explicit design precedence algorithm (slide design → deck design → resolved theme → engine defaults) with worked examples.
- Added a `warnings` array to `ValidationResult`. The validator now warns — never errors — on unknown bare catalog ids (`narrative`, `design.theme`, `design.colorScheme`, `design.fontScheme`, chart `type`) and on broken catalog cross-links in audience, purpose, and tone records (`recommendedNarratives`, `recommendedTones`). Documents that declare matching inline `catalogs.<kind>.records[]` or a custom `catalogs.<kind>.source` are exempt. Warnings never affect `valid` or `assertValid`.
- Added [`spec/README.md`](./spec/README.md) orienting readers to the spec directory layout, including what the optional `spec/openapi.yaml` reference contract is for.
- Bundled example decks and catalog cross-links are now checked for unknown catalog ids in the package test suite.
- Added [`examples/technical/full-feature-tour.opf.json`](./examples/technical/full-feature-tour.opf.json), a single fixture exercising every major schema surface: intent metadata, organizations and speakers, narrative beat overrides, design with slide-level overrides, assets, inline catalog records, all ten content payload kinds, blocks, regions, hidden slides, and extensions.
- Expanded `docs/how-opf-works.md` with an anatomy diagram, the region-grid diagram, a catalog-resolution flow diagram, and runnable examples for every content shape, plus a complete small deck. Added the precedence-stack and base-plus-overrides diagrams to `docs/design-resolution.md` and the region-grid cheat sheet to `docs/content-payloads.md`.
- Presentation-shaped JSON examples embedded in the shipped docs are now validated in the package test suite, so documentation examples cannot drift from the schema.
- Added span-composition diagrams (sidebar + main, headline band + body, and their combination) to the region docs in `docs/how-opf-works.md` and `docs/content-payloads.md`.
- Added a "Start in three steps" section to the README and a root `llms.txt` index so human and agent adopters both get a direct path from problem to first validated deck.
- Shipped every `.opf.json` deck under `examples/` inside the npm package and exposed them via `@openpresentation/opf/examples` (`examples`, `galleries`, `exampleCategories`, `getExample`, `getGallery`, `getExamplesByGallery`, `getExamplesByCategory`). Each example deck is validated against the presentation schema at build time.
- Shipped the top-level `docs/*.md` reference pages inside the npm package and exposed them via `@openpresentation/opf/docs` (`docs`, `getDoc`). Subdirectories like `docs/migrations` and `docs/plans` are intentionally excluded.
- Shipped the upstream `README.md` markdown at the pinned release version via `@openpresentation/opf/repo-readme` so consumer sites can mirror it without a network fetch.
Expand Down
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,14 @@ That's the shift that lets LLMs actually *author* decks. When the format stops f

And 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.

## Start in three steps

1. **Install the format package.** `npm install @openpresentation/opf`.
2. **Author and validate a deck.** Write a `*.opf.json` file — start from [`docs/how-opf-works.md`](./docs/how-opf-works.md) or copy [`examples/technical/full-feature-tour.opf.json`](./examples/technical/full-feature-tour.opf.json) — and run `validatePresentation` on it.
3. **Build on it.** Browse presets at [pptx.gallery](https://pptx.gallery), pin the schemas in your pipeline, and track the [toolkit roadmap](#toolkit-roadmap) for the render and convert libraries.

Your deck lives in git from the first commit. Nothing in these steps calls a hosted service, and nothing ever will — that boundary is the point.

## JavaScript and TypeScript

The 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 — expect breaking changes between minor versions until 1.0). Its responsibility is local and format-level only:
Expand All @@ -54,7 +62,7 @@ The OPF format package is shipping first. The planned toolkit lives outside this

These repos provide OSS primitives only. Downstream applications own hosting, auth, storage, collaboration, queues, previews, analytics, support, and workflow UX.

### Expected Usage
## Usage

Install from npm:

Expand Down Expand Up @@ -89,7 +97,8 @@ const deck: Presentation = {
};

const result = validatePresentation(deck);
console.log(result.valid);
console.log(result.valid); // schema correctness
console.log(result.warnings); // advisory issues, e.g. unknown catalog ids
console.log(audiences.length, purposes.length, tones.length);
```

Expand Down Expand Up @@ -125,6 +134,8 @@ node packages/cli/dist/index.js validate path/to/deck.opf.json
| Path | Contents |
|---|---|
| [`spec/schemas/opf.schema.json`](./spec/schemas/opf.schema.json) | Canonical JSON Schema for top-level OPF `Presentation` documents. |
| [`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. |
| [`docs/design-resolution.md`](./docs/design-resolution.md) | The design precedence algorithm (slide design → deck design → resolved theme → engine defaults) with worked examples. |
| [`docs/schema-reference.md`](./docs/schema-reference.md) | Author-facing reference for top-level OPF fields and every presentation schema `$defs` object/type. |
| [`docs/catalog-schema-reference.md`](./docs/catalog-schema-reference.md) | Author-facing reference for every companion catalog schema. |
| [`docs/content-payloads.md`](./docs/content-payloads.md) | Author-facing notes for slide and region content payloads, including chart and table object shapes. |
Expand Down
45 changes: 44 additions & 1 deletion docs/content-payloads.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,50 @@ Timeline-specific fields are grouped under `timeline`. An array value is shortha

## Regions

The same payload objects work inside regions:
Region keys address a 3×3 grid of rows (`top`, `middle`, `bottom`) and columns (`left`, `center`, `right`):

```
left center right
+--------------------+--------------------+--------------------+
top | top:left | top:center | top:right |
+--------------------+--------------------+--------------------+
middle | middle:left | middle:center | middle:right |
+--------------------+--------------------+--------------------+
bottom | bottom:left | bottom:center | bottom:right |
+--------------------+--------------------+--------------------+
```

- A bare column key (`left`) spans all three rows; a bare row key (`top`) spans all three columns.
- `+` spans adjacent rows or columns: `center+right`, `top+middle`.
- `row:column` combines the two: `top:left`, `middle+bottom:center+right`.
- Keys on one slide must not overlap, and regions cannot be mixed with root payload fields.

Spans compose into common slide shapes:

```
"left" + "center+right" "top" + "middle+bottom"
(sidebar + main) (headline band + body)
+----------+------------------+ +-------------------------------+
| | | | top |
| | | +-------------------------------+
| left | center+right | | |
| | | | middle+bottom |
| | | | |
+----------+------------------+ +-------------------------------+

"top" + "middle+bottom:left" + "middle+bottom:center+right"
(headline band, then sidebar + main)
+---------------------------------------------+
| top |
+---------------+-----------------------------+
| | |
| middle+bottom | middle+bottom:center+right |
| :left | |
| | |
+---------------+-----------------------------+
```

The same payload objects work inside regions — here, the sidebar-plus-main shape:

```json
{
Expand Down
130 changes: 130 additions & 0 deletions docs/design-resolution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# Design Resolution

How 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.

## Precedence

For every design field independently, the most specific source wins:

```
wins +--------------------------------------------------------+
^ | 1. slide design slides[i].design.* |
| +--------------------------------------------------------+
| | 2. deck design design.* on the presentation root |
| +--------------------------------------------------------+
| | 3. resolved theme colorScheme, fontScheme, |
| | background, dimensions from the |
| | theme record |
| +--------------------------------------------------------+
loses | 4. engine defaults e.g. spec/reference/ |
v | engine-defaults.json |
+--------------------------------------------------------+
```

1. **Slide design** — `slides[].design.*`
2. **Deck design** — `design.*` on the presentation root
3. **Resolved theme** — defaults carried by the theme record (`colorScheme`, `fontScheme`, `background`, `dimensions`)
4. **Engine defaults** — engine configuration such as [`spec/reference/engine-defaults.json`](../spec/reference/engine-defaults.json)

Resolution 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.

Two field-level rules complete the picture:

- **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`.

```
"colorScheme": { "id": "cool-horizon", "accent1": "#0F4C81" }

catalog record "cool-horizon" sibling fields on the object
accent1: "#2874A6" <-- replaced -- accent1: "#0F4C81"
accent2: "#1B4F72" <-- kept
light1: "#FFFFFF" <-- kept
|
v
effective scheme: accent1 from the override, everything else
from the record
```
- **Explicit suppression.** `watermark`, `header`, and `footer` accept `false` to switch off an inherited value — distinct from omitting the field, which inherits.

Catalog lookups inside this chain follow the standard resolution order (inline `catalogs.<kind>.records[]` → `catalogs.<kind>.source` → default catalog); see [`how-opf-works.md`](./how-opf-works.md).

## Worked example 1: color scheme through every level

```json
{
"design": {
"theme": "classic",
"colorScheme": "forest-green"
},
"slides": [
{ "title": "Inherits the deck" },
{
"title": "Slide override",
"design": {
"colorScheme": { "id": "cool-horizon", "accent1": "#0F4C81" }
}
}
]
}
```

- 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`.
- 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.

There 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.

## Worked example 2: backgrounds and suppression

```json
{
"design": {
"theme": "dark",
"background": "light1",
"footer": {
"left": { "text": "Acme Corp" },
"right": { "slideNumber": true }
}
},
"slides": [
{ "title": "Light slide in a dark theme" },
{
"title": "Section divider",
"design": {
"background": {
"type": "gradient",
"gradient": {
"angle": 90,
"stops": [
{ "color": "#0B1B2B", "position": 0 },
{ "color": "#123A5F", "position": 1 }
]
}
},
"footer": false
}
}
]
}
```

- Slide 1: the deck-level `background: "light1"` overrides the `dark` theme's default background. `light1` is a theme slot — it resolves through the effective color scheme, which itself resolved through the chain above.
- 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.

## Worked example 3: font scheme models

```json
{
"design": {
"fontScheme": {
"id": "aptos",
"code": { "family": "JetBrains Mono" }
}
}
}
```

The `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`–`accent6`, `dark1/2`, `light1/2`) round-trip directly, abstract roles (`primary`, `text`, `surface`, …) are mapped onto slots by the engine.

## What is *not* part of this chain

Content payloads carry no design controls in v1 — `position`, `fontSize`, per-payload colors and the like were deliberately kept out while the content model stabilizes (see [`content-item-design-overrides.md`](./content-item-design-overrides.md)). The design system above, plus layout hints (`titleAlignment`, `contentBox`, `chartPrimary`, …), is the entire styling surface of an OPF document.
2 changes: 2 additions & 0 deletions docs/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ The `examples/` directory has three layers:

## Technical Fixtures

Start with [`examples/technical/full-feature-tour.opf.json`](../examples/technical/full-feature-tour.opf.json), one deck that touches every major schema surface — useful as a copy-paste source and as a single fixture for renderer smoke tests.

Use `examples/technical/` when you want a small file that exercises a specific schema surface:

- content payloads, rich text, blocks, charts, tables, media, metrics, quotes, and timelines
Expand Down
Loading
Loading