patterns.gf.cx · the pattern library

The gf.cx specimen book — named moves that raise the floor

Named moves for problems that keep coming back

43 patterns since May 2026 Craft 19 · Operations 14 · Foundation 10

New here? Start with Why patterns — the frontispiece essay tracing the idea from Alexander (1977) through the Gang of Four (1994) to directing AI agents.

01 Craft 19

Primitives and presentation that have to travel between pages without falling out of sync.

UX primitives· 12

affordances drifting out of sync

  • The way back up, only when the page earns it

    A ↑ top affordance that appears only when a page earns it — one shared script, runtime scroll-height gate (scrollHeight ≥ max(1400px, 2.2×innerHeight)), injected once, works everywhere. Singleton-guarded, no-op if a hand-wired a.backtop exists. Two vectors: sweep for hand-authored pages, generator wiring for generated surfaces.

  • Context that lives in the field it qualifies

    Small inline pills embedded mid-row that tag a data point with its origin — country, UA, or source — without a drill-down. The qualifier sits in the field with the field it qualifies.

  • One badge, two ways to mean state

    A small mono uppercase pill that signals a record's state. Two flavours from one primitive: a fixed lifecycle vocabulary (neutral / alert / resolved / service / warning), and an urgency gradient where the band is computed from time-to-deadline — one pill walks green → amber → red as a due date nears, then flips to red OVERDUE N. The urgency flavour is emitted by the maintenance-timer, with a weeks-days data-tip countdown.

  • A tooltip you can reach into

    The CSS-only data-tip tooltip is text-only — no HTML, no links, no interactive elements. data-tip-href upgrades a glossary term into a JS-powered card with a clickable "Learn more" link, held open by a 120ms delay so the cursor can travel from trigger to card. Its placement reads the room — above by default, flipping below when a trigger sits too high.

  • A picker that finds it as you type

    A <select> can't search and a long static list stops scaling past ~15 options — and hand-rolling a combobox per surface (keyboard, focus/blur races, aria, click-outside) is exactly the drift the shelf kills. The type-ahead picker turns a labelled list into a searchable combobox where the value rides the label and member names are search aliases: type 'iberia' and land on Avios, 'klm' on Flying Blue, 'AA' on AAdvantage. One behaviour, one shelf source, mounted with a markup skeleton plus one Typeahead.mount() call.

  • Define the jargon where it's read

    A CSS [data-tip] primitive and server-side annotator that wraps jargon terms in themed hover definitions — FCP, LCP, CrUX — inside reports and dashboards. No JS required for the base pattern; one stylesheet import.

  • Placing a facility on the map, in three beats

    The 'good-map' pattern for placing a facility in a location dossier: a three-beat sequence — aerial → close-up hover → street-view. Two duality axes: (A) for maps, reverse the hover so it starts on the close-up and zooms OUT to the wider context; (B) street-view either deferred (.svfacade, click-to-load) or always-on (.embed3d). An optional fourth beat dreams the Street-View still into a Studio-Ghibli twin on hover (image-to-image via fal.ai FLUX Kontext). One CDN css+js, themed off local vars. Lifted from srvc.gf.cx/transit.

  • A quiet heartbeat in a row of icons

    A staggered wink applied to a row of sibling icons: each glyph pulses in sequence via nth-child animation-delay, turning static decoration into a quiet surface heartbeat.

  • A closer look, one click away

    A thumbnail that earns a click opens one shared enlargement modal (lightbox) — image or inline <svg> — with caption, closable by ×/backdrop/Escape. The overlay DOM injects itself on demand; mark any element data-modal and it's keyboard-native. One CDN-hosted css+js, themed off local vars. The favicon-control-plane model applied to media enlargement; lifted from the bespoke modal on srvc.gf.cx/transit.

  • When the window is open, across time zones

    A solid-green gate-hero carrying an action window paired with a UTC-anchored multi-row timeline, live now-tick, and clickable zone overlays. Flips to a shared charcoal field when the window is closed.

  • See how deep the safety net goes

    Turn a bare backup count into a native <details> accordion + HTML dot-timeline — one dot per point-in-time copy, placed by true date, each with a data-tip hover readout ('3 days ago · 3rd August 2026'). A count says 'backed up'; the timeline shows how deep the safety net goes and when it got regular.

  • Words that follow the video, line by line

    A vendor-hosted HLS video player with word-by-word karaoke captions, a CC toggle, and a click-to-seek transcript — synced to true player position over the Player.js postMessage protocol, with a self-demoting wall-clock fallback for environments where the protocol can't connect.

Editorial & presentation· 7

