Blocks Cinema Pack

Blocks & themesStable
@wabbit/tome-blocks-cinema-packv0.4.5

Video and full-bleed display blocks for cinematic sections — cinema feature, trigger tile, video wall/spread, chaptered walkthrough, scrub story, testimonial rail, ambient band, scene plates and captions, statement band, media panel, and pull interlude, built on the house field/motion/style/video primitives.

Install
  1. Get a registry token from your credentials page. You need a purchase that includes this package, or a Craft Library membership.

  2. Add the registry and your token to the .npmrc at the root of your project, with your token in place of YOUR_TOKEN:

    @wabbit:registry=https://npm.wabbit.com/
    //npm.wabbit.com/:_authToken=YOUR_TOKEN
  3. Then install:

    npm install @wabbit/tome-blocks-cinema-pack

Overview

@wabbit/tome-blocks-cinema-pack

Video and full-bleed display blocks for cinematic sections, promoted from wabbit.com's site-local blocks into a sellable Tome block pack (family: block-packs, tier: addon). Program B of the Tome Blocks — Storefront Expansion and House Packs spec (2026-09-05).

The pack ships 13 blocks under one bundle descriptor (cinema-pack): two display blocks (Media Panel, Pull Interlude) and eleven video-family blocks. It is built on @wabbit/tome-blocks-core (block/registry/render contracts) and @wabbit/tome-blocks-house (shared field/motion/style/video primitives ported from the wabbit.com site — see that package's PORT-NOTES.md, and this package's own PORT-NOTES.md).

Blocks

| Slug | Name | Variants | Notes | |---|---|---|---| | media-panel | Media Panel | — | Full-viewport cover image with a docked, translucent copy card anchored to one corner; optional CTA below the panel | | pull-interlude | Pull Interlude | default, hatched | Full-bleed dark painterly art band (or hatched placeholder) carrying one centered display-serif pull-line; entrance reveal | | cinema-feature | Cinema Feature | — | Full-bleed cinematic frame: a poster crossfades to on-demand video on click, with an optional context band above and a caption rail below | | trigger-tile | Trigger Tile | — | Performance-safe inline 16/9 poster tile with a play glyph and duration chip; click opens a page-local modal that mounts the video and tears it down on close | | video-wall | Video Wall | — | Grid of muted looping video cells that autoplay only while in view; click opens a lightbox with sound | | video-spread | Video Spread | video-right, video-left | 50/50 editorial spread — heading, body and optional link beside a full-height video panel, in loop or click-to-play preview mode | | chaptered-walkthrough | Chaptered Walkthrough | — | Video player with a click-to-seek chapter rail; each chapter shows title, duration and a live progress fill | | scrub-story | Scrub Story | — | Tall pinned section whose video scrubs with scroll while 2–5 copy beats highlight in step; degrades to stills, then a stacked read for reduced motion | | testimonial-rail | Testimonial Rail | — | Scroll-snap rail of video testimonial cards — poster first, sound on request, one clip playing at a time | | ambient-band | Ambient Band | — | Full-bleed muted looping-video band with overlay copy; still poster for reduced motion, labeled placeholder when no media is set | | scene-plate | Scene Plate | plate, cinema | Repeatable full-viewport act/chapter plate — scene image behind a large display heading, optional subline, reading panel and CTA | | scene-caption | Scene Caption | — | Quiet full-bleed interlude — background scene, accent rule and one small italic caption line, bottom-anchored | | statement-band | Statement Band | — | A verdict stated once on a full-bleed band — centered statement with an accent phrase and an optional support line that inks in |

Install into an existing Payload project

npm install @wabbit/tome-blocks-cinema-pack

@wabbit/tome-blocks-core and @wabbit/tome-blocks-house are required peers and install automatically (npm 7+/pnpm). Add the blocks you want to an existing blocks field and render them — see @wabbit/tome-blocks-core's "Add Tome blocks to an existing Payload project" for the full walkthrough:

// payload.config.ts
import { mediaPanelBlock, pullInterludeBlock } from '@wabbit/tome-blocks-cinema-pack'
// blocks: [...existingBlocks, mediaPanelBlock.block(), pullInterludeBlock.block()]
// blockComponents.ts
import { renderers as cinemaRenderers } from '@wabbit/tome-blocks-cinema-pack/render/register'
import { adaptRenderersForPayload } from '@wabbit/tome-blocks-core/render'
// blockComponents: { ...adaptRenderersForPayload(cinemaRenderers) }
@import '@wabbit/tome-blocks-core/styles.css';

Registering everything from scratch instead of adding to an existing field:

// payload.config.ts
import { BlockRegistry, BundleRegistry } from '@wabbit/tome-blocks-core/registry'
import { register } from '@wabbit/tome-blocks-cinema-pack'

const blockRegistry = new BlockRegistry()
const bundleRegistry = new BundleRegistry()

register(blockRegistry, bundleRegistry)
import { registerRenderers } from '@wabbit/tome-blocks-cinema-pack/render/register'

registerRenderers()

| Peer | Range | Required | |---|---|---| | payload | >=3.67.0 | yes | | @payloadcms/richtext-lexical | >=3.67.0 | yes | | react | >=19.0.0 | yes | | react-dom | >=19.0.0 | yes | | @wabbit/tome-blocks-core | >=0.22.0 <1.0.0 | yes | | @wabbit/tome-blocks-house | >=0.8.4 <1.0.0 | yes |

gsap and hls.js are not peers of this package at all — they are real dependencies of @wabbit/tome-blocks-house (a required peer above) and install automatically with it, regardless of which video-family block a site actually uses. See @wabbit/tome-blocks-house/video's useHlsVideo for the HLS/Mux attach contract.

Public API

| Export | Subpath | Description | |---|---|---| | Block descriptors (mediaPanelBlock, pullInterludeBlock, and one xBlock per video-family block) + register(blockRegistry, bundleRegistry) | . | Payload block configs and bundle registration | | Render components (MediaPanel, PullInterlude, CinemaFeature, TriggerTile, VideoWall, VideoSpread, TestimonialRail, ChapteredWalkthrough, …) | ./render | Legacy self-registering render barrel | | renderers map + registerRenderers() | ./render/register | Explicit renderer registration | | getDemoProps(blockSlug, variant, ctx?) plus per-block demo functions | ./demo | Demo-props dispatcher feeding the auto-gallery route | | cinemaPackBlockMeta | ./meta | Payload-free block metadata for a storefront gallery |

Server / client posture

Thirteen files under src/render/ carry 'use client': twelve *.client.tsx islands (video players, scrub engine, motion wrappers) plus PullInterlude.tsx. Every other renderer is a server component that hands only the interactive part to its island, so a block renders from a server tree and hydrates just the player or motion.

Block configs load under plain Node: they import videoSourceFields from @wabbit/tome-blocks-house/video/fields, which has no React components on its import graph, so a Payload CLI command, seed or type generator loads this pack's main entry without pulling in render code. The render components import the full @wabbit/tome-blocks-house/video barrel; its stylesheets ship precompiled, so that loads under plain Node too.

Tokens and motion

Consumes @wabbit/tome-ui tokens exclusively, via @wabbit/tome-blocks-house's reduced field/background vocabulary — no literal hex/hsl/px in any render CSS Module (0/1px hairlines excepted, plus ScenePlate.tome-css's fixed hsl(0 0% 0% / *) text-shadows, which are deliberately theme-invariant black so heading legibility over painted art doesn't depend on the active theme), no hardcoded font-family. No render component depends on a consumer's named page-grid lines: the four that sit on the reading lanes (below) get them from LaneGrid, which lays out the same tracks itself where the page has no grid. Entrance motion uses @wabbit/tome-blocks-house/motion; reduced motion is honored with a direct prefers-reduced-motion check, so this pack has no dependency on @wabbit/tome-motion.

Reading lanes

Statement Band, Scene Plate, Scene Caption and Pull Interlude render as a bleeding LaneGrid (@wabbit/tome-blocks-house/components): the band paints edge to edge, and its text sits on the page's named lines. The grid subgrids the page grid when it sits in it, and lays out the same tracks itself everywhere else. From 1024px:

| Block | Part | Lane | |---|---|---| | statement-band | statement and support line, statementFace: 'serif' | reading slot | | statement-band | statement, statementFace: 'display' | wide slot (the content column) | | statement-band | section strip | content column (the strip places itself) | | scene-plate | copy, seated panel row, CTA | wide slot; the copy is centred in it (plate) or starts at its left edge (cinema) | | scene-plate | seat: 'left' / 'right' panel | the content column's left or right half, split at the page's centre line | | scene-plate | seat: 'center' panel | prose-start / prose-end, capped by --tome-prose-max-width | | scene-caption | rule and caption | content-start / reading-end (placed by line name) | | pull-interlude | pull-line | wide slot (the content column), centred there at up to 34ch |

Below 1024px every part takes the content column. The side space comes from the page's --tome-grid-padding gutter, so Pull Interlude's line, which runs the whole band on a phone, stays inside the gutter.

Site tokens

Each falls back to the value shown, so a site that sets none of them sees the defaults. Set them on the block or any ancestor; they are read where the block renders.

