Menu

D47. Storyline and Rise modules are imported as Elabora modules: a slide is read, not traced; what has no block yet falls back to a text, a picture or a note (15 Oct 2026, beta)

Authors come with Storyline and Rise modules; « Nouveau module » should take them, as a beta that grows with time, and the design question comes first: how absolute positions on a Storyline slide become a responsive module.

What is read (v1). Storyline 360 keeps its project in a .story, an OPC package (as .pptx is) of undocumented XML (story/story.xml: scenes, variables, quizzes, a media registry; one part per slide: loc boxes, zOrder, texts twice, as plain text and as a Document of styled spans, layers, trigLst triggers, scoreData); its publications (web or LMS) hold the same course as JSON in html5/data/js/*.js, each a window.globalProvideData('<kind>', '<JSON in a JS string>') (slides, layers, objects with positions, textLib/vartext, imagelib, events and actions, data.js questions with their right answers, frame.js menu and notes); Rise 360 has no source file, only exports, whose course is JSON in base64 in the player’s page (window.course = '…' in 2018, window.courseData = "…" 2021–2023, a locales/<locale>.js file 2024–2025, deserialize("…") since September 2025). The reading was checked on real third-party modules kept out of the repository (12 .story projects and their 11 publications under GPL-3.0, 4 Rise exports of public repositories): all 27 give modules that pass elabora validate.

  • Options weighed: the .story only (what most authors have, but undocumented and reverse-engineered by one open-source writer); the publications only (documented by many parsers, faithful, but not every author keeps one); all three. Decided: all three, each detected by its content, zipped or not: a .story (the « structured » level: structure, texts, pictures, layers, questions, simple triggers), a publication (the « faithful » level: the player’s own data, its triggers and questions’ answers), a Rise export (web, SCORM 1.2 and 2004, xAPI: its JSON is the course). Flash-only publications and Articulate’s Review or Reach links are not read. A Storyline block inside Rise is reported; its publication can be imported on its own.

A slide is read, not traced. Options weighed for the absolute positions: (a) keep them, a slide scaled as a picture in a free object or a positioned component (faithful at 1600×900, unreadable on a phone, against docs/design.md §2 « a slide is never scaled down as a picture », words out of blocks, no reflow, no accessibility); (b) one column in the source’s z-order (simple, but z-order is not reading order); (c) a reading order computed from the boxes, with the layout the boxes imply. Decided: (c).

  • Reading order: a recursive XY cut (the model also takes the author’s own focus order, which no reader finds yet: Storyline’s custom focus order cannot be told from its default one): the slide is cut into bands where no object spans the gap (an overlap under 4 slide pixels still cuts, for text padding), each band into columns, left to right, and so on; objects that overlap both ways are read by their top, then their left edge. Items without a box (a slide’s sound) come first.
  • Blocks: a text box is a text block (Markdown of its spans: bold, italic, lists; colours, sizes and fonts left to the theme), or a heading when its style says so; consecutive texts of one column and one step merge into one text block; the visual title (a short text in the top quarter, in the largest type) becomes the screen’s title; two columns of one block each sit side by side (width: half); an image that covers 80 % of the slide is its background, a shape without text is decoration: both are left to the theme and counted, the backgrounds as a decision (« Les garder, décoratives »). Text set in a symbol font (Wingdings) is an icon: decoration.
  • Presentation: Storyline slides become slides (presentation.mode: slides, checked by elabora fit at the reference and minimum windows, read as a page on phones), offered as scrolling pages in the report; Rise lessons are pages that scroll.
  • Layers become layers: dialog when the slide behind cannot be used (Storyline’s modal), else panel. A question’s feedback layers (Correct, Incorrect, by the answer that shows them or by their name) become its options’ feedback. A layer with nothing kept is dropped and reported.
  • States: Normal is kept; Hover, Down, Visited, Disabled and Selected are the player’s ([data-t-visited] styles the visited); a custom state is reported and its Normal look kept; an object hidden at first and shown by a trigger is a block hidden: true shown by show-block.
  • Triggers → events: clicks on buttons, slide start, a layer closed, a medium ended, a variable changed; actions to jump to a slide (or next, previous), show or hide a layer or an object, set or add to a variable, play or pause a medium, exit; conditions on variables (all of them: « and »). Elabora clicks only buttons, which the keyboard reaches too: a clickable picture keeps its picture and gains a button, an invisible hotspot becomes a button named after the text under it (a decision: « relisez leur libellé »). What has no equivalent is reported, the event left out: hover, drag, keys, motion paths, lightboxes, URLs, « else » branches, conditions on states, and JavaScript, which Elabora never runs. Storyline’s own triggers (rollovers, its navigation buttons, attempt counts, _hover, lastSlideViewed) are the player’s and are not imported.
  • Variables: only those an imported trigger reads or writes, typed (number, boolean, string as long as the longest value written: a text-entry variable would weigh in the suspend data for nothing); Storyline’s built-in ones never.
  • Questions: multiple choice, true/false and multiple response become quizzes (a single choice with several right answers becomes multiple), an exact numeric answer a numeric block; Rise’s quiz lessons a page of questions and a results block, its passing score the mastery score. Fill-in, matching, sequence, drag and drop, hotspots, word banks, Likert and question banks have no block yet: their instructions and items in a text block, with a note. A question without feedback gets a generic one until the author writes it (a decision; Elabora asks every option for its feedback, D1).
  • Media: copied as they are into assets/ (the importer never re-encodes; W_MEDIA_NOT_OPTIMIZED and elabora media optimize do it later), streamed from the archive; Storyline’s .mpeg parts are MP4. Flash pictures of old publications are replaced by the asset’s own PNG when it has one, else reported. An image without alternative text is marked decorative (a decision); a video or sound without captions and transcript is marked decorative for now, so the module validates, or keeps its errors (a decision).
  • Timing: an object that appears along the slide’s timeline is shown at once (an Elabora screen without narration shows everything); the report offers steps instead (one per start time, revealed by Continue). Entrance and exit animations are not imported. Narration with its timeline (D24, D28) is not yet: a slide’s sound is an audio block, its notes go to the plan item’s description (they are often the voice-over’s script).
  • Rise maps nearly one to one: text and headings, statements to callouts, lists, images (galleries one under the other), audio and video, accordions; tabs and flashcards as accordions, labelled graphics as the image and an accordion of its markers, processes and timelines as one text, embeds and attachments as links or names, charts as tables, sorting and scenarios as text: each with a note. A continue divider opens the next step (steps), once the activity above is answered when it asks so and there is one.
  • The plan is a draft (D35): one item per screen, its kind guessed (the first an introduction, a question page an assessment, a results page a summary), one objective « À écrire ».

Licences. Articulate’s terms (§2.6) and the Content Library FAQ forbid using its characters, photos, icons and templates outside an Articulate product: media whose original path is in Articulate’s folders (the Content Library, the textures it installs) and Storyline characters are never copied; a note marks each place and the report says how many (« Compris »). A publication keeps no original paths: its library media cannot be told and are copied, which the report’s beta wording says. Fonts: a family Elabora vets (@elabora/fonts) is embedded as elabora font add does; any other (Storyline’s own « Articulate », Arial, Frutiger…) has no web licence Elabora knows and is replaced by a vetted family of its kind (Source Sans 3, Source Serif 4, JetBrains Mono, Caveat, Oswald), a decision per family (« 29 textes en Frutiger LT passent en Source Sans 3 », « Accepter les 29 », or the theme’s font); the source’s font files are never copied. No Articulate code is read or kept.

The report (import-report.json, format elabora-import-report/1, in the module and returned): one sentence (« 34 diapositives du projet Storyline deviennent 34 écrans : 212 éléments repris, 18 en repli simple, 6 non repris et 140 formes décoratives laissées au thème. 3 choix vous attendent. »), then only what needs a person’s choice, grouped, each with its count, the choice applied and the others (the import runs again with them: choices, --choose), then every loss with its status (fallback: kept in a simpler form, not-yet: the importer cannot read it yet, dropped: left out on purpose), its source and where it went, as the LESSON.md export lists its own (D11); French or English after the course’s language. The block standing for a lost feature carries a note for the author.

Interfaces. @elabora/node/import/index: detectImport(file) (kind, root inside the source, packaging, beta) and importCourse({ file, dir?, id?, title?, language?, choices?, author? }) → the module’s folder (or a new project of the library when no dir is given, built in its staging folder), its report, the files written, the fonts added (journaled add_font changes) and the validation counts. elabora import <file> [dir] (an Elabora archive or folder goes on into the library as before). No MCP tool: the server works on one course, and importing makes another; agents run the command. The reading and the conversion are pure (@elabora/core/import/), so the cloud and a browser can import too. In the app (15 Oct 2026). A Storyline or Rise module joined on « Nouveau module » is imported as the new module, with the brief of D51 kept as a new course keeps it (importCourse({ brief, defaultLanguage }): who it is for, the business goal and the duration in the draft plan, the LMS in course.json, the notes in AGENTS.md; the presentation answered is the presentation choice’s default; the language chosen is the module’s when the source says none, as Storyline does not). The report stays in the module until the author closes it: settle_import_report { accept?, close? } marks decisions accepted or deletes import-report.json, each one journaled change that undo reverts. Another choice imports the module again in its own place (importCourse({ replace: <project id>, choices }), report.choices holding what the import was made with): as an archive’s replacement does, the project keeps its id, folder, history and sources, a version of it is taken just before (reason import, which restoring undoes) and its files go to the trash; it keeps its title, course id, language, AGENTS.md and what the author said of it (D51), and loses what was done since, which the app says (the source is closed before the folders move: Windows refuses to move a folder holding an open file, and the app reads it from the module’s own sources/). A module imported into the library gets a course id no other module there has, its title’s numbered when taken. Revisit if: authors bring Storyline 360 projects whose XML differs (tested on Storyline 3; the storyline_MCP writer documents 360’s), modules lean on drag and drop, hotspots or fill-in questions (blocks to make), narrated slides should keep their timeline (lines from captions, timed blocks from start times), the Content Library can be recognised in publications, or an author holds a web licence for a font Elabora does not vet (then elabora font add --file after the import, or an import option).

23 Oct 2026: Rise scenarios become dialogues

With the dialogue block (D61), a Rise scenario block is imported as a dialogue instead of a text: each content of each scene becomes a node, the line a line of the scene’s character (a speaker made from its name, in course.json), the scene description a narration, the answers options with where they go (another content or scene, « try again » as retry, End Scenario as an end), their feedback a trainer’s note and the Correct / Neutral / Incorrect marks of the newer format a quality. The characters’ poses and the scenes’ backdrops are not kept; the block’s note and the report say so. The reader was written from the scenario’s documented model and the fields earlier exports showed (items → slides → description, responses with feedback); the field names of a destination and of a pose are read in several forms until a real export says which.