# D28. The fine timeline: timed blocks, anchors to words, effects set to the time (11 Oct 2026)

Phase 2 of the timeline design (D24), on the decisions of 8 October: what is seen is recomputed, triggers fire only in playback; seconds only without narration; trajectories only in a scene or a free object. Storyline authors expect objects that appear as the voice names them, with entrance and exit animations, and a seek bar that drags the slide like a video.
- **Declarative, a pure function of the time.** A block's `timing.in` and `timing.out` say when it comes and goes; nothing shows or hides a block on a cue (that would be Storyline's imperative timeline, wrong as soon as the learner seeks back). The player computes the state of every timed block at the time t at each move: before its moment hidden in its place (`visibility: hidden`, inert: out of reach of the keyboard and of screen readers), during its effect a Web Animation created paused whose `currentTime` is t minus its start, then there, then gone the same way. Playing, seeking back and forth, the playback speed, the editor's playhead and captures are one computation, so a seek never forgets to hide something. Focus inside a block a seek hides goes to the seek bar; a block that comes does not take the focus and is not announced (the voice and a screen reader would talk over each other).
- **Anchors name what is said.** A moment is a line, a word or a few words of it, its end, with an offset; seconds only on screens without narration (`E_TIMING_SECONDS_NARRATED`), from the start of a step. Words are counted by one tokenizer (`narrationWords`: runs of letters and digits joined by apostrophes and hyphens, digits by `.,:/`; a French elision is a word of its own, so « imprimante » in « l'imprimante » can be named) shared by anchors, the aligner and the editor. A word's time comes from its line's word times (the sidecar's `words`, forced alignment: D27); a line out of date keeps the times of the words it still says (a word diff), and without word times words are placed in proportion to the text (`I_TIMELINE_WORDS_ESTIMATED`). Editing a line's text through Elabora takes its anchors along with their words (the same diff); an anchor whose words are gone stays as written and the validator reports it (`E_TIMELINE_ANCHOR_MISSING`), the block falling back to the start of its line. Cues (`timeline.reached`) take the same anchors and are compiled to times; `seek-timeline` moves the playhead as a seek, crossing nothing.
- **No effect is cut by a step's end.** A step's stretch lasts until its last line ends or until the last effect anchored in it ends, whichever is later, and the next step's first line keeps its pause after that; the build lays the track's silences from this layout (`TimelineLayout.gaps`), and the course data's times follow the silences it wrote. A screen without narration but with blocks or cues in seconds has a timeline too, on the page's clock (no track), each step as long as its moments or `steps[n].duration`.
- **Effects are presets relative to the block**: `none`, `fade` (default, 0.4 s), `rise` (0.5 s), `slide` (0.5 s, a direction), `zoom` (0.4 s), `wipe` (0.6 s, a direction), `draw` (1.2 s: the strokes of the block's inline drawing, a wipe for blocks without one). They change opacity, translate, scale, clip-path or strokes, never the layout, so they hold on a phone and never move the slide. A theme adds its own (`theme.effects`; its stylesheet's `@keyframes t-fx-<name>`, read from the page's stylesheets and played as Web Animations, `-out` for leaving or the same backwards). Under reduced motion every effect is a short fade (0.2 s) at the same time. GSAP stays excluded (its licence; D24).
- **A stack holds what Storyline stacks**: the built-in block `stack` (« Pile ») puts its contents in one grid cell the size of the largest, each shown from its moment until the next one's, with a transition (crossfade, cut, slide). Without a timeline its contents come one under the other.
- **What learners can still do.** A timed activity is usable as soon as it is there; one that leaves while playback goes on, before it stops for the learner (the end of a learner step, a step that opens once answered, the end of the screen), is an error (`E_ACTIVITY_LEAVES_UNANSWERED`), as is a block that leaves before it comes (`E_TIMING_ORDER`). Text shown less than its reading time (17 characters a second, 1.5 s at least) and captions said faster than 25 characters a second are warnings (`W_TEXT_TOO_FAST`), as are more than five seconds of effects running into one another (`W_MOTION_LONG`, WCAG 2.2.2: the bar's Pause stops them, but motion should rest).
- **The bar**: dragging the playhead holds playback while the screen follows and a bubble says the time and the words said; it goes on where it is let go. Shortcuts keep their modifiers (Ctrl+Alt+P, R, C); their list opens with Shift+? on the bar only (a character key acts only where it has the focus, WCAG 2.1.4) or from the settings. A step that ends is said once in the live region (the voice has stopped).
- **For editors and agents**: `timelineView` and `screenAt` (engine requests `timeline`, `timelineAt`), the canvas at a time or an anchor (`canvasView { at }`), `set_block_timing` (`elabora timing`, `elabora_set_timing`), `elabora timeline` with the timed blocks, `look --at` and `screenshot --at` at any moment.
- **The storyboard and the script's tools** (12 Oct 2026): a timed screen's marks (its start, each block that comes or goes, each cue, each step's end, captured once each effect has played) make a contact sheet for agents (`elabora look --sheet`) and the Revue's storyboard (`timelineMarks`). A step too long is cut at a line (`split_step`, « Couper à une réplique »): later steps and everything that names them move one on, and blocks that come on a moved line go with it. The validated plan may give an item its voice-over, line by line (`voiceover`, translated with the plan): a screen covering it takes it as its script (`narration_from_plan`, « Reprendre la voix off du plan »). Recordings of several lines are imported together, each to the line its name gives or the line the word aligner finds in it (D27); a duplicated screen keeps its lines' audio; the editor draws the waveform from `narrationPeaks`.
- **For the editor** (12 Oct 2026): the canvas takes the playhead posted by the app itself (`elabora/view` with `at`, on each move while the author drags it) and reports each timed block's state and effect progress in its layout (`BlockLayout.timed`: before, entering, shown, leaving, after); `ghost` shows every step with those after the first faded in their place (the phone width). `effects` lists the effects a timing can take with their default durations and directions; the timeline's findings carry structured `details` (the block, the anchor and what it lost, the times, the step). The plan item's voice-over is written by `set_plan_voiceover` in a draft plan and proposed as a change request in an approved one (agents always propose: `elabora_set_plan_voiceover`).
- **Word anchors follow translation.** A narration line's XLIFF unit carries the words its anchors name as inline markers, `<mrk id="w-imprimante" type="elabora:anchor">imprimante</mrk>` (XLIFF 2.0's annotation element, which CAT tools keep; the id is the words and their occurrence, the same for every anchor on them). The translator puts each marker around the words of the translation that say the same thing (`<mrk id="w-imprimante">printer</mrk>`), in the XLIFF, through `elabora_translate_text` or with the app's « Accrocher » (`anchors: [{ id, word }]`). The translated course anchors to those words, and its own voice, aligned in its language, gives them their times: no time is translated. A marker the translation has not placed is an anchor to place (`elabora translate status`, `anchors.toPlace`); the translated build refuses it, and a draft (`--allow-missing`) anchors it to its line's start, which the timeline in that language reports (`unplaced`). Markers are kept with the words when a target is written again without them; a marker id the source does not have is refused.
*Revisit if:* authors need per-object timelines on layers (phase 3: layer timelines), trajectories outside a scene component, emphasis effects (phase 3), or a timed block needs to stay usable after it left.

*Revised by [D62](D62.md) (23 Oct 2026):* a layer has a timeline of its own (its narration, its timed blocks and its cues), played from its opening; timing on a layer's blocks applies there instead of being ignored.
