Validate OPF files
Every OPF pipeline should validate documents against the canonical JSON Schema before rendering. Here are three ways to do it.
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 Ajv from "ajv"
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"))
const ajv = new Ajv({ 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 ajv-cli validate -s opf.schema.json -d deck.opf.json --spec=draft2020 -c ajv-formatsThe OPF package
The @openpresentation/opf package bundles the schema and exposes a validatePresentation helper, so you don't need to fetch the schema separately:
import { validatePresentation } from "@openpresentation/opf"
import { readFileSync } from "node:fs"
const deck = JSON.parse(readFileSync("deck.opf.json", "utf8"))
const result = validatePresentation(deck)
if (!result.valid) {
console.error(result.errors)
process.exit(1)
}Newer versions of the validator also return a separate warnings array for advisory issues, such as references to unknown catalog ids. Warnings never affect valid — treat them as hints, not failures. Check the developer docs for the package's current publication status.
Color references, variables, and bundling
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 pinned @openpresentation/opf npm release — upgrade the package when a new registry version ships ColorRef support so local and hosted validation match.
Sample fixture (not in the published examples corpus): color-references.opf.json.
Use the CLI to inline catalog references for offline handoff. Remote assets are not copied:
opf bundle authored.opf.json portable.opf.json
# Bundling inlines every bundled catalog record the document references
# (including transitive theme → color/font scheme ids) into catalogs.<kind>.records.
# Custom catalog sources and remote media (https: images, chart data URLs) stay external.See CLI for agents for the full opf bundle 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 ajv-cli validate -s opf.schema.json -d "$deck" --spec=draft2020 -c ajv-formats
done