Developer Reference

Fernlight — Developer & Theme Reference

Fernlight is a calm, editorial full-site-editing (FSE) block theme for writers and slow-living blogs. It ships a curated palette, a Cormorant Garamond / DM Sans type pairing, a consistent spacing scale, 7 style variations, and 59 inserter-enabled block patterns — plus an AI-native, machine-readable surface. This is the technical reference for the theme and its companion plugin.

Requirements

  • WordPress 6.7 or newer (the native Abilities API surface activates on 6.9+)
  • PHP 8.0 or newer
  • A block-theme-capable (FSE) environment. No page builder required.

At a glance

  • Type: Block theme (theme.json v3 with a documented design-intent contract), full site editing.
  • Patterns: 59 inserter-enabled + 8 template-only helper patterns (67 pattern files).
  • Style variations: 7 (Sage default, plus Warm Sand, Clay, Sky, Dusk, Ink, and Dark).
  • Block styles: 14 brand styles across button, navigation, details, separator, paragraph, and heading.
  • Companion plugin: fernlight-companion 1.2.26 — 8 optional editorial blocks plus the REST/Abilities surface. The theme is fully functional without it.
  • Front-end JS: 0 KB from the theme. CSS is split into conditional layers (always-loaded base under 10 KB).
  • Dark mode: automatic (system prefers-color-scheme, off by default, toggle in Settings) plus a selectable Dark style variation.
  • i18n: translation-ready (POT included), full RTL stylesheet, Polylang/WPML compatible.
  • AI/MCP-ready: a design-intent contract, the native WordPress Abilities API, and five public read-only REST endpoints.

Design tokens (theme.json)

Color — semantic roles

Fernlight uses role-named color slugs (not hue names), so every style variation re-skins the theme by swapping the same eight roles. Default (Sage-adjacent base) values:

SlugDefaultRole
contrast#2C4A5APrimary text / strong foreground
muted#4A7589Secondary text, meta, eyebrows
accent#C8D8B0Accent / highlight
surface#F4F7FARaised surface (cards, bands)
surface-2#DDE8EFSecondary surface
on-invert#FFFFFFText on inverted backgrounds
base#FFFFFFPage background
invert#2C4A5AInverted background (dark blocks)

Patterns reference these roles only (e.g. backgroundColor:"surface", textColor:"muted"), never raw hex — which is what makes a one-file variation swap re-skin the whole library.

Semantic tokens & spacing roles

Beyond the raw palette, theme.json documents semantic intent under settings.custom.designIntent — consumed by the /tokens and /type endpoints:

  • Text roles: primary, secondary, muted, invert.
  • Surface roles: page, card, section, subtle, invert.
  • Border roles: subtle, strong.
  • Spacing roles: contentRhythm (s/1rem), clusterGap (m/1.5rem), cardPadding (l/2rem), sectionPadding (2xl/5rem), gutter (--gutter/5vw), inset (xl/3rem).

Typography

  • Families: cormorant (Cormorant Garamond — display/headings), dm-sans (DM Sans — body and chrome). 8 self-hosted WOFF2 faces; the 500 weight of each is preloaded.
  • Font sizes (fluid clamp()): small 0.875rem · body 1rem · medium 1.125rem · large 1.5rem · h3 1.5rem · h2 2rem · h1 3rem.
  • Measures & rhythm: reading measure 42rem, editorial measure 52rem; body leading 1.65, prose leading 1.8, display leading 1.06; baseline unit 0.75rem.

Spacing scale & layout

Spacing: 2xs 0.25 · xs 0.5 · s 1 · m 1.5 · l 2 · xl 3 · 2xl 5 rem (reference as var:preset|spacing|m). Layout: contentSize 720px (reading measure) · wideSize 1140px.

Block styles

Registered on init in inc/block-styles.php (14 total):

BlockStyles
core/buttonfern-primary (default), fern-outline-light, fern-outline-dark, fern-ghost
core/navigationfern-mega
core/detailsfern-accordion
core/separatorfern-sage, fern-pale
core/paragraphfern-lede, fern-deck, fern-kicker, fern-baseline
core/headingfern-display, fern-compact

Pattern catalog