| Token | Block | Default | What it sets | |---|---|---|---| | --tome-cinema-statement-display-tracking | statement-band | var(--tome-type-tracking-tight) | Letter-spacing of the display face only. The serif face keeps the tracking the page gives its h2, so a site can match its own display tracking without moving the serif statement. | | --tome-cinema-caption-duration | scene-caption | the house entrance timing (--tome-motion-base on :root, else 0.3s) | Duration of the caption's entrance, as a CSS time (560ms, 0.56s). Read from the caption element, so a scoped value works. | | --tome-cinema-px | video-wall, testimonial-rail | 0.0625rem | The unit for sizes stated in pixels: Video Wall's play ring (56), title chip offsets, gap, padding and lift (14, 8, 6/10, 6); Testimonial Rail's card widths (280, 340, 400), edge-fade mask (56) and track inset (36, 18 below 40em). The default is one pixel at a 16px root, so each size is the rem it always was. A site whose root font size is not 16px sets 1px to keep them at their pixel size. | | --tome-cinema-panel-accent | media-panel | var(--blk-accent-ink, var(--tome-color-accent-on-solid-dark)) | Kicker colour. By default a band's accent ink, else tome-ui's accent ink for the solid-dark surface (legible on the dark dock in both themes). | | --tome-cinema-panel-border | media-panel | var(--tome-color-on-solid-dark) | Ink of the dock's hairline border (mixed at 30%). Set it to var(--tome-color-accent-on-solid-dark) for an accent hairline. | | --tome-cinema-scrub-crossfade | scrub-story | var(--tome-motion-slow) | Duration of the stills/video crossfade. The beat change keeps --tome-motion-slow, so the media can fade slower than the copy. | | --tome-cinema-feature-poster-fade | cinema-feature | var(--tome-motion-base) | Duration of the poster-to-video crossfade on play. | | --tome-cinema-feature-inset | cinema-feature | 0px | Side inset of the frame, context and caption inside the band, and the CTA's start padding (the CTA renders after the inner column, so it reads the token itself). A site that places the block full-bleed on its page grid sets it to var(--tome-grid-padding) so they sit on the content column while the band paints edge to edge. | | --tome-cinema-ambient-copy-inset | ambient-band | 0px | Moves the copy column in from the band's left edge (and caps its width to keep the same distance on the right). A site that spans the band across its page grid sets var(--tome-grid-padding) so the copy starts on the content column. | | --tome-cinema-walkthrough-max-width | chaptered-walkthrough | 72rem | Width cap of the player, rail and copy (centred). none fills the block's width. | | --tome-cinema-rail-name-variation | testimonial-rail | normal | font-variation-settings on the card name. Set on the name itself, so a page rule that thins every <p> through the variable-font axis does not reach it and its 600 weight holds. | | --tome-cinema-interlude-placeholder-base | pull-interlude | var(--tome-color-surface-solid-dark) | Base colour of the empty-art placeholder under its washes; the band and art layer stay solid-dark. | | --tome-cinema-video-well | video-wall, testimonial-rail, cinema-feature, trigger-tile | var(--tome-color-surface-solid-dark) | The well behind a playing video (the colour that shows in letterbox bars): Video Wall's tile video, lightbox video and lightbox embed; Testimonial Rail's card video and its wrapper; Cinema Feature's video and its wrapper (the frame itself stays solid-dark); Trigger Tile's lightbox video. Set #000 for true-black bars. | | --tome-cinema-ambient-scrim-base | ambient-band | var(--tome-color-surface-solid-dark) | The colour the copy-side scrim gradient is mixed from (the scrim select still sets its strength). | | --tome-cinema-readout-gap | scrub-story | var(--tome-space-lg, 1.25rem) | Gap between the source state and the scrub percent in the pinned readout. | | --tome-cinema-ambient-cta-pad-block | ambient-band | var(--tome-space-4, 0.85rem) | Top and bottom padding of the bordered CTA button (its side padding stays --tome-space-6). | | --tome-cinema-chapter-gap | chaptered-walkthrough | var(--tome-space-sm, 0.65rem) | Gap between a chapter's index, title and duration. | | --tome-cinema-chapter-progress-gap | chaptered-walkthrough | var(--tome-space-sm, 0.55rem) | Space above a chapter's progress line. | | --tome-cinema-walkthrough-below-margin | chaptered-walkthrough | var(--tome-space-8, 2rem) | Space above the below-player copy's hairline, wider than 640px. | | --tome-cinema-walkthrough-below-pad | chaptered-walkthrough | var(--tome-space-5, 1.25rem) | Space between that hairline and the heading, wider than 640px. | | --tome-cinema-walkthrough-below-margin-narrow | chaptered-walkthrough | var(--tome-space-6, 1.5rem) | The same space above the hairline at 640px or less. | | --tome-cinema-walkthrough-below-pad-narrow | chaptered-walkthrough | var(--tome-space-4, 1rem) | The same space under the hairline at 640px or less. | | --tome-cinema-rail-placeholder-pad | testimonial-rail | var(--tome-space-lg, 1rem) | Padding of the label in an empty card. | | --tome-cinema-rail-edge-inset | testimonial-rail | calc(36 * var(--tome-cinema-px, 0.0625rem)) | The track's side inset that clears the edge fade, wider than 40em. The status line and the CTA follow it. | | --tome-cinema-rail-edge-inset-narrow | testimonial-rail | calc(18 * var(--tome-cinema-px, 0.0625rem)) | The same inset at 40em or less. | | --tome-cinema-rail-fade | testimonial-rail | calc(56 * var(--tome-cinema-px, 0.0625rem)) | Width of the edge fade (the mask) on each side of the rail. | | --tome-cinema-rail-cta-inset | testimonial-rail | --tome-cinema-rail-edge-inset, --tome-cinema-rail-edge-inset-narrow below 40em | Start inset of the CTA (the track's edge inset). One value replaces both; a site that places the rail full-bleed on its page grid sets var(--tome-grid-padding) so the CTA starts on the content column. | | --tome-cinema-wall-cta-inset | video-wall | clamp(1.5rem, 4vw, 3rem) | Start inset of the CTA. A site that places the wall full-bleed on its page grid sets var(--tome-grid-padding) so the CTA starts on the content column. | | --tome-cinema-spread-media-width-narrow | video-spread | 100% | Width of the video and poster inside the stacked panel (below 64em), anchored at its start edge and clipped by the panel. The default fills the panel and the cover crop shows the middle of the frame. max(100%, 35.5556rem) (20rem at 16:9) gives the wider, left-anchored crop of a panel sized from its 20rem floor, without the panel overflowing the column. The play button and sound chip stay centred in the panel. |

Editorial CTA register. Every block CTA except Ambient Band's bordered button reads the house editorial CTA register from @wabbit/tome-blocks-house (--tome-house-cta-editorial-family, -size, -weight, -tracking, -transform, -margin, -color; see that package's README, "The editorial CTA register"). Unset, each falls back to the block's own value, so nothing changes: Scrub Story and Chaptered Walkthrough set no type (the block's family, size, weight, tracking and case), tome-ui's link colour (--tome-color-primary) and a --tome-space-md top margin; Video Wall, Testimonial Rail, Trigger Tile and Cinema Feature set the mono face, --tome-text-xs, the inherited weight, --tome-house-tracking-cta-editorial, uppercase, tome-ui's link colour and a --tome-space-lg top margin; Media Panel keeps its centred, underlined link (the mono face, --tome-type-size-sm, --tome-type-tracking-wide, uppercase, the solid-dark ink, a --tome-space-lg top margin) and only its type and colour read the tokens. Set the tokens on a block's scope to give its CTA one register. On a grid parent a register CTA takes --tome-house-cta-cols and starts its row; Cinema Feature's CTA renders after the block's inner column and reads --tome-cinema-feature-inset as its start padding, so it lines up with the frame. Media Panel's CTA is stacked above the panel's image and scrim (z-index: 2). A site whose global link rule outranks one class (:root a { color: inherit }) keeps colouring these links itself; the colour token reaches them only where nothing outranks the block's own rule.

Band companions read first: Scene Caption's placeholder wash reads --blk-primary-ink before --tome-color-primary; Pull Interlude's placeholder washes read --blk-primary-ink and --blk-accent-ink before the theme tokens (the block has no background field, so only a site sets these); Scene Plate's panel kicker and panel italic read --blk-primary-ink before --tome-color-primary-on-solid-dark; Chaptered Walkthrough's active chapter, focus ring and progress fill and Cinema Feature's eyebrow read --blk-accent-ink before --tome-color-accent-text.

Bands: Video Wall, Testimonial Rail and Cinema Feature paint a chosen background on their root (--blk-bg, --blk-fg) and carry data-band-tone. With no background set the root stays transparent and takes the page's ink.

Chaptered Walkthrough's video loads nothing before play (preload="none"). A site that maps its own stored blocks onto the renderer can pass videoPreload: 'metadata' on the block (not an editor field) so the last chapter's length and range use the real duration before playback.

Images

Every background or poster image that fills a box the block sizes (Scene Plate's scene, Scene Caption's and Pull Interlude's art, Media Panel's image, Cinema Feature's and Ambient Band's posters, Scrub Story's stills and reduced-motion frames, Trigger Tile's uploaded poster) calls resolveMedia with options from fillMediaOptions (@wabbit/tome-blocks-house/components): className (fills the box), imgClassName (the image's own object-fit), fill: true and sizes ('100vw' for the bands and stills, '(max-width: 768px) 100vw, 60vw' for Scrub Story's reduced-motion frames, '(max-width: 768px) 90vw, 65ch' for Trigger Tile). The built-in media adapter renders the same single <img> as before, carrying both classes and a sizes attribute. A site adapter that wraps its image puts className on the wrapper and should render the image in fill mode with imgClassName on it (see MediaProps in @wabbit/tome-blocks-core/adapters).

Blocks

media-panel

A tall, full-viewport cover image where the photograph IS the layout — a translucent, docked copy card (kicker, fig label, heading, body) anchors to one corner, with an optional call to action below the panel.

When to use
  • A single strong photograph needs to carry a section on its own, with copy annotating it rather than competing with it
  • A cinematic full-bleed moment between denser content sections
  • A case-study or gallery opener where the image IS the argument
Page types
  • landing
  • about
  • marketing
  • editorial-article
  • portfolio
How to use

Upload a full-bleed cover image, then choose which corner the docked copy card anchors to (bottom left by default). Fill in a kicker, fig label, heading, and body as needed — the dock only renders if at least one is set. Add an optional call to action below the panel, and choose a panel height (Tall or Standard).

