OPF
SpecAuthoring schema referenceView source

Narrative Template

Schema for narrative records. A narrative is a plan: a named story arc (e.g. 'problem-solution', 'scqa') as an ordered list of beats, each saying what its slide must do. A document points at one with the string 'narrative' and links its slides to beats with 'slides[].beat'; a narrative the document defines itself is a record in catalogs.custom.narratives. Core validate warns about a 'slides[].beat' id the resolved narrative does not define (opf/unknown-beat) and about a root 'duration' outside this record's 'duration' range (opf/duration-outside-narrative), and reports a beat no slide references (opf/unused-beat). A document references a record as a bare id or 'name:id' and resolves it in its own catalogs groups first, then in the catalog the host registered for the group's source; engines never fetch a catalog. A published record file carries '$schema' and 'id'; the copy a document embeds under catalogs.<group>.<kind>.<id> carries neither (the key is the id) and no 'x-*' display metadata.

Schema $id
https://openpresentation.org/schema/opf-narrative/v1
Type
object
Source
spec/schemas/narrative.schema.json
Fields
10 · 4 required

Field index

FieldTypeReq.DefaultDescription
$schemaconstyes—Identifies a published record file as a narrative record. Required in a published file; an embedded copy omits it.
$schema · Allowed values
"https://openpresentation.org/schema/opf-narrative/v1"
idstringyes—The narrative's id in its catalog, lowercase kebab-case. Required in a published record file; a document references the record by it (a bare id, or 'name:id' for a named group) and embeds it keyed by it, without this field.
namestringyes—Human-readable template name, e.g. 'Problem → Solution'.
summarystring——One-sentence description of when and why to use this narrative.
descriptionstring——Longer prose describing the narrative arc and ideal use cases. Used by AI-driven generation to seed deck-level direction.
audienceFitarray<string>——Audiences this narrative works well for, e.g. ['executive', 'investor', 'customer'].
durationobject——Typical talk length this narrative suits, as a range in minutes. A deck's own target is the root 'duration' (one number); core validate warns when that target lies outside this range, and when 'min' is greater than 'max'.
tagsarray<string>——Free-form labels for filtering and search, e.g. ['business', 'pitch', 'internal'].
previewobject——Visual previews of the record, used by picker UIs and inline rendering. All sub-fields are optional; engines fall back gracefully when previews aren't available.
beatsarray<ref:Beat>yes—Ordered list of beats that make up the narrative arc.

$schema

typeconstrequiredyesdefault—

Identifies a published record file as a narrative record. Required in a published file; an embedded copy omits it.

$schema · Allowed values
"https://openpresentation.org/schema/opf-narrative/v1"
$schema.json
{
  "$schema": "https://openpresentation.org/schema/opf-narrative/v1"
}

id

typestringrequiredyesdefault—pattern^[a-z][a-z0-9-]*$

The narrative's id in its catalog, lowercase kebab-case. Required in a published record file; a document references the record by it (a bare id, or 'name:id' for a named group) and embeds it keyed by it, without this field.

name

typestringrequiredyesdefault—

Human-readable template name, e.g. 'Problem → Solution'.

summary

typestringrequirednodefault—

One-sentence description of when and why to use this narrative.

description

typestringrequirednodefault—

Longer prose describing the narrative arc and ideal use cases. Used by AI-driven generation to seed deck-level direction.

description.json
{
  "description": "Open with the cost of slow agentic workflows, contrast with what becomes possible at sub-second latency, then walk through our architecture and benchmark results, ending with a concrete adoption ask."
}

audienceFit

typearray<string>requirednodefault—

Audiences this narrative works well for, e.g. ['executive', 'investor', 'customer'].

duration

typeobjectrequirednodefault—

Typical talk length this narrative suits, as a range in minutes. A deck's own target is the root 'duration' (one number); core validate warns when that target lies outside this range, and when 'min' is greater than 'max'.

