The content model
How a built module is stored — the snapshot envelope, typed scenes, the layout union, and the draft and publishable contracts.
A Vidext module is typed, validated data, not opaque media. This page describes the shape Vidext stores and plays. For the product view, start with Scenes and layouts.
No public API returns this
No MCP tool or other public endpoint returns a module's snapshot or scenes. The Operator tools list modules and read sources; a module's content is seen and edited in the Vidext app. This page is background for understanding what a module is made of.
The snapshot envelope
A module's playable content is a module snapshot: a versioned JSON envelope around the module itself. Each built version of a module is one immutable snapshot.
ModuleSnapshot { schemaVersion, createdAt, updatedAt?, createdBy?, useCaseId, language?, narrableContentId? }
└── Module { id, title, description?, built? }
└── Chapter[] { id, title, description? }
└── Scene[]languageis the language the module's narration was written and spoken in.builtis present on a module that Vidext's agents built in the chat:{ by: "sandbox", mapper }, wheremappernames the version of the build that laid it out.useCaseIdisnullunless the module was planned with a use case.
Snapshots are validated when read and written. A malformed snapshot is refused, never half-served.
Scenes: a discriminated union
Each scene is:
Scene { id, layoutId, content, audioNarration?, sourceSubsectionLabel?, sourceRefs?, visualConcepts? }layoutId is the discriminant: it names the kind of scene and selects the schema its content follows. It has seven values:
cover · chapter · beat · quiz · video · interactive · closingSix of them are the module's structure: its cover, the start of a chapter, a quiz, a video, an interactive scene, and its closing. Every teaching moment is a beat.
Beat
A beat's content is the beat as the build laid it out, plus what it says:
{ title, screen { kind, …elements }, form, segmentsMs?, avatar?, paragraphs }screen.kindsays what shape the information has (one claim, a set, ordered steps, a timeline, and so on) and decides which elements the screen holds. Each element carries anid, the shorttextwritten for the screen and, when the speech was aligned,at: the milliseconds into the scene's speech at which the voice reaches it. When a long beat is split over several scenes, an element said in an earlier scene is at0and one said in a later scene is at3600000, which this scene never reaches. An element may also carry adescription, a line under its text that forms drawing titles alone leave out.formis how that kind is drawn, its look in product terms, and it must be a form that draws the screen's kind. The build chooses and stores it, so a version renders the same everywhere.nullmeans none was chosen, and the player picks one for the kind.segmentsMs?is how long each speech segment ran when the elements were timed, so new speech for the same text (a translation, another voice) moves each element with it.avatar?appears only on a beat drawn with thepresenterform:image, a still of the module's presenter, andvideo, the presenter speaking the scene's narration. The video is rendered after the build, so a player shows the still until it loads. New speech for the same text keeps the still and drops the video.paragraphsare the one to six paragraphs the beat speaks, one audio segment each. They are heard, not shown: what a learner reads on a beat comes from its title and its screen's elements, plus captions when subtitles are on.
A beat names no chapter: a scene's chapter is the one that holds it.
Quiz
A quiz scene holds one to three questions, and speaks each question as one audio segment. Each question has a kind:
select: three or four answers, exactly one correct;multi: three or four answers, at least two correct;boolean: true or false.
Each question carries an explanation, and select and multi answers can each carry their own feedback.
Video
A video scene names its src, which must be an https URL, and a title. It may also carry measured: the video's length in seconds, as the build read it, with the file size it was read from.
Interactive
An interactive scene carries a small built program the player runs in the scene: its title, a summary of what it teaches and what the learner does (read to screen readers and given to the learner's AI tutor in place of the code), the kit version it runs on, its strings, the built code, and a sha256 of that code. A module carries the whole program, so a version plays without fetching anything but its kit.
Cover, chapter, and closing
A cover carries the module's title and a spoken description, and may carry a promise shown under the title and points, the learning points listed under it. A chapter scene carries the chapter's title and a spoken line, and a closing an optional spoken line.
Scene-level fields
audioNarration?is the generated speech for the scene: ordered segments, each anchored to what it speaks (a beat's paragraph, a quiz's question), with its audio URL, duration, and subtitle cues.sourceRefs?is scene-level provenance: references to the evidence that grounded the scene, each with adocumentId(an uploaded source) or aurl(a web finding), plus anexcerptand arelevancenote. Modules built in the chat by Vidext's agents leave it out: the script a module is built from names the source of each beat instead.visualConcepts?names, in order, what each image slot in the scene depicts.
Draft and publishable: two strictness levels
Most schemas have two variants:
- Draft is permissive: fields may be empty while content is being written.
- Publishable is strict: non-empty strings, positive audio durations, at least one chapter, and at least one scene in each chapter.
Video and interactive scenes use one schema for both: even a draft video needs its title and an https source, and an interactive scene is always written whole.
Content must pass the publishable contract before a version can be built, and only a built version can go live. This is the type-level form of the product's draft, built, and live states. A build by Vidext's agents is checked against the publishable schemas before it is kept, which is why a build cannot produce a structurally broken module.
Last updated on