voice & format drift

  • A thesis and a handful of moves

    Compose how-to and advice articles as a thesis plus 3–4 imperative micro-moves — each subhead is independently skimmable, the set rolls up into a single takeaway. The structure that lowers the bar to write and raises the value for the reader.

  • Say it in the margin, not the sentence

    Superscript markers link to a numbered list at page foot — collapsed rows show one keyword each, opened bodies lead with the full title. Two type signatures (red italic + bold) carry distinct emphasis weights through the annotation.

  • Show your work

    A figure baked into a page — a restated price, a depreciation %, a score — is opaque: the reader can't see how it was derived or check it. The how-we-calculate pattern gives the calculation its own page (formula, exact inputs, worked arithmetic, why the inputs are frozen) and links the figure to it via the interactive tooltip's 'Learn more ↗'.

  • The plate that outgrows its column

    One block on a page — a chart, a table, a map — needs to be wider than the prose around it. Publish the container's side padding as a --page-pad custom property and let the child cancel it, instead of hard-coding a negative margin that silently desyncs the day the padding changes. Print, which zeroes the padding, collapses the bleed for free.

  • A masthead that doesn't fight the report

    The dare.co.uk report masthead drifted into an oversized italic serif h1 that fought a solid, sans-bodied report. Three live header specimens on the shared page-header primitive — sans, upright serif, canonical italic — to compare and graduate. Specimen B shipped corpus-wide; page-header v0.2.0 gained the title voice + colour-chip variants.

  • A visual language for pitch decks

    A dark-mode pitch-deck visual language — ten design tokens from near-black field to icy-blue accent, three-tier typography, five-move narrative architecture, and six reusable slide layouts. Extracted from the YouExec Hardware Innovation deck; travels wherever investor credibility is the load-bearing requirement.

  • The ledger: folded by default, open on demand

    A telemetry or records page that opens as a summary — the load-bearing status stays pinned up top, every section is a collapsed-by-default disclosure fold with a left bird-beak marker, an expand-all control sits under the strip, and the build-provenance stamp folds into the Built-with footer. Two shelf primitives, ledger.css and ledger.js, so no surface hand-rolls its own accordions.

02 Operations 14

Proving a thing works and shipping it — without trusting a job that quietly stopped.

Ops & verification· 7

stale-green, unproven paths

  • Decode the jump

    An aggregate metric — bytes stored, object count, index size — jumps, and the sparkline shows THAT it moved but not WHAT changed. The decode-the-jump pattern periodically captures a content fingerprint (a by-group manifest: count, total bytes, average size per file type), keeps a short manifest history, and diffs the two most recent captures to itemize the delta — the before/after answer to the mystery. The cheap aggregate metric is itself the trigger: a bucket is re-fingerprinted only on the runs where it actually moved.

  • Keep the probes out of the reader's numbers

    Every gf.cx surface ships diagnostic probe endpoints — /ip, /cf, /trace — stamped in by the scaffold. The quarantine panel filters them out of reader analytics and surfaces them in a compact, collapsible instrument: status dots, measured request counts, country-of-origin chips, and scanner-UA classification, worst verdict pinned to top.

  • Flag an agent to investigate

    A failing or at-risk item on any surface should be one click away from a durable, trackable investigation. One shared script, one central endpoint, a data-flag-* contract — drop a flag anchor anywhere and it files a dedupe-aware GitHub issue plus a push, no per-surface wiring.

  • Turn a cold RED into a dispatched investigation

    On a status board, a failing asset's detail page carries a collapsible panel that surfaces the attributed failure point — which audit flagged it, the signature, the restore verdict — and hands the operator a copy-ready, asset-scoped agent brief to paste into an AI coding agent. Native <details> reveal, zero JS; shown only where there's something to fix.

  • Where the stack stands, at a glance

    An R/Y/G collapsible status block that turns an operator README into a live session-log — colored-dot tier headers, count summaries per panel, done items kept with dates, and a how-to-fix sub-line per open item.

  • Prove the round-trip before it touches production

    Every vendor integration gets a self-contained sandbox surface first — sandbox credential, full round-trip, proved end-to-end. Only then does the production credential wire in. Keeps secrets isolated, experimental wiring contained, and the integration's edge-cases out of the live order path.

  • “Looks good from here” isn't verified

    "Looks good from here" is not deploy verification. An independent witness on a third-party network answers two questions in one shot: does it resolve from outside, and does the rendered page look right?

Cloudflare & deploy mechanics· 3