tags

typearray<string>requirednodefault—

Free-form labels for filtering and search, e.g. ['business', 'pitch', 'internal'].

preview

typeobjectrequirednodefault—

Visual previews of the record, used by picker UIs and inline rendering. All sub-fields are optional; engines fall back gracefully when previews aren't available.

beats

typearray<ref:Beat>requiredyesdefault—

Ordered list of beats that make up the narrative arc.

beats[].type · Allowed values
"text""list""image""video""chart""table""code""metric""quote""timeline"
Complete definition constraints
Schema constraints
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://openpresentation.org/schema/opf-narrative/v1",
  "$comment": "The v1 in the $id is the pre-1.0 line, not a frozen contract: this schema may change in any 0.x minor release. The release that produced this copy is the version of the @openpresentation/opf package it came from (opf --version; opf schemas lists it next to each id). See docs/schema-versioning.md.",
  "title": "Narrative Template",
  "description": "Schema for narrative records. A narrative is a plan: a named story arc (e.g. 'problem-solution', 'scqa') as an ordered list of beats, each saying what its slide must do. A document points at one with the string 'narrative' and links its slides to beats with 'slides[].beat'; a narrative the document defines itself is a record in catalogs.custom.narratives. Core validate warns about a 'slides[].beat' id the resolved narrative does not define (opf/unknown-beat) and about a root 'duration' outside this record's 'duration' range (opf/duration-outside-narrative), and reports a beat no slide references (opf/unused-beat).\n\nA document references a record as a bare id or 'name:id' and resolves it in its own catalogs groups first, then in the catalog the host registered for the group's source; engines never fetch a catalog. A published record file carries '$schema' and 'id'; the copy a document embeds under catalogs.<group>.<kind>.<id> carries neither (the key is the id) and no 'x-*' display metadata.",
  "type": "object",
  "required": [
    "$schema",
    "id",
    "name",
    "beats"
  ],
  "properties": {
    "$schema": {
      "type": "string",
      "const": "https://openpresentation.org/schema/opf-narrative/v1",
      "description": "Identifies a published record file as a narrative record. Required in a published file; an embedded copy omits it."
    },
    "id": {
      "type": "string",
      "pattern": "^[a-z][a-z0-9-]*$",
      "description": "The narrative's id in its catalog, lowercase kebab-case. Required in a published record file; a document references the record by it (a bare id, or 'name:id' for a named group) and embeds it keyed by it, without this field."
    },
    "name": {
      "type": "string",
      "description": "Human-readable template name, e.g. 'Problem → Solution'."
    },
    "summary": {
      "type": "string",
      "description": "One-sentence description of when and why to use this narrative."
    },
    "description": {
      "type": "string",
      "description": "Longer prose describing the narrative arc and ideal use cases. Used by AI-driven generation to seed deck-level direction.",
      "examples": [
        "Open with the cost of slow agentic workflows, contrast with what becomes possible at sub-second latency, then walk through our architecture and benchmark results, ending with a concrete adoption ask."
      ]
    },
    "audienceFit": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Audiences this narrative works well for, e.g. ['executive', 'investor', 'customer']."
    },
    "duration": {
      "type": "object",
      "additionalProperties": false,
      "description": "Typical talk length this narrative suits, as a range in minutes. A deck's own target is the root 'duration' (one number); core validate warns when that target lies outside this range, and when 'min' is greater than 'max'.",
      "properties": {
        "min": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Shortest talk length, in minutes, this narrative suits."
        },
        "max": {
          "type": "number",
          "exclusiveMinimum": 0,
          "description": "Longest talk length, in minutes, this narrative suits."
        }
      }
    },
    "tags": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "description": "Free-form labels for filtering and search, e.g. ['business', 'pitch', 'internal']."
    },
    "preview": {
      "type": "object",
      "description": "Visual previews of the record, used by picker UIs and inline rendering. All sub-fields are optional; engines fall back gracefully when previews aren't available.",
      "properties": {
        "src": {
          "type": "string",
          "format": "uri",
          "description": "Main preview image (PNG/JPG). Used as the primary visual in picker UIs and previews of the record.",
          "examples": [
            "https://www.pptx.gallery/narratives/classic-story.png"
          ]
        },
        "thumbnailSrc": {
          "type": "string",
          "format": "uri",
          "description": "Smaller thumbnail preview suited to dense grid views.",
          "examples": [
            "https://www.pptx.gallery/narratives/classic-story.thumbnail.png"
          ]
        },
        "vectorSrc": {
          "type": "string",
          "format": "uri",
          "description": "SVG / vector preview for crisp scaling at any size.",
          "examples": [
            "https://www.pptx.gallery/narratives/classic-story.svg"
          ]
        }
      }
    },
    "beats": {
      "type": "array",
      "minItems": 1,
      "items": {
        "$ref": "#/$defs/Beat"
      },
      "description": "Ordered list of beats that make up the narrative arc."
    }
  },
  "$defs": {
    "Beat": {
      "type": "object",
      "description": "A single narrative beat — a labeled segment of the story arc with a specific dramatic purpose. One beat is one slide: 'type' is that slide's Slide.type and 'layout' is its Slide.layout, so a planner copies them straight into a skeleton deck. Split a heavy beat into several beats rather than giving it several slides.",
      "required": [
        "id",
        "name"
      ],
      "properties": {
        "id": {
          "type": "string",
          "pattern": "^[a-z][a-z0-9-]*$",
          "description": "Stable slug used by Slide.beat to reference this beat. Lowercase kebab-case.",
          "examples": [
            "opening",
            "problem",
            "evidence",
            "ask",
            "next-steps"
          ]
        },
        "name": {
          "type": "string",
          "description": "Human-readable beat name, e.g. 'The Problem'.",
          "examples": [
            "Opening",
            "The Problem",
            "Why Now",
            "The Ask"
          ]
        },
        "description": {
          "type": "string",
          "description": "Curator-written prose that explains what this beat should accomplish.",
          "examples": [
            "Quantify the pain customers feel today, with one striking stat the audience can repeat afterward."
          ]
        },
        "instructions": {
          "type": "string",
          "description": "Short author-facing instruction for the beat — typically one phrase. Complements 'description' with a concise directive.",
          "examples": [
            "Capture audience attention",
            "Introduce problem",
            "Detail implementation",
            "Inspire & conclude"
          ]
        },
        "type": {
          "type": "string",
          "enum": [
            "text",
            "list",
            "image",
            "video",
            "chart",
            "table",
            "code",
            "metric",
            "quote",
            "timeline"
          ],
          "description": "Default content kind for the beat's slide: the same values as Slide.type. Helps engines and planners choose a layout when only the beat is known."
        },
        "layout": {
          "type": "string",
          "description": "Suggested layout id for the beat's slide, e.g. 'section-divider', 'title-slide', 'text-left'. Resolves the same way as Slide.layout — against catalogs.layouts and the default catalog at https://www.pptx.gallery/layouts.",
          "examples": [
            "section-divider",
            "title-slide",
            "title-left",
            "two-column",
            "text-left"
          ]
        },
        "thoughtCues": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "Optional speaker or thinking cues for the beat: questions the slide should answer. A planner or author turns them into the slide's notes; no engine copies them there on its own.",
          "examples": [
            [
              "What pain is the audience feeling right now?",
              "Why hasn't anyone solved this yet?"
            ]
          ]
        }
      }
    }
  }
}

Definition choices

Values declared by this schema and its nested definitions. Paths ending in [] describe array items; * describes each dictionary entry. Variant paths apply within the named schema branch.

$defs.Beat.type · Allowed values
"text""list""image""video""chart""table""code""metric""quote""timeline"