Add design tokens - #255
Open
amjadr360 wants to merge 48 commits into
Open
Conversation
…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.
amjadr360
force-pushed
the
add-design-tokens
branch
from
August 3, 2026 07:03
a6ac3a1 to
e1c3f6a
Compare
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
WIP