Validate OPF files
Run the OPF checker before rendering. Use Ajv when you need only the JSON Schema format check.
The OPF package
The @openpresentation/opf package bundles the schema and exposes a validate function, so you don't need to fetch the schema separately:
npm install @openpresentation/opf @openpresentation/gallery@^0.31.0import { validate } from "@openpresentation/opf"
import { gallery as defaultCatalog } from "@openpresentation/gallery"
import { readFileSync } from "node:fs"
const deck = JSON.parse(readFileSync("deck.opf.json", "utf8"))
// The package ships no catalog records: register the catalogs your documents reference (the first is the host default).
const report = validate(deck, { only: ["format", "references"], catalogs: [defaultCatalog] })
if (!report.valid) {
console.error(report.findings.filter((finding) => finding.severity === "error"))
process.exit(1)
}The report is one list of findings. Advisory issues, such as a reference that resolves in no embedded or registered catalog (opf/unresolved-reference), are findings with severity warning. Register the catalogs your documents use with the catalogs option, for example validate(deck, { catalogs: [defaultCatalog] }) with defaultCatalog from @openpresentation/gallery; without one, only the records a document embeds resolve. Warnings never affect valid — treat them as hints, not failures. Check the developer docs for the package's current publication status.
Get the schema
The canonical OPF v1 JSON Schema is served at https://openpresentation.org/schema/opf/v1 — the same URL every deck references in its $schema field. Fetch it once and validate locally:
curl -sL https://openpresentation.org/schema/opf/v1 -o opf.schema.jsonA browsable version with field-by-field documentation is at the OPF schema reference.
Ajv in Node.js
Ajv is the standard JSON Schema validator for JavaScript. Install ajv and ajv-formats, then:
import Ajv2020 from "ajv/dist/2020.js"
import addFormats from "ajv-formats"
import { readFileSync } from "node:fs"
const schema = JSON.parse(readFileSync("opf.schema.json", "utf8"))
const deck = JSON.parse(readFileSync("deck.opf.json", "utf8"))
// The OPF schema is JSON Schema draft 2020-12: use Ajv's 2020 build (the default "ajv" export is draft-07).
const ajv = new Ajv2020({ allErrors: true })
addFormats(ajv)
const validate = ajv.compile(schema)
if (validate(deck)) {
console.log("Valid OPF document")
} else {
console.error(validate.errors)
process.exit(1)
}ajv-cli
Validate from a terminal or script without writing any code:
npx -p ajv-cli -p ajv-formats ajv validate -s opf.schema.json -d deck.opf.json --spec=draft2020 -c ajv-formats-p ajv-formats installs the formats plugin next to ajv-cli, where -c ajv-formats looks for it. The command exits 0 for a valid deck and 1 with the schema errors otherwise.
Color references, variables, and embedding
Content colors accept literal hex, color-scheme slot or role names (accent2, textSecondary), and document variables as var:<id>. Define variables at the top level with a hex string or { "type": "color", "value": "#…" }. The format card compresses the authoring rules; content payloads and design resolution explain table cells and themes in depth.
The hosted schema at /schema/opf/v1 tracks the OPF repository snapshot this site syncs on build. The in-browser playground validates with the installed core and Gallery packages. ColorRef, variables and embedding are supported by the current contract; register matching catalogs or embed the records your deck uses.
Sample fixture (not in the published examples corpus): color-references.opf.json.
Use the CLI to embed the catalog records a document references for offline handoff, so it renders the same where no catalog is registered. Remote assets are not copied:
opf embed authored.opf.json portable.opf.json
# Embedding copies every catalog record the document references (including the color scheme and font
# scheme a theme names) into catalogs.<group>.<kind>.<id>, once, under the catalog it came from.
# Records the document already embeds are kept. Remote image URLs stay external. Chart and table data is inline or references a deck dataset.See CLI for agents for the full opf embed report fields.
Validate in CI
If decks live in your repository, validate them on every push so invalid documents never reach a renderer:
# .github/workflows/validate-decks.yml
name: Validate OPF decks
on: [push, pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: curl -sL https://openpresentation.org/schema/opf/v1 -o opf.schema.json
- run: |
shopt -s nullglob
for deck in decks/*.opf.json; do
npx -p ajv-cli -p ajv-formats ajv validate -s opf.schema.json -d "$deck" --spec=draft2020 -c ajv-formats
done