Skip to content

Add design tokens - #255

Open
amjadr360 wants to merge 48 commits into
mainfrom
add-design-tokens
Open

Add design tokens#255
amjadr360 wants to merge 48 commits into
mainfrom
add-design-tokens

Conversation

@amjadr360

Copy link
Copy Markdown
Contributor

WIP

amjadr360 added 14 commits July 22, 2026 03:55
…reset families

Semantic color roles (text-strong/weak/brand, background-base) join the
palette as aliases of each variation's own foreground/background/primary,
so every style variation — dark included — re-inks them from its own
colors. Role swatches are hidden from the picker (label-based editor CSS,
same mechanism as the existing block-style hiding). Adds the generated
block-preset families, colors, and typography variations.
…our variations

The token layer stops adding its own semantic swatches to settings.color.palette —
the palette returns to exactly the six stock slugs (background, foreground,
foreground-alt, primary, secondary, tertiary), so the editor colour picker shows those
six with no duplicates and the editor-CSS that hid the extra swatches is removed
(nothing left to hide). The semantic tokens stay in settings.custom.color as aliases of
the stock palette (text-strong→foreground, background-base→background, a fg/bg mix for
the weak inks, stroke/fill mixes), so patterns that reference them inline still re-ink
from whichever style variation is active, light or dark.

