Stories lets you build, edit, and publish interactive “stories”. A story is made of connected parts. Each part can play a video and optionally show an interactive overlay such as an announcement or quiz. Branching rules control how parts follow each other.
Stories includes:
An anthology is a list of stories that are played in sequence.
A story is the full interactive experience a viewer plays through.
A part is one step in the story. Every part has:
Parts are connected using branching logic, which decides which part plays next.
Currently, a background layer is always a video. Supported video sources are (1) .m3u8 stream URLs and (2) YouTube URLs.
Foreground layers appear on top of the video. Available foreground types are currently:
Branching rules decide which part plays next. They are what makes a story interactive instead of linear.
Stories supports two types of branching:
Each part can define a default next part. This is the part that plays automatically when the video finishes. Use this when your story should continue normally without requiring input. Example: Part A finishes → Part B starts.
If a part contains a quiz, the next part can be chosen based on the viewer’s answers. Quiz branching uses rules such as:
Quiz rules are evaluated when the quiz is completed. You can also define a fallback part (default rule) for answers that do not match any specific rule.
⚠️ Important: If you use quiz branching, avoid setting a normal default next part for the video ending unless you want the quiz to be time-limited. Otherwise the video may end and continue before the viewer answers.
In the Story editor, Stories are displayed as a canvas of cards. Each card represents one part.
You can:
Each part can contain:
Before you can fully build parts, you usually need to define story-wide assets in Settings.
You maintain a story video library.
Create reusable announcement templates and translations.
Create reusable quiz templates, add questions, answer options, and reorder them.
⚠️ Quiz branching is configured per part, not per quiz. This means the same quiz can be reused in multiple parts, and each part can send the viewer to different next parts. To edit the branching rules for the quiz in the current part, click the cog icon (⚙️) next to the selected quiz name.
A Story may support multiple display orientations. Allowed orientations are: portrait (aspect ratio of 16:9; this is usually the default in mobile-first designs), landscape (aspect ratio of 9:16), and square (aspect ratio of 1:1).
When adding videos (or thumbnails), you see an Orientation selector next to the URL field. You choose Default, Portrait, Landscape, or Square, and then paste the URL for that orientation.
The value default is the fallback when a specific orientation is not provided. For orientations, the system looks for the requested orientation first, then falls back to default, then to portrait. This ensures a video still plays even if you only set a single source.
In practical terms: if you only fill in default, that value will be used everywhere until you add specific orientation variants.
When editing a story, announcements, or quiz text, you’ll see language‑aware input fields. You pick a language from the Language dropdown (flag or world icon), and then type the text for that language. Switching the dropdown lets you fill in another language for the same field.
In particular, this applies to:
The value default (displayed with 🌐 in the editor) is the fallback when a specific language is not provided.
For translations, the system looks for the requested language first, then falls back to default, then to English. This ensures something is always shown even if a translation is missing.
In practical terms: if you only fill in default, that value will be used everywhere until you add specific language variants.
The public story player is designed (with a transparent body) to be embedded through an iframe. The player triggers an event (using postMessage) back to the parent when the story completes. This means you can place the public story URL in an iframe and listen for completion events in the host page, using something like:
<iframe
id="story"
title="Story"
frameborder="0"
style="overflow:hidden;height:100%;width:100%"
height="100%"
width="100%"
src="{src}"
sandbox="allow-scripts allow-same-origin allow-presentation"
allow="autoplay; encrypted-media; picture-in-picture; fullscreen"
>
</iframe>
export class StoryEvent {
isCompleted: boolean;
start: Date;
end: Date;
watchTime: number;
watchTimePercentage: number;
}
const allowedOrigins = ['http://localhost:5174', 'https://stories.example.com'];
window.addEventListener('message', (event: MessageEvent) => {
if (!allowedOrigins.includes(event.origin)) {
return;
}
const story = event.data as StoryEvent;
});
⚠️ Always validate event.origin. Never trust messages from unknown domains.
The player supports choosing an orientation through the embed URL. Supported values are portrait, landscape, or square. For example: /square forces a square layout.
The player chooses language from the embed URL. To set a language, add the language code as a path segment. For example: add /nl for Dutch.