Blocks Cinema Pack
Blocks & ThemesVideo 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.
npm install @wabbit/tome-blocks-cinema-packOverview
@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 wabbit-site-core — 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.18.0 <1.0.0 | yes | | @wabbit/tome-blocks-house | >=0.3.0 <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 CSS on its import graph, so a Payload CLI command, seed or type generator can load this pack's main entry without a bundler. Only the render components import the full @wabbit/tome-blocks-house/video barrel, which pulls in EmbedFrame's CSS Module and needs a bundler.
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), no hardcoded font-family. Every render component is self-contained and width-agnostic (no dependency on a consumer's named page-grid lines). 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.
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.
- 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
- landing
- about
- marketing
- editorial-article
- portfolio
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).
- pull-interlude
- scene-plate
- statement-band
- 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
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).
- 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
- landing
- about
- marketing
- editorial-article
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.
- media-panel
- statement-band
- scene-plate
- 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
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.
- 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
- landing
- marketing
- about
- portfolio
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.
- video-wall
- testimonial-rail
- trigger-tile
- 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
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.
- 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
- blog
- editorial-article
- docs
- about
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.
- cinema-feature
- video-wall
- 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
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.
- Showcasing several short clips together as a single ambient composition
- A "reel wall" or gallery of motion moments rather than one flagship video
- landing
- marketing
- portfolio
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.
- cinema-feature
- testimonial-rail
- trigger-tile
- There is one flagship video that deserves full-bleed emphasis — use cinema-feature
- The clips are client testimonials with names/quotes — use testimonial-rail
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.
- A rhythm-break moment pairing a short editorial statement with motion
- Introducing a process, place, or product with ambient video alongside supporting copy
- landing
- marketing
- about
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.
- cinema-feature
- video-wall
- 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
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.
- 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
- landing
- marketing
- about
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.
- cinema-feature
- video-wall
- 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
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.
- 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
- landing
- marketing
- docs
- about
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.
- scrub-story
- ambient-band
- 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
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.
- 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
- landing
- marketing
- about
- portfolio
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.
- chaptered-walkthrough
- ambient-band
- 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
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.
- 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
- landing
- marketing
- about
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.
- scrub-story
- chaptered-walkthrough
- 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
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.
- 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
- landing
- about
- editorial-article
- marketing
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.
- scene-caption
- statement-band
- 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
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.
- 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
- landing
- about
- editorial-article
- marketing
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.
- scene-plate
- statement-band
- 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
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.
- 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
- landing
- pricing
- about
- marketing
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.
- scene-plate
- ambient-band
- 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
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
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.
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.
Updated dependencies [e044594] - @wabbit/tome-blocks-core@0.16.6
- Updated dependencies [e044594] - @wabbit/tome-blocks-core@0.16.6
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
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.