Documentation menu
Documentation / Blocks & themes / theme-grounds
Theme Grounds
npm install @wabbit/tome-theme-groundsFirst install from our registry?
Get a registry token from your credentials page. You need a purchase that includes this package, or a Craft Library membership.
Add the registry and your token to the
.npmrcat the root of your project, with your token in place ofYOUR_TOKEN:@wabbit:registry=https://npm.wabbit.com/ //npm.wabbit.com/:_authToken=YOUR_TOKEN
Grounds, a Tome theme for places people visit: parks and athletic complexes, event venues, marinas and waterfronts, historic districts and market halls. The signboard is the design: a key plate names every place, the Today Board says what is on and when, a drawn plan sits beside the list, and the booking desk is one honest form. Overpass and Figtree, an indigo-and-coral default (Pennant), four palettes plus derived opposite modes, self-hosted OFL fonts, activated by data-tome-theme="grounds".
Overview
Grounds is a Tome theme for places people visit: parks and athletic complexes, event venues, marinas and waterfronts, historic districts and market halls. Its stance is "the signboard is the design". A small key plate names every place (a letter, a number, "Lot C"), the Today Board says what is on and when, a drawn plan sits beside the list of places, and the booking desk is one honest form. It never decorates: no marquee, no ticket shapes, no auto-advancing stack, and nothing set over a photograph but its credit.
This package is a theme (a ThemeManifest of kind: 'theme'). It owns no blocks. It declares the whole token surface blocks read, self-hosts its two OFL font families, and restyles blocks and chrome through their public hooks. The blocks it is composed from are local-pack's local-facilities, local-logistics and local-live-status; event-list and division-card from org-pack; stat and contact from agency-essentials; zone-directory from dossier-pack; section-header and layoutGrid from extras; the marketing-starter high-impact-hero (variant venue), banner, testimonial and faq; and the directory pack's directoryListingGrid and directoryPromotionsRail.
Layer: ui · Family / tier: themes / addon · Versioning: independent.
Peer dependencies
| Peer | Range | Required |
|---|---|---|
@wabbit/tome-ui | >=0.22.0 <1.0.0 | yes |
@wabbit/tome-core | >=1.25.0 <2.0.0 | no (optional) |
@wabbit/tome-ui is a CSS-contract peer. Its tokens.css re-declares the var()-aliased Layer 2 under [data-tome-theme] and defines the fixed-band ink family this theme sets, and it ships the platform scroll reveal Grounds turns on. @wabbit/tome-core is needed only for the @wabbit/tome-theme-grounds/register subpath and the ThemeManifest type.
What is in this release
0.1.1 ships the whole theme: the manifest, the tokens, the self-hosted fonts and a treatment for every surface of the two demo homes and their flow pages.
- Four palettes, each light with a derived dark mode: Pennant (indigo sign, coral flag; the default and the bare selector), Trailhead (bronze, blaze blue), Lido (aqua, violet, with the 1.5px ink plate edge) and Marquee (claret, moss). See Palettes.
- Styled blocks (
GROUNDS_STYLED_BLOCKS, 15 slugs, each restyled through its public hooks):banner(the dismissible alert in the header slot),high-impact-hero(venue: up to four visitor doors and the photo credit),section-header,event-list(the Today Board, and the Upcoming lead and dated rows),local-facilities(the grouped list, the pinned plan, the phone plan sheet and the event page's locator inset),local-logistics,division-card(program and space cards with their plan plates),stat,testimonial,faq,contact(the booking desk, including its no-script errors),layoutGrid,text-block,directoryListingGridanddirectoryPromotionsRail(the tenant board and offers rail). Chrome gets the header, the footer and the phone bar with Directions and Book. The event page's locator inset shows "See Field 4 on the full plan" as an outlined action when the site sends it to the full plan (local-pack'sshowOnPlanHrefTemplate), and hides it while it would point at the inset's own marker. - Companion packs. Grounds owns no blocks; the demos are composed from these packs' blocks (
GROUNDS_RECOMMENDED_BLOCKS): local-pack (local-facilities,local-logistics,local-live-status), org-pack (event-list,division-card), agency-essentials (stat,contact), dossier-pack (zone-directory), extras (section-header,layoutGrid,text-block), marketing-starter (banner,high-impact-hero,testimonial,faq) and directory-pack (directoryListingGrid,directoryPromotionsRail). The board's events come from tome-org, the tenants from tome-directory, and the booking desk from tome-forms with tome-intake. - The Today Board keeps to the clock. The chips ("Live now", "Starts 2:00 PM", "Finished") come from each event's start and end, never from authored text, and the board hides at the end of its day. A closure leads the board while it is in force and leaves it when it ends (org-pack 0.9.1 and later, on the server and on a cached page), so after a 3:30 PM hold the board agrees with the alert and the facilities list. Earlier org-pack releases keep an ended closure at the top until the day ends.
Usage
Import the stylesheet once at the app root, after tome-ui's tokens, and activate the theme on <html>:
// app/layout.tsx
import '@wabbit/tome-ui/tokens.css'
import '@wabbit/tome-theme-grounds/styles.css'
import '@wabbit/tome-theme-grounds/fonts.css'<html data-tome-theme="grounds"> <!-- Pennant, light -->
<html data-tome-theme="grounds" data-tome-palette="trailhead"> <!-- Trailhead, light -->
<html data-tome-theme="grounds" data-tome-palette="lido" data-theme="dark"> <!-- Lido, derived dark -->With no data-tome-palette the theme renders Pennant. Every palette is a light design and data-theme="dark" gives it its derived dark mode: the band becomes the page and the sign becomes a light plate with dark lettering.
To have the admin ThemeSwitcher, createThemeConfig() and other registry readers list it, register it on the server before building the Payload config:
import '@wabbit/tome-theme-grounds/register'The sign fills; the accent punctuates
The sign colour fills action plates, key plates and bands. The accent is punctuation only: the live dot, the active nav marker, the section square and the focus ring. In Pennant, Trailhead and Marquee the accent text is the sign colour itself, so only Lido carries a separate accent text. The mark against the ink is low in every palette, so no state depends on the accent's colour alone: weight, an underline and the key plate carry state.
Lido's plate edge
Lido's aqua sign is under 3:1 against its ground, so Lido's plates, key plates and primary buttons carry a 1.5px ink edge (--grounds-plate-edge-w and --grounds-plate-edge). The other three signs clear 3:1 unaided, so their edge width is 0.
Errors are not red
The palettes have no error role, so --error, --destructive and the error text are the ink. A field error is a 2px ink border, a "!" plate and plain words, and the block that draws it never relies on colour.
Fonts
Two variable faces ship inside the package as latin-subset woff2 files, each with its SIL OFL 1.1 licence: Overpass (wght 400 to 900: the display, the key plates and the big numerals; fonts/OFL-Overpass.md) and Figtree (wght 400 to 700: the body and the meta voice; fonts/OFL-Figtree.md). There is no third-party font request by default. Three ways to deliver them:
import '@wabbit/tome-theme-grounds/fonts.css': the bundler resolves the files from this package.- Your own host: copy the files from
@wabbit/tome-theme-grounds/fonts/*and injectgetGroundsFontStyles({ src }). next/font/local, using the files fromgetGroundsFontFaces().
import { getGroundsFontPreloads } from '@wabbit/tome-theme-grounds/fonts'
// in <head>: preload the two faces
{getGroundsFontPreloads({ src: '/fonts/grounds/' }).map((l) => <link key={l.href} {...l} />)}Sources, recorded in scripts/subset-fonts.py (the build never runs it) and checked by SHA-256:
| Face | Source | Pinned at |
|---|---|---|
| Overpass | google/fonts ofl/overpass/Overpass[wght].ttf | commit 8b0a1d0f5983c89bc2b93f1b5fb55f9e252744b5, SHA-256 970717df17a7f9911dee45f60695d05bfa9d745fa0a11fc5c348371fa21f0073 |
| Figtree | google/fonts ofl/figtree/Figtree[wght].ttf | commit a60a77e14f28abd4ef243a1b5dfc48df0cec5205, SHA-256 26ad3db9b31ff7dde67a91ff515d022d2f495cd506590699cf264f0bfe6fb714 |
Both faces' default figures are proportional and both carry tnum and pnum. Times and columns set tabular-nums in Figtree (the meta voice); the big numerals set proportional-nums in Overpass. The recipe checks, for both faces and at every tested weight, that the ten tabular figures share one advance, and the test suite re-checks the shipped files. Figtree's tabular advance grows a little with weight, so a column is set at one weight. Albert Sans was the step-0 alternate; it has no tabular figures, so it is not shipped. No italic is shipped: emphasis is weight.
Public API
| Export | Subpath | Purpose |
|---|---|---|
groundsThemeManifest (ThemeManifest) | ., @wabbit/tome-theme-grounds/manifest | The theme's manifest: name grounds, kind: 'theme', tier addon, four palettes, fonts and one pairing, recommended blocks and chrome (Navbar 1, footer 7), styledBlocks, requires.tomeUi. |
GROUNDS_PALETTE_IDS, GroundsPaletteId | ., @wabbit/tome-theme-grounds/manifest | ['pennant', 'trailhead', 'lido', 'marquee'], the data-tome-palette values. |
GROUNDS_PALETTE_DEFAULT_MODES | ., @wabbit/tome-theme-grounds/manifest | The mode each palette opens in: light for all four. |
GROUNDS_STYLED_BLOCKS, GROUNDS_RECOMMENDED_BLOCKS, GROUNDS_PENDING_CATALOG_BLOCKS | ., @wabbit/tome-theme-grounds/manifest | The block slugs the theme restyles, the slugs its demos are composed from, and the ones whose pack has not yet registered them in the block catalog. |
ThemeManifest (type) | . | Re-exported from @wabbit/tome-core/registry/theme. |
getGroundsFontFaces(), getGroundsFontStyles({ src }), getGroundsFontPreloads({ src }) | ., @wabbit/tome-theme-grounds/fonts | Font descriptors, @font-face CSS for a custom host, and preload links. |
GROUNDS_FONT_STACKS, GROUNDS_FONT_LICENSES, GROUNDS_LATIN_UNICODE_RANGE, GROUNDS_DISPLAY_WEIGHTS, GROUNDS_UI_WEIGHTS | ., @wabbit/tome-theme-grounds/fonts | The CSS stacks the tokens use, the licence files, the subset range, and the weights used. |
GroundsFontFace, GroundsFontPreloadDescriptor, GroundsFontStylesOptions (types) | ., @wabbit/tome-theme-grounds/fonts | The descriptor shapes. |
| side effect | @wabbit/tome-theme-grounds/register | Registers groundsThemeManifest in tome-core's theme registry. |
| stylesheet | @wabbit/tome-theme-grounds/styles.css | Tokens and treatments. The file that does everything visual. |
| stylesheet | @wabbit/tome-theme-grounds/fonts.css | The @font-face rules. Optional. |
| font files | @wabbit/tome-theme-grounds/fonts/* | The woff2 files and their OFL licences, for self-hosting. |
import { groundsThemeManifest } from '@wabbit/tome-theme-grounds/manifest'
groundsThemeManifest.palettes.map((p) => p.label)
// ['Pennant', 'Trailhead', 'Lido', 'Marquee']Tokens
The theme sets Layer 1 (the names tome-ui's tokens.css reads: --background, --foreground, --card, --primary, --accent, --muted, --border, --input, --ring, the feedback, chart and muted2 names) and lets tome-ui's generated re-resolution derive the aliased Layer 2. It sets the Layer-2 names that have no Layer-1 input behind them:
--tome-color-accent-text, the feedback*-textweights, and--tome-color-surface-tint- the fixed-band inks (
--tome-color-surface-solid-darkand its family,--tome-color-surface-inverseand its family) - the four
--tome-type-*families, each paired with its--font-*slot
The colour roles Grounds adds are private --grounds-* tokens: the sign (-sign, -on-sign), the mark and the accent text (-mark, -accent-text), the ink, muted, rule and input, the band (-band, -on-band, -band-muted, -band-accent, -ring-on-band), the card and desk set (-card-ink, -card-muted, -card-line, -card-input, -card-tint, -desk-bg), the chip fill (-chip-bg), the footer zone (-footer-bg) and the plate edge (-plate-edge-w, -plate-edge).
Selector ladder (specificity, never load order):
| Selector | Specificity | Holds |
|---|---|---|
[data-tome-theme="grounds"] | 0,1,0 | Pennant light, type, radius, rhythm, lanes, motion |
[data-tome-theme="grounds"][data-theme="dark"] | 0,2,0 | Pennant dark |
[data-tome-theme="grounds"][data-tome-palette="p"] | 0,2,0 | palette light |
[data-tome-theme="grounds"][data-tome-palette="p"][data-theme="dark"] | 0,3,0 | palette dark |
The palette files are generated by scripts/generate-tokens.mjs from scripts/palette-roles.json, the output of the palette script (scripts/palettes.mjs --fix), and copied, never retyped.
Shape and rhythm. The key plate is 4px, media and plates 8px, the sign panel 20px and the booking desk 24px. Actions are pills and bands are square. Rules are 1px in the palette's rule colour. The prose measure is 600px. The page lanes are three marginalia columns each side and one prose-pad column, and the 54px gutter holds.
Type scale. The approved mockups were authored on a 16px root and tome-ui sets html { font-size: 18px }, so every rem value is converted (x 8/9) and the vw terms are kept.
Palettes
| Palette | Ground / surface / tint | Ink / muted | Sign (action, key plate, band) | Accent (mark) |
|---|---|---|---|---|
| Pennant (default) | #F3F4FB / #FCFCFF / #E9E9F5 | #101029 / #675B87 | indigo #332178 | coral #C34F51 |
| Trailhead | #F7F4EA / #FDFCF7 / #EFE8D8 | #171700 / #706142 | bronze #643E0D | trail-blaze blue #0D7CB6 |
| Lido | #EFF8F8 / #F9FDFE / #DDF0F0 | #000D14 / #2B7279 | aqua #36BABA, with a 1.5px ink edge | violet #7444B4 |
| Marquee | #FCF1EE / #FFFBFA / #F6E4E1 | #2C070D / #825555 | claret #5C0109 | moss #697C09 |
Each palette's text, sign and accent roles clear an OKLab distance of 0.05 from every palette shipped before it; grounds, surfaces and tints are reported for information only.
Contrast
All ratios are WCAG 2.x. Text must reach at least 4.5. Marks, field outlines, the focus ring and the plate boundary must reach at least 3. The test suite re-measures every pair in all eight palette modes from the shipped values, the band pairs included, and pins the step-0 table: Lido's muted text on its tint at 4.70 and Marquee's input outline on its tint at 3.08 are the tightest passes, and Lido's aqua sign at 2.19 against its ground is why Lido carries the plate edge.
Server / client posture
The package is pure CSS plus constants. It has no React components and no 'use client' files, so it is inert under React Server Components. It adds nothing to a client bundle beyond the stylesheets the consumer imports. @wabbit/tome-theme-grounds/register is a server-side import. The Today Board, the facilities island and the banner's dismissal are the blocks' own islands, not this package's.
Tests
pnpm --filter @wabbit/tome-theme-grounds testThe vitest suites cover:
- the theme conformance check in theme mode (Layer-1 surface,
*-textliterals, radius and font slots, the full dark redeclaration, palette coverage for all four palettes in both modes, scoping, no module class names, font pairing) and in platform mode - manifest validation, its agreement with
package.json(the version is read from the newest CHANGELOG heading, or 0.0.0 before the first release), registration, and the pending-catalog tripwire for blocks whose pack has not yet registered them - every palette defining the full required set in both modes, every value agreeing with the palette script's output, the sign model, the plate edge present exactly where the sign is under 3:1
- a contrast test that re-measures every text pair at 4.5 and every mark or boundary at 3 in all eight modes and pins the step-0 table
- the A4.1 font pairing, the weight tokens, every rule setting both its family and its weight, the self-hosted faces with their licences,
tnum,pnumand the axes read out of the woff2 files,tnumacross the weight range for both faces (needs Python with fontTools; setGROUNDS_FONT_PYTHONto run it), and the subset range - hook coverage: every hook in the frozen contract is classified as already emitted, pending a sibling branch, or not drawn, and the hooks a later wave styles are not styled early
- the measure: every running-text hook resolves to 600px and nothing widens it
- no colour literal outside
src/tokens/, no comment that swallows a rule, no class selector, no hand-coloured shadow, no scrim or overlay on a photograph, the shape tokens, and every treatment rule scoped to the theme - the reveal switch and timing, the page lanes, the motion tokens and the reduced-motion path
License
Commercial, see LICENSE.md. Published to the private registry at https://npm.wabbit.com/.
Exports
| Import path |
|---|
@wabbit/tome-theme-grounds |
@wabbit/tome-theme-grounds/manifest |
@wabbit/tome-theme-grounds/register |
@wabbit/tome-theme-grounds/fonts |
@wabbit/tome-theme-grounds/styles.css |
@wabbit/tome-theme-grounds/fonts.css |
@wabbit/tome-theme-grounds/fonts/* |
Changelog
0.1.xMinor
First release of Grounds, a Tome theme for places people visit: parks, sports grounds, venues, market halls and districts.
Grounds puts the visitor first: what is on today, where it is on the grounds, and how to get there, then how to book. Four palettes, each light and dark: Pennant (indigo sign, coral flag, the default), Trailhead (bronze and blaze blue), Lido (aqua and violet) and Marquee (claret and moss).
Type is Overpass for headings, with figures that line up for times and scores, and Figtree for reading; both are self-hosted.
It styles the Today Board (live, starting and finished events, said in words as well as colour), the facilities guide with its illustrated site plan and the phone plan sheet, the dismissible alert, the venue hero with up to four visitor doors and a photo credit, the Upcoming lead event, programme cards with plan links, the tenant directory and promotions rail, the booking desk (including its errors when a visitor posts without JavaScript), the numbers, voices, questions and footer bands, and the phone bar with Directions and Book.
3 fixes (0.1.1 – 0.1.2)
- 0.1.2
The event page's locator shows its "See Field 4 on the full plan" link when the link goes to the full plan on another page.
The locator card hid "Show on plan" outright, because it used to point at the card's own marker. It now hides only a link to an in-page marker, and a link to the full plan elsewhere (local-facilities'
showOnPlanHrefTemplate) shows as the card's last outlined action, as the event page design draws it. - 0.1.2
The README's "What is in this release" now describes what 0.1.1 ships.
It said the block treatments would come "in the next wave", though 0.1.0 shipped them. It now lists the four palettes, the 15 styled blocks, the companion packs the demos are built from, and how the Today Board treats a closure once it ends.
- 0.1.1
The theme's manifest lists the blocks it restyles.