The OAF format
The Open Authoring Format is the representation everything converts through. A reader's job is to produce a valid OAF package; a writer's job is to consume one. Neither needs to know the other exists.
The current specification version is 1.0, carried on every package as
metadata.oafVersion.
Package shape
An OAF package is six parts:
interface OAFPackage {
metadata: OAFMetadata; // title, author, language, dates, source format
course: OAFCourse; // scene refs, navigation, variables, settings
scenes: OAFScene[]; // each holds slide refs
slides: OAFSlide[]; // the actual content
quizzes: OAFQuiz[]; // referenced from slide objects
media: OAFMediaRef[]; // manifest of every asset
}
Scenes and slides are stored flat and referenced by path, not nested. A
OAFSceneRef points at scenes/scene-001.json; a OAFSlideRef points at
slides/slide-001.json. The schema enforces those path shapes.
Storing them flat means a single slide can be read without parsing the whole course.
Content model
The nesting that matters is inside a slide:
Slide
└── Layer (a content group, with its own visibility)
└── Object (text, image, video, audio, shape, button, hotspot, quiz)
├── position (x, y, width, height, rotation, zIndex)
├── content (for text objects)
├── media (for image/video/audio objects)
├── quiz (for quiz objects)
└── styles
Layers carry a visible flag, which is how source tools represent content that
appears in response to something the learner does.
Text
Text is structured, not a string. A OAFTextContent holds blocks; a block is a
heading, paragraph, or list; each block holds spans, and formatting lives on the
span:
interface OAFTextSpan {
text: string;
bold?: boolean;
italic?: boolean;
underline?: boolean;
strikethrough?: boolean;
link?: string;
color?: string;
fontSize?: number;
fontFamily?: string;
}
This is what lets a Markdown writer emit ## Heading and **bold** rather than
guessing from font sizes.
textContentToPlain() flattens the structure when a writer only needs the
words.
Behavior
Three constructs carry interactivity, and they are the ones flat text outputs cannot represent.
Interactions hang off an object and fire on click, hover, focus,
dragstart, or drop.
Triggers hang off a slide and fire on slideStart, slideEnd,
timelineStart, timelineEnd, or variableChange. A trigger may carry an
OAFCondition that gates it.
Both resolve to an action:
type OAFActionType =
| 'navigate' | 'showLayer' | 'hideLayer'
| 'playMedia' | 'pauseMedia'
| 'setVariable' | 'jumpToSlide' | 'openUrl';
Variables are declared at course level with a name, a type
(string | number | boolean), and a default. Triggers read them through
conditions and write them through setVariable.
Quizzes
Quizzes are stored separately and referenced from a slide object by
OAFQuizRef, because the same question can appear in more than one place.
Seven types are defined: multiple-choice, true-false, fill-blank,
matching, drag-drop, sequence, and essay.
A quiz carries its question as OAFTextContent, its options, its correct
answer (a string or an array), and optional points, per-answer feedback,
attempt limit, shuffle flag, and required flag.
Navigation
OAFCourse.navigation.mode is one of:
| Mode | Meaning |
|---|---|
linear | Slides are taken in order |
free | The learner moves anywhere |
restricted | Movement is gated, typically on completion |
Alongside it sit showMenu, allowSeeking, and allowSkipping.
Schema validation
Five JSON Schemas ship with @oaf/spec, under src/schemas/:
| Schema | Covers |
|---|---|
metadata.schema.json | Package metadata |
course.schema.json | Course structure and navigation |
scene.schema.json | Scenes and their slide references |
slide.schema.json | Slides, layers, and objects |
quiz.schema.json | Quiz definitions |
They are drafted against JSON Schema 2020-12 and set
additionalProperties: false throughout, so an unrecognized field is an error
rather than something silently carried along. A converter emitting a field the
schema does not know about will fail validation, which is the intent.
Related
- Format support — what converts to what today
- Type reference — the full type surface
- Inspect and validate — checking a package