Importing Storyline and Rise modules
How Storyline 360 and Rise 360 modules are read into one model and converted into Elabora modules, with a report of every loss (beta, D47). Part of the architecture, the contract every change follows.
A module made with Storyline 360 or Rise 360 becomes an Elabora module: its blocks, layers, events and variables, its media copied, a draft plan, and its report. Elabora never traces a slide: it reads it (decision D47).
| Part | Role |
|---|---|
@elabora/core import/model.ts |
One model for every source: sections of pages, items in the source’s terms (a text with its fonts and size, an image, a question…, or a fallback or unsupported feature), boxes on a slide, start times, hidden items, layers, triggers with conditions and actions, variables |
import/storyline-source.ts |
The .story (an OPC package of XML parts): story/story.xml (scenes, variables, quizzes, the media registry, matched to story/media/ by MD5, else by size), each slide part (loc boxes, zOrder, plain and Document texts, pictures, buttons, questions and their scoreData, layers and feedback layers, trigLst triggers and trigCond conditions) |
import/storyline-published.ts |
A publication’s html5/data/js/ (parseProvidedData: the globalProvideData wrapping): data.js (scenes, slides, variables, questions with their right answers, assets), frame.js (scene titles, notes), each slide (layers, objects with their boxes, vartext as HTML or blocks of spans, imagelib, events and action groups, the timeline’s show times); questions as D63’s activities: matching and drag and drop (the right answer’s pairs) as a sort in pairs, sequence as a sort in order, fill in the blank and word bank as fill-ins, Likert as reflections on a scale; the player’s own triggers and variables left out |
import/rise.ts |
A Rise export’s course JSON (findRiseCourse: the ways a page embeds it: 2017 var data, 2018 window.course, 2021–2023 window.courseData, 2025 deserialize(…), or a locale file named by the page, readRiseLocale; and the 2026 runtime-data.js, readRiseRuntime), its lessons, sections, blocks and quiz lessons, a scenario block read as a dialogue (D61); D63’s blocks: statements A–D, quotes (author, portrait, on a picture), image presentations (Rise’s crop as the focal point), galleries, two columns, dividers, panels and tabs (an item’s picture; its embed a link, its video after the panels), flip cards, process and timeline as steps, labeled graphics as interactive pictures (markers in percent), sorting (unscored categories, twelve cards a sort), matching and fill in the blank as activities, charts as D60’s, 2017’s map and sorting lessons; a Continue that waits for the block above opens once explored (once answered after knowledge checks only); media found by their crushed key, src or key |
import/layout.ts |
A slide’s reading order: a recursive XY cut (bands, then columns), or the author’s focus order when a reader gives one; its visual title; its backgrounds |
import/convert.ts |
The model as files (course.json, plan.json, screens/*.json), the media to copy, the vetted fonts to add, and the report; choices take the report’s decisions otherwise. A reader gives D60’s and D63’s blocks as block items, their props as written and their media with where each goes and what its absence does (the prop left out, the entry gone, or the item’s otherwise); assets never take a name a sync service’s conflict copy would have |
import/report.ts |
The report’s shape (elabora-import-report/1) and words, in French or English |
@elabora/node import/source.ts |
A ZIP (ZipReader) or a folder read alike: paths, small texts read whole, media copied by streams and hashed in chunks; nothing outside the source is reachable |
import/index.ts |
detectImport(file) (by content: story/story.xml, html5/data/js/data.js, a Rise player page or a 2026 runtime-data.js, the one nearest the root first, so a Rise course that holds a Storyline block’s publication, or an older export in a folder, is imported as the Rise course; an Elabora archive or folder told apart), importCourse({ file, dir?, … }): the module written into dir, or built in the library’s staging folder and moved into place, its fonts added as elabora font add does (journaled add_font changes), import-report.json, then validated; brief and defaultLanguage (the app’s « Nouveau module », D51), replace: <project id> (imported again in its place, history and sources kept, replaceWithStaged) |
- Inputs: a
.story; a publication, a folder or its zip (the course may sit in a folder of the zip), or itsstory.html; a Rise export, web, SCORM or xAPI, zipped or not. A Storyline block inside a Rise export is reported, not imported. - Storyline’s source (
.story): its matching, sequence, fill in the blank, word bank and Likert questions stay fallbacks (their instruction in a text): the format of those questions in the source is not read yet. - What is never taken: Articulate’s code, media whose original path is in Articulate’s folders (the Content Library, its textures) and Storyline characters (a note marks the place), the source’s font files (fonts without a web licence Elabora knows become vetted fonts, a decision per family), the author’s JavaScript.
- The CLI:
elabora import <file> [dir] [--title] [--id] [--lang] [--choose <decision>=<choice>,…] [--json]. No MCP tool: the MCP server works on one course and importing makes another; agents run the command. The app callsimportCoursefrom « Nouveau module » and shows the report (its sentence, its decisions with their choices;choicesruns it again).