Adds four referential colour variations whose stock slugs point at each variation's own
concrete semantic customs (foreground=var(--…--text-strong), background=
var(--…--background-base), foreground-alt=var(--…--text-weak),
tertiary=var(--…--background-sunken); primary/secondary concrete) — one value per
variation drives both the named swatch and any inline custom-var, with the customs
concrete in the same file so resolution never cycles.
Adds settings.custom.space-snug (8px), space-cozy (24px), and
space-block (56px), each riding the existing space-scale density
knob. The theme keeps all 7 spacingSizes as-is (8 would hit the
editor slider's RANGE_CONTROL_MAX_SIZE ceiling); these three fill
gaps the fluid presets can't hit exactly on desktop.
Reverses the heading-1..6/regular/tiny/eyebrow additions from "Add design
tokens" — patterns now speak only the theme's own five font-size slugs
(small/medium/large/x-large/xx-large), same reasoning as the palette
reversal: fewer moving parts in the picker, nothing for a future upstream
merge to reconcile.
Ports Lattice's linen -> Heath repaint into the live theme: warm-cream
paper/wash, sage/sand/mauve/charcoal 4-slab card cycle, ink action
color, Inter display type (tracking -0.01em, line 1.1), airy density.

Files: styles/block-presets/group/linen-1/** (footer-1, header-1,
item-card-1 align-center/align-start, section, template),
styles/block-presets/media-text/linen-1/card-1, styles/colors/linen-
palette.json, styles/globals/linen-globals.json, styles/typography/
linen-typography.json.
…linen-1

Only three variation families are wanted on this install, so the rest of the
previously-ported set is removed and the port now ships a marked subset
instead of everything it can generate.

Removed: 11 vibe families' block presets (77 directories, 231 preset files)
plus the identity partials no remaining family references — 17 colors, 17
typography and 9 globals. Also drops the legacy butterscotch.json, whose
replacement (retro-palette.json) has been in place since the identity
filenames were unprefixed.

Nothing native is touched. The removal matches only the -palette.json /
-typography.json / -globals.json naming convention crossed with the
generator's own roster, so styles/colors/lilac.json (this theme's) survives
while lilac-palette.json (generated) goes; all 40 stock palettes, all 18
stock type variations, the seven stock variation families, ext-section-dark,
the ext-* button styles and every pattern remain.

The 21 modified files are a routine catch-up: the checkout had not been
re-synced since Jul 29, so retro-1's presets, the natural-1 icon baselines,
retro's three identity partials and theme.json are brought up to date with
the generated sources.
Per-vibe GLOBAL theme.json settings (settings.layout, settings.custom scale
knobs, and the element typography a vibe's heading scale produces) now live in
inc/ext-vibe-globals.json, keyed by full vibe slug.

Deliberately not under styles/: WordPress auto-reads that tree as selectable
style variations, so these payloads were surfacing in the Site Editor's style
browser -- and because a payload of only styles.elements matches the
elements+typography filter exactly, one was being offered as a font named "Retro
Globals". Outside styles/ the file is inert to WP and nothing can surface it by
accident.

inc/ext-vibe-globals.php registers GET /extendable/v1/vibe-globals (whole
manifest, or one payload via ?vibe=<slug>, 404 on an unknown slug). Server-side
callers can read the file directly; the route exists for browser clients, which
cannot. Read is public because the JSON is already world-readable as a static
file at a known path, so a nonce would add no privacy while making it unreachable
to the clients that need it.

functions.php gains one require_once, matching how inc/animations.php is loaded.
The manifest is served by a public REST route, so a build-script path in the
response is internal detail no consumer can use. The reason the file sits outside
styles/ is documented in inc/ext-vibe-globals.php instead.
… style sets

The read endpoint landed before the data it serves. inc/ext-vibe-globals.json
now carries linen-1 and retro-1 in the shape the SDK's globals layer expects —
settings for the layout and font-size scale a vibe pins, styles.elements for the
heading sizes that bind to them.

styles/globals/{linen,retro}-globals.json go. WordPress auto-reads styles/ as
selectable variations, so those two surfaced in the SDK's font picker as "Retro
Globals" and "Linen Globals" — style variations a user could pick that were never
meant to be pickable. The same data now lives under inc/, outside the tree
WordPress scans, behind a route that hands it to the one consumer that wants it.

styles/typography/fraunces-dm-sans.json goes too: a Fraunces + DM Sans pairing
no shipping vibe wears. Retro pairs Fraunces with Heebo and has its own
retro-typography.json, so this one was only ever picker clutter.

The preset churn is the generator's, regenerated from the current vibe sources.
Regenerated from the vibe source. retro-1 gains settings.typography.fontSizes —
the expressive set, small 1.125rem through xx-large 5.25rem, fluid from large up
— and its styles.elements h1/h2 stop carrying hand-computed clamps and reference
the presets instead.

Only the manifest moves. A type scale is a globals concern, so no block preset
changes with it.
Regenerated. retro-1 gains settings.layout, matching linen — the measure its
expressive scale and card grid were composed against, rather than the theme's
narrower 42rem/80rem default.
Regenerated. The SDK filters the theme's colour variations by slug against an
allowlist when the active theme is extendable, so a partial without one is
dropped before it can be offered. Both now carry the slug the allowlist names.
Generated from Lattice, same as linen-1 and retro-1. 21 block presets, the
Playdate colour partial (cream #FDF1E7 paper, navy #1B3A8C ink, orange #F26A2E
accent, peach wash) and modern-saas-typography, the voice it uses.

Two things in it that no shipping vibe carried before:

A scalloped band edge, on the same masked full-bleed strip wave-1 uses.

And DECORATIVE OBJECTS in the band background — a new axis. Layered data-URI SVG
shapes in currentColor, positioned into the band's own top and bottom padding. The
padding is deliberate: a section's inset is empty by construction, so a shape never
lands under text and the contrast audit's opacity cap for washes does not apply.
Painted as background-images on the band rather than a pseudo-element, because the
divider already owns both of those — a vibe can wear a scalloped edge AND objects,
and Playdate wears both.

Verified on a real render: round 32px cards, 9999px pill buttons, the object layer
and the scallop mask all present.
The scalloped edge and the background objects both qualified on
`.has-background-base-background-color`, which no element wears. `background-base`
is a custom token name; the class WordPress emits comes from the palette slug,
`background`. So the selector matched nothing and neither decoration rendered.

The divider bug predates Playdate — haven-1 was the only vibe asking for a
scallop and haven-1 is not ported, so nothing rendered it and nothing noticed.

Regenerated. Playdate's section preset now carries both against the class the
band actually wears.
The objects were background-images whose SVG carried fill="currentColor", which
cannot work — an SVG loaded as an image is a separate document with no cascade to
inherit from. They rendered unpainted.

Masks now: the SVG gives the shape, background-color gives the ink, taken from the
palette's `primary`. Objects take ::before and the scalloped divider keeps its
bottom edge, since a band has two pseudo-elements and both decorations need one.

Regenerated from Lattice.
The divider strip inherits its band's colour and sits outside the band, so it only
reads where the band differs from what it overlays. The rule qualified on the paper
band over a paper page — cream on cream, invisible. wave-1 qualifies on
.has-tertiary-background-color for exactly this reason.

Emitted for both band classes now, and Playdate gains bandCycle 2 so every other
band is peach #FBDCC4 against #FDF1E7 paper — the reference puts its scalloped edge
on the peach footer band, not a cream one.

Regenerated from Lattice.
…roll

Three arrangements per object set, rotated by :nth-of-type(3n + k) so consecutive
bands do not repeat the same shapes in the same corners. The pseudo-element now
sits behind the band's content (children lifted to z-index 1 rather than the
pseudo going negative, which would hide it behind the band's own background), and
inks from `tertiary` instead of `primary` — decoration should not pull the eye off
the copy.

theme.json gains the @Keyframes the drift needs: a block-style variation cannot
declare an at-rule, so ext-object-drift lives in the global css, with a
prefers-reduced-motion override that flattens it. The preset references it by name
and fails soft — an unknown animation-name is ignored and the shape stays still.

Presets regenerated from Lattice.
Writing theme.json back through a JSON serializer reformatted every compact
array ("postTypes": ["page", "post"] onto four lines), so a two-at-rule
addition arrived as 123 insertions and 36 deletions of pure noise in a shared
file. Re-applied as a string edit to the styles.css value alone: one line
changed, formatting untouched, render unaffected.
Objects occupy ::before only on the paper band, but the divider was suppressing
::before on both band classes — so a tinted band gave up its top scallop to
nothing, leaving a hard flat join wherever a tinted band followed a paper one. The
yield is now conditional on the class that actually uses the pseudo-element.

Regenerated from Lattice.
Objects ride the paper band, so they landed on the very first band of a page —
directly under the header, where a floating shape reads as a mistake rather than
decoration. Skipped with :not(:first-child), which is the restraint wave-1 gets for
free by only ever decorating a tinted band.

Regenerated from Lattice.
A band gets tinted two ways. templates-resource-server's inversePattern trades
has-background-background-color for has-tertiary-background-color, which is what a
two-ground cycle gets. From the third ground on there is no stock slug left, so a
band is stamped ext-tint-k with a structured token fill and the slug class is
deleted — so a tertiary-only rule would leave every 3/4-ground vibe with flat
joins.

All four carriers now take both scalloped edges. The paper band still yields its top
edge to the background objects.

Regenerated from Lattice.
margin-block was on every band, but a paper band's strip is its own colour over a
paper page and can never be seen — so the margin opened a dead gap below every paper
band. Strips and margin now go only on a tinted band; the paper band keeps position
and the horizontal clip for the objects layer.

Regenerated from Lattice.
wash and cards[0] were both #FBDCC4, so a card on a wash band vanished into it.
First card is a deeper peach (#F8C9A9) and the third swaps pale pink for pale
periwinkle (#DCE4F7), which also gives the ladder a cool rung — the reference has
blue objects and the palette had nothing cool in it.

Contrast re-run and a11y clean on all three. Regenerated from Lattice.
accent becomes the navy ink, so chips and derived tint accents build off the brand
rather than a second hue. Card 1 moves to #FAD3B7 — lighter than before, still a
clear step darker than the #FBDCC4 wash.

Contrast re-run and a11y clean. Regenerated from Lattice.
All three card grounds now sit at OKLCH L 0.885 / C 0.055 with hue alone
distinguishing them (peach 55, blush 10, periwinkle 262). Previously lightness
and chroma both drifted: one card was darkest and most saturated, another sat
lighter than the wash beneath it.

Navy ink contrast spread across the three falls from 1.54 to 0.15.
- the card's mark centers (a block-level box needs inline margins; text-align
  cannot move it), and social icons get the flex axis they actually answer to
- the icon-ROW card stays start-aligned — its mark sits beside a copy column
- the icon-row's mark slot no longer shrinks (flex-shrink:0; WP's child-layout
  support exposes flex-basis and flex-grow, never flex-shrink)
- a quote card's attribution stays start-aligned

playdate-1 also takes its own typography partial with a serif display (Source
Serif Pro over Manrope), replacing the borrowed modern-saas pairing.
icon-row, icon-corner, media-left and media-right keep their default alignment
under a centering vibe — a centered copy column beside a mark reads as a mistake.
Emitted as exclusions, so an exempt body carries no text-align declaration and
still inherits.

Also moves the mark-centering rule onto the band preset: the centered item-card
preset is referenced by no pattern, so a rule placed there never fired.
The structured blocks style centered .wp-block-heading and p directly, so it beat
any container-level exclusion and centered the icon-row card too. Alignment is now
raw css on the item-card preset, where the variant class is the element itself:
icon-row, icon-corner, media-left and media-right carry no text-align at all.
Opts out of the content-aware corner squaring: every position keeps 32px rather than
flattening the pair facing the copy. Affects the image-1/content-* presets, which no
pattern references yet — the visible radius already comes from the item-card and
media-text presets, both uniform. This keeps the dormant slots consistent with them.
Renames the vibe: its old name locked a deliberately general-purpose style to
childcare. marzipan joins the material register the other partials use (linen,
umber) and carries the warmth without naming a colour.

Adds the marzipan-1 partials and removes the 53 orphaned playdate-1 files — the
port's prune could not reach them, since a renamed vibe leaves the globals manifest
entirely and so reads as unknown rather than unmarked. No visual change: the presets
are byte-identical, only the slug moved.
Missed by the rename commit, which staged only styles/ — inc/ext-vibe-globals.json
still keyed its entry playdate-1, so the theme carried a slug no preset answered to.
Square corners, hairline-bordered pale panels, airy rhythm, no dividers — plotted
dot-field panels behind each band do the separating instead, rotating through three
different fields so consecutive sections don't look alike.

Also gives layout:staggered a WP twin. It previously existed only as a canvas rule, so
the axis was inert here. The offset collapses below 48rem through a clamped value rather
than a media query, which a preset css string cannot carry.

Palette Quartz: near-white paper, near-black ink at 17.6:1, three panel tints sharing one
lightness and chroma with hue alone distinguishing them.
The vibe-globals manifest no longer carries space-scale 1.5 for stipple-1: standard
density means no multiplier, so the entry's settings block goes away entirely.
A repeating mark tile intersected with a gradient, so the field covers the band from one
edge and fades out across it. Three arrangements rotate per section: blocks fading left to
right, mixed marks fading right to left, and a diagonal speck field.

Mask-based rather than a background image, because only a mask inks from the element's own
colour — the same reason the divider strips are masks.
The vibe was cut. Deletes its 23 partials and its globals-manifest entry.

Deleted by hand rather than pruned: a vibe absent from vibes/ leaves the globals manifest
entirely, so the port's --prune-unmarked reads it as unknown rather than unmarked and holds
its files. All 23 came from 9942335.
Industrial vibe: square corners, flat surfaces, hairline section rules, uppercase display,
and a three-slab card cycle (orange / sky / signal yellow) on a warm-grey page.

Every palette partial also gains a seventh duotone preset, primary-and-background — primary
in the shadows, the page's own paper in the highlights. The existing six all pair two
ink-side or two surface-side colours, so none of them covered a photo grade.
So the slug exists for every colorway, not only the ones whose partial generates it. Primary
in the shadows, the page's background in the highlights — the one pairing the existing eight
root presets don't cover, since they all pair two ink-side or two surface-side colours.

Root carries the theme's own default pair, exactly as the existing eight do. A colorway whose
partial defines its own primary-and-background overrides it (the Lattice palettes all do, from
the palette generator), and one that doesn't inherits the default.

Edited as a string insert rather than re-serialized: json.dump reformatted this file once
before and produced 123 lines of whitespace noise that had to be reverted. Diff is 5 lines.
A duotone cannot be token-driven: WP compiles the two colours into an SVG filter in PHP
(colord_parse handles hex, rgb(), hsl() and named colours only — no custom property), so one
entry in root theme.json can only ever carry ONE pair. That made the root entry actively
misleading: any colorway without its own would grade photos in the default purple, and a wrong
colour is harder to notice than a missing one.

So the entry moves out of root and into all 39 colorways that lacked it, each derived from its
own palette primary and background. 44/44 now define it. Root goes back to its original 8.

Not a new convention — cairo already shipped primary-and-background, so this brings the other
43 in line with a slug the theme had already established.

Two duotone vocabularies exist across the colorways and each needed its own anchor: 29 files
use the "and" family (primary-and-secondary, primary-and-tertiary, ...) and 10 mirror root's
own names (grayscale, primary, secondary, ...) with no primary-and-tertiary to insert after.

Edited by string insert, never re-serialized: json.dump reformatted theme.json once before and
produced 123 lines of whitespace noise. Every file re-parsed after writing; the diff is +5
lines per colourway and nothing else.

Verified live: with foundry active, wp_get_global_settings returns
primary-and-background = ["#111113","#F2F2F0"] — the palette's own pair, not a fallback.
Applies the palette's own primary-and-background grade via a preset slug, so it follows
whichever colorway is active. Front-end renders did not honour it in testing (WP maps duotone
per block name, and a style variation is not a block node) — shipped to test in the editor,
which applies variations through a different path.
The theme.json schema defines filter.duotone and has no duotone under color at all — color.
duotone is the block-attribute contract, so the previous shape was invalid theme.json.

The $schema on every generated preset moves from wp/6.8 to trunk, matching this theme's own
theme.json and all 44 colorway partials. Both cap version 3, so nothing about validation
changes; it removes the only files in the tree claiming an older contract.
The version this target runs (7.0.2), replacing trunk. Verified it caps version 3 and defines
styles.filter.duotone identically, so validation is unchanged — this only stops the reference
being a moving document.
The duotone moves to styles.blocks.core/image|core/cover .filter.duotone in the vibe globals
manifest — the only path WP actually reads, since its duotone map is keyed per block name and a
style variation is invisible to it. IBM Plex Mono headings at 400 uppercase over Manrope,
uppercase buttons, and a 56rem/120rem measure.
layout: staggered on the vibe, so the section preset emits the stagger. Its offset collapses
below 48rem through a clamped value rather than a media query, which a preset css string
cannot carry.
headingCase moves from an h3-only entry onto the shared heading element, which theme.json
applies to every level. Affects foundry-1 (newly set) and retro-1, which had asked for
uppercase headings and only ever got h3.
headingCase returns to h3-only so retro-typography.json matches what shipped; h1-h6 is opt-in
now. Foundry's wash #E4E4E0 -> #D5D5D0, a 0.056 lightness step off the paper instead of 0.010,
so a sunken band reads as sunken.
headingCaseLevels now survives the type expansion, so foundry-1's heading element carries the
transform for every level. retro-1 unchanged. The image/gallery/media-text/cover presets lose
their filter.duotone — WP never read it there; the vibe globals block node is the live path.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant