Menu

D65. Continuity between screens: a block that carries on from one screen to the next (28 Oct 2026)

A module about canal locks shows the same 3D lock on four screens, each with other settings (a camera, a mode, a journey). The founder asked for it to transform from one screen to the next, as PowerPoint’s Morph or Keynote’s Magic Move do, instead of being loaded again. Until now the player tore down every screen, its free objects with it, and each block kept a state of its own. The rule that changing screens moves nothing stays the default: only a continuity the author asks for moves something.

Weighed, to keep a free object running across a change of screen (its frame must never leave the page, or the browser loads it again):

  • moveBefore (the editor’s canvas already uses it when it updates a screen in place). It moves a frame without reloading it, but only Chromium has it: in Firefox and Safari the frame would reload. Courses run in every browser of their LMS. Rejected.
  • Keeping the departing screen as a carrier for the frame. Every screen of the chain would stay in the page. Rejected.
  • A layer of the page for the frame, placed over the block’s own frame. Chosen: the same in every browser, and the frame can glide from the departing block’s place to the arriving one’s.

Weighed, for the other blocks (a title, an image that glides to its new place):

  • The View Transitions API. It glides and cross-fades named elements, but the swap of the screen waits for a frame. Navigation, the canvas’s layout reports, fit measures and tests would all become asynchronous. Rejected for now.
  • A glide made with the Web Animations API (FLIP). The new screen is placed at once, then the block glides from where its counterpart was, in every browser. Chosen.

Decided:

  • The key. A block of a screen may say continuity: { "key": "lock" }. Blocks that share a key, on different screens, are one thing to the learner. When the learner goes from one of those screens to another, the block carries on instead of appearing again. This works for every change of screen: Next, Previous, the outline, a go-to event, a narration that goes on by itself. duration (milliseconds, 0 to 3000, default 700) is the arriving block’s. Nothing else on the screen moves. With less motion asked the change is a clean cut, but the object still carries on. The schemas get the field in 0.1.2 (D64: an additive change).
  • Which blocks. Blocks sharing a key have the same type, and free objects the same object (E_CONTINUITY_MISMATCH). A key appears once per screen (E_CONTINUITY_DUPLICATE). A key is never on a block of a layer, and never on a free object that has a timing (E_CONTINUITY_PLACE). A key on one block only does nothing (W_CONTINUITY_ALONE).
  • How the object stays alive. A free object with a key has its frame in #t-main’s keep layer (.t-keep), after the screen. The frame sits over the block’s own frame, which keeps the size and takes no clicks. The keep layer is not a stacking context, so the frame is drawn above what the layout draws without a z-index (its backgrounds), and below what it places over the block with one (a title floating over a stage). The block’s ancestors up to the screen let clicks through to the frame, their other children keep their own behaviour. Screen readers read the frame in the block (aria-owns). Keyboard focus reaches it after the screen’s other controls.
  • The transition. When the screen changes, the frame glides from the departing block’s box to the arriving block’s box, and at the same time object/update-props sends the arriving block’s props, its strings and its safe area, and transition: { from, to, direction, duration, reducedMotion }, where from and to are { screen, block } and direction is forward or back. The frame calls the object’s update(props, transition), so the object can move its camera, its scene and its own controls over the same duration. An object that ignores the second argument applies the props at once. The duration is 0 with less motion asked.
  • What follows the arriving block. Its events (the target of object.event, interactions, completion), its title and description on the frame, its text version, and its safe area, sent with the transition. The completion stays the block’s own.
  • One state per key. The chain’s state is saved under the lock entity continuity:<key> (in o of the suspend data, as an object’s state), whichever block’s event saved it. The worst case counts it once.
  • Navigation cases. On a resume in the middle of the chain, the object mounts with the chain’s state and makes no transition. A language switch mounts it again. The same block shown again (the canvas starting a screen over) mounts it again. When the arriving screen has no block with the key, the object stops as it does today and its state stays. The next screen that has the key mounts it with that state.
  • Ordinary blocks glide from the departing block’s box to their own (translate and scale, the arriving block’s duration, the player’s cubic-bezier(.77, 0, .175, 1), as the frame of a continued object). The departing block is gone at once. Under less motion they do not move.
  • For authors and agents. The app’s inspector says it in words: the block continues the one of the previous screen, and how long the passage lasts. elabora block continue (MCP elabora_set_continuity) links two blocks, cuts a chain or sets the passage’s length in one change. The agent’s skills and the free-object contract say how to write the key and how an object reads the hint. An agent sees a passage in the object’s tests: a set-props step with transition gives the props as a passage does, the next steps advance through it, a snapshot shows it on its way, and elabora object replay plays it in the course page. No look option for passages: the tests already draw them frame by frame, and keep them.

Revisit if: a layout must draw something over a continued object without a z-index, keyboard users need the object at its block’s place in the tab order, authors want the departing content to cross-fade (then View Transitions where the browser has them), or moveBefore reaches every browser of the LMS matrix.