Pairs with
  • pull-interlude
  • scene-plate
  • statement-band
Avoid when
  • The section needs more than one image or a gallery of photos — use a video wall or scene plates instead
  • The copy is the primary content and the image is secondary — use a standard media + content block instead
Register in

marketing-landing

pull-interlude

A full-bleed dark band (a painterly background image, or a hatched placeholder when none is set) carrying ONE centered display-serif pull-line. Wrap a run in `**double asterisks**` for an accent-colored span. A single-line entrance reveal plays on scroll (honors reduced motion).

When to use
  • A mid-argument cinematic pause between two dense sections — letting one line of copy breathe on its own
  • A single memorable statement that deserves a full-bleed art moment, not a bullet in a list
  • A page that already has a features/content grid and needs a tonal break before the next section
Page types
  • landing
  • about
  • marketing
  • editorial-article
How to use

Write the Pull line — one sentence, wrap a phrase in `**double asterisks**` for an accent-colored run. Optionally add Background Art (a full-bleed painterly scene); an empty slot renders a labeled hatched placeholder, never a blank band. Set a Background Art Note to customize the placeholder tag text.

Pairs with
  • media-panel
  • statement-band
  • scene-plate
Avoid when
  • The moment needs a heading plus supporting body copy — use a standard statement or interstitial block instead (this block is exactly one line)
  • The page already has a full-bleed band immediately above or below it — back-to-back full-bleed bands read as one shapeless section
Register in

marketing-landing

cinema-feature

One flagship full-bleed video frame — an optional eyebrow + heading context band, a 21:9 (or 16:9) poster that swaps to a real player on click, and a hairline-topped caption rail with title/duration/description. Zero video bytes load until the visitor clicks play. Renders a hairline placeholder frame when no video is set, so the block ships before content exists.

When to use
  • A flagship reel or hero clip that should feel restrained until requested
  • The single most important piece of video on a page
  • A moment that wants a cinematic full-bleed frame rather than an inline tile
Page types
  • landing
  • marketing
  • about
  • portfolio
How to use

Set the video (upload or an external URL — direct file, Mux, YouTube, Vimeo, or Bunny Stream) and choose a ratio (21:9 cinematic or 16:9). Optionally add an eyebrow + heading context band above the frame, and a caption (title, duration, description) below it. Leave the video unset to show an intentional placeholder frame during authoring.

Pairs with
  • video-wall
  • testimonial-rail
  • trigger-tile
Avoid when
  • The video is one of several clips in a set — use video-wall instead
  • The video needs to sit inline in a reading column rather than as a full-bleed hero — use trigger-tile
Register in

marketing-landing

trigger-tile

One inline video tile with zero video bytes at rest — a poster tile inside the reading flow, click opens a modal that mounts a real player on demand and tears it down completely on close. Framed (inset within the column) or edge-to-edge styles.

When to use
  • A single clip that belongs inline in an article or long-form page, not as a full-bleed hero
  • Dropping a supporting video into prose flow without loading any video bytes until requested
Page types
  • blog
  • editorial-article
  • docs
  • about
How to use

Set the video (upload or an external URL) and an optional poster. Title feeds the accessible label only; Caption is the visible mono line under the tile. Duration is display-only, shown in the corner chip and caption line. Choose Framed (inset within the column) or Edge-to-edge.

Pairs with
  • cinema-feature
  • video-wall
Avoid when
  • The video is the page hero — use cinema-feature for a full-bleed treatment
  • Several clips need to sit side by side — use video-wall
Register in

editorial

video-wall

A grid of 2 or 3 columns of video cells — muted loops that play only while their cell is in view, pausing off-screen. Click opens a page-local lightbox with controls and sound. An empty cell renders a hairline placeholder slot, so a wall can mix filled and empty cells while it is being authored.

When to use
  • Showcasing several short clips together as a single ambient composition
  • A "reel wall" or gallery of motion moments rather than one flagship video
Page types
  • landing
  • marketing
  • portfolio
How to use

Add clips (upload or external URL), each with an optional title shown in the hover chip and lightbox label. Choose 2 or 3 columns and a gap (seamless seals the wall into one continuous field of motion). Autoplay-in-view is on by default and always forced off under reduced motion.

Pairs with
  • cinema-feature
  • testimonial-rail
  • trigger-tile
Avoid when
  • There is one flagship video that deserves full-bleed emphasis — use cinema-feature
  • The clips are client testimonials with names/quotes — use testimonial-rail
Register in

marketing-landing

video-spread

A 50/50 spread pairing copy (eyebrow, heading, rich body, optional accent link) with a full-height video panel on the other side. Loop mode plays muted ambient motion in view with a sound-on-request chip; click-to-play shows a poster and play affordance until clicked. Reduced motion always forces click-to-play. Two variants swap which side carries the video.

When to use
  • A rhythm-break moment pairing a short editorial statement with motion
  • Introducing a process, place, or product with ambient video alongside supporting copy
Page types
  • landing
  • marketing
  • about
How to use

Write an eyebrow, heading, and body, plus an optional accent link. Set the video (upload or external URL) and pick loop or click-to-play preview mode. Choose the video-right (default) or video-left variant, an appearance band, and optional per-element type-size overrides.

Pairs with
  • cinema-feature
  • video-wall
Avoid when
  • The video is the sole focus with no supporting copy — use cinema-feature
  • Several short clips need to sit together as a set — use video-wall
Register in

marketing-landing

testimonial-rail

A drag-to-scroll, scroll-snap rail of portrait video testimonial cards. Each card swaps its poster for a playing video on click, with strict one-at-a-time playback — starting a new card stops whichever one was playing. Name, role, and a one-line quote sit under each card. A card with no video renders a hairline placeholder, so a rail can mix filled and empty cards while it is being authored.

When to use
  • A set of client or customer video testimonials on a landing or about page
  • Social proof that benefits from a face and a voice, not just a quote
Page types
  • landing
  • marketing
  • about
How to use

Add testimonials: each needs a video (upload or external URL), an optional poster, and a name/role/quote. Choose a card width (compact/standard/wide) and a gap (seamless butts cards edge-to-edge). Add an optional call to action below the rail, e.g. linking to all client stories.

Pairs with
  • cinema-feature
  • video-wall
Avoid when
  • The testimonials are text-only, with no video — use a text testimonial block instead
  • There is only one testimonial to feature — a single card in a rail reads sparse
Register in

marketing-landing

chaptered-walkthrough

A real <video> element next to (or above) a chapter rail. Chapter durations and each chapter's progress fill are derived live from the chapters' start times and the video's real length — nothing is stored. Clicking a chapter seeks and plays from that point.

When to use
  • A product demo or engagement walkthrough with distinct named sections a visitor may want to skip between
  • A recorded call, training video, or long-form explainer that benefits from a visible table of contents
  • Any single video where "jump to the part I care about" is the primary way people will use it
Page types
  • landing
  • marketing
  • docs
  • about
How to use

