diff --git a/CHANGELOG.md b/CHANGELOG.md index 226b875..0a23bac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ - 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. +- Repositioned the repo docs around the OpenPresentation OSS boundary: specs, catalogs, examples, local validation, and planned local render/edit/convert libraries, with hosted service layers left to downstream applications. ## 0.2.2 @@ -28,11 +29,11 @@ - Kept the canonical spec npm artifact on the existing `@openpresentation/opf` package instead of adding a separate `@openpresentation/opf-spec` package. - Removed Xano-hosted chart preview URL objects from the bundled chart-type catalog records and chart-type index. - Kept the JavaScript package boundary local and format-level: schemas, catalogs, generated TypeScript types, and local validation only. -- Included the full raw `spec/` tree in the packed JavaScript package, including `spec/openapi.yaml`, schemas, catalogs, reference files, and catalog indexes. +- Included the full raw `spec/` tree in the packed JavaScript package, including the optional downstream-service reference `spec/openapi.yaml`, schemas, catalogs, reference files, and catalog indexes. - Added typed raw spec file manifest exports at `@openpresentation/opf/spec-files`. - Added a GitHub Actions npm publish workflow for semver tags with npm provenance. - Clarified that the OPF CLI remains local-only and is not published as part of `@openpresentation/opf` v0.2.0. ### Not Included -- No hosted rendering, parsing, generation, remote catalog fetching, or PPTX.dev client behavior is included in this release-prep change. +- No hosted rendering, parsing, generation, remote catalog fetching, or hosted-service client behavior is included in this release-prep change. diff --git a/PRODUCT.md b/PRODUCT.md index 5c026b3..38f73a0 100644 --- a/PRODUCT.md +++ b/PRODUCT.md @@ -1,33 +1,40 @@ # Product Strategy: OPF — Open Presentation Format -## Tier in the presentation stack +## Position in the OpenPresentation ecosystem -**Tier 1 — open-source primitive (MIT).** OPF is the foundation of the Open Presentation / PPTX.dev presentation stack. +**Open-source primitives (MIT).** OPF is the foundation of the OpenPresentation project. ``` -Top: STORYD2 (+ DeckChat) — commercial consumer wrappers (Tier 3) -Middle: pptx.dev — hosted engine / metered pay-per-use API (Tier 2) -Bottom: OPF + pptx.gallery + SDKs — open-source primitives, MIT (Tier 1) ← you are here +OpenPresentation OSS: + Current: OPF spec, schemas, catalogs, examples, validation, and local CLI + Planned: local render/edit/convert libraries + opf-render / opf-editor / opf-pptx + +Downstream applications: + Hosted services, agent workflows, custom editors, internal tools, + and self-hosted systems built by integrators ``` -- **Role in Tier 1:** OPF is the interchange format. It defines the JSON contract between LLM intent and rendered presentations so every agent in the ecosystem — ours or a third party's — can produce interoperable deck documents. -- **Siblings in Tier 1:** [pptx.gallery](https://www.pptx.gallery) provides the human-browsable shared vocabulary. The canonical package source for machine consumers lives in this repo under `spec/` and `@openpresentation/opf`. -- **Relationship to Tier 2 (pptx.dev):** OPF documents flow into `https://api.pptx.dev/v1` for rendering, parsing, generation, and export. The hosted engine is the paid surface. Core OPF packages do not call that API. -- **Relationship to Tier 3 (STORYD2, DeckChat):** Commercial wrappers produce OPF and hand it to pptx.dev. Keeping OPF MIT makes STORYD2 and DeckChat *more* valuable, not less — the format is open so every AI tool standardizes on it, and the consumer products compete on UX and agent strategy. +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. Downstream applications can wrap the OSS primitives in their own products and services. + +- **Role in OpenPresentation OSS:** OPF is the interchange format. It defines the JSON contract between authoring intent and rendered presentations so agents, editors, validators, renderers, and converters can interoperate. +- **Siblings in OpenPresentation OSS:** [pptx.gallery](https://www.pptx.gallery) provides the human-browsable shared vocabulary. The canonical package source for machine consumers lives in this repo under `spec/` and `@openpresentation/opf`. +- **Relationship to downstream applications:** Integrators can use OPF and the toolkit to build hosted services, chatbot or agent workflows, custom editors, internal automation, and self-hosted systems without depending on OpenPresentation-hosted functions. +- **Relationship to hosted services:** Hosted services are downstream products. They may consume OPF, run the renderer or converters, store files, manage users, or provide workflow UX, but those service layers are outside the OpenPresentation OSS boundary. ## Vision -**The portable, LLM-native document format for slide decks.** `.pptx` is a zipped XML bundle that humans can't diff, LLMs can't reliably write, and git can't track. OPF is plain JSON — a real document format that models can *author*, not just decorate. Every agent, IDE, chat surface, or shell can read and write OPF, and one hosted engine (pptx.dev) renders it to `.pptx`, PDF, SVG, or PNG. +**The portable, LLM-native document format for slide decks.** `.pptx` is a zipped XML bundle that humans can't diff, LLMs can't reliably write, and git can't track. OPF is plain JSON — a real document format that models can *author*, not just decorate. Every agent, IDE, chat surface, or shell can read and write OPF, then render or convert it locally with OSS tooling or hand it to downstream applications. ## Target Users 1. **AI agent developers** building tools that generate or edit presentations programmatically (Claude Code, Cursor, Codex, LangChain, LlamaIndex, custom agents). -2. **Developers** embedding presentation workflows in SaaS, notebooks, CI/CD, or content pipelines. -3. **LLM application vendors** who want their product to emit durable, versionable deck artifacts without shipping their own OOXML generator. +2. **Developers** embedding presentation workflows in SaaS, notebooks, CI/CD, internal systems, or content pipelines. +3. **Application builders** who want durable, versionable deck artifacts without shipping their own presentation schema. ## Positioning -"A JSON document format for slide decks — write it by hand, generate it with an agent, render it with one API call." OPF is the shared format; pptx.dev is the shared engine; gallery is the shared vocabulary. +"A JSON document format for slide decks — write it by hand, generate it with an agent, validate it locally, and render or convert it with open tooling." OPF is the shared format; OpenPresentation provides open specs and libraries; integrators build the products around them. ## Distribution surfaces @@ -39,30 +46,35 @@ One format, every runtime: | JSON Schema | `https://openpresentation.org/schema/opf/v1` | Any JSON Schema validator, editor, or agent | | JavaScript/TypeScript OPF package | `@openpresentation/opf` (public npm package, pre-stable 0.x) | Schemas, catalogs, types, local validation | | Local OPF CLI | `opf` (local workspace source; distribution deferred) | Validate, format, and inspect OPF locally | +| Future render toolkit | `opf-render` | Local and embeddable SVG, PNG, and PDF rendering | +| Future editor toolkit | `opf-editor` | Headless bindings and optional embeddable editor components | +| Future PPTX toolkit | `opf-pptx` | Local OPF-to-PPTX export and PPTX-to-OPF import | | Future Python OPF package | TBD | Local models, schemas, catalogs, validation | | Future Go OPF module | TBD | Local structs, embedded schemas/catalogs, validation | -PPTX.dev-specific `@pptx/sdk`, `pptx-dev`, `pptx.dev/go`, `@pptx/cli`, and `pptx-mcp` source belongs to PPTX.dev-owned repositories. Those packages consume OPF and handle hosted generation/rendering workflows; they are not the canonical OPF package direction. +Hosted-service clients, managed workflows, and product-specific client libraries should live outside the core OPF repo. They consume OPF and the toolkit as downstream integrators; they are not the canonical OpenPresentation package direction. ## Monetization -**None in Tier 1.** OPF, the JSON schema, the SDKs, the CLIs, and the MCP server are MIT-licensed public goods. Revenue flows to Tier 2 (metered pay-per-use on the hosted engine) and Tier 3 (subscriptions on STORYD2 and DeckChat). The more widely OPF is adopted, the more valuable the Tier-2 engine becomes as the default renderer. +**None in OpenPresentation OSS.** OPF, the JSON schemas, local packages, CLI source, docs, examples, and planned render/edit/convert toolkit (`opf-render`, `opf-editor`, `opf-pptx`) are MIT-licensed public goods. The project optimizes for adoption, interoperability, local execution, and embeddable primitives. Downstream vendors may build hosted or managed products separately; OpenPresentation does not ship those hosted layers. ## Current Priorities -1. **v1 spec freeze** — finalize the OPF JSON Schema, OpenAPI contract, and TS/Python/Go type surfaces so downstream SDKs can ship stable releases. +1. **v1 spec freeze** — finalize the OPF JSON Schema, optional reference OpenAPI contract, and TS/Python/Go type surfaces so downstream packages can ship stable releases. 2. **Canonical OPF packages** — JavaScript first, then Python and Go local-only packages for schemas, catalogs, types/models, and validation. -3. **Local OPF CLI** — validate, format, and inspect OPF without calling PPTX.dev. -4. **Gallery integration** — OPF documents reference catalog items by slug; packages expose the canonical bundled catalogs while pptx.gallery remains the browsable reference. -5. **Ecosystem adoption** — inbound partnerships with agent frameworks (Claude Code, Cursor, Codex, LangChain, LlamaIndex) so OPF is the default deck format. +3. **Local OPF CLI** — validate, format, and inspect OPF without calling a hosted service. +4. **Render/edit/convert toolkit** — ship MIT local libraries for SVG/PNG/PDF rendering, embeddable editing, and PPTX import/export. +5. **Gallery integration** — OPF documents reference catalog items by slug; packages expose the canonical bundled catalogs while pptx.gallery remains the browsable reference. +6. **Ecosystem adoption** — make OPF the default deck format for agents, editors, self-hosters, and downstream applications. ## Key Decisions -- **MIT license, always.** The format and client tools must stay open so every AI tool (including competitors) can produce OPF. Format lock-in is not the moat — ecosystem adoption is. +- **MIT license, always.** The format and client tools must stay open so every AI tool and application can produce OPF. Format lock-in is not the goal — ecosystem adoption is. - **Open Presentation Format is the public name.** `OPF` is shorthand, and `*.opf.json` is the recommended filename pattern for complete JSON deck documents. -- **Spec + local format packages live together, service clients move separately.** This repo owns the OPF spec, schemas, catalogs, and local validation packages. Hosted PPTX.dev clients and MCP tooling should live with the PPTX.dev service. -- **Vanity URLs are stable.** `pptx.dev/go`, `@pptx/*`, `pptx-dev` (PyPI), and `https://openpresentation.org/schema/opf/v1` do not move even as source repos move. Existing users do not need to update import paths. -- **PPTX.dev consumes OPF.** The hosted engine generates, renders, parses, stores, and previews presentations. OPF packages define and validate the data contract locally. +- **OpenPresentation owns OSS primitives only.** This repo owns the OPF spec, schemas, catalogs, examples, local validation packages, and local tooling. The render/edit/convert toolkit lives in separate MIT repos and depends on this format package. +- **No OpenPresentation-hosted runtime.** OpenPresentation libraries must run without required network calls, hosted callbacks, hidden telemetry, or managed infrastructure assumptions. +- **Downstream applications own product surfaces.** Auth, storage, collaboration, queues, jobs, previews, billing, analytics, support, and workflow UX belong to integrators building on the OSS primitives. +- **Stable integration seams matter.** Packages should expose predictable APIs, structured errors, package-addressable assets, custom catalog/font/theme/asset hooks, and documented semver compatibility with `@openpresentation/opf`. ## What OPF models diff --git a/README.md b/README.md index 80ef033..0abf73b 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Public npm package: [`@openpresentation/opf`](https://www.npmjs.com/package/@ope Open Presentation Format is the portable, human-readable JSON document format for slide decks. -This repository is the canonical home for the OPF **spec**, **JSON Schemas**, **catalog presets**, generated developer types, and local validation tooling. Anything that renders PowerPoint files, fills presentations with AI, parses `.pptx`, or calls the hosted [pptx.dev](https://pptx.dev) API belongs to PPTX.dev-specific packages, not the core OPF package. +This repository is the canonical home for the OPF **spec**, **JSON Schemas**, **catalog presets**, examples, generated developer types, local validation tooling, and planning docs for the future 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. ## File naming @@ -18,7 +18,7 @@ Avoid using bare `*.opf` for OPF JSON. The `.opf` extension is already used by o ## Naming and reuse -The 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, and describe support for Open Presentation Format without using PPTX.dev branding. +The 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. ## Why OPF @@ -40,7 +40,19 @@ The canonical JavaScript/TypeScript package is published at [`packages/javascrip - generate TypeScript types, with `Presentation` as the top-level type - validate OPF JSON and catalog records locally -It does not render `.pptx`, parse `.pptx`, generate content with AI, fetch remote catalogs, or call PPTX.dev. +It does not render `.pptx`, parse `.pptx`, generate content with AI, fetch remote catalogs, call hosted APIs, or provide managed services. Future render/edit/convert packages are planned as separate MIT repos that depend on `@openpresentation/opf`. + +## Toolkit roadmap + +The OPF format package is shipping first. The planned toolkit lives outside this format-only repo: + +| Planned repo | Role | Boundary | +|---|---|---| +| `opf-render` | OPF to SVG/PNG/PDF | Local and embeddable rendering library | +| `opf-editor` | WYSIWYG bindings/components | Headless editor primitives plus optional UI components | +| `opf-pptx` | OPF to PPTX and PPTX to OPF | Pure local import/export library for browser and server use where supported | + +These repos provide OSS primitives only. Downstream applications own hosting, auth, storage, collaboration, queues, previews, analytics, support, and workflow UX. ### Expected Usage @@ -119,20 +131,20 @@ node packages/cli/dist/index.js validate path/to/deck.opf.json | [`docs/examples.md`](./docs/examples.md) | Guide to the expanded scenario-oriented examples under `examples/gallery/`. | | [`spec/schemas/*.schema.json`](./spec/schemas) | Companion schemas for catalog records and sub-objects. | | [`spec/catalogs//`](./spec/catalogs) | Canonical bundled catalog records. | -| [`spec/openapi.yaml`](./spec/openapi.yaml) | OpenAPI contract included as raw spec content in the npm package. | +| [`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. | | [`examples/technical/`](./examples/technical) | Focused OPF fixtures for validator, renderer, catalog-resolution, design, content-payload, and region behavior. | | [`examples/gallery/`](./examples/gallery) | Broader OPF example decks organized by industry, function, education, government, presentation type, international, and design/media scenarios. | | [`packages/javascript/`](./packages/javascript) | Public pre-stable source for `@openpresentation/opf`. | | [`packages/cli/`](./packages/cli) | Local-only OPF CLI source; native distribution is deferred. | -| [`legacy/`](./legacy) | Tombstone for PPTX.dev clients, CLIs, SDKs, and MCP source migrated to PPTX.dev-owned repositories. | +| [`legacy/`](./legacy) | Tombstone for service-specific clients, CLIs, tool integrations, and workflows removed from the OpenPresentation OSS repo. | -## Package Boundary +## OpenPresentation Boundary -OPF defines the format and bundled presets. PPTX.dev consumes OPF to provide hosted generation, rendering, parsing, storage, authentication, jobs, previews, and AI workflows. +OpenPresentation 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. -Future non-JavaScript OPF packages should follow the same local-only boundary: Python and Go packages should expose schemas, types/models, catalogs, and validation, not PPTX.dev rendering or generation. +Future 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. -The published JavaScript package copies package-addressable OPF schemas, catalogs, reference assets, and `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. +The 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. ## License diff --git a/docs/plans/opf-toolkit.md b/docs/plans/opf-toolkit.md new file mode 100644 index 0000000..943a93c --- /dev/null +++ b/docs/plans/opf-toolkit.md @@ -0,0 +1,233 @@ +# OPF Toolkit — open-source render, edit, and PPTX conversion + +Plan for the open-source toolkit that turns OPF documents into pixels and PowerPoint files, and PowerPoint files back into OPF. Everything here is free and MIT, runs in Node and the browser, and has **no hosted service in the critical path**. OpenPresentation ships code and documentation only; downstream applications can wrap these primitives in their own products, services, agents, and workflows. + +This repo ([`openpresentation/opf`](https://github.com/openpresentation/opf)) stays **format-only**: schemas, catalogs, examples, types, local validation. The toolkit lives in **separate MIT repos** that depend on [`@openpresentation/opf`](https://www.npmjs.com/package/@openpresentation/opf). This document is the cross-cutting plan; it lives here because the format and the toolkit move together conceptually, and because the build leans hard on the spec assets in [`spec/`](../../spec). + +## Executive summary — key decisions + +1. **Three new repos, not one package, and not in this repo.** `opf-render` (Phase 1), `opf-editor` (Phase 2), and `opf-pptx` (Phases 3+4). Each is MIT, versions independently, and depends on `@openpresentation/opf` for schemas, catalogs, and types. Rationale and alternative groupings in [§1](#1-repo-topology). + +2. **`opf-render` is the foundation and the canonical visual truth.** SVG is the canonical render; PNG and PDF are conversions off the SVG; the PPTX export only has to be *close* to the SVG. Everything downstream (editor overlays, golden tests, export verification) keys off the renderer, so it ships first and the others depend on it. + +3. **Determinism is a hard requirement, not a nice-to-have.** Same OPF in → byte-stable SVG out. No browser, no network, no clock, no locale drift, no font fallback roulette in the render path. This is what makes caching, diffing, golden-file tests, and the WYSIWYG round-trip work at all. Treated as a cross-cutting discipline in [§6](#6-cross-cutting-determinism-and-golden-files). + +4. **The renderer resolves the catalog system itself.** Layout, theme, colorScheme, fontScheme, chart type (`Chart.type`), audience/purpose/tone references resolve through the documented order (inline `catalogs..records[]` → `catalogs..source` → engine defaults → default catalog) exactly as [`opf.schema.json`](../../spec/schemas/opf.schema.json) describes. The toolkit bundles the canonical catalogs via `@openpresentation/opf` and ships an `engine-defaults.json` matching [`spec/reference/`](../../spec/reference). + +5. **Layout binding follows the placeholder model.** Rendering keys off the `placeholders` array described in [`layout-placeholders.md`](layout-placeholders.md): `title`/`subtitle`/`tag` bind to slide fields, other content binds by `slot` in array order. The renderer is the first real consumer of that model, so building it will validate (or expose gaps in) the placeholder plan. + +6. **`data-opf-path` is the whole editor binding.** A one-line change in the renderer — stamp every emitted element with its JSON path — is what makes Phase 2 a thin overlay instead of a second rendering engine. We bake it in from Phase 1, gated behind a render option so production SVG can omit it. + +7. **PPTX export starts on `pptxgenjs`, then graduates to a hand-written OOXML emitter.** Working `.pptx` fast, 1:1 fidelity later. Both live behind one stable `toPptx(opf)` API so the swap is invisible to callers. + +8. **OpenPresentation boundary.** Making the renderer MIT is a deliberate strategy change: OpenPresentation owns open specs, catalogs, local libraries, and integration seams — not hosted APIs, managed infrastructure, or product workflows. [`PRODUCT.md`](../../PRODUCT.md) is updated in the same change set to reflect render/convert as OpenPresentation OSS primitives. + +--- + +## 1. Repo topology + +Three repos under the `openpresentation` org, all MIT, all depending on `@openpresentation/opf`: + +| Repo | Phase | Public API (sketch) | Depends on | +|---|---|---|---| +| `openpresentation/opf-render` | 1 | `renderSvg(opf, opts)`, `svgToPng(svg)`, `svgToPdf(svgs)` | `@openpresentation/opf` | +| `openpresentation/opf-editor` | 2 | React/Svelte components + headless `bindEditor(state)` | `opf-render`, `@openpresentation/opf` | +| `openpresentation/opf-pptx` | 3 + 4 | `toPptx(opf)`, `fromPptx(buffer)` | `@openpresentation/opf` (+ `opf-render` for chart rasterization, [§3.4](#34-charts)) | + +**Why three, not one.** Each has a distinct dependency footprint and audience: `opf-render` is the universal core (everyone needs pixels); `opf-editor` pulls in a UI framework and is browser-only; `opf-pptx` carries OOXML/ZIP concerns and a heavyweight optional LibreOffice verification path. Splitting keeps install weight honest and lets a consumer take the renderer without the editor. + +**Why 3 and 4 share a repo.** OPF→PPTX and PPTX→OPF are the two directions of the same OOXML domain — they share the ZIP packaging code, the `[Content_Types].xml`/`.rels` model, the part graph, the EMU math, and the OOXML↔OPF type maps. Splitting them duplicates that surface. + +**The convenience facade.** A thin optional `opf-toolkit` meta-package can re-export `render(opf, "svg"|"png"|"pdf"|"pptx")` and `import(pptx)` over the three repos for the "just give me one import" caller. It carries no logic — pure re-export — so it is not on the critical path of any phase. + +**Alternative considered — split Phase 3 from Phase 4 (`opf-pptx-out` / `opf-pptx-in`).** Rejected for v1: the shared OOXML surface is large and the two directions are co-developed. Revisit only if import grows an AI dependency that export shouldn't carry. + +--- + +## 2. Integrator contract + +The toolkit is library-first. Downstream applications should be able to embed it in hosted services, agent workflows, custom editors, internal automation, and self-hosted systems without relying on OpenPresentation-hosted functions. + +- **Stable APIs.** Keep entry points small and predictable: `renderSvg`, `svgToPng`, `svgToPdf`, editor bindings/components, `toPptx`, and `fromPptx`. Use semver and document compatibility with `@openpresentation/opf`. +- **Offline by default.** No required network calls, hosted callbacks, hidden telemetry, or remote asset fetches in the core runtime path. Catalog, font, image, and media resolution must be injectable so hosts can run offline or use private sources. +- **Host-controlled product surface.** OpenPresentation does not provide auth, storage, collaboration, queues, jobs, previews, analytics, support, or workflow UX. Hosts compose those layers around the OSS primitives. +- **Runtime portability.** Support Node and browser where the package promises it. Server-side APIs must be safe for batch jobs and concurrent requests, avoid global mutable config, and return structured errors. +- **License and project hygiene.** Each repo ships MIT licensing, contribution guidance, security reporting, dependency license policy, font/media licensing notes, trademark/name usage guidance, and a compatibility policy. + +--- + +## Phase 1 — Make it visible. OPF → SVG → PNG + PDF. + +**Repo:** `opf-render`. **Goal:** a deterministic renderer — same OPF in, same SVG out — that turns a deck into one SVG per slide, with PNG and PDF as conversions off it. + +### 1.1 Validate & resolve + +- Parse the OPF JSON and validate against the bundled schemas via `@openpresentation/opf`'s `validatePresentation` (AJV under the hood). Reject invalid input at the boundary; trust it internally thereafter. +- Resolve catalog references in the documented order (inline records → document `source` → engine defaults → default catalog at `pptx.gallery/`). Bundle the canonical catalogs from `@openpresentation/opf/catalogs`; ship an `engine-defaults.json` mirroring [`spec/reference/engine-defaults.json`](../../spec/reference). +- Pick the layout: resolve `Slide.layout` to a layout record, read its `placeholders` array. Layout = fixed regions on a fixed-size canvas (default 1280×720; EMU-equivalent so Phase 3 shares the geometry). +- Bind content to placeholders per [`layout-placeholders.md`](layout-placeholders.md) §2.2: `title`/`subtitle`/`tag` from slide fields (with presentation-level fallback), the rest by `content[].slot` in array order. The `blocks` form (renderer-positioned, see [`block-composition.opf.json`](../../examples/technical/block-composition.opf.json)) is laid out by a deterministic region allocator rather than fixed placeholders. + +### 1.2 Lay out text — the hard part + +- Parse the font for glyph metrics, shape the runs, break lines, shrink-to-fit when a box overflows. +- Greedy line-breaking is fine to start; leave a seam for Knuth–Plass later. +- Shrink-to-fit (autofit) mirrors PowerPoint's normAutofit so the SVG and the eventual PPTX agree on whether text fits. +- **Determinism watch:** font selection must be explicit and bundled — never fall back to a system font, because that changes per machine and breaks golden files. + +### 1.3 Emit SVG + +- ``, ``, ``, `` into a fixed `viewBox`. +- Every emitted element carries a `data-opf-path` (e.g. `slides.2.title`, `slides.2.content.0`) **when `opts.trace` is set** — this is the Phase 2 binding, baked in now (decision 6). Production SVG can omit it for size. +- Subset and embed fonts in the web SVG so it renders identically off-box. + +### 1.4 SVG → PNG + +- Rasterize with `resvg-js` (WASM, no browser). Deterministic output at a given scale. + +### 1.5 SVG → PDF + +- One slide = one vector page. Keep real text + subsetted embedded fonts for fidelity and selectable text; outline glyphs to `` when bulletproof rendering matters more than text selection. +- Start with `svg2pdf.js` + `jsPDF`; SVG path data maps closely onto PDF path operators, so a hand-written content-stream emitter is a viable later step if the libraries constrain us. + +### 1.6 Golden-file tests + +- Render every deck in [`examples/`](../../examples) to PNG, diff against approved images. The example suite ([`examples/technical/`](../../examples/technical), [`examples/gallery/`](../../examples/gallery)) is the corpus; `scripts/validate-examples.mjs` already gates validity, this adds visual gating. + +### 1.7 Key stack + +TypeScript · AJV (via `@openpresentation/opf`) · `fontkit` or `opentype.js` for glyph metrics, `harfbuzzjs` (WASM) for proper kerning/ligatures · `resvg-js` for PNG · `svg2pdf.js` + `jsPDF` for PDF (or a hand-written content stream). All permissive; Node + browser. + +--- + +## Phase 2 — Make it human. WYSIWYG. + +**Repo:** `opf-editor` (depends on `opf-render`). **Goal:** embeddable editor primitives where editing the slide writes straight back to the OPF JSON, which stays the single source of truth. This is not a hosted product shell; hosts own auth, storage, collaboration, branding, workflow, and UI chrome. + +### 2.1 Traceable renderer + +- Already delivered by Phase 1's `data-opf-path` (decision 6). The editor renders with `opts.trace: true`. No second rendering engine. + +### 2.2 Click-to-edit primitives + +- Click an element → read its `data-opf-path` → expose the edit target to the host UI → write the value back into the JSON at that path → re-render. Re-render is cheap because the renderer is pure. Optional components can provide default overlays, but the headless binding is the core API. + +### 2.3 Structured controls + +- Layout, theme, colorScheme, fontScheme, chart type (`Chart.type`), audience/purpose/tone are **controls that set catalog-id fields**, populated from `@openpresentation/opf/catalogs` or host-supplied catalogs — not freeform manipulation. This is where the catalog system pays off in embedding contexts. + +### 2.4 Side-by-side JSON + +- Optional CodeMirror/Monaco components can bind to the same state object; edits flow both ways. Hosts may hide JSON entirely, replace the code editor, or use their own state layer. Re-validate with AJV on every change so output stays clean OPF. + +### 2.5 Undo/redo as a JSON Patch log + +- RFC 6902 JSON Patch operations form a clean, diffable, replayable history. `immer` produces the patches as a side effect of immutable updates. + +### 2.6 Key stack + +Headless TypeScript core · optional React or Svelte components · optional CodeMirror or Monaco · `immer` (immutable updates + patch generation) · JSON Patch (RFC 6902) · AJV via `@openpresentation/opf`. + +--- + +## Phase 3 — Make it usable. OPF → PPTX. + +**Repo:** `opf-pptx`. **Goal:** emit a real, editable `.pptx` PowerPoint opens without complaint through a pure local library API. It only has to be *close* to the SVG — the SVG is canonical. + +### 3.1 The package shape + +- A `.pptx` is a ZIP of XML parts: `[Content_Types].xml`, `_rels/`, `ppt/presentation.xml`, per-slide XML, slide layouts, masters, `theme1.xml`. +- Map OPF → OOXML: layout placeholders → `` placeholders, OPF `design.theme`/`colorScheme`/`fontScheme` → ``, text runs → ``/``. Convert canvas units to EMUs (914400/inch). Reuse Phase 1's geometry so positions agree. + +### 3.2 Two paths behind one API + +- **v1:** write an OPF→`pptxgenjs` mapping for working output fast. +- **v2:** replace the internals with a hand-written OOXML emitter for a 1:1 mapping (owning the emitter removes the impedance mismatch with `pptxgenjs`'s API). +- Both sit behind one stable `toPptx(opf)` so the swap is invisible. The runtime path has no required network call, AI dependency, LibreOffice dependency, or hosted callback. +- Server and batch callers get reproducible ZIP output, deterministic part ordering, fixed timestamps, bounded resource controls, and structured errors for validation, unsupported features, missing assets/fonts, and packaging failures. + +### 3.3 Placeholder mapping caveat + +- [`layout-placeholders.md`](layout-placeholders.md) §1 explicitly defers the OOXML round-trip (`title` vs `ctrTitle`, `body`→``, `picture`→`` vs fill). Phase 3 is where those decisions get made and fed back as a follow-on to the placeholder plan. + +### 3.4 Charts + +- v1: render charts as images (via `opf-render`) and embed as pictures. v2: real chart XML (``). + +### 3.5 Verify against the canonical SVG + +- Render the generated `.pptx` with **LibreOffice headless** (free, optional, verification-only — the single non-JS dependency anywhere, and never in the runtime path) and diff against the Phase 1 SVG/PNG. This is a test-suite tool, not a dependency consumers install. + +### 3.6 Key stack + +TypeScript · `fflate` or `jszip` (packaging) · `pptxgenjs` initially · LibreOffice headless for verification only. + +--- + +## Phase 4 — Make it unavoidable. PPTX → OPF. + +**Repo:** `opf-pptx` (same repo as Phase 3). **Goal:** import existing PowerPoint decks into clean, valid OPF JSON. + +### 4.1 Mechanical import + +- Unzip the `.pptx`, parse the XML parts with `fast-xml-parser`, read slides/shapes/text/theme. + +### 4.2 Best-effort semantic mapping + +- Recognize common patterns (title+body → bullets, etc.) and map to OPF layouts; fall back to `blocks` with explicit positioning for anything that doesn't fit cleanly. Aim for "editable and recognizable," not pixel-perfect. + +### 4.3 Optional AI pass + +- A post-import classifier that re-maps slides into proper layouts and tidies text. **Optional and clearly isolated** — the mechanical importer must work fully without it, so the AI dependency never becomes load-bearing for the OSS core. Hosts can add their own classifier without changing the local importer contract. + +### 4.4 Output discipline + +- Output must validate against the schemas (`validatePresentation`) and **round-trip back out** through Phase 3 — `fromPptx` then `toPptx` is a test invariant. + +### 4.5 Key stack + +TypeScript · `fflate`/`jszip` · `fast-xml-parser`. All permissive. + +--- + +## 6. Cross-cutting: determinism and golden files + +Two disciplines hold across all four phases: + +- **Determinism / byte-stability.** No clock, no `Math.random`, no locale-dependent collation, no network fetch, no system-font fallback in any render or emit path. Stable key ordering in emitted JSON/XML. ZIP entries written with fixed timestamps and ordering so `.pptx` bytes are reproducible. This is what makes caching and diffing real. +- **Golden-file tests per phase.** Every example deck in [`examples/`](../../examples) has an approved render (Phase 1 PNG), an approved `.pptx` (Phase 3, verified via LibreOffice), and a round-trip assertion (Phase 4). CI fails on any unreviewed pixel or byte change. The existing [`scripts/validate-examples.mjs`](../../scripts/validate-examples.mjs) and [`scripts/check-text-integrity.mjs`](../../scripts) are the model to extend. + +--- + +## 7. Dependencies between phases + +``` +opf-render (P1) ──┬──> opf-editor (P2) needs traceable SVG + └──> opf-pptx (P3) needs chart rasterization + geometry +opf-pptx (P3) <──────── opf-pptx (P4) round-trip invariant +``` + +Build order: **P1 → (P2 ∥ P3) → P4.** P2 and P3 are independent once P1 lands and can proceed in parallel. P4 depends on P3 for the round-trip test. + +--- + +## 8. Risks / open questions + +1. **Text layout fidelity vs PowerPoint.** PowerPoint's line-breaking and autofit are not fully documented. Greedy + normAutofit approximation gets close; exact parity is a long tail. Golden files against LibreOffice-rendered PPTX bound the drift. +2. **`harfbuzzjs` determinism across versions.** Pin the WASM build; shaping output can shift between HarfBuzz versions and silently invalidate golden files. Treat font + shaper versions as part of the golden-file contract. +3. **Placeholder→OOXML map is unspecified today.** Phase 3 must resolve what [`layout-placeholders.md`](layout-placeholders.md) deferred; until then, OPF→PPTX placeholder typing is best-effort. Feed decisions back as a follow-on to that plan. +4. **`blocks` layout is renderer-defined.** The renderer-positioned `blocks` form has no fixed regions, so its layout algorithm *is* the spec for those slides. Two renderers could disagree. Document the allocation rule in `opf-render` and treat it as canonical, or promote it into the spec later. +5. **Import is lossy by nature.** PPTX→OPF can't recover authoring intent perfectly. Set expectations at "editable and recognizable"; the AI pass ([§4.3](#43-optional-ai-pass)) narrows the gap but stays optional. +6. **LibreOffice in CI.** Headless LibreOffice is heavy and occasionally non-deterministic across versions. Pin the container image; keep it verification-only and out of the runtime/install path. + +--- + +## 9. OpenPresentation OSS boundary + +Making the renderer and converters MIT changes the boundary described in the current [`PRODUCT.md`](../../PRODUCT.md). The deliberate change: + +- **Render and convert become OpenPresentation OSS primitives** (these three repos), siblings of the format and the gallery. +- **OpenPresentation provides code, not hosted functions.** The org does not ship hosted APIs, queues, storage, auth, jobs, previews, SLAs, telemetry, or managed infrastructure. +- **Downstream applications own the product layer.** Hosted services, agent products, internal tools, and self-hosted systems can wrap the OSS libraries in their own environments. +- **The adoption goal is interoperability.** The format, renderer, editor primitives, and converters should be useful to any integrator without forcing a specific product architecture. + +`PRODUCT.md` is updated in this change set to reflect render/edit/convert as open primitives and to keep hosted-service concerns outside the OpenPresentation OSS repos. The `legacy/README.md` tombstone is unaffected — those were service-specific clients, distinct from these new local primitives. diff --git a/legacy/README.md b/legacy/README.md index 5645001..c9bb8a5 100644 --- a/legacy/README.md +++ b/legacy/README.md @@ -1,10 +1,12 @@ -# Legacy PPTX.dev Code +# Legacy Service Code -The copied PPTX.dev client, CLI, Go SDK, and MCP source trees were removed from -this repository after migration to PPTX.dev-owned workspaces. +The copied service-specific client, CLI, Go package, tool integration, and +workflow source trees were removed from this repository after migration to +service-owned workspaces. OPF now keeps format-owned assets only: schemas, catalogs, examples, docs, -generated local types, and the local OPF CLI. +generated local types, the local OPF CLI, and planning docs for local OSS +render/edit/convert libraries. | Previous path | New location | |---|---| diff --git a/packages/cli/README.md b/packages/cli/README.md index cd6f33b..5d3521d 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -1,6 +1,6 @@ # @openpresentation/cli -Local-only CLI source for OPF. This is not a published package in v0.2.0, and it is not a PPTX.dev client. It does not render, parse, generate, call remote APIs, fetch catalogs, or use AI. +Local-only CLI source for OPF. This is not a published package in v0.2.0, and it is not a hosted-service client. It does not render, parse, generate, call remote APIs, fetch catalogs, emit telemetry, or use AI. Native Mac/Linux/Windows distribution and npm CLI publishing are intentionally deferred until a separate CLI package is approved. diff --git a/packages/javascript/README.md b/packages/javascript/README.md index a1b0731..043fa62 100644 --- a/packages/javascript/README.md +++ b/packages/javascript/README.md @@ -2,9 +2,9 @@ Canonical Open Presentation Format package for JavaScript and TypeScript. -Publishes the OPF schemas, catalog presets, raw spec files, generated TypeScript types, and local validation helpers. The schema is pre-stable (0.x — expect breaking changes between minor versions until 1.0). This package does not render PowerPoint files, parse `.pptx`, fetch remote catalogs, or use AI. +Publishes the OPF schemas, catalog presets, raw spec files, generated TypeScript types, examples, docs, and local validation helpers. The schema is pre-stable (0.x — expect breaking changes between minor versions until 1.0). This package does not render PowerPoint files, parse `.pptx`, fetch remote catalogs, call hosted APIs, provide telemetry, or use AI. -The canonical npm package remains `@openpresentation/opf`; a separate `@openpresentation/opf-spec` package is not used for v0.2.0 so existing downstream imports stay stable. The packed npm artifact includes package-addressable OPF schemas, catalogs, reference files, and `openapi.yaml` under `spec/`. +The canonical npm package remains `@openpresentation/opf`; a separate `@openpresentation/opf-spec` package is not used for v0.2.0 so existing downstream imports stay stable. The packed npm artifact includes package-addressable OPF schemas, catalogs, reference files, and an optional downstream-service reference `openapi.yaml` under `spec/`. Repository: https://github.com/OpenPresentation/opf @@ -170,7 +170,7 @@ import presentationSchema from "@openpresentation/opf/spec/schemas/opf.schema.js }; ``` -The raw spec manifest exposes typed package paths for files that should be resolved from npm instead of GitHub: +The raw spec manifest exposes typed package paths for files that should be resolved from npm instead of GitHub. `openapi.yaml` is a reference contract for downstream services that choose to expose OPF over HTTP; OpenPresentation does not host that API. ```ts import { specFileEntries } from "@openpresentation/opf/spec-files"; diff --git a/spec/openapi.yaml b/spec/openapi.yaml index ed8dbf1..792b730 100644 --- a/spec/openapi.yaml +++ b/spec/openapi.yaml @@ -1,32 +1,32 @@ openapi: 3.1.0 info: - title: pptx.dev API + title: OPF Service API Reference version: "1.0.0" description: | - REST API for parsing, validating, converting, generating, and rendering presentations. + Reference REST API shape for downstream services that parse, validate, convert, generate, or render presentations with OPF. OPF (Open Presentation Format) is the JSON contract; schema URL: `https://openpresentation.org/schema/opf/v1`. - **Authentication:** Send `Authorization: Bearer ` on every request, or use a signed-in browser session (Studio). `POST /v1/preview` is anonymous (IP rate-limited) for the OPF Playground. + OpenPresentation does not host this API. Implementers may use this contract as a starting point for their own hosted services, internal tools, or self-hosted deployments. - Human-readable docs: [pptx.dev/docs](https://www.pptx.dev/docs) + **Authentication:** Send `Authorization: Bearer ` on authenticated requests. `POST /v1/preview` is shown as an optional unauthenticated preview endpoint for services that choose to expose one. contact: - name: pptx.dev - url: https://www.pptx.dev + name: OpenPresentation + url: https://openpresentation.org license: name: MIT url: https://opensource.org/licenses/MIT servers: - - url: https://api.pptx.dev - description: Production API + - url: https://api.example.com + description: Downstream service endpoint - url: http://localhost:3000/api - description: Local Next.js App Router (`/api` prefix) + description: Example local development endpoint tags: - name: playground - description: Anonymous OPF playground helpers (IP rate limits) + description: Optional unauthenticated OPF preview helpers - name: validate - description: OPF schema validation (no billing for validation) + description: OPF schema validation - name: parse description: Upload and inspect .pptx files - name: convert @@ -421,7 +421,7 @@ components: bearerAuth: type: http scheme: bearer - description: Clerk user or org API key (`ppx_…`), or session cookie from signed-in Studio user. + description: Service-defined bearer token. parameters: ParseId: @@ -479,7 +479,7 @@ components: OpfDocument: type: object - description: OPF v1 document. See https://www.pptx.dev/docs/opf for field reference. + description: OPF v1 document. See https://openpresentation.org/schema/opf/v1 for the canonical schema. additionalProperties: true properties: $schema: