Menu

D62. Layer timelines and voice lines on every track of a screen (23 Oct 2026)

On this page

Storyline authors expect a layer to speak: it opens, a voice explains, and its contents come as the voice names them, like the slide under it. Until now a layer showed every block at once, and timing on a block of a layer was ignored (W_TIMING_IGNORED). Branching dialogues, built at the same time, also need lines said outside the screen’s narration. Both need the voice tools (generation, takes, alignment, transcription, audio status, translation, anchors) to see every line of a screen, wherever it is written. The founder asked for layer timelines in the same piece of work as the dialogues’ voices (23 Oct 2026).

Voice lines

  • One shape. defs.schema.json voiceLine holds what every spoken line has: id, speaker, text, delivery, pronunciations. A screen’s narration line is a voice line with step and pauseBefore, a layer’s with pauseBefore; each holder closes the shape with unevaluatedProperties: false (the type generator reads it, so ScreenNarrationLine is VoiceLine & { step?; pauseBefore? }).
  • Ids unique in the screen, every track counted (E_NARRATION_LINE_DUPLICATE). The audio of a line keeps its path, assets/narration/<language>/<screen>/<line>.m4a, whatever holds it: no new folder, and a line moved from one holder to another keeps its audio.
  • One API. @elabora/core narration/voice-lines.ts screenVoiceLines(project, screen) gives each line with its track ({ kind: 'screen' }, { kind: 'layer', layer }, later { kind: 'dialogue', block, node, option? }), its translation unit and where it is written. narrationLines (the audio’s state), the voice tools, alignment, recordings and transcription, translation units and anchors, the report and the engine’s data read lines through it. A new holder is one more source in VOICE_LINE_SOURCES.
  • Units: a layer’s line is screen.<screen>.layer.<layer>.narration.<line>.text, with the markers of its word anchors (D28).

A layer’s timeline

  • Format. layers[].narration (lines, seek). A layer has one stretch and no steps; it plays through. Its blocks take timing (D28), anchored to the layer’s lines, or { "seconds": n } from its opening when it has no narration. A layer with a narration, timed blocks or cues has a timeline of its own.
  • Anchors stay on their timeline. A block or a cue of a layer names the layer’s lines; one of the screen names the screen’s (E_TIMELINE_ANCHOR_TRACK). An event’s cue on a layer’s line is on that layer’s timeline by itself; layer on the trigger says so for seconds and for timeline.ended; pause-timeline, play-timeline and seek-timeline take layer.
  • Player. Each layer’s timeline is an instance of the screen’s (createTimeline): the same clock, captions and seek rules, a compact bar (play and pause, replay, seek as seek allows, captions) placed beside the layer’s Close button, its captions above it, in the layer. It starts at 0 when the layer opens, stops when it closes. While a layer speaks, the screen’s timeline is held with the existing hold/release (a dialog until it closes, a panel until its narration ends): two voices never overlap. The learner’s Pause stops what is in the layer; the layer’s shortcuts take over the screen’s while it is open; the screen’s transcript adds each layer’s lines under its title.
  • Package. One track per narrated layer, narration/<screen>.<layer>.m4a with its .vtt, built as a screen’s (D24). A dot is never in an id (screens and layers are slugs, language folders are language tags), so the name collides with no screen’s track, in any language folder; narration/<screen>/<layer>.m4a would collide in a package of several languages (narration/<lang>/…) with a screen named like a language.
  • Tools. renderScreen(…, { layer, at }) and the canvas put a moment on the timeline of the layer shown; elabora screenshot --layer x --at …, elabora look --layer x --at …|--sheet and MCP elabora_look capture it; elabora timeline reports each layer after its screen; the engine’s narration, timeline, timelineAt and timelineMarks take layer.

Set aside

  • Seconds for layers only, no narration. A layer explained by a voice is the common case in Storyline; seconds would break as soon as the voice is generated again or translated (D24).
  • A layer’s lines in the screen’s narration, with a layer field. The script would mix two timelines; a step and a layer would both say where a line plays.
  • One timeline for the screen and its layers, the layer’s stretch inserted in the screen’s. A layer opens on an event, at any time, any number of times: its place on the screen’s timeline is not known.
  • Both voices at once (a panel speaking over the screen). Learners cannot follow two voices (redundancy and split attention); the screen waits.

Revisit if: authors need steps inside a layer (a layer that waits for Continue), a layer’s voice that the screen does not wait for (ambient sound), or nested layers with their own voices.