the same edge, the hard way

  • Go live by editing one line

    Export one BASE_URL constant from one shared module. Binding day = one-line edit + redeploy. Prevents the hand-find-replace that always misses at least one hardcoded preview URL.

  • Let one subdomain use its own CA

    A gf.cx subdomain fronted by a non-Cloudflare CA (AWS ACM → Amplify, CloudFront, ELB) can't get a cert: the apex serves Cloudflare's auto-managed CAA set, and CAA resolution walks UP to it for any subdomain lacking its own CAA — so a CA that isn't on that list is refused. The fix: give the subdomain its OWN CAA record permitting the CA. Resolution stops at the first name that has CAA records, so the walk never reaches the apex — zero blast radius on the rest of the zone.

  • When the Worker never runs on a navigation

    A Cloudflare Pages project with a _worker.ts + assets binding looks like it should serve dynamic routes from the Worker and static files from the asset layer. In practice, browser navigations…

Routing & URL design· 3

where a thing lives, moving

  • Keep the taxonomy, add a memorable door

    Keep the taxonomy, add a memorable door. A short vanity alias 301-redirects to the deep canonical path — so crawlers and sitemaps get the structured URL while humans get the one they actually remember.

  • A short tag and a readable one, both first-class

    QR-encoded asset tags need to be dense (a phone camera reads /1042 faster than /sennheiser-hd-560s-headphones) and re-assignable. Both forms are first-class peers in the Worker — neither redirects to the other. Canonicalisation happens at render-time, not routing-time.

Storage & data movement· 1

bytes moving through a distant sink

  • Round-trips, not bytes

    A remote object store fronted across an ocean (OneDrive's Singapore geo, pulled from NJ) costs per-request round-trips, not bytes: large files stream near line-rate but a long tail of tiny files collapses to ~100 KiB/s at ~135 ms RTT. Three moves fall out — store packed blobs not loose trees; hold concurrency low (more parallelism trips the per-drive 429 throttle); and for a big pull do the file-work on a VM in the store's own region, then ship one packed blob home. The cost is round-trips, so kill the round-trips.

03 Foundation 10

The floor every surface stands on — the baseline that holds the portfolio against drift.

Scaffolding & baseline· 6

surfaces shipping under-finished

  • A new surface that ships finished, not minimal

    One script encodes the current state of what a fresh gf.cx subdomain looks like: Pages project, custom-domain binding, five-layer UX baseline, CF Access, diagnostic probes, and og:image capture — all injected at scaffold time so every surface ships finished, not minimal.

  • Reconcile onto the template

    A surface built before the canonical page template drifts — wrong fonts, bespoke header CSS diverging page by page. The fix isn't to rebuild each page by hand; it's to retrieve the existing pattern (the template) and re-home the page's content onto it, preserved byte-for-byte. Reconciliation is retrieval, not reconstruction.

  • Edit the generator, not its output

    A page regenerated from data overwrites anything you hand-add to it — the tempting one-off paste into the rendered HTML is gone by the next build. Durable content lives in the generator: emit the section from the renderer that owns the page, gated to the one surface it belongs to (grep the siblings to prove containment), and rebuild it as native shelf markup rather than a screenshot. The render is the source of truth; edit the press, not the print.

  • A social card that admits the page is a stub

    A neutral, brand-aligned social-card image for pages whose content is known to be incomplete — archive stubs, pending-recovery placeholders. Sits in og:image so social shares stay coherent without faking an article hero.

  • Three pages that happened to agree

    A repeated page type — three vehicle pages, six dashboards, every product page — has a structure, but it lives only in the files themselves, kept in sync by hand. Publish it as a spec the generators read and an audit can fail on, and the copies stop drifting apart in ways only a human reading all of them could catch.

Meta· 4

keeping the library honest

  • Why patterns · a named move for a recurring problem

    The library's frontispiece essay — what a design pattern is, traced from Christopher Alexander (1977) through the Gang of Four (1994) to directing AI agents (2026), and how the gf.cx library frames its own operating patterns against that lineage. A named move can be catalogued, searched, cited, taught — and requested precisely; the same skeleton (context, problem, forces, solution, consequences) survives the jump from code structure to shipping surfaces.

  • Show the pattern, don't just describe it

    The primitive every pattern entry on patterns.gf.cx uses to show rather than tell — a sandboxed live demo beside tabbed HTML/CSS/JS source, authored as <template data-tab> fragments inside one <div class="pattern-preview">.

  • Proof the patterns travel: a surface built from them

    brand.gf.cx assembled in one session from the portfolio patterns — gfcx_subdomain_new.py scaffold, five-layer surface baseline, site.config.json, smart-404, social card, and a first piece of content ingested and footed with the built-with primitive. The clearest proof these patterns travel.

  • The map the library draws of itself

    A human sitemap page — a dare.co.uk/sitemap-style 3-column ledger — whose structure AND per-family counts are GENERATED from the corpus's own meta.json files via a fail-loud taxonomy validator. Every pattern slug must be mapped into exactly one family; the generator refuses to emit until a newly-shipped pattern is categorised. So the map can never silently drift from the library: single-source, anti-drift, self-referential (this pattern counts itself into Foundation > Meta).