Upload a video or paste a direct file URL (this block only plays a file it can seek directly — no YouTube/Vimeo/Bunny Stream embeds). Add at least two chapters with a title and a start time in seconds; each chapter's length is computed automatically from the next chapter's start (or the video's real duration for the last one). Choose whether the rail sits to the right of the player or below it.

Pairs with
  • scrub-story
  • ambient-band
Avoid when
  • The clip has no meaningful sections to jump between — use a plain video block instead
  • You need an embeddable YouTube/Vimeo/Bunny Stream link — this block only plays a direct file it can seek
Register in

marketing-landing

scrub-story

A pinned, full-viewport scroll container: as the reader scrolls through it, the video's current time lerps toward the scroll position — the reader scrubs the clip by reading. Beats (2-5) activate a left-rail copy stack at their own scroll-progress thresholds. Three-tier degrade: scrub (seekable video) -> crossfading beat stills -> reduced-motion unpinned static stacked beats.

When to use
  • A product or process story that unfolds as the visitor scrolls, rather than one they must press play on
  • A narrative with 2-5 clear beats that benefit from scroll-synced pacing
  • A cinematic, editorial-feeling section that should feel authored, not just embedded
Page types
  • landing
  • marketing
  • about
  • portfolio
How to use

Upload a video or paste a direct file URL (this block only plays a file it can seek directly — no YouTube/Vimeo/Bunny Stream embeds). Add 2-5 beats in scroll order, each with an activation percent (0-100, first beat at 0), an eyebrow, a heading, body copy, and an optional still image (used as the crossfade fallback and the reduced-motion frame). Choose a pin length — longer pins slow the scrub across the same footage.

Pairs with
  • chaptered-walkthrough
  • ambient-band
Avoid when
  • The content has fewer than 2 beats — this block requires at least 2
  • You need an embeddable YouTube/Vimeo/Bunny Stream link — this block only plays a direct file it can seek
Register in

marketing-landing

ambient-band

A full-bleed band filled by a muted, looping video (or its poster, for reduced-motion visitors) with a scrim and a left-weighted copy column — eyebrow, heading, coda, and an optional ghost-button link. A visual "breath" between two denser sections rather than a content-heavy moment.

When to use
  • A pacing break between two sections that wants atmosphere rather than another message
  • A short ambient loop (b-roll, product-in-motion) with a light supporting line of copy
  • A quieter, slower cinematic beat than a full autoplay hero
Page types
  • landing
  • marketing
  • about
How to use

Upload a video or paste a direct file URL (this block only plays a file — no YouTube/Vimeo/Bunny Stream embeds). Choose a band height and scrim strength, then add an eyebrow, heading, coda, and an optional CTA label + URL. Leave the video unset and add a poster for a fully static ambient band, or leave both unset to show an intentional placeholder frame.

Pairs with
  • scrub-story
  • chaptered-walkthrough
Avoid when
  • The moment needs to be the flagship, attention-demanding video on the page — use cinema-feature instead
  • The video needs a click-to-play affordance rather than an ambient muted loop
Register in

marketing-landing

scene-plate

A full-viewport (or medium/tall) chapter plate: a full-bleed scene image with an optional gradient scrim, and a display heading (wrap a phrase in *asterisks* for an accent span) — either centered as an act plate, or seated bottom-left as a cinema-frame chapter title. An optional side-seated reading panel adds a subline and rich-text body for prose-adjacent scene breaks.

When to use
  • Opening or dividing a long-form piece into named acts or chapters
  • A full-viewport scene-backed statement with an optional supporting paragraph
  • A repeatable page-opening moment, used more than once down a page
Page types
  • landing
  • about
  • editorial-article
  • marketing
How to use

Write a heading (wrap a span in *asterisks* for the accent-serif treatment) and pick a treatment: Act Plate (centered) or Cinema Frame (bottom-left, display scale). Add a background scene — an empty slot renders a placeholder label. Choose a scrim and height, and optionally seat a reading panel (left/right/center) with a subline and rich-text body alongside the plate.

Pairs with
  • scene-caption
  • statement-band
Avoid when
  • The page needs a short atmospheric pause with no headline — use scene-caption instead
  • Back-to-back full-bleed plates already precede it — two in a row reads as one shapeless section
Register in

editorial

scene-caption

A small, quiet cinematic beat: full-bleed atmospheric art (or a labeled hatched placeholder when unset) under a hatch texture and scrim, with a bare 2px accent rule and one left-anchored italic caption line. Deliberately smaller and quieter than a hero — a breathing space, not a second headline moment.

When to use
  • A quiet pause between two denser sections that wants atmosphere and a single understated line, not another headline
  • A recurring "chapter breath" in a long-form narrative page
  • A moment that needs to feel authored and cinematic without competing for attention
Page types
  • landing
  • about
  • editorial-article
  • marketing
How to use

Add a background art image (an empty slot renders a hatched placeholder, never a blank band) and a short italic caption line. Leave the art unset during authoring — the placeholder carries an editable note tag so the gap stays visible and intentional.

Pairs with
  • scene-plate
  • statement-band
Avoid when
  • The moment needs a real headline or a call to action — use scene-plate or full-bleed-interstitial instead
  • Back-to-back full-bleed atmospheric bands already precede it — two in a row reads as one shapeless section
Register in

editorial

statement-band

A single centered statement on a full-bleed band, reading like the closing line of an argument rather than a marketing headline. Wrap a phrase in *asterisks* for the accent emphasis. An optional support line beneath it inks in from muted to fully-colored as it scrolls through view. Two faces: a quieter serif italic (default) or a heavier display register for an event-scale moment.

When to use
  • A single verdict or promise the page wants to state once, plainly — a guarantee, a pricing philosophy, a closing thought
  • A pacing beat between denser sections that wants one line of real weight rather than a new topic
  • A closing statement for a pricing or proof-heavy page
Page types
  • landing
  • pricing
  • about
  • marketing
How to use

Write the statement (wrap the emphasis phrase in *asterisks*). Choose the Statement Face — Serif for the quieter default register, Display for a heavier event-scale moment. Add an optional support line, which inks in on scroll. Toggle the section header strip on to add a mono label + section-number locator above the statement.

Pairs with
  • scene-plate
  • ambient-band
Avoid when
  • You need more than one statement or any supporting body copy beyond the single support line
  • The moment needs a call to action — this block has none by design; follow it with a block that does
Register in

marketing-landing

Exports

  • @wabbit/tome-blocks-cinema-pack
  • @wabbit/tome-blocks-cinema-pack/render
  • @wabbit/tome-blocks-cinema-pack/render/register
  • @wabbit/tome-blocks-cinema-pack/demo
  • @wabbit/tome-blocks-cinema-pack/meta

Changelog

v0.4.5patch

d10e467: Muted labels and captions now meet WCAG AA contrast on light surfaces. - Labels, captions, column heads, struck and absent values, and placeholder labels that mixed their ink at 40–60% now mix it at 70% (63 rules). Small muted ink below about 61% fails 4.5:1 on cream and tinted light surfaces; a live CompareLedger row label measured 3.92:1 at 55%. - This includes the house `mono-label-muted` and `placeholder-label` mixins, and the defaults of `--tome-dossier-thumb-placeholder-ink`, `--tome-campaign-placeholder-ink` and `--tome-campaign-tier-pledge-ink`. Set those properties to keep the old ink. - Decorative ink is unchanged: outline numerals, scrims, corner brackets and the EvidencePlate sources separator. - Muted text reads slightly darker on every surface.

  • d10e467: Muted labels and captions now meet WCAG AA contrast on light surfaces. - Labels, captions, column heads, struck and absent values, and placeholder labels that mixed their ink at 40–60% now mix it at 70% (63 rules). Small muted ink below about 61% fails 4.5:1 on cream and tinted light surfaces; a live CompareLedger row label measured 3.92:1 at 55%. - This includes the house `mono-label-muted` and `placeholder-label` mixins, and the defaults of `--tome-dossier-thumb-placeholder-ink`, `--tome-campaign-placeholder-ink` and `--tome-campaign-tier-pledge-ink`. Set those properties to keep the old ink. - Decorative ink is unchanged: outline numerals, scrims, corner brackets and the EvidencePlate sources separator. - Muted text reads slightly darker on every surface.
v0.4.4patch

fc84e67: Self-animating motion components now mark their own root with `data-tome-motion="self"`, so the opt-in platform scroll reveal in `@wabbit/tome-ui` never animates their blocks a second time. - `@wabbit/tome-blocks-core`: the `Reveal` boundary carries the marker, which covers every block that wraps its root in `Reveal`. - `@wabbit/tome-blocks-dossier-pack`: the entrance and motion islands (`StageMotion`, `DossierReveal`, the phase-ledger rail, case-file rows, evidence plate, receipts trio, record roster and proof plates) carry it. `RevealScope` renders no element of its own; when the pack reveal is on, it renders `DossierReveal`, which carries the marker. - `@wabbit/tome-blocks-campaign-pack`: `CampaignReveal` carries it. As in the dossier pack, `RevealScope` adds no element. - `@wabbit/tome-blocks-cinema-pack`: the pull interlude, scene caption and statement band motion and the scrub story stage carry it. - `@wabbit/tome-blocks-extras`: the animated `Showcase` root carries it. The static fallback does not, because it does not animate. The attribute changes nothing else. Markup, styles and motion are otherwise unchanged.

  • fc84e67: Self-animating motion components now mark their own root with `data-tome-motion="self"`, so the opt-in platform scroll reveal in `@wabbit/tome-ui` never animates their blocks a second time. - `@wabbit/tome-blocks-core`: the `Reveal` boundary carries the marker, which covers every block that wraps its root in `Reveal`. - `@wabbit/tome-blocks-dossier-pack`: the entrance and motion islands (`StageMotion`, `DossierReveal`, the phase-ledger rail, case-file rows, evidence plate, receipts trio, record roster and proof plates) carry it. `RevealScope` renders no element of its own; when the pack reveal is on, it renders `DossierReveal`, which carries the marker. - `@wabbit/tome-blocks-campaign-pack`: `CampaignReveal` carries it. As in the dossier pack, `RevealScope` adds no element. - `@wabbit/tome-blocks-cinema-pack`: the pull interlude, scene caption and statement band motion and the scrub story stage carry it. - `@wabbit/tome-blocks-extras`: the animated `Showcase` root carries it. The static fallback does not, because it does not animate. The attribute changes nothing else. Markup, styles and motion are otherwise unchanged.
v0.4.3patch

b452c7b: Testimonial Rail's edge inset and edge fade become tokens; Media Panel's CTA paints above the panel image; Cinema Feature's CTA lines up with the frame when a site insets it. No change until a site sets the token: - `--tome-cinema-rail-edge-inset` (default `calc(36 * var(--tome-cinema-px, 0.0625rem))`) and `--tome-cinema-rail-edge-inset-narrow` (default `calc(18 * var(--tome-cinema-px, 0.0625rem))`, at 40em or less): Testimonial Rail's track side inset. The status line and the CTA follow it; `--tome-cinema-rail-cta-inset` still overrides the CTA and now falls back to these tokens. - `--tome-cinema-rail-fade` (default `calc(56 * var(--tome-cinema-px, 0.0625rem))`): the width of the rail's edge fade on each side. - Cinema Feature's CTA now reads `--tome-cinema-feature-inset` (default `0px`) as its start padding. The CTA renders after the block's inner column, so `.inner`'s padding never reached it; with the token set, the CTA now starts on the same line as the frame and caption. Unset, nothing moves. The stylesheet comment that said the CTA sits inside `.inner` is corrected. Visible change on a default render: - **Media Panel's CTA shows.** The CTA is now `position: relative; z-index: 2`, so it paints above the absolutely positioned image (z-index 0) and scrim (z-index 1) instead of under them. A CTA that the image covered is now visible; its placement, type and colour are unchanged.

  • b452c7b: Testimonial Rail's edge inset and edge fade become tokens; Media Panel's CTA paints above the panel image; Cinema Feature's CTA lines up with the frame when a site insets it. No change until a site sets the token: - `--tome-cinema-rail-edge-inset` (default `calc(36 * var(--tome-cinema-px, 0.0625rem))`) and `--tome-cinema-rail-edge-inset-narrow` (default `calc(18 * var(--tome-cinema-px, 0.0625rem))`, at 40em or less): Testimonial Rail's track side inset. The status line and the CTA follow it; `--tome-cinema-rail-cta-inset` still overrides the CTA and now falls back to these tokens. - `--tome-cinema-rail-fade` (default `calc(56 * var(--tome-cinema-px, 0.0625rem))`): the width of the rail's edge fade on each side. - Cinema Feature's CTA now reads `--tome-cinema-feature-inset` (default `0px`) as its start padding. The CTA renders after the block's inner column, so `.inner`'s padding never reached it; with the token set, the CTA now starts on the same line as the frame and caption. Unset, nothing moves. The stylesheet comment that said the CTA sits inside `.inner` is corrected. Visible change on a default render: - **Media Panel's CTA shows.** The CTA is now `position: relative; z-index: 2`, so it paints above the absolutely positioned image (z-index 0) and scrim (z-index 1) instead of under them. A CTA that the image covered is now visible; its placement, type and colour are unchanged.
v0.4.2patch

eee4d87: Seven block CTAs read the house editorial CTA register, two gain inset tokens, and five blocks gain spacing tokens. **CTA register.** The CTAs of Scrub Story, Chaptered Walkthrough, Video Wall, Testimonial Rail, Trigger Tile, Cinema Feature and Media Panel read `--tome-house-cta-editorial-family`, `-size`, `-weight`, `-tracking`, `-transform`, `-margin` and `-color` from `@wabbit/tome-blocks-house`, each falling back to that block's current value: Scrub Story and Chaptered Walkthrough set no type and keep a `--tome-space-md` top margin; Video Wall, Testimonial Rail, Trigger Tile and Cinema Feature keep the mono face, `--tome-text-xs`, the editorial tracking, uppercase and a `--tome-space-lg` top margin; Media Panel keeps its centred, underlined link and its type and colour. On a grid parent each (Media Panel excepted) takes `--tome-house-cta-cols` and starts its row. Ambient Band's bordered button is not on the register. No change until a site sets the token: - `--tome-cinema-wall-cta-inset` (default `clamp(1.5rem, 4vw, 3rem)`) and `--tome-cinema-rail-cta-inset` (default the track's inset, `calc(36 * var(--tome-cinema-px))`, 18 below 40em; one value replaces both): the CTA's start inset, so a site that places the block full-bleed can start it on the content column with `var(--tome-grid-padding)`. - `--tome-cinema-ambient-cta-pad-block` (default `var(--tome-space-4, 0.85rem)`): Ambient Band's button top and bottom padding. - `--tome-cinema-chapter-gap` (default `var(--tome-space-sm, 0.65rem)`) and `--tome-cinema-chapter-progress-gap` (default `var(--tome-space-sm, 0.55rem)`): Chaptered Walkthrough's chapter row gap and the space above each progress line. - `--tome-cinema-walkthrough-below-margin` / `-below-pad` (defaults `var(--tome-space-8, 2rem)` / `var(--tome-space-5, 1.25rem)`) and `--tome-cinema-walkthrough-below-margin-narrow` / `-below-pad-narrow` (defaults `var(--tome-space-6, 1.5rem)` / `var(--tome-space-4, 1rem)`, at 640px or less): the space above and under the below-player copy's hairline. - `--tome-cinema-rail-placeholder-pad` (default `var(--tome-space-lg, 1rem)`): the label padding in an empty Testimonial Rail card. - `--tome-cinema-spread-media-width-narrow` (default `100%`): the width of Video Spread's video and poster inside the stacked panel (below 64em), anchored at its start edge and clipped by the panel. `max(100%, 35.5556rem)` gives the wider, left-anchored crop of a panel sized from its 20rem floor, without the panel overflowing the column. Visible change on a default render: - **Cinema Feature's CTA** no longer stretches across the block's column: the link's box (its clickable and focus area) now ends at its label. The label itself does not move. - **Link colour.** Scrub Story's, Chaptered Walkthrough's, Video Wall's, Testimonial Rail's, Trigger Tile's and Cinema Feature's CTAs now declare `var(--tome-color-primary)`, the colour tome-ui's base stylesheet gives every link, so on a tome-ui site they are unchanged. On a site whose own element-level `a { color }` rule coloured them differently, they now take `--tome-color-primary` unless the site sets `--tome-house-cta-editorial-color`; a link rule with a class or `:root` in it still wins as before.

  • eee4d87: Seven block CTAs read the house editorial CTA register, two gain inset tokens, and five blocks gain spacing tokens. **CTA register.** The CTAs of Scrub Story, Chaptered Walkthrough, Video Wall, Testimonial Rail, Trigger Tile, Cinema Feature and Media Panel read `--tome-house-cta-editorial-family`, `-size`, `-weight`, `-tracking`, `-transform`, `-margin` and `-color` from `@wabbit/tome-blocks-house`, each falling back to that block's current value: Scrub Story and Chaptered Walkthrough set no type and keep a `--tome-space-md` top margin; Video Wall, Testimonial Rail, Trigger Tile and Cinema Feature keep the mono face, `--tome-text-xs`, the editorial tracking, uppercase and a `--tome-space-lg` top margin; Media Panel keeps its centred, underlined link and its type and colour. On a grid parent each (Media Panel excepted) takes `--tome-house-cta-cols` and starts its row. Ambient Band's bordered button is not on the register. No change until a site sets the token: - `--tome-cinema-wall-cta-inset` (default `clamp(1.5rem, 4vw, 3rem)`) and `--tome-cinema-rail-cta-inset` (default the track's inset, `calc(36 * var(--tome-cinema-px))`, 18 below 40em; one value replaces both): the CTA's start inset, so a site that places the block full-bleed can start it on the content column with `var(--tome-grid-padding)`. - `--tome-cinema-ambient-cta-pad-block` (default `var(--tome-space-4, 0.85rem)`): Ambient Band's button top and bottom padding. - `--tome-cinema-chapter-gap` (default `var(--tome-space-sm, 0.65rem)`) and `--tome-cinema-chapter-progress-gap` (default `var(--tome-space-sm, 0.55rem)`): Chaptered Walkthrough's chapter row gap and the space above each progress line. - `--tome-cinema-walkthrough-below-margin` / `-below-pad` (defaults `var(--tome-space-8, 2rem)` / `var(--tome-space-5, 1.25rem)`) and `--tome-cinema-walkthrough-below-margin-narrow` / `-below-pad-narrow` (defaults `var(--tome-space-6, 1.5rem)` / `var(--tome-space-4, 1rem)`, at 640px or less): the space above and under the below-player copy's hairline. - `--tome-cinema-rail-placeholder-pad` (default `var(--tome-space-lg, 1rem)`): the label padding in an empty Testimonial Rail card. - `--tome-cinema-spread-media-width-narrow` (default `100%`): the width of Video Spread's video and poster inside the stacked panel (below 64em), anchored at its start edge and clipped by the panel. `max(100%, 35.5556rem)` gives the wider, left-anchored crop of a panel sized from its 20rem floor, without the panel overflowing the column. Visible change on a default render: - **Cinema Feature's CTA** no longer stretches across the block's column: the link's box (its clickable and focus area) now ends at its label. The label itself does not move. - **Link colour.** Scrub Story's, Chaptered Walkthrough's, Video Wall's, Testimonial Rail's, Trigger Tile's and Cinema Feature's CTAs now declare `var(--tome-color-primary)`, the colour tome-ui's base stylesheet gives every link, so on a tome-ui site they are unchanged. On a site whose own element-level `a { color }` rule coloured them differently, they now take `--tome-color-primary` unless the site sets `--tome-house-cta-editorial-color`; a link rule with a class or `:root` in it still wins as before.
v0.4.1patch

7c94229: Pull Interlude keeps its line inside the page gutter on narrow screens, and four blocks gain tokens for their video wells, scrim and readout. Visible change on a default render: - **Pull Interlude, below the width where its 34ch line fits.** The block now renders a bleeding lane grid (`LaneGrid` from `@wabbit/tome-blocks-house`) with the pull-line on the content column, as the line on the page grid always intended. On a phone the line used to run the whole band, edge to edge; it now stops at the side gutter (`--tome-grid-padding`, the page grid's padding column when the block sits on the page grid). Where the 34ch line fits inside the content column, typically from tablet width up, nothing moves. In a block wrapper narrower than the content column the line spans the wrapper with no gutter, as before. The band, art layer, scrim and tag are unchanged, and the root still spans its whole host row. No other change until a site sets a token: - `--tome-cinema-video-well` (default `var(--tome-color-surface-solid-dark)`): the well behind a playing video, the colour of its letterbox bars, in Video Wall (tile video, lightbox video and embed), Testimonial Rail (card video and its wrapper), Cinema Feature (video and its wrapper; the frame stays solid-dark) and Trigger Tile (lightbox video). - `--tome-cinema-ambient-scrim-base` (default `var(--tome-color-surface-solid-dark)`): the colour Ambient Band's scrim gradient mixes from; the scrim select still sets its strength. - `--tome-cinema-readout-gap` (default `var(--tome-space-lg, 1.25rem)`): the gap inside Scrub Story's pinned readout. - Testimonial Rail's edge-fade mask (56), track inset (36, 18 below 40em), status line and CTA insets are now stated in `--tome-cinema-px` units, so they are the same 3.5rem, 2.25rem and 1.125rem at the default unit and follow a site that sets the unit.

  • 7c94229: Pull Interlude keeps its line inside the page gutter on narrow screens, and four blocks gain tokens for their video wells, scrim and readout. Visible change on a default render: - **Pull Interlude, below the width where its 34ch line fits.** The block now renders a bleeding lane grid (`LaneGrid` from `@wabbit/tome-blocks-house`) with the pull-line on the content column, as the line on the page grid always intended. On a phone the line used to run the whole band, edge to edge; it now stops at the side gutter (`--tome-grid-padding`, the page grid's padding column when the block sits on the page grid). Where the 34ch line fits inside the content column, typically from tablet width up, nothing moves. In a block wrapper narrower than the content column the line spans the wrapper with no gutter, as before. The band, art layer, scrim and tag are unchanged, and the root still spans its whole host row. No other change until a site sets a token: - `--tome-cinema-video-well` (default `var(--tome-color-surface-solid-dark)`): the well behind a playing video, the colour of its letterbox bars, in Video Wall (tile video, lightbox video and embed), Testimonial Rail (card video and its wrapper), Cinema Feature (video and its wrapper; the frame stays solid-dark) and Trigger Tile (lightbox video). - `--tome-cinema-ambient-scrim-base` (default `var(--tome-color-surface-solid-dark)`): the colour Ambient Band's scrim gradient mixes from; the scrim select still sets its strength. - `--tome-cinema-readout-gap` (default `var(--tome-space-lg, 1.25rem)`): the gap inside Scrub Story's pinned readout. - Testimonial Rail's edge-fade mask (56), track inset (36, 18 below 40em), status line and CTA insets are now stated in `--tome-cinema-px` units, so they are the same 3.5rem, 2.25rem and 1.125rem at the default unit and follow a site that sets the unit.
v0.4.0minor

be6c393: **BREAKING:** Statement Band, Scene Plate and Scene Caption now lay out on the page's reading lanes, so their text moves on the page; background images ask the media adapter for fill mode. **Migration:** upgrade `@wabbit/tome-blocks-house` to 0.8.0 or later (the peer range is now `>=0.8.0 <1.0.0`; these blocks use its lane grid). No content or config changes. There is no switch back to the old fixed-width layout. What you will see move, from 1024px wide (below that every part takes the content column, inset by the page's grid gutter instead of the block's own side padding): - **Statement Band.** The serif statement and support line sit in the reading column instead of a 46rem box, and the display face runs the content column instead of a 64rem box, so on a wide screen a statement takes fewer lines. The section strip runs the content column instead of the full band. - **Scene Plate.** The copy sits on the content column instead of a 60rem box; on the centred `plate` variant it is centred as before, and the `cinema` variant now starts at the content edge. Left and right seated panels split the content column at the page's centre line, and the centre panel sits on the prose lane. The CTA, when set, sits under the copy above the scrim. The heading's `*accent*` phrase is set without the heading's tight tracking. - **Scene Caption.** The caption runs from the content edge to the end of the reading column instead of a 44ch box at the band's edge; its text keeps its 34ch measure. Other visible changes: - **Scene Plate paints its band.** A plate with no stored background now shows its dark band behind the scene and copy (before, only the scrim used it). A stored `inherit` still paints nothing. - **Scene Caption placeholder.** With no art, the pink wash reads the band's primary ink first, so on the default dark band it is the lighter on-dark primary. Additive: - **Images that fill a box.** Scene Plate's scene, Scene Caption's and Pull Interlude's art, Media Panel's image, and Cinema Feature's and Ambient Band's posters pass the media adapter `fill: true`, an `imgClassName` and `sizes: '100vw'`, so an adapter that wraps its image can fill the box with a cover crop. The built-in adapter renders the same `<img>` with a second class and a `sizes` attribute; it looks the same. - **`--tome-cinema-statement-display-tracking`** sets Statement Band's display-face tracking (default `var(--tome-type-tracking-tight)`) without moving the serif face. - **`--tome-cinema-caption-duration`** sets Scene Caption's entrance duration on the block (default: the house entrance timing). - Pull Interlude's placeholder washes and Scene Plate's panel kicker and italic read the band companions (`--blk-primary-ink`, `--blk-accent-ink`) before the theme tokens. Nothing in the pack changes for these with the default bands.

  • be6c393: **BREAKING:** Statement Band, Scene Plate and Scene Caption now lay out on the page's reading lanes, so their text moves on the page; background images ask the media adapter for fill mode. **Migration:** upgrade `@wabbit/tome-blocks-house` to 0.8.0 or later (the peer range is now `>=0.8.0 <1.0.0`; these blocks use its lane grid). No content or config changes. There is no switch back to the old fixed-width layout. What you will see move, from 1024px wide (below that every part takes the content column, inset by the page's grid gutter instead of the block's own side padding): - **Statement Band.** The serif statement and support line sit in the reading column instead of a 46rem box, and the display face runs the content column instead of a 64rem box, so on a wide screen a statement takes fewer lines. The section strip runs the content column instead of the full band. - **Scene Plate.** The copy sits on the content column instead of a 60rem box; on the centred `plate` variant it is centred as before, and the `cinema` variant now starts at the content edge. Left and right seated panels split the content column at the page's centre line, and the centre panel sits on the prose lane. The CTA, when set, sits under the copy above the scrim. The heading's `*accent*` phrase is set without the heading's tight tracking. - **Scene Caption.** The caption runs from the content edge to the end of the reading column instead of a 44ch box at the band's edge; its text keeps its 34ch measure. Other visible changes: - **Scene Plate paints its band.** A plate with no stored background now shows its dark band behind the scene and copy (before, only the scrim used it). A stored `inherit` still paints nothing. - **Scene Caption placeholder.** With no art, the pink wash reads the band's primary ink first, so on the default dark band it is the lighter on-dark primary. Additive: - **Images that fill a box.** Scene Plate's scene, Scene Caption's and Pull Interlude's art, Media Panel's image, and Cinema Feature's and Ambient Band's posters pass the media adapter `fill: true`, an `imgClassName` and `sizes: '100vw'`, so an adapter that wraps its image can fill the box with a cover crop. The built-in adapter renders the same `<img>` with a second class and a `sizes` attribute; it looks the same. - **`--tome-cinema-statement-display-tracking`** sets Statement Band's display-face tracking (default `var(--tome-type-tracking-tight)`) without moving the serif face. - **`--tome-cinema-caption-duration`** sets Scene Caption's entrance duration on the block (default: the house entrance timing). - Pull Interlude's placeholder washes and Scene Plate's panel kicker and italic read the band companions (`--blk-primary-ink`, `--blk-accent-ink`) before the theme tokens. Nothing in the pack changes for these with the default bands.
  • fb10584: **BREAKING:** Needs `@wabbit/tome-blocks-house` 0.8.4 or later; Video Wall, Testimonial Rail and Cinema Feature paint a chosen background; Media Panel's kicker takes the accent colour. **Migration:** upgrade `@wabbit/tome-blocks-house` to 0.8.4 or later (the peer range is now `>=0.8.4 <1.0.0`; every image that fills a box now builds its options with that package's `fillMediaOptions`, and the pack's own copy is gone). No content or config changes. What you will see change: - **Media Panel kicker.** The kicker reads a band's accent ink if one is set, else tome-ui's accent ink for the solid-dark surface (`--tome-color-accent-on-solid-dark`), instead of the plain on-dark ink. It is the panel's one accent colour, and it stays legible on the dark dock in both themes. The fig label, heading, body and the dock's hairline keep the on-dark ink. - **Video Wall, Testimonial Rail and Cinema Feature paint their band.** A block with a background chosen now shows it behind the wall, rail or frame, and its text takes the band's ink; before, the band's colours were set but nothing painted them. With no background set the root stays transparent, as before. The three roots also carry `data-band-tone`. - **Accents on a dark band.** Chaptered Walkthrough's active chapter, focus ring and progress fill, and Cinema Feature's eyebrow, read the band's accent ink (`--blk-accent-ink`) before `--tome-color-accent-text`. With no background, or a theme-following one, nothing changes; on a fixed dark band the accent is the band's own legible one. - **Scene Plate panel body.** A seated panel whose rich-text body holds only a list (or only linked text) now renders. The emptiness check looks for text at any depth instead of only directly under each top-level block. - **Testimonial Rail names.** The card name sets `font-variation-settings` itself (`normal`), so a page rule that thins every paragraph through the variable-font weight axis no longer thins the name below its 600 weight. Pages without such a rule look the same. Images that fill a box: - Scrub Story's stills (`sizes: '100vw'`, the first still keeps `priority`) and reduced-motion frames (`'(max-width: 768px) 100vw, 60vw'`), and Trigger Tile's uploaded poster (`'(max-width: 768px) 90vw, 65ch'`), pass the media adapter `fill: true`, an `imgClassName` and `sizes`, so an adapter that wraps its image fills the frame with a cover crop. The built-in adapter renders the same `<img>` with a second class and a `sizes` attribute; it looks the same. No change until a site sets a token or prop (each defaults to the value it replaced): - `--tome-cinema-px` (default `0.0625rem`): the unit for Video Wall's play ring and title chip and Testimonial Rail's card widths, which are now stated in pixels times the unit. A site whose root font size is not 16px sets `1px` to keep them at their pixel size. - `--tome-cinema-panel-accent` (Media Panel kicker) and `--tome-cinema-panel-border` (the dock hairline's ink, default the on-dark ink). - `--tome-cinema-scrub-crossfade` (Scrub Story's stills/video crossfade, default `--tome-motion-slow`; the beat change keeps `-slow`) and `--tome-cinema-feature-poster-fade` (Cinema Feature's poster-to-video fade, default `--tome-motion-base`). - `--tome-cinema-feature-inset` (Cinema Feature) and `--tome-cinema-ambient-copy-inset` (Ambient Band's copy), both `0px`: set them to the page grid's side gutter to put the frame or copy on the content column of a full-bleed band. - `--tome-cinema-walkthrough-max-width` (Chaptered Walkthrough, default `72rem`; `none` fills the block). - `--tome-cinema-rail-name-variation` (Testimonial Rail name, default `normal`). - `--tome-cinema-interlude-placeholder-base` (Pull Interlude's empty-art base, default `--tome-color-surface-solid-dark`). - `videoPreload: 'metadata'` on a Chaptered Walkthrough block (a render prop, not an editor field) loads the video's metadata on mount, so the last chapter's length and range use the real duration before playback. The default stays `none`. The looping-video pause button, the play-ring styling and the entrance timers are unchanged.
v0.3.4patch

775f90a: Published packages now contain compiled JavaScript and type declarations under a one-line licence banner, and no longer include source maps. What you install: one compiled `.js` (ESM) and `.cjs` (CommonJS) file per source module, its `.d.ts` / `.d.cts` declarations, and the stylesheets, fonts and other assets a package already shipped. Every JavaScript module opens with a comment naming the package and its licence: `/*! @wabbit/<package> — © Wabbit, LLC. Wabbit Tome Commercial License (see LICENSE.md). Not for redistribution. */`. The `.map` files and the `sourceMappingURL` comments that pointed at them are gone, which roughly halves the size of each tarball. Debugging: the code is still unbundled and unminified, one readable file per module, so a stack trace points at real code with real names. Line numbers in a stack trace are one higher than before, because of the banner line. A `'use client'` directive stays the first statement of its module (the banner is a comment above it), so React Server Component boundaries are unchanged. No API change, no runtime behaviour change, and nothing to do on upgrade. In `@wabbit/tome-blocks-gallery`, the source snapshots `extractGallerySource` writes from an installed pack leave out the licence banner line, so a component or config snapshot starts at the code and a paid block's preview shows its first 15 lines of real code.

  • 775f90a: Published packages now contain compiled JavaScript and type declarations under a one-line licence banner, and no longer include source maps. What you install: one compiled `.js` (ESM) and `.cjs` (CommonJS) file per source module, its `.d.ts` / `.d.cts` declarations, and the stylesheets, fonts and other assets a package already shipped. Every JavaScript module opens with a comment naming the package and its licence: `/*! @wabbit/<package> — © Wabbit, LLC. Wabbit Tome Commercial License (see LICENSE.md). Not for redistribution. */`. The `.map` files and the `sourceMappingURL` comments that pointed at them are gone, which roughly halves the size of each tarball. Debugging: the code is still unbundled and unminified, one readable file per module, so a stack trace points at real code with real names. Line numbers in a stack trace are one higher than before, because of the banner line. A `'use client'` directive stays the first statement of its module (the banner is a comment above it), so React Server Component boundaries are unchanged. No API change, no runtime behaviour change, and nothing to do on upgrade. In `@wabbit/tome-blocks-gallery`, the source snapshots `extractGallerySource` writes from an installed pack leave out the licence banner line, so a component or config snapshot starts at the code and a paid block's preview shows its first 15 lines of real code.
v0.3.3patch

868c087: The looping video blocks (ambient band, video wall, video spread) now have a visible pause and play button. Pausing stops the video and keeps it stopped when the block scrolls back into view; the ambient band's slow zoom stops with it. The video wall has one button that pauses every looping tile. The button is always visible and reachable by keyboard; reduced-motion visitors, who already get a still poster, see no button. Needs `@wabbit/tome-blocks-house` with `LoopVideoControl`.

  • 868c087: The looping video blocks (ambient band, video wall, video spread) now have a visible pause and play button. Pausing stops the video and keeps it stopped when the block scrolls back into view; the ambient band's slow zoom stops with it. The video wall has one button that pauses every looping tile. The button is always visible and reachable by keyboard; reduced-motion visitors, who already get a still poster, see no button. Needs `@wabbit/tome-blocks-house` with `LoopVideoControl`.
  • d08fc38: The video spread block no longer overflows a phone-width screen when its link label is long. The stacked layout's grid track can now shrink, and the link wraps within its column instead of holding its full text width.
v0.3.2patch

c14a133: The pack works on a stock Next.js site: its per-block stylesheets now ship precompiled, so the site needs no next.config plugin. Each renderer's `.tome-css` stylesheet is compiled when the pack is built, into a JS module next to it (`<Name>.tome-css.js` / `.cjs`), and the renderers import that. A site no longer has to wrap next.config with `withTomeBlockStyles` to use the pack, and `./render` and `./render/register` now load under plain Node, so seed scripts, tests and the Payload CLI can import them. Each block's CSS is still inlined only on pages that render the block. A site that already uses `withTomeBlockStyles` needs no change. Scoped class names change once, because they are now keyed on the package rather than on where it is installed. The raw `.tome-css` files stay in the package as readable source.

  • c14a133: The pack works on a stock Next.js site: its per-block stylesheets now ship precompiled, so the site needs no next.config plugin. Each renderer's `.tome-css` stylesheet is compiled when the pack is built, into a JS module next to it (`<Name>.tome-css.js` / `.cjs`), and the renderers import that. A site no longer has to wrap next.config with `withTomeBlockStyles` to use the pack, and `./render` and `./render/register` now load under plain Node, so seed scripts, tests and the Payload CLI can import them. Each block's CSS is still inlined only on pages that render the block. A site that already uses `withTomeBlockStyles` needs no change. Scoped class names change once, because they are now keyed on the package rather than on where it is installed. The raw `.tome-css` files stay in the package as readable source.
v0.3.1patch

8c84e70: statement-band, scene-plate, scene-caption and video-spread read the band's accent and primary inks from `resolveBackground`, so the accent on their solid-dark plates is readable in light themes. pull-interlude, which is always solid-dark, reads `--tome-color-accent-on-solid-dark` for its strong runs.

  • 8c84e70: statement-band, scene-plate, scene-caption and video-spread read the band's accent and primary inks from `resolveBackground`, so the accent on their solid-dark plates is readable in light themes. pull-interlude, which is always solid-dark, reads `--tome-color-accent-on-solid-dark` for its strong runs.
v0.3.0minor

**Breaking: block stylesheets are now per-block (`.tome-css`).** Each block's CSS ships only on pages that render it, instead of in every page's CSS bundle. The 13 stylesheets moved from `X.module.css` to `X.tome-css`, and each renderer renders `<BlockStyles sheet={styles} />` from `@wabbit/tome-blocks-core/block-styles`. **Required in the consuming site:** wrap next.config with `withTomeBlockStyles` (`@wabbit/tome-blocks-core/next`, blocks-core 0.22.0 or later); without it the `.tome-css` imports fail to build. See the blocks-core README, "Per-block stylesheets". - The `@wabbit/tome-blocks-core` peer range is now `>=0.22.0 <1.0.0`. - PullInterlude (client) is now a server-safe wrapper around `PullInterlude.client.tsx`, its exported types re-exported. The blocks already split into a server renderer plus a client half (players, motion, engines) keep that split; the client halves import the same `.tome-css` for class names. Exported names and props are unchanged. - Block CSS now loads after all bundled CSS. A site-level rule that overrode one of this pack's classes at equal specificity, and won only by loading later, no longer wins.

  • **Breaking: block stylesheets are now per-block (`.tome-css`).** Each block's CSS ships only on pages that render it, instead of in every page's CSS bundle. The 13 stylesheets moved from `X.module.css` to `X.tome-css`, and each renderer renders `<BlockStyles sheet={styles} />` from `@wabbit/tome-blocks-core/block-styles`. **Required in the consuming site:** wrap next.config with `withTomeBlockStyles` (`@wabbit/tome-blocks-core/next`, blocks-core 0.22.0 or later); without it the `.tome-css` imports fail to build. See the blocks-core README, "Per-block stylesheets". - The `@wabbit/tome-blocks-core` peer range is now `>=0.22.0 <1.0.0`. - PullInterlude (client) is now a server-safe wrapper around `PullInterlude.client.tsx`, its exported types re-exported. The blocks already split into a server renderer plus a client half (players, motion, engines) keep that split; the client halves import the same `.tome-css` for class names. Exported names and props are unchanged. - Block CSS now loads after all bundled CSS. A site-level rule that overrode one of this pack's classes at equal specificity, and won only by loading later, no longer wins.
v0.2.2patch

7862f30: Swaps the plain primary token for the on-solid-dark pairing on text and borders that sit on a dark surface in three packs. `@wabbit/tome-blocks-dossier-pack`: the `evidence-sheet` block's `ledger` treatment now uses the on-solid-dark pairing for its kicker, headline emphasis, body link and row-label text, instead of the plain primary token — that token is a surface-tint fill, not guaranteed legible as text on the block's dark surface. `@wabbit/tome-blocks-cinema-pack`: the `scene-plate` block's seated panel kicker and body emphasis text get the same on-solid-dark pairing, since the panel itself is a partially-opaque dark surface over the scene image. `@wabbit/tome-blocks-catalog-pack`: the `price-table` block's highlighted-tier border now uses the on-solid-dark pairing specifically on the `dark` variant, leaving the default/light variant's border on the plain primary token unchanged.

  • 7862f30: Swaps the plain primary token for the on-solid-dark pairing on text and borders that sit on a dark surface in three packs. `@wabbit/tome-blocks-dossier-pack`: the `evidence-sheet` block's `ledger` treatment now uses the on-solid-dark pairing for its kicker, headline emphasis, body link and row-label text, instead of the plain primary token — that token is a surface-tint fill, not guaranteed legible as text on the block's dark surface. `@wabbit/tome-blocks-cinema-pack`: the `scene-plate` block's seated panel kicker and body emphasis text get the same on-solid-dark pairing, since the panel itself is a partially-opaque dark surface over the scene image. `@wabbit/tome-blocks-catalog-pack`: the `price-table` block's highlighted-tier border now uses the on-solid-dark pairing specifically on the `dark` variant, leaving the default/light variant's border on the plain primary token unchanged.
v0.2.1patch

c3468b0: `register()` is now built with blocks-core's `createPackRegistrar`, and media fields take their `relationTo` from `mediaRelation(config)` instead of a local `as CollectionSlug` cast. Behaviour and signatures are unchanged. The `@wabbit/tome-blocks-core` peer floor goes up to `>=0.18.0` because that is the first version exporting the helpers.

  • c3468b0: `register()` is now built with blocks-core's `createPackRegistrar`, and media fields take their `relationTo` from `mediaRelation(config)` instead of a local `as CollectionSlug` cast. Behaviour and signatures are unchanged. The `@wabbit/tome-blocks-core` peer floor goes up to `>=0.18.0` because that is the first version exporting the helpers.
v0.2.0minor

404d325: Tome block packs now install into an existing Payload project the way the README says: one `npm install`, one CSS import, no undocumented steps. Proven by the new fresh-install smoke test (`scripts/blocks-fresh-install-smoke.mjs`) against a brand-new `create-payload-app` website-template site. **Consumers: list `@wabbit/tome-blocks-core` and `@wabbit/tome-ui` in your own `package.json`** if you import from them (npm 7+ and pnpm install required peers automatically, so a fresh `npm install` of a pack already brings them in). - **One shared `blocks-core` per site.** Every pack, `blocks-house` and `blocks-extras` now declare `@wabbit/tome-blocks-core` (and, where used, `-house` / `-extras`) as a required peer with an explicit range instead of a regular dependency, so a site gets exactly one hoisted copy and one adapter registry. - **No more ERESOLVE in plain Payload sites.** `blocks-core` no longer declares `@wabbit/tome-core` or `@wabbit/tome-catalog` (their optional peer graph pulled `better-auth` → `@sveltejs/kit` → `vite@8` against a site's `vite@7`). The `block-bundle` product type still auto-registers when both are installed; new structural types `BlockBundleProductTypeDeps`, `BlockBundleProductTypeRegistryLike`, `RegisterProductTypeHooksLike`. - **Tokens in one line:** `@import '@wabbit/tome-blocks-core/styles.css';` (new export; imports `@wabbit/tome-ui/tokens`). `@wabbit/tome-ui` is now a required peer of `blocks-core`. - **Rich text and images render with no adapter setup.** Built-in defaults render Lexical through `@payloadcms/richtext-lexical/react` and resolve populated Payload uploads; an unpopulated upload id warns once in every environment (previously content vanished silently in production). Registered adapters still win. - **Payload's spread-props convention:** new `adaptRenderersForPayload(renderers)` / `adaptRendererForPayload(Component)` wrap any pack's `renderers` map for a site that renders `<Block {...block} />`. - **Slug collisions with Payload's templates** (`cta`, `banner`, `archive`, `content`, `code`): new `applyBlockSlugOverrides(blocks, overrides)` and `remapRendererSlugs(renderers, overrides)` (`@wabbit/tome-blocks-core/slugOverrides`). Defaults are unchanged; no stored data migrates. - **`blocks-house`** owns `gsap` and `hls.js` as dependencies (previously optional peers that still broke the build when missing), and registers GSAP's `ScrollTrigger` itself before first use. - **Full-bleed bands actually span the grid.** Eight `pinnedBand` blocks (cinema-pack AmbientBand, MediaPanel, PullInterlude, SceneCaption, ScenePlate, ScrubStory, StatementBand; blocks-house FullBleedInterstitial) now declare `grid-column: 1 / -1` at their root as the contract requires. **Visible change:** inside a tome-ui `.grid`, these render edge to edge where they were previously squeezed to content width. - **`@wabbit/tome-ui`:** `.grid` declares `reading-start` / `reading-end` below 768px (aliased to the content column), so blocks placed on the reading column no longer collapse to a sliver on phones. - Every pack README gains an "Install into an existing Payload project" section and a peer table that matches `package.json`; `blocks-core`'s README carries the full walkthrough.

  • 404d325: Tome block packs now install into an existing Payload project the way the README says: one `npm install`, one CSS import, no undocumented steps. Proven by the new fresh-install smoke test (`scripts/blocks-fresh-install-smoke.mjs`) against a brand-new `create-payload-app` website-template site. **Consumers: list `@wabbit/tome-blocks-core` and `@wabbit/tome-ui` in your own `package.json`** if you import from them (npm 7+ and pnpm install required peers automatically, so a fresh `npm install` of a pack already brings them in). - **One shared `blocks-core` per site.** Every pack, `blocks-house` and `blocks-extras` now declare `@wabbit/tome-blocks-core` (and, where used, `-house` / `-extras`) as a required peer with an explicit range instead of a regular dependency, so a site gets exactly one hoisted copy and one adapter registry. - **No more ERESOLVE in plain Payload sites.** `blocks-core` no longer declares `@wabbit/tome-core` or `@wabbit/tome-catalog` (their optional peer graph pulled `better-auth` → `@sveltejs/kit` → `vite@8` against a site's `vite@7`). The `block-bundle` product type still auto-registers when both are installed; new structural types `BlockBundleProductTypeDeps`, `BlockBundleProductTypeRegistryLike`, `RegisterProductTypeHooksLike`. - **Tokens in one line:** `@import '@wabbit/tome-blocks-core/styles.css';` (new export; imports `@wabbit/tome-ui/tokens`). `@wabbit/tome-ui` is now a required peer of `blocks-core`. - **Rich text and images render with no adapter setup.** Built-in defaults render Lexical through `@payloadcms/richtext-lexical/react` and resolve populated Payload uploads; an unpopulated upload id warns once in every environment (previously content vanished silently in production). Registered adapters still win. - **Payload's spread-props convention:** new `adaptRenderersForPayload(renderers)` / `adaptRendererForPayload(Component)` wrap any pack's `renderers` map for a site that renders `<Block {...block} />`. - **Slug collisions with Payload's templates** (`cta`, `banner`, `archive`, `content`, `code`): new `applyBlockSlugOverrides(blocks, overrides)` and `remapRendererSlugs(renderers, overrides)` (`@wabbit/tome-blocks-core/slugOverrides`). Defaults are unchanged; no stored data migrates. - **`blocks-house`** owns `gsap` and `hls.js` as dependencies (previously optional peers that still broke the build when missing), and registers GSAP's `ScrollTrigger` itself before first use. - **Full-bleed bands actually span the grid.** Eight `pinnedBand` blocks (cinema-pack AmbientBand, MediaPanel, PullInterlude, SceneCaption, ScenePlate, ScrubStory, StatementBand; blocks-house FullBleedInterstitial) now declare `grid-column: 1 / -1` at their root as the contract requires. **Visible change:** inside a tome-ui `.grid`, these render edge to edge where they were previously squeezed to content width. - **`@wabbit/tome-ui`:** `.grid` declares `reading-start` / `reading-end` below 768px (aliased to the content column), so blocks placed on the reading column no longer collapse to a sliver on phones. - Every pack README gains an "Install into an existing Payload project" section and a peer table that matches `package.json`; `blocks-core`'s README carries the full walkthrough.
v0.1.3patch

Updated dependencies [e044594] - @wabbit/tome-blocks-core@0.16.6

  • Updated dependencies [e044594] - @wabbit/tome-blocks-core@0.16.6
v0.1.2patch

a2f2dfa: cinema-pack's block configs now load under plain Node — no bundler, no CSS loader. Eight of cinema-pack's block configs (`src/blocks/*/index.ts`) imported `videoSourceFields` from `@wabbit/tome-blocks-house/video`. That entry is a barrel that also re-exports the `'use client'` `EmbedFrame` and its CSS Module. Next.js resolves that CSS; plain Node does not. So any script that loaded cinema-pack's main entry outside a bundler (a Payload CLI command, a seed, a type generator) failed with `ERR_UNKNOWN_FILE_EXTENSION ".css"` before a single block registered. - **blocks-house (minor):** new `./video/fields` export for `videoSourceFields` and its resolvers. It points at the module the package already built and has no CSS on its import graph. `./video` is unchanged, so existing imports keep working. - **cinema-pack (patch):** the eight block configs import from `@wabbit/tome-blocks-house/video/fields`. Render components still use `./video`, because they need `EmbedFrame` and `useHlsVideo`. Verified against the rebuilt dist: importing `@wabbit/tome-blocks-cinema-pack` and calling `register()` under bare Node now registers all 13 blocks. The same import failed with the CSS error on `main`. cinema-pack's smoke test no longer needs a CSS stub loader, and the stub is removed. No consumer changes are needed. wabbit-site-core and tome-starter import only cinema-pack's `./meta`, `./demo`, `./render` and `./render/register` entries, none of which reached the barrel.

  • a2f2dfa: cinema-pack's block configs now load under plain Node — no bundler, no CSS loader. Eight of cinema-pack's block configs (`src/blocks/*/index.ts`) imported `videoSourceFields` from `@wabbit/tome-blocks-house/video`. That entry is a barrel that also re-exports the `'use client'` `EmbedFrame` and its CSS Module. Next.js resolves that CSS; plain Node does not. So any script that loaded cinema-pack's main entry outside a bundler (a Payload CLI command, a seed, a type generator) failed with `ERR_UNKNOWN_FILE_EXTENSION ".css"` before a single block registered. - **blocks-house (minor):** new `./video/fields` export for `videoSourceFields` and its resolvers. It points at the module the package already built and has no CSS on its import graph. `./video` is unchanged, so existing imports keep working. - **cinema-pack (patch):** the eight block configs import from `@wabbit/tome-blocks-house/video/fields`. Render components still use `./video`, because they need `EmbedFrame` and `useHlsVideo`. Verified against the rebuilt dist: importing `@wabbit/tome-blocks-cinema-pack` and calling `register()` under bare Node now registers all 13 blocks. The same import failed with the CSS error on `main`. cinema-pack's smoke test no longer needs a CSS stub loader, and the stub is removed. No consumer changes are needed. wabbit-site-core and tome-starter import only cinema-pack's `./meta`, `./demo`, `./render` and `./render/register` entries, none of which reached the barrel.
  • Updated dependencies [a2f2dfa] - @wabbit/tome-blocks-house@0.3.0
v0.1.1patch

1dcc935: pull-interlude carries a `media` tag so the gallery files it under Media with its siblings instead of a stray "Layout" facet.

  • 1dcc935: pull-interlude carries a `media` tag so the gallery files it under Media with its siblings instead of a stray "Layout" facet.