@openpresentation/opf
v0.11.0
Published
Canonical Open Presentation Format schemas, catalogs, TypeScript types, and local validation.
Maintainers
Readme
@openpresentation/opf
Canonical Open Presentation Format package for JavaScript and TypeScript.
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 an optional downstream-service reference openapi.yaml under spec/.
Repository: https://github.com/OpenPresentation/opf
File naming
Use *.opf.json for complete Open Presentation Format documents, such as deck.opf.json.
OPF documents are plain JSON, and the .opf.json suffix keeps that visible to editors, validators, agents, and repository tooling. Avoid bare *.opf for OPF JSON because that extension is already used by other document and project formats.
Install
pnpm add @openpresentation/opf
# or: npm install @openpresentation/opf
# or: yarn add @openpresentation/opfRequires Node 24 starting with version 0.10.0. Earlier published versions retain their recorded runtime requirements.
Usage
Use the common root API for most application code:
import {
presentation,
audiences,
tones,
catalogs,
validate,
validatePresentation,
} from "@openpresentation/opf";
import type { Presentation } from "@openpresentation/opf";
const deck: Presentation = {
name: "Quarterly Review",
slides: [{ title: "Quarterly Review", items: ["Revenue", "Product", "Hiring"] }],
};
console.log(presentation.$id);
console.log(validatePresentation(deck).valid);
console.log(validate(tones[0], "tones").valid);
console.log(audiences.map((audience) => audience.id));
console.log(Object.keys(catalogs));Use focused imports when you only need one surface:
import { presentation, audience } from "@openpresentation/opf/schemas";
import { audiences, tones } from "@openpresentation/opf/catalogs";
import { specFileEntries } from "@openpresentation/opf/spec-files";
import { validate, assertValid } from "@openpresentation/opf/validator";
import {
layoutPreviews,
getLayoutPreview,
hasLayoutPreview,
} from "@openpresentation/opf/previews";
import type { Presentation, Audience, Tone } from "@openpresentation/opf/types";The root entry exports every schema, catalog, and validation helper for convenience. Prefer the focused subpaths above when a package consumer only needs one surface, so the root bundle's full catalog/schema payload is not loaded unnecessarily.
Contextual lint (0.10.0)
Version 0.10.0 adds lintSource(source, options) and lintPresentation(document, options) from @openpresentation/opf/lint and the root API. They report strict JSON syntax, duplicate keys, schema constraints, local catalog alternatives, asset registry errors, and explicit host contracts. Source diagnostics retain original UTF-16 ranges without rewriting the document. Options accept already loaded catalogs and contracts; no remote resources are fetched.
Earlier versions do not include these APIs. See the lint guide for configuration and the source CLI. Passing lint does not certify layout, fonts, or native export fidelity.
Layout previews
@openpresentation/opf/previews ships pre-rendered HTML thumbnails for the
slide layouts catalogued at pptx.gallery. Each preview is a Tailwind-styled
fragment sized to fill a 16:9 container and only depends on the standard
--background, --foreground, --card, --muted, --muted-foreground,
--accent, and --border CSS variables.
import { getLayoutPreview } from "@openpresentation/opf/previews";
export function LayoutThumbnail({ slug }: { slug: string }) {
const html = getLayoutPreview(slug);
if (!html) return null;
return (
<div
className="aspect-[16/9] overflow-hidden rounded-lg border border-border bg-card"
dangerouslySetInnerHTML={{ __html: html }}
/>
);
}Raw HTML source-of-truth lives under spec/previews/layouts/<slug>.html and is
also addressable via @openpresentation/opf/spec/previews/layouts/<slug>.html.
Example decks
@openpresentation/opf/examples ships every .opf.json file from examples/
in the upstream repo, already parsed and validated against the presentation
schema at build time.
import {
examples,
galleries,
getExample,
getExamplesByGallery,
} from "@openpresentation/opf/examples";
const compliance = getExample("compliance-readiness-review");
const businessDecks = getExamplesByGallery("business-functions");
console.log(`${examples.length} example decks across ${galleries.length} galleries`);Each ExampleRecord includes the parsed Presentation object plus its
repo-relative path, top-level category (gallery, technical, …), and
gallery slug when applicable.
Documentation pages
@openpresentation/opf/docs ships the top-level docs/*.md reference pages
(schema-reference, catalog-schema-reference, content-payloads,
content-item-design-overrides, examples). Subdirectories like
docs/migrations and docs/plans are intentionally excluded — those move too
quickly to ship inside a pinned npm release.
import { docs, getDoc } from "@openpresentation/opf/docs";
for (const doc of docs) {
console.log(`${doc.title} — ${doc.file}`);
}
const schemaRef = getDoc("schema-reference");
console.log(schemaRef?.markdown.slice(0, 200));Upstream README
@openpresentation/opf/repo-readme exposes the raw markdown of the upstream
OpenPresentation/opf README.md at the version pinned by this release. Use it
when you want to mirror the canonical README inside another site or app
without doing a network fetch.
import { repoReadme } from "@openpresentation/opf/repo-readme";
console.log(repoReadme.split("\n").slice(0, 3).join("\n"));Validation results carry errors (structural problems that make valid
false) and warnings (advisory issues such as unknown catalog ids in
narrative, design, or chart type references — these never affect
valid). Documents that declare matching inline catalogs.<kind>.records[]
or a custom catalogs.<kind>.source are exempt from unknown-id warnings for
that kind.
const result = validatePresentation(deck);
if (!result.valid) console.error(result.errors);
for (const warning of result.warnings) console.warn(warning.path, warning.message);Validate catalog records locally:
import { audiences, validateCatalogRecord } from "@openpresentation/opf";
for (const record of audiences) {
const result = validateCatalogRecord("audiences", record);
if (!result.valid) {
console.error(result.errors);
}
}Raw canonical JSON is published under spec/:
import presentationSchema from "@openpresentation/opf/spec/schemas/opf.schema.json" with {
type: "json",
};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.
import { specFileEntries } from "@openpresentation/opf/spec-files";
const openApi = specFileEntries.find((entry) => entry.path === "openapi.yaml");
console.log(openApi?.packagePath);Package-addressable catalog paths can be used by OPF catalog resolvers:
{
"catalogs": {
"narratives": {
"source": "pkg:@openpresentation/opf/spec/catalogs/narratives"
}
}
}Development
pnpm --filter @openpresentation/opf typecheck
pnpm --filter @openpresentation/opf test
pnpm --filter @openpresentation/opf pack:dry-runsrc/generated/ and dist/ are generated from the root spec/ directory and are intentionally ignored by git.
