The Rivergate Review

Reading the Dort in close-up

Everything on this page is host-page furniture: a sticky masthead, a centred reading column, serif body copy and a footer. The viewers below are dropped into that flow exactly as a third-party site would embed them, with no styling help from the demo stylesheet.

Scroll slowly. Watch what happens to the controls when the element is narrower than the window, when it is shorter than its content wants to be, and when the page itself is doing the scrolling.

The manuscript, in the reading column

The first embed sits in the article column, so its width comes from the host page rather than the viewport. Container queries mean it should adopt its compact layout here even on a wide monitor.

Wunder der Vererbung, Lux-Lesebogen 103. Embedded at the article column width.

Text continues after the viewer. The element must not bleed outside its figure, must not introduce horizontal page scrolling, and must not steal the page's scroll when a finger crosses it.

A second paragraph, so there is something to scroll past on a phone before the next section arrives.

The story viewer, full-bleed on a dark section

Here the host section is wider than the reading column and sets its own dark background and light text. Inherited colour and font choices should not leak into the viewer's own chrome.

Content below the story viewer, to confirm the page keeps scrolling normally once the pointer leaves the element.

The column beside this text is 22rem wide on desktop and collapses to full width on smaller screens. The viewer inside it is a good test of element-relative breakpoints: the window may be 1600px wide while the element is barely 350px.

If the layout responded to the viewport instead of the element, the aside would show a desktop layout crammed into a phone-sized box.

It should instead look like the phone layout, with the compact control rail and a persistent toolbar.

A deliberately short embed

Some hosts pin a height. This one sets mango-viewer { height: 400px }, which used to squeeze the image to nothing and clip the transport controls.

An embedder often wants to point at one page, not the front cover — the plate a paragraph is discussing, framed the way the author meant it. That is a property of the embed, so it belongs in the config attribute rather than in a script: initialCanvasIndex picks the page and initialViewBox frames a region of it, in image coordinates.

The viewer below opens on page 7 of 36, already zoomed to a 1900 × 1300 region of a 2411 × 3372 scan. No host-page JavaScript runs at all — reload and it lands there every time.

Deep-linked at embed time: page 7, framed on the upper illustration.

The same recipe, other collections

Nothing above is specific to that one manifest. These two embeds come from different institutions and open on different parts of their canvas: the left one high up on the sitter's face, the right one well past the midpoint of a tall canvas. Both are a single config attribute, and the coordinates are in each image's own pixel space — a 2087 × 2550 photograph and a 4066 × 6684 one — so the same region numbers would mean quite different things in each.

Harvard Art Museums — Van Gogh, Self-Portrait Dedicated to Paul Gauguin. Opened on 560, 880 · 980 × 800.
Yale Center for British Art — Hayman, The Good Samaritan. Opened at 700, 3900 · 2200 × 1800, well down a 6684-pixel-tall canvas.

Because the framing is expressed in image coordinates rather than screen ones, each embed keeps pointing at the same part of the painting whatever width the host column happens to be. Narrow the window and the region stays put; only the surrounding margin changes.

The same two settings, back in the column

Width is the variable worth watching. These two are the same recipe again — different manifests, different regions — but back at reading column width, so each element is about half as wide as the pair above. The viewer swaps to its compact layout at this size: the control rail wraps to a second row and the thumbnail strip sheds entirely.

The framing is unaffected by any of that. A region is a property of the image, not of the surface it is drawn on, so both embeds open on exactly the part they were told to — the manuscript on a painted figure well down the page, the photograph on its right-hand side.

Bodleian Library, MS. Ind. Inst. Misc. 22 — a 5392 × 8158 page, opened at 900, 3000 · 2600 × 2200.
IIIF Cookbook, recipe 0005 — a 4032 × 3024 landscape image, opened on its right-hand side at 2400, 900 · 1500 × 1300.

Driving the viewer from the host page

The same three things are settable at any time through the element's public API. The buttons below are ordinary host-page buttons — they are not viewer chrome, and they reach the viewer only through the methods on the element.

Pages move with setCanvasByIndex(i), zoom with setZoom(percent) where 100% is fit-to-view, and position with panTo(x, y) or the fuller setViewBox({ x, y, w, h }). The readout underneath is fed by the pageChange and zoomChange events, so it also tracks whatever you do with the viewer's own controls.

Panning is clamped to the edges of the image, which is why the position buttons do most of their visible work vertically on a portrait scan: at fit-to-view the whole page width is already on screen, so there is nowhere sideways to go until you zoom in.

Page
Zoom
Position

Page · zoom · viewBox

Every button above is host-page JavaScript calling the element's public methods.
Checklist while resizing this page: nothing clipped, no horizontal page scrollbar, the play button and scrubber always visible, the icon rail swipeable where it overflows, and fullscreen covering the sticky masthead rather than sitting under it.

A final run of body copy so that both viewers have content above and below them at every screen size, which is how they will actually be met by readers.