Patterns auto-register from patterns/*.php via header comments. Four Fernlight categories are registered in inc/block-patterns.php: fernlight-editorial, fernlight-page-sections, fernlight-post-parts, and fernlight-archive. 59 patterns are inserter-enabled; the 8 Inserter: no template-* patterns are wired into block templates (404 text, search form, no-results messages). Full-page patterns (page-about, page-now, page-resources, page-work-with-me, page-contact, page-essay, wow-page-start-here) use templateLock:"contentOnly" so editors replace copy without breaking the layout.

Companion blocks

fernlight-companion (separate, optional install) adds eight server-rendered editorial blocks: post-hero, pull-quote, post-callout, divider, related-grid, newsletter (provider-neutral sign-up), icon (12 inline SVGs), and tabs (ARIA tabbed panels; the only block with a front-end script). It also provides the archive layout switcher, load-more / instant search, per-category accents, reading enhancements, and the REST/Abilities surface below. The theme never hard-depends on the plugin.

AI-native surface

REST endpoints

Provided by Fernlight Companion in the fernlight/v1 namespace. All five are public and read-only.

EndpointReturns
/wp-json/fernlight/v1/capabilitiesMaster discovery: versions, all fernlight/* blocks & patterns, the endpoint map, and the abilities descriptor.
/wp-json/fernlight/v1/patternsRegistered patterns, filterable by intent, purpose, limit (1–25).
/wp-json/fernlight/v1/tokensLive palette, semantic-token CSS variables, and the semanticTokens intent.
/wp-json/fernlight/v1/typeFont families, sizes, spacing, layout, and the full typographySystem block.
/wp-json/fernlight/v1/perfVersions, WP/PHP requirement booleans, CSS KB, js_front_kb: 0, font inventory, dark-mode flag.

Abilities API (WordPress 6.9+)

Companion registers a fernlight-content ability category and three read-only abilities — they suggest, they never change content:

  • fernlight/list-patterns (public) — patterns filtered by natural-language intent/purpose/limit, ranked by keyword match.
  • fernlight/compose-page (requires edit_posts) — a deterministic page recipe (title, ordered pattern_slugs, <!-- wp:pattern --> reference markup, notes) for page_type home / about / resources / start-here / essay-index / newsletter / landing. Does not create content.
  • fernlight/get-performance-report (public) — same payload as /perf.

Hooks & filters

  • do_action( 'fernlight_getting_started_after_links' ) — inject links into the wizard’s Build tab (used by Companion).
  • apply_filters( 'fernlight_pillar_slug_class_map', $map, $categories ) — override the category-slug → accent-class map.
  • apply_filters( 'fernlight_blog_grid_categories', $pillars ) / fernlight_blog_grid_base_url / fernlight_posts_index_url — customize the

    No posts found for this filter yet. Show all posts.

    shortcode.

CSS architecture

Fernlight loads no front-end JavaScript and splits its CSS into conditional layers, enqueued from functions.php and version-busted with FERNLIGHT_VERSION:

  • Always: post-styles.min.css (base, under ~10 KB), view-transitions.min.css, and print.min.css (media="print").
  • Conditional: components, buttons, typography, newsletter (loaded when matching classes/blocks appear in content); single (is_single()); archive (home/archive/search); mega-menu (header uses is-style-fern-mega); dark-mode (only when auto dark mode is not disabled); woocommerce (only when WooCommerce is active).
  • The same files (minus print) register as editor styles via add_editor_style() plus editor.css.
  • Minified .min.css files are the production artifacts (built with lightningcss).

Performance & accessibility

0 KB front-end JS, self-hosted fonts (the 500 weight of each preloaded with fetchpriority="high"), and a ~191 KB critical path. Lighthouse on real content, with the Companion active: 100 / 100 / 100 / 100 on mobile and desktop. WCAG 2.2 AA contrast across every variation; a core skip link to #fern-main; strengthened :focus-visible states; single non-duplicated banner/contentinfo landmarks; reduced-motion-aware View Transitions; a reading-first print stylesheet.

Build & tooling

npm run build:css     Minify CSS layers (lightningcss)
npm run lint          composer lint (WPCS) + stylelint
npm run i18n          regenerate the .pot translation template
npm run package       build installable dist zips (bin/build-zip.sh)

CI runs PHP syntax + WPCS, stylelint, JS/JSON checks, and the WordPress.org theme-review action, then uploads the packaged zips. The complete version-by-version build history is kept in an internal build log. All user-facing strings use the fernlight text domain.