PAGE MODE SPEC - SyberLabs/RISE GitHub Wiki

Page Mode β€” the Illuminated Reader

A second projection of a reading: not words flowing through time (the RSVP Stream), but text and image composed in space β€” an automated typesetter that lays out beautiful, re-readable pages from the same session the Stream plays.

Status: IMPLEMENTED (v1) β€” the illuminated single-column reader ships. A sibling to CONTINUOUS-FIELD-SPEC. Direction chosen: an automated typesetter (the engine composes; the reader reads β€” never a manual frame-dragging canvas). Rulings by the creator are marked ✦; open questions ⁇.

Implementation ledger β€” v1

Layer Module Proof
1 Β· Flow (story) src/page/flow.js 9 unit tests; binds via the SAME cueForAtom the Stream uses
2 Β· Compositor (layout) src/page/compositor.js 13 unit tests; pure data, no DOM
3 Β· Page renderer src/page/PageReader.js + page.css 12 unit tests; lazy + decode-before-reveal
Wiring Chamber.js Stream⇄Page toggle e2e over real Matthew 27

Strictly additive. Page Mode adds a projection; it modifies no Stream, cortex, or flash-economy behavior. The only change outside src/page/ is a new read-only cortex accessor, resolveCollectionWorks(collectionId), which routes through the existing _getProviderForCategory dispatch so there is never a second, drifting source path. Full suite green at 1018 unit + 12 e2e.

Two contracts worth recording, both found by live probe:

  • Providers speak two shapes. getRandom returns nested { name, data:{url,…} }; getImagesInCategory returns flat { title, url, artist,… }. The accessor normalizes to the nested form so consumers (and normalizeArtworkLabel) see one contract.
  • A bleed must be earned by prose. Matthew 27's seven short episodes each open a plate; without a text-debt rule the chapter renders as seven stacked full-bleed images β€” a reel, not a book. BLEED_TEXT_DEBT makes intervening prose, not a mere scene change, buy the next full-bleed placement.

1. The insight

R.I.S.E. today is a temporal medium: RSVP streams words through time. The first outside eyes wanted a spatial one β€” text and image arranged in a page. These are not two products; they are two projections of one session. The Stream flows the reading's atoms through time; the Page flows the same atoms through space. Same corpus, same pericope bindings, same reverence β€” one renderer plays it, the other typesets it.

This is the fourth stance in NORTH-STAR.md ("Study") given a body.

Why R.I.S.E. is unusually ready for this

A layout engine is only as good as the structured content it lays out, and we already produce it:

  • Atoms carry structure (models.js): content, modality (text/image/symbol), weight (semantic importance 0–1), complexity, tags, phase, and β€” for scripture β€” chapter/verse coordinates.
  • The pericope engine already binds image to passage. The visual program's disjoint, ordered segments (pericope-program.js) say which collection belongs to which verse range. The Page does not have to guess where a painting goes β€” the domain already authored it.
  • We have an aesthetic. The reverent, dim, glass-tile look (Genesis, behind-stream, the Gallery) is the Page's visual language already.

So the Page is a new renderer over data we already produce β€” exactly as the Gallery was a new presenter over pools the cortex already resolves. It invents no new content and no new source machinery.

2. What it is (and is NOT)

✦ An automated typesetter, not an authoring canvas (creator's ruling). The engine composes each page from the flow; the reader reads. There is no drag-and-drop, no manual frames, no guides. This is not a scope compromise β€” it is the philosophy: content authors, the runtime follows, the cortex renders. Putting composition in the user's hands would contradict the law the whole system is built on.

✦ First incarnation: the illuminated single-column reader. A vertically scrolling column of well-typeset text down which, at each pericope boundary, the passage's bound image appears in a composed placement β€” full-bleed, inset, or margin. No multi-column grid, no text wrap, no spread pagination in v1. ~80% of the emotional payoff (the right image beside the right word, in space, re-readable, shareable) for a fraction of the effort, and it reuses the pericope engine directly. The full grid engine grows underneath this later (Β§9), never blocking it.

The Page:

  • Typesets, never streams. The whole reading is present at once; the reader moves at their own pace, re-reads, lingers. (Contrast the Stream, which the reader cannot outpace.)
  • Places the bound image at its passage. The Christ-before-Pilate plate lands with the verses it illustrates, because the program already said so.
  • Honors reverent degradation. A work that will not load is simply absent β€” the text composes without it, never a broken frame, never a placeholder. Sacred imagery stays pinned and never searched; the face of Christ is never procedurally generated. A works-less episode is sanctioned stillness: text alone, beautifully set.
  • Is theme-aware and legible. The dim, glass aesthetic; text always readable over imagery (a scrim, exactly as the Gallery uses).

3. Architecture: flow β†’ composition β†’ render

Three stages, mirroring InDesign's own separation of story, layout, and page β€” and mapping cleanly onto our three-layer law.

   atoms + visualProgram                    (content, already authored)
            β”‚
            β–Ό   the FLOW COMPILER  (Layer 1 β€” domain-shaped)
   an ordered Flow of BLOCKS
            β”‚
            β–Ό   the COMPOSITOR    (Layer 2 β€” generic, aesthetic rules)
   a Composition (blocks + placements + breaks)
            β”‚
            β–Ό   the PAGE RENDERER (Layer 3 β€” DOM, theme, scroll)
   the illuminated reading on screen

3.1 The Flow (the "story")

The flow compiler turns a session's atoms + visual program into an ordered list of blocks:

  • TextBlock β€” a run of text grouped by paragraph (and, for scripture, by verse), carrying its coordinate, weight, and tags. Verse numbers become optional marginal marks.
  • ImagePlacement β€” a passage-bound image: { collectionId, atRange, emphasis }. Emphasis derives from the segment (a whole-episode plate is full-bleed; a single-verse image is inset). The image URL is resolved lazily by the same provider path the cortex uses β€” the Page is a pool consumer, not a new fetcher.
  • StructuralMark β€” chapter opening, episode boundary (a pericope segment edge β†’ a natural section break/rule), pause.

This is Layer 1: domain-shaped, the only stage that knows what a pericope or a verse means. Non-scripture readings still compile a flow (text blocks + whatever sourced/curated imagery the reading carries), just without verse coordinates β€” the Page is not Chapel-only.

3.2 The Composition (the "layout")

The compositor is generic and domain-agnostic β€” it knows blocks, emphasis, and aesthetic rules, not pericopes. It decides, for the single-column v1:

  • Placement of each ImagePlacement relative to its bound text: full-bleed band, inset figure (with caption), or margin plate. Driven by emphasis and a small rule set, not per-work authoring.
  • Rhythm: spacing before/after images, section breaks at episode boundaries, the opening drop for a chapter.
  • Widow/orphan restraint even in one column (don't strand a lone verse under an image).
  • Reverent gaps: a works-less episode gets deliberate breathing room, not a scramble to fill it.

The compositor emits a Composition: an ordered list of positioned blocks the renderer can lay out top-to-bottom. It is pure data β€” unit-testable with a fake flow, no DOM (the lesson from the Gallery presenter and the scheduler).

3.3 The Page renderer (Layer 3)

DOM + CSS. Takes the Composition and renders the scrolling column: typeset text on the reading's ground, images in their composed placements with the legibility scrim, verse marks in the margin, section breaks at episodes. Theme-aware (light/dark), responsive (the column re-flows to width; images max-width:100%; full-bleed bands honor the viewport). Lazy-loads images as they approach the viewport, decode-before-reveal (SacredImage's contract).

4. Relationship to the Stream (and the stances)

Page and Stream are two renderers of one compiled session β€” the reader chooses the projection, and can switch. Neither is primary.

  • Selected as the "Study" stance (NORTH-STAR.md) or a Stream⇄Page toggle in the reading surface.
  • Both consume the same atoms and the same visualProgram. The Page reads the program as spatial placement; the Stream reads it as temporal cues. The program-loss discipline (persist visualProgram with the reading β€” mt27-program-loss) protects both equally; the Page is if anything a forcing function to get that right.
  • A whole-reading focal, including a focal retained as Scored fallback authority, is held once above the opening title. A passage-scored focal is a smaller static presence at the same source-span boundary the Stream follows. Project images resolve from sequenceVisualAssets; they are never sent to an external provider.
  • Projection controls execution, not authorship. A Page-first launch may defer Gallery, video, Genesis, Attractor, and focal presenters, but it must not rewrite visualConfig or visualProgram. Returning to Stream activates the deferred capability and presenter from the unchanged session.
  • Static projection parity includes sourced images, whole-reading/fallback focal authority, passage focal cues, and project-owned focal media. It does not flatten a score's several dynamic field configurations into the one whole-reading sampler configuration: that is the deferred projection phase specified below.
  • ✦ The Page has no flash economy and no advance clock β€” it is static space, not timed presence. Therefore no VisualFlashGate, and photosensitivity is moot for motion (there is none). Reduced-motion is trivially satisfied.

5. Safety & reverence

  • Reverent degradation as everywhere: a missing work is absent, never broken; the text composes around its absence.
  • Sacred invariants hold: pinned imagery never searched; no generated face of Christ; fixed liturgical forms unchanged; a works-less pericope is stillness (text alone), never substituted.
  • No new provider surface. The Page resolves images through the existing pool/provider path; it introduces no new fetch, no new category, no new registry. aic-* ids untouched.
  • Legibility is a safety property here: text over imagery always passes the scrim; a full-bleed image never swallows its own caption or the verses it serves.

6. What v1 deliberately excludes (grows later, Β§9)

  • Multi-column grids, baseline grid, text wrap around figures. v1 is one column; wrap and columns are the grid engine's job.
  • Spread pagination (book-like left/right pages). v1 scrolls; pagination is an alternate renderer over the same Composition later.
  • Manual overrides (pin bigger, force break, choose template). The automated composition ships first; a thin override layer is the "automated + light overrides" middle path, added once we see what readers actually reach for.
  • Export (PDF/image/MP4). Distribution, not experience β€” deferred with the MP4 note in NORTH-STAR.md. A well-built Page is, however, natively screen-recordable and print-CSS-friendly, which gets 80% of sharing for free.

6.1 Deferred dynamic score projection β€” recorded 2026-08-11

Two authored visual kinds cross the Stream/Page boundary but do not yet have a complete static projection contract:

  1. Cue-specific Genesis and Attractor fields. A whole-reading dynamic mode has one active configuration and can be sampled parametrically through the Chamber's existing collection resolver. A scored reading may contain several field clips with different system, palette, form, preset, or glass settings. Page therefore needs a config-keyed static sampler, abort ownership, bounded caching, and a per-reading sample budget. Configuration must remain in the canonical cue; it must not be encoded into synthetic collection ids.
  2. Sequence MP4 posters. Stream owns temporal playback. Page needs one deterministic static poster per video asset, with extraction/storage, cancellation, and degradation rules. It must not mount or play video merely to obtain a frame, and reduced-motion behavior must not become the accidental poster API.

These are deliberately parked after static focal parity. They are new projection capabilities, not correctness gaps in the Page-first lifecycle.

7. Build order

  1. The Flow compiler (src/page/flow.js or sibling): atoms + visualProgram β†’ ordered blocks. Pure, unit-testable with fake atoms + a fake program. Reuses the scheduler's coordinate logic (cueForAtom) so image↔passage binding is the same truth the Stream uses β€” not a parallel implementation.
  2. The Compositor (src/page/compositor.js): flow β†’ Composition, the placement/rhythm/restraint rules. Pure, unit-testable with a fake flow and a fake image-resolver. This is where the "InDesign intelligence" lives, and where the aesthetic is encoded.
  3. The Page renderer (src/page/PageReader.js + CSS): Composition β†’ the scrolling illuminated column. Theme-aware, responsive, lazy + decode-before- reveal. Reuses the glass/scrim language from Chamber.css.
  4. Reading-surface wiring: the Stream⇄Page toggle (or the "Study" stance), sharing the compiled session. No new session machinery.
  5. Safety & reverence pass: missing-work absence, works-less stillness, legibility scrim, sacred-invariant tests.
  6. Live verify + a shareable moment: a Gospel chapter reads as an illuminated column, images at their passages; confirm print-CSS and screen-record both look composed.

8. Why this order

The flow and compositor are pure data transforms β€” the hard, valuable, testable core, provable without a browser (the discipline that made the Gallery and the scheduler solid). The renderer is the last, thinnest layer. And because the flow reuses the scheduler's coordinate logic, the Page and the Stream can never disagree about which image belongs to which verse β€” one binding, two projections.

9. The path to the full grid engine (later, not now)

The single-column reader is the floor, not the ceiling. The Composition is a deliberately renderer-agnostic data structure so the grid engine can grow underneath it without a rewrite:

  • v2: a grid/baseline system β€” columns, a baseline grid so text and images align, real text wrap around inset figures.
  • v3: master pages / templates β€” a small library expressing the aesthetic (a chapter-opening spread, an episode plate, a psalm setting), chosen by the compositor per section.
  • v4: spread pagination β€” the same Composition rendered as book-like spreads, and the light override layer (pin/break/template) for the reader who wants a nudge.

Each is an enrichment of the compositor or an alternate renderer over the same Composition β€” never a fork of the flow. The illuminated single-column reader earns its keep first; the InDesign-grade engine follows the demand it reveals.


The frame is the creator's: an InDesign-like framework meaning an automated typesetter β€” the engine composes beautiful pages from structured content, the reader reads them β€” beginning with a single illuminated column where the right painting lands beside the right word, in space this time, re-readable and shareable. Built as pure flow + composition transforms with a thin renderer, reusing the pericope binding the Stream already trusts, honoring every sacred and reverent invariant, with the full grid engine mapped to grow underneath.


Published from docs/vision/PAGE-MODE-SPEC.md. Edits made here are overwritten on the next push to main.