Four Content Kinds Supported Within the Scene Generic in OpenMAIC: Complete TypeScript Reference

The Scene generic in OpenMAIC supports four persisted content kinds—Slide, Quiz, Interactive, and PBL (Project-Based Learning)—defined as a discriminated union in lib/types/stage.ts that extends the base @openmaic/dsl contract.

OpenMAIC implements a flexible content architecture through its generic Scene type, which wraps the contract-defined @openmaic/dsl Scene to support diverse educational content. The generic parameter SceneContent creates a type-safe union encompassing four distinct content kinds, enabling developers to handle everything from static slides to complex project-based learning configurations within a single consistent interface.

Understanding the Scene Generic Architecture

The Scene type in OpenMAIC serves as a generic wrapper that enriches the base contract with application-specific content variants. Located in lib/types/stage.ts (lines 57-90), this implementation defines SceneContent as a four-way union that accommodates varying pedagogical content structures while maintaining strict TypeScript type safety.

The generic structure allows the Scene type to hold both an actions array and a discriminated content field, where the type property determines which of the four supported kinds is active.

The Four Content Kinds Supported Within the Scene Generic

OpenMAIC extends the base @openmaic/dsl contract—which only includes slide and quiz—with two additional kinds to form the complete union.

Slide Content (slide)

The Slide kind represents standard slide content containing text, images, videos, and other static media elements. As the foundational content type inherited from the base DSL contract, it supports rich multimedia layouts without interactive requirements.

Quiz Content (quiz)

The Quiz kind handles interactive assessment elements including questions, options, and answer configurations. This type manages both single-select and multiple-choice interactions, storing question metadata and scoring logic within the scene's content field.

Interactive Content (interactive)

The Interactive kind enables embedded web pages and iframes through the InteractiveContent type, which utilizes a WidgetConfig-based payload. This extends the base contract capabilities by allowing external tools and widgets to run within the scene framework, configured via the widgetConfig property.

PBL Content (pbl)

The PBL (Project-Based Learning) kind stores complex project configurations through the PBLContent type. It maintains both legacy project configuration data and optional V2 runtime state (projectV2), supporting long-form collaborative learning experiences that persist across multiple sessions.

TypeScript Type Definitions and Unions

The type system defines the relationship between these content kinds through a hierarchical union structure. According to the source code in lib/types/stage.ts:

export type AppSceneContent = DslSceneContent | InteractiveContent | PBLContent;
export type SceneContent = AppSceneContent;   // the four-way union used by Scene

Here, DslSceneContent represents the base contract types (slide and quiz), while InteractiveContent and PBLContent are OpenMAIC-specific extensions. The Scene generic uses this SceneContent union to ensure that only valid content payloads are assigned to a scene's content field.

Practical Implementation Examples

The following TypeScript examples demonstrate how to instantiate each content kind within the Scene generic:

Slide Scene:

import type { Scene, Action } from '@/lib/types/stage';

const slideScene: Scene = {
  id: 's1',
  order: 0,
  title: 'Intro Slide',
  actions: [] as Action[],
  type: 'slide',
  content: { type: 'slide', elements: [{ text: 'Welcome' }] },
};

Quiz Scene:

const quizScene: Scene = {
  id: 's2',
  order: 1,
  title: 'Quiz Time',
  actions: [] as Action[],
  type: 'quiz',
  content: {
    type: 'quiz',
    questions: [{ id: 'q1', type: 'single', prompt: 'What?' }],
  },
};

Interactive Scene:

import type { InteractiveContent } from '@/lib/types/stage';

const interactiveScene: Scene = {
  id: 's3',
  order: 2,
  title: 'Embedded Tool',
  actions: [] as Action[],
  type: 'interactive',
  content: {
    type: 'interactive',
    src: 'https://example.com/tool',
    widgetConfig: { /* widget-specific config */ },
  } as InteractiveContent,
};

PBL Scene:

import type { PBLContent } from '@/lib/types/stage';

const pblScene: Scene = {
  id: 's4',
  order: 3,
  title: 'Project-Based Learning',
  actions: [] as Action[],
  type: 'pbl',
  content: {
    type: 'pbl',
    projectConfig: { /* legacy config */ },
    projectV2: { /* runtime state */ },
  } as PBLContent,
};

Key Source Files and Type Dependencies

Several files work together to implement the four content kinds within the OpenMAIC architecture:

  • lib/types/stage.ts: Declares the Scene generic, the four content kind definitions, and the makeScene factory function.
  • @openmaic/dsl (external package): Provides the base contract types SlideContent and QuizContent that form the foundation of the union.
  • lib/types/action.ts: Defines the Action type used in every Scene instance's actions array.
  • lib/types/widgets.ts: Supplies the WidgetConfig interface consumed by InteractiveContent payloads.
  • lib/pbl/legacy/read.ts and lib/pbl/v2/types.ts: Contain the legacy and V2 project configuration types referenced by PBLContent.

Summary

  • OpenMAIC's Scene generic supports four content kinds: Slide, Quiz, Interactive, and PBL.
  • The base @openmaic/dsl contract provides Slide and Quiz, while OpenMAIC adds Interactive and PBL extensions.
  • Type definitions reside in lib/types/stage.ts, utilizing a union type SceneContent that encompasses all four variants.
  • Each content kind uses TypeScript discriminated unions via the type property for compile-time type narrowing.
  • Interactive content relies on WidgetConfig from lib/types/widgets.ts, while PBL content references legacy and V2 types from the lib/pbl/ directory.

Frequently Asked Questions

What is the difference between the base contract and OpenMAIC's Scene generic?

The base @openmaic/dsl contract defines only Slide and Quiz content kinds. OpenMAIC's Scene generic extends this through the AppSceneContent union type, adding Interactive and PBL kinds to support embedded widgets and project-based learning workflows. This widening occurs in lib/types/stage.ts where SceneContent combines both base and extended types.

How does the Interactive content kind handle external widget configuration?

The Interactive kind uses the InteractiveContent type, which includes a widgetConfig property typed as WidgetConfig from lib/types/widgets.ts. This configuration object manages iframe sources, sizing parameters, and widget-specific metadata, allowing external tools to integrate seamlessly within the scene framework while maintaining type safety through the generic parameter.

Can I extend the Scene generic with additional content types?

While the current implementation in lib/types/stage.ts defines a fixed four-way union, TypeScript's structural typing allows extension by modifying the AppSceneContent union to include new content interfaces. Any new kind must implement the discriminated union pattern with a unique type property and should be added to the SceneContent definition to maintain compatibility with the generic Scene type constraints.

Where is the PBL legacy configuration defined in the codebase?

The PBL content kind references legacy project configurations defined in lib/pbl/legacy/read.ts, while the modern V2 runtime state is declared in lib/pbl/v2/types.ts. The PBLContent interface aggregates both structures, storing legacy data in projectConfig and optional V2 data in projectV2, enabling backward compatibility with existing project-based learning content while supporting new feature iterations.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →