Phox Framework
A design token framework for Breakdance and Oxygen. Set your colours, type scale and spacing once; the framework generates the tokens, writes the stylesheet, and syncs everything into your builder's own variables so every control can use them.
Overview
Phox Framework turns a handful of decisions into a complete, consistent design system: every colour shade, every heading size, every spacing step and every corner radius, generated from a small configuration and delivered as CSS custom properties.
The configuration lives in one place, in Phox Framework in wp-admin. Saving it does three things at once, always together: it rewrites the framework stylesheet, pushes every token into your page builder's native variable collection, and fills any empty slots in the builder's own Global Settings. Those three representations of your design system can never drift apart, because one save produces all of them.
Colour that derives
One hex per slot generates six shades, a hover state and a readable foreground, all placed in OKLCH so the steps are perceptually even.
Fluid type and space
Every size is a clamp() between a small-screen and a large-screen value, so nothing needs a breakpoint to look deliberate on a phone.
Dark areas
Mark a section as dark and every piece of text inside it switches to its dark value. Nothing inside needs styling a second time.
Native to the builder
Tokens appear in Breakdance and Oxygen's own variable pickers, and a token button sits on their colour and size controls.
Requirements & installation
| Requirement | Notes |
|---|---|
| PHP | 7.4 or newer |
| Page builder | Breakdance 3.0 or newer, or Oxygen 6.2 or newer. Both are supported natively; neither is a second-class port. Older Breakdance releases run the framework in compatibility mode (see below): the tokens and the stylesheet work, but the builder does not expose its variables system to plugins, so there is no variable sync, no Global Settings fill and no agent tools. |
| Browser | Any browser supporting CSS custom properties and clamp(). Dark mode additionally uses light-dark(), which older browsers ignore, falling back to the light value. |
- Install the plugin. Go to Plugins → Add New → Upload Plugin, choose the
phox-framework.zipfile and click Install Now. - Activate it. A Phox Framework item appears in the main admin menu, and the framework stylesheet is generated for the first time.
- Enter your licence key. On the Licence tab, paste your key and activate. This enables automatic updates.
- Pick a starting point. Open the Presets tab and apply one, or go straight to Colours and set your own brand colour.
Any user who can Manage Options (administrators) can change the design system. The same capability guards the admin screens, every AJAX write and every agent tool, because all of them rewrite a stylesheet the whole front end loads.
If no supported builder is active, or Breakdance is older than 3.0, the framework runs in compatibility mode: it still generates the stylesheet and the tokens, and the token picker still works, writing plain var() text instead of a builder binding. It simply has nowhere to sync variables to. The Dashboard health check tells you when this is the case.
Quick start
The fastest route to a working design system is a preset, then one colour.
- Open Phox Framework from the admin menu and go to the Presets tab.
- Apply a preset whose feel is closest to the site you are building. Each one sets a palette, a type scale, line heights, fonts, a spacing rhythm and corner radii. You can undo it in one click.
- Set your brand colour. On the Colours tab, select the Primary slot and paste your brand hex into Source colour. The shade ramp, the hover state and the readable foreground all regenerate as you type.
- Watch the preview. The panel at the bottom of the screen shows the whole system reacting live, before you save.
- Save. The stylesheet is rewritten, the tokens are pushed into the builder's variables, and empty Global Settings slots are filled.
- Use them. Open any page in the builder. Your tokens are in the native variable picker, and a token button sits beside the colour and size controls.
The admin interface
Everything lives on one screen, split into tabs.
| Tab | What it holds |
|---|---|
| Dashboard | Token counts, the health check (what is being generated, whether the sync can run, whether the stylesheet is current), and buttons to regenerate the CSS or re-sync the variables. |
| Presets | Five complete starting points. Applying one is a single click, with a confirmation and a one-step undo. See Presets. |
| Colours | The colour slots and their generated ramps, the ink roles with their contrast grades, and the dark mode settings. |
| Typography | Fonts, the base size range, the scale ratios, line heights, and per-token size overrides. |
| Spacing | The spacing base and ratios, section padding, content width, the readable measure, the rhythm roles and the corner radii. |
| Utilities | The optional utility class layer, off by default. See Utility classes. |
| Classes | The optional class modules for buttons, forms, borders and more, all off by default. See Class modules. |
| Tokens | Every generated token with its name, value and group. The place to look up what to type. |
| Settings | Token prefix, the fluid viewport range, builder sync options, export and import, and reset. |
| Licence | Your licence key and its status. |
The screen tracks unsaved changes and the live preview updates from your draft, not from what is on the site. Discard changes puts everything back to the last save.
Presets
A preset is a complete starting design. Applying one replaces your palette, type scale, line heights, fonts, spacing rhythm and corner radii in a single step.
| Preset | Character |
|---|---|
| Studio | Cool and precise, almost monochrome, with one warm accent. Crisp corners and a tight heading rhythm. |
| Editorial | Warm paper, old-style serif headings and a long measure. Built for pages that are mostly words. |
| Commerce | Bright, dense and rounded, with the semantic colours switched on because a shop actually uses them. |
| Brutal | Square corners, huge type and a jolt of electric lime on near-black. |
| Calm | Muted sage and stone, soft corners and a lot of air. |
What a preset does and does not touch
| Replaced | Left alone |
|---|---|
| Every colour slot and whether it is enabled; the type scale, line heights and fonts; the spacing base, ratios, section padding and rhythm roles; all three corner radii. | Your token prefix; the fluid viewport range; the content width and readable measure; whether dark mode is on and how it is triggered; the builder sync settings; the class modules and the utility layer. |
If you had hand-picked an individual shade, a dark value or a specific heading size, applying a preset clears those. They were chosen against the design being replaced, and carrying them forward would leave the new palette wearing colours from the old one.
Immediately after applying a preset, an Undo button restores exactly what you had. It withdraws itself the moment you save something of your own, so it can never throw away newer work.
The design system
Colours & shade ramps
The palette is built from slots. Each slot has a job, and you give it one source colour; everything else is generated.
| Slot | Group | What it is for |
|---|---|---|
| Primary | Brand | Actions, links, the colour the brand is known for. |
| Secondary | Brand | Supporting brand colour. |
| Accent | Brand | Highlights and small emphasis moments. |
| Base | Neutral | Page backgrounds and body text. This slot does more work than it looks: the page surface and the darkest text both come from its ramp. |
| Neutral | Neutral | Borders, dividers, muted surfaces. |
| Success, Warning, Danger, Info | Semantic | Confirmations, cautions, errors and neutral information. |
Only enabled slots generate tokens. A fresh install enables Primary, Base and Neutral; switch on the rest as you need them, and switch off any you do not to keep the stylesheet small.
The generated ramp
Each enabled slot produces eight values plus a readable foreground:
| Token | What it is |
|---|---|
--pxf-primary | The source colour, exactly as you set it. |
--pxf-primary-ultra-light--pxf-primary-light--pxf-primary-semi-light | Three lighter steps, at OKLCH lightness 0.97, 0.90 and 0.79. |
--pxf-primary-semi-dark--pxf-primary-dark--pxf-primary-ultra-dark | Three darker steps, at lightness 0.50, 0.38 and 0.24. |
--pxf-primary-hover | The pressed state. Resolved relative to the source rather than being a step on the ladder, so it always reads as "the same colour, pressed". |
--pxf-on-primary | Black or white, whichever is readable on the source colour. |
Shades are generated in the OKLCH colour space rather than by lightening and darkening in sRGB. The practical difference is that every step moves by the same perceived amount, so a yellow ramp and a blue ramp feel like siblings instead of one going muddy and the other going neon at the extremes. Chroma is also scaled down at both ends, which is what stops the palest tints looking radioactive.
Overriding a single shade
Any generated shade can be replaced with a hand-picked colour, for both the light and the dark palette, without disturbing the rest of the ramp. Overridden shades are marked in the interface so you can see at a glance what is generated and what is pinned.
Ink: readable text
Text colour is the one part of a token system that cannot be a constant. A single global text colour works right up until a section has a dark background, at which point every heading and paragraph inside it becomes unreadable.
So the framework generates five ink roles, and each holds two colours: one for use on a light surface, one for use on a dark one. Each is grown from a palette slot to hit a real WCAG contrast target.
| Role | Token | Grown from | Target on light | Target on dark |
|---|---|---|---|---|
| Heading | --pxf-heading | Base | 11:1 | 15:1 |
| Text | --pxf-text | Base | 7:1 (AAA) | 12:1 |
| Muted | --pxf-muted | Neutral | 4.6:1 (AA) | 7:1 |
| Link | --pxf-link | Primary | 4.6:1 (AA) | 7:1 |
| Link hover | --pxf-link-hover | Primary | 4.6:1 (AA) | 7:1 |
A few of those choices are worth knowing about. Headings sit higher than body copy because a heading at the same contrast as the paragraph beneath it reads as washed out, even when it is technically legible. Muted is grown from Neutral rather than Base, which is what makes it read as a different voice instead of just faded body text. And links keep the brand colour wherever it already clears the target, moving along their own hue only when it does not, so a link still looks like your brand.
Any role can be given a specific colour for either context. Leave a value empty and it goes back to being derived, so you only ever store the ones you cared enough to change.
Dark mode
Dark mode is a second palette, grown from the same source colours. Turn it on with Generate a dark palette on the Colours tab.
What happens to a colour depends on what kind of colour it is, and this is the part most systems get wrong. A brand colour holds still. Your brand is your brand at midnight; only the shades around it turn over. A near-neutral inverts, because "the dark grey" has to be dark relative to the page, and the page has turned over.
When dark mode applies
| Strategy | Behaviour |
|---|---|
| Follow the visitor's system | Dark switches on for anyone whose device is set to dark, and the data-pxf-scheme attribute can still override that in either direction. The right choice unless your theme ships its own toggle. |
| Only when the attribute is set | The system preference is ignored entirely. Dark appears only when something sets the attribute. |
To wire up your own toggle, set the attribute on the html element:
<!-- Force dark -->
<html data-pxf-scheme="dark">
<!-- Force light -->
<html data-pxf-scheme="light">
<!-- Remove the attribute to hand the decision back to the device -->
The plugin ships a Dark Mode Toggle element that does all of this, including remembering the visitor's choice.
The interface still shows you the dark half of every ramp so you can judge it, but nothing dark reaches the site until you switch it on. Text on dark sections is a separate feature that works either way, which is next.
Dark areas
A dark area is a section of an ordinary light page that has a dark background. It is not dark mode, and it works whether or not dark mode is switched on.
Mark the section, and every piece of text inside it switches to its dark reading. Headings, body copy, captions and links, at any depth, with nothing inside styled a second time.
<section data-pxf-context="dark" style="background: var(--pxf-surface-dark)">
<h2>This heading takes its dark value</h2>
<p>So does this paragraph, and <a href="#">this link</a>.</p>
</section>
In Breakdance and Oxygen you do not write that by hand. Every element gains a Colour context setting with three values:
| Setting | Effect |
|---|---|
| Inherit | Take whatever the nearest ancestor decided. The default. |
| Light area | Force the light ink values for this element and everything inside it. |
| Dark area | Force the dark ink values for this element and everything inside it. |
--pxf-surface-light and --pxf-surface-dark give you the two reference surfaces the ink roles are graded against, along with --pxf-on-surface-light and --pxf-on-surface-dark. Use the dark surface as the background of a dark area and the contrast grades you see in the admin are the grades you get.
Typography
Type is fluid. You set a size for small screens and a size for large ones, and every value in between is interpolated with clamp(). There is no breakpoint to write and no size that is only correct at the widths someone remembered to test.
What you configure
| Setting | What it controls |
|---|---|
| Root font size | The rem basis for the whole system. |
| Body size, min and max | The body copy size at the small and large viewport anchors. |
| Scale ratio, min and max | How much bigger each step is than the one below, on small and large screens. |
| Line height | One value for body copy, one for headings. |
| Fonts | A heading font and a body font. Choose a system stack (nothing to download), any font registered in your builder, or a custom stack you type yourself. |
The tokens it produces
Six heading sizes and six text sizes, plus the fonts and line heights:
| Tokens | Notes |
|---|---|
--pxf-h1 through --pxf-h6 | Heading sizes, one to six steps up the scale from body size. |
--pxf-text-xs, -s, -m, -l, -xl, -2xl | Body sizes, with text-m being body copy itself. |
--pxf-line-height-heading, --pxf-line-height-body | The two line heights. |
--pxf-font-heading, --pxf-font-body | The two font stacks. Emitted as custom properties once you have actually chosen a font; a fresh install has none set, so nothing is declared and the browser falls back to your theme. |
Steps below body size divide by the ratio, so if the mobile ratio is much gentler than the desktop one, small sizes can invert and end up larger on mobile than on desktop. The rule of thumb: your body max divided by body min should stay above the ratio gap squared. If you get this wrong the audit reports it by name, and you can always pin the offending size with an override.
Per-token overrides
Any individual size can be pinned to a specific minimum and maximum, ignoring the scale. Useful when a scale you like everywhere else produces an H1 that is simply too big.
The design systemSpacing & layout
Spacing works exactly like type: a base value and a ratio, at two viewport anchors, producing a fluid scale.
| Setting | Produces |
|---|---|
| Base and ratio | --pxf-space-xs through --pxf-space-3xl, seven fluid steps. |
| Section padding | --pxf-section-space, the vertical breathing room a page section gets. |
| Content width | --pxf-content-width, your site's container width. |
| Readable measure | --pxf-text-width, in ch, so a line of text never outruns comfortable reading length. |
Rhythm roles
Three named roles point at steps that already exist, rather than adding three more tokens to scroll past:
| Role | Custom property | Meaning |
|---|---|---|
| Flow | --pxf-prose-space | The gap between paragraphs. |
| Heading | --pxf-prose-heading | The space above a heading. |
| Tight | --pxf-prose-tight | The space below a heading, before the text it introduces. |
These three are aliases rather than separate values: each one resolves to a spacing step you already have, which is why they do not appear in the token list or the picker. Point a role at a different step and everything using it moves together. The rhythm is applied automatically inside the builder's Rich Text and Post Content elements and inside ordinary WordPress post content; any other container can opt in with the Smart spacing setting.
The defaults are the classic prose relationship: a heading gets more air above it than paragraphs get between them, and almost none below it, because a heading belongs to the text it introduces rather than floating between two blocks. Retune the scale and the rhythm retunes with it.
Set the maximum viewport on the Settings tab to match your content width. That way the largest values in every fluid scale are reached exactly when your layout stops growing, rather than somewhere past it.
Radius
Corner radius is static, and that is a deliberate claim rather than a simplification. Type and spacing scale with the viewport because reading distance and layout density change with it. A corner does not: a 40px button is a 40px button on a phone and on a desktop, so a corner that grows with the window changes its proportion within a component that has not moved.
| Token | Default |
|---|---|
--pxf-radius-s | 4px |
--pxf-radius-m | 8px |
--pxf-radius-l | 16px |
--pxf-radius-full | A pill, for anything fully rounded. |
Zero is a legal value; square corners are a design choice.
In your builder
The token picker
The picker is the part you will use most. A small token button appears beside the builder's own colour and size controls; clicking it opens a searchable list of your tokens, grouped and previewed.
- Hover to preview. Moving through the list previews each token on the real element, so you choose by looking rather than by name.
- Type to filter. The search matches names and groups, so "space" or "primary" narrows the list immediately.
- Only what fits. A colour control is offered colours; a size control is offered sizes. A picker that let you put a spacing token in a colour box would be worse than no picker.
- Multi-value controls work. Padding, margin and other four-sided controls take a token on every side.
Tints
Any colour token can be taken at reduced strength. The picker offers 100, 60, 40, 20, 10 and 5 percent and writes a real color-mix() expression, so the tint follows the token: change the source colour and every tint of it changes too.
A tint is chosen from a small vocabulary: a five or ten percent wash, a fifth, a half. Those are the values a design system wants repeated across a site, byte for byte. A slider's job is to find a value nobody has named yet, which is the opposite of what a token system is for. Anyone who genuinely needs 37% still has the CSS they always had.
How a pick is written
On a builder that supports variables, picking a token writes the builder's own variable binding. The field shows the token's human name, the builder knows the value is a reference rather than a string, and the binding survives a token rename or a prefix change. This is what the Picking a token inserts setting on the Settings tab controls; its other value, Plain CSS you can edit, writes var(--pxf-x) text instead, which is useful when you want to compose on top of the value with a fallback or a calc().
A tint is an expression over a variable, and a binding can only name exactly one variable. So tints are always written as CSS text whichever form the setting asks for. That is a constraint of the builder's binding format, not a preference.
Dark background prompt
Set a section's background to a dark colour and the picker offers to mark that section as a dark area for you, so the text inside it stays readable. Decline it and it stays out of your way.
In your builderElement settings
Every element in Breakdance and Oxygen gains a Phox section on its Settings tab, in the same place as the builder's own per-element settings. It holds three things, and an element nobody has touched emits no CSS at all, so leaving the section alone costs nothing.
| Control | What it does |
|---|---|
| Colour context | Inherit, Light area or Dark area. Marks this element and everything inside it as a light or dark area so the ink roles switch. Covered under Dark areas. |
| Smart spacing | Automatic, On or Off. Gives this element's children the prose rhythm from the Spacing tab. |
| Text: smallest / largest (px) | A fluid text size for this one element, between two sizes you choose. |
Smart spacing
The rhythm roles already apply on their own inside Rich Text and Post Content, and inside ordinary WordPress post content. That is what Automatic means. Switch it On for any other container, a Section or a Div that stacks headings and text, and its children take the same rhythm: flow space between blocks, heading space above a heading, tight space below one. On also sets the container's row gap to zero, because rhythm and a uniform gap are two answers to the same question, and a container that had both would look broken on exactly the elements you would try this on first. Off removes the space between the element's children, which is how you take the rhythm away from something that would otherwise get it.
A fluid size for one element
The builder's font size control can give an element one size per breakpoint, or a token, which is fluid but over the site's range. Neither says "this hero heading runs from 32px to 96px". Two numbers here do: the smallest the text gets and the largest. Between them it scales with the viewport, using the same interpolation as the site type scale and the same viewport range you set on the Settings tab. The largest field appears once smallest has a value, and nothing is written until both do, because a clamp with one end is a fixed size dressed as a fluid one.
In your builderVariable sync
Every token is pushed into your builder's own variable collection, so they appear in the native variable pickers throughout the interface, not only in ours.
| Setting | Purpose |
|---|---|
| Sync on save | Push the tokens into the builder every time you save. Switch it off to sync by hand from the Dashboard instead. |
| Collection name | The name of the variable group the tokens appear under. Defaults to Phox. |
| Picking a token inserts | A builder variable, or plain CSS you can edit. See The token picker. |
The sync preserves variable IDs across saves, which is what makes a binding survive a rename. Renaming a token in Phox Framework does not break a page that was bound to it.
The framework declares every token in its own stylesheet as well as syncing them. That is deliberate: the builder's variables stylesheet is not present on every rendered page, so a sync that is switched off, stale, or has had its variables pruned would otherwise delete most of the design system. Because the framework's copy sits inside a cascade layer and the builder's is not, wherever the sync has written a value that value still wins.
Global Settings
Breakdance and Oxygen have their own Global Settings panel with colour and typography fields. Phox Framework fills the empty slots there with your tokens, so the builder's own panel reflects your design system instead of its factory defaults.
| Global Settings slot | Filled with |
|---|---|
| Brand, Brand hover | --pxf-primary, --pxf-primary-hover |
| Text, Headings | --pxf-text, --pxf-heading |
| Links, Links hover | --pxf-link, --pxf-link-hover |
| Background | --pxf-base-ultra-light |
Who wins
Ownership is decided per property, not per panel. Where you have chosen a value in Global Settings, the framework steps aside for it. Where a slot merely holds the value the sync put there, the framework keeps declaring it, because deferring in that case would mean deferring to itself.
The sync only ever fills empty slots. Once you put your own value in one, or point it at a different token by hand, the framework leaves it alone on every subsequent save.
Dark Mode Toggle element
An element in the Phox Framework category that lets visitors switch the site between light and dark. It writes the data-pxf-scheme attribute described in Dark mode and remembers the choice.
| Style | Appearance |
|---|---|
| Switch | A track and thumb, with an optional icon inside. |
| Icon button | A single sun or moon button. |
| Eclipse | A moon that fills into a sun, animated. The disc that bites the crescent out takes the page colour by default, so it disappears into whatever is behind the button. |
All three take their colours from your palette by default, and every colour is overridable per element. The Eclipse style also exposes its glow size and transition duration.
The Switch and Icon button styles accept your own sun and moon icons from the builder's icon control. An icon is cleaned to a safe subset of SVG before it is written into the page: shapes, paths, groups, gradients and their presentation attributes stay; scripts, links, external references, styles and event handlers are removed. An icon with nothing drawable left after that falls back to the built-in one.
The occluder disc defaults to the page surface token, which is correct on an ordinary page. If you place the toggle in a coloured header, set Behind the button to that colour so the crescent still reads.
Workflow
The specimen page
The specimen renders your design system against itself: the full type scale with the pixel range each level spans, every colour ramp with hex values and token names, the ink roles graded on a light surface and a dark one, a dark area, buttons and cards, the spacing scale and the corner radii.
It is generated live from your current tokens, so it is always accurate. Two ways to reach it:
- The Specimen toggle in the live preview panel at the bottom of the Colours tab.
- Directly, at
yoursite.com/?pxf_preview=specimen. The preview panel has a button that opens exactly that in a new tab, which is worth doing because the page has more to show than a 420px panel can hold.
The specimen doubles as a deliverable. It is the answer to "what does our design system actually contain", and it updates itself whenever the design changes.
The preview URL only renders for users who could change the tokens anyway. It is a front-end URL, so it must never become a way for the public to get a differently behaving version of the site.
Live preview
The panel at the bottom of the admin screen shows your draft, not what is saved. Drag a colour picker and the preview reacts as you move, before anything is written.
| Control | What it does |
|---|---|
| Specimen / Site | Preview the generated specimen, or your actual front page with the draft tokens applied. |
| Moon icon | Preview in dark mode. This works whether or not dark mode is switched on for the site, so you can answer "what would dark look like?" before committing to it. |
| Open in a new tab | Opens whichever mode is showing, full width. |
| Reload | Refreshes the frame. |
Previewing the Site is the honest test on an established site. Previewing the Specimen is more useful on a new one, where the front page has not been built with these tokens yet and so will not react to them.
WorkflowSettings
| Setting | Purpose |
|---|---|
| Token prefix | What the tokens are called. --pxf-primary becomes --acme-primary if you set the prefix to acme. Useful when another framework on the site already owns a name. It must start with a letter; a prefix that sanitises to nothing goes back to pxf rather than producing bare names. |
| Viewport minimum | The small-screen anchor. Everything fluid reaches its minimum at or below this width. |
| Viewport maximum | The large-screen anchor. Set it to match your content width. |
| Builder sync | See Variable sync. |
| Export / Import | See below. |
| Reset to defaults | Returns every value to the factory design system. Export first if there is any chance you will want the palette back. |
The prefix changes the token names everywhere at once: the stylesheet, the builder variables and the picker. Builder bindings survive it, because they reference a variable by ID rather than by name. Any CSS you have written by hand against the old names will not, so search your custom CSS before changing it on an established site.
Export & import
The entire design system is one JSON file. Export it from the Settings tab to move a design between sites, keep it in version control, or take a snapshot before a big change.
Import either by choosing a file or by pasting the JSON. Importing replaces the entire configuration and regenerates the stylesheet immediately.
A file is checked for at least two recognisable top-level sections before anything is written. Without that check, a JSON file that was not ours would import "successfully" and silently wipe your design system, because the sanitiser would happily turn an arbitrary array into a valid default configuration.
Optional layers
Class modules
Class modules are an optional layer of ready-made component CSS built entirely from your tokens. Every one of them ships switched off. The framework's job is the tokens; these are there if you want components too.
| Module | What it adds |
|---|---|
| Buttons | A tokenised button system: .pxf-btn plus a variant per colour slot, sized off the space and type scales. |
| Forms | Inputs, selects, choices and buttons built from the palette and the spacing scale, with focus states you can actually see. |
| Borders | One width, one style, one colour, so every border on the site composes from the same three tokens. |
| Rules | A horizontal rule whose thickness, colour and surrounding space all come from tokens. |
| Icons | Makes SVG icons and icon fonts behave the same: sized from the type scale, coloured by the text around them. |
| Contextual Spacing | Names the four spacing areas (content, container, section and grid) so each can be set once instead of chosen step by step. |
| Layout | Grids that wrap on the space they have rather than on breakpoints, plus a content grid whose children can break out of the measure. |
Switch a module on and its tokens join the registry and its CSS joins the stylesheet. Switch it off and both leave again, so an unused module costs nothing.
Optional layersUtility classes
A separate optional layer of single-purpose classes, also off by default. Four groups, each independently switchable: colours, spacing, text and layout.
/* With the colour utilities on */
<div class="pxf-bg--primary--light pxf-text--base--ultra-dark">
/* A background utility also sets a legible foreground, and a dark one */
/* flips the ink for everything inside it, exactly like a dark area. */
In a page builder you set values on controls, not by adding classes to markup. The utility layer exists for people hand-writing templates or dropping in custom HTML blocks. Leaving it off keeps the stylesheet meaningfully smaller.
Developer reference
Using tokens in CSS
Every token is a CSS custom property on :root. Use them anywhere you would use a value.
.my-card {
background: var(--pxf-base-ultra-light);
color: var(--pxf-text);
padding: var(--pxf-space-l);
border: 1px solid var(--pxf-neutral-light);
border-radius: var(--pxf-radius-m);
font-size: var(--pxf-text-m);
}
On a default install the framework generates 66 tokens, in six groups:
| Group | Contains |
|---|---|
| colors | Each enabled slot's source, six shades, hover state and readable foreground, plus the surface tokens. |
| ink | The five text roles. |
| typography | Six heading sizes, six text sizes, two fonts, two line heights. |
| spacing | Seven fluid steps plus section padding. |
| radius | Three steps plus the pill. |
| layout | Content width and readable measure. |
Enabling more colour slots or class modules adds to that count. The Tokens tab lists every one for the current configuration, which is the authoritative answer for your site.
The framework also emits a small fixed set of names for its own elements to reference: --pxf-el-surface, --pxf-el-base, --pxf-el-primary and --pxf-el-neutral-light. These exist because an element's CSS is a static file that cannot know you renamed your prefix. They are an internal contract, not a second vocabulary; use the real token names in your own CSS.
The cascade layer
Everything the framework emits sits inside a named CSS cascade layer:
@layer phox {
/* tokens, prose rhythm, module CSS, utilities */
}
Unlayered author styles beat any layer, whatever their specificity. That means your own CSS always wins without a single !important and without counting selectors. It is a floor under your design, not a ceiling over it.
Two things sit deliberately outside the layer, and both for the same reason: they have to win an argument against the builder's own bare-element rules, which are themselves unlayered.
- The base element rules, printed inline late in
<head>, which set the body colour and background, heading sizes and link colours. - The dark mode block.
Both keep their selectors bare (body, h1, a) so anything with a class beats them, which includes every per-element style you set in the builder and every rule you write yourself.
WP-CLI
The framework is fully drivable from a terminal, which is what makes it usable in a deployment script.
| Command | Purpose |
|---|---|
wp phox status | Configuration summary, token count, stylesheet and sync state. Supports --format=json. |
wp phox tokens | List every token. Filter with --group=colors; output CSS with --format=css. |
wp phox regenerate | Rebuild the framework stylesheet from the current configuration. |
wp phox sync | Push every token into the builder's variables. |
wp phox export | Write the whole design system to stdout as JSON. |
wp phox import <file> | Replace the design system from a file, or from stdin with -. Refuses a JSON file that is not a framework export, the same check the admin import makes. |
wp phox license statuswp phox license activate <key>wp phox license deactivate | Manage the licence without a browser. |
# Move a design system between environments
wp phox export > design-system.json
wp phox import design-system.json
# Extract just the tokens as CSS
wp phox tokens --format=css > tokens.css
# Rebuild after a deploy
wp phox regenerate && wp phox sync
Developer reference
Agent tools (MCP)
The framework registers five tools on Breakdance's own MCP server, so an AI assistant can work with your design system directly rather than guessing at hex codes and hard-coding them into pages.
| Tool | What it does |
|---|---|
| Get Design System | Returns the configuration, every token with its value, type and computed pixel range, the full colour ramps with contrast grades, and how to reference each token in CSS or in the builder. |
| Set Design Tokens | Applies a partial change. Only the keys sent are changed; the result is validated, saved, the stylesheet regenerated and the variables pushed in one atomic step. Supports a dry run that computes the result without saving. |
| Generate Palette | Derives a complete palette from a single brand colour, relating the hues by a colour theory strategy and placing every colour in OKLCH, so the slots read as siblings and the neutrals carry a trace of the brand hue. Also supports a dry run. |
| Audit Design Tokens | Reports colour pairs failing WCAG AA, fluid tokens whose minimum exceeds their maximum, builder variable name conflicts, a stale stylesheet, and a sync that is on but cannot run. Each with a specific fix. |
| Sync Design System | Rebuilds the stylesheet and re-pushes every token. Safe to run repeatedly; it is a rebuild, not a change. |
The tools follow Breakdance's own MCP switch, so they exist only when you have agents turned on. Every write additionally requires the same capability as editing the design system by hand, because these tools rewrite a stylesheet the whole front end loads.
To disable them regardless of the builder's setting:
add_filter( 'phox_framework_abilities', '__return_false' );
Developer reference
Hooks & filters
// Whether the framework registers its agent abilities at all.
add_filter( 'phox_framework_abilities', function ( $enabled ) {
return $enabled;
} );
// The registered class modules, keyed by slug. Add your own, or
// remove one you never want offered.
add_filter( 'phox_framework_modules', function ( $modules ) {
return $modules;
} );
Reading the configuration from PHP
use PhoxFramework\Config;
use PhoxFramework\Tokens;
$hex = Config::value( 'colors.palette.primary.hex' );
$prefix = Config::value( 'prefix', 'pxf' );
// Every token, as records with name, value, type, group and meta.
$tokens = Tokens::all();
// A var() reference for one token, prefix-aware.
$ref = Tokens::ref( 'space-l' ); // var(--pxf-space-l)
If you change the configuration programmatically, use Config::commit() rather than writing the option directly. It saves, regenerates the stylesheet, pushes the variables and updates Global Settings as one step. Writing the option alone leaves three representations of the design system disagreeing with each other.
Uninstalling
Deleting the plugin through WordPress cleans up after itself, in this order:
- Global Settings are withdrawn. Any slot still holding exactly the value the sync wrote is emptied. A slot you changed yourself is left alone, because that value is yours.
- The framework's own variables are removed, after the Global Settings step. Only variables the framework created are touched; one you added by hand inside the Phox collection, or a collection of your own you pointed the sync at, survives. The order matters too: doing it the other way round would leave the panel holding bindings to variables that no longer exist.
- The generated stylesheet is deleted from the uploads directory.
- Options are removed: the configuration, the variable map, the stylesheet record, the migration marker, the Global Settings record and the preset undo snapshot.
Deliberately. Reinstalling should not mean finding the key again. Deactivate the licence from the Licence tab first if you are moving it to another site.
Help
Troubleshooting
My tokens are not in the builder's variable picker
Check the Dashboard's health check first: it reports whether the sync can run at all. The most common causes are that Sync on save is switched off on the Settings tab, or that no supported builder is active, in which case the framework runs in compatibility mode and has nowhere to sync to. If both look right, press Sync to builder on the Dashboard to force a push.
I changed a colour and the front end did not change
Almost always a caching layer holding the old stylesheet. The framework versions the file so browsers pick up changes, but aggressive page caches and CDNs sometimes serve the old one. Clear the site cache, then the CDN. If the Dashboard reports the stylesheet as stale, press Regenerate CSS.
A colour I set in Global Settings is being ignored
It should not be, and this is worth reporting if it happens. The framework decides ownership per property: where you have chosen a value it steps aside, and where a slot merely holds what the sync put there it keeps declaring. If your choice is not winning, check the value in the builder's panel is actually saved rather than showing a placeholder.
Text is unreadable on a dark section
The section needs marking as a dark area. Set Colour context to Dark area on the section, or add data-pxf-context="dark" to it. Setting a dark background colour alone does not tell the framework anything about the text inside, because a dark background is not always meant to carry light text.
Small text is bigger on mobile than on desktop
An inverted fluid range. Your mobile scale ratio is outrunning your body size range, so steps below body size cross over. Bring the two ratios closer together on the Typography tab, or pin the affected size with a per-token override. The audit tool names any token this is happening to.
The Eclipse toggle shows two overlapping circles instead of a crescent
The occluder disc is not matching what is behind the button. It defaults to the page surface token, so this shows up when the toggle sits on a coloured header or a section with its own background. Set Behind the button on the element to that colour.
The token picker is not appearing on a control
The picker only offers itself where a token could actually be used, and it matches types: a colour control is offered colours, a size control is offered sizes. Controls that hold something else, or that hold a locked unit the builder will not accept a variable in, are left alone. In that case use the builder's own variable button, which the picker's decline message points you at.
Something I styled by hand is being overridden
It should not be. Everything the framework emits sits inside a cascade layer, and unlayered author styles beat any layer. The two exceptions are the base element rules and the dark mode block, which sit outside the layer but keep bare selectors, so anything with a class beats them. If your CSS uses a bare body or h1 selector and loads before ours, give it a class or raise its specificity.
I changed the token prefix and my custom CSS broke
Expected. Builder bindings survive a prefix change because they reference variables by ID, but CSS you wrote by hand against --pxf-primary does not. Search your custom CSS and stylesheets for the old prefix and update them, or change the prefix back.
Fatal error mentioning a duplicate constant
Two copies of the plugin are active at once, usually the original folder plus a second upload such as phox-framework-latest. WordPress loads both. Remove one so a single phox-framework folder remains, and update in place rather than adding a parallel folder.
FAQ
Does it work with Oxygen as well as Breakdance?
Both, natively. The token picker, the variable sync, the Global Settings integration and the elements all run in either builder. There is no compatibility mode doing a worse job on one of them.
Do I have to use a preset?
No. Presets are a starting point, not a requirement. Every colour, ratio, size and step is editable, and you can go straight to the Colours tab and build from your own brand colour.
Can I use it without a page builder?
Yes, with a caveat. The stylesheet and the tokens are generated regardless, so you can use them in a theme or in custom CSS. What you lose without a supported builder is the variable sync, the token picker and the Global Settings integration, since all three need a builder to talk to.
Will it fight my existing CSS?
No. Everything sits inside a CSS cascade layer, and unlayered author styles beat any layer, so your own CSS wins without !important and without counting specificity.
How is this different from just writing CSS variables by hand?
Three things a hand-written file cannot do. The tokens are synced into the builder's own variable collection, so they appear in every native picker and a binding survives a rename. The shades and text colours are generated, so you change one hex and the ramp, the hover state and the readable foreground all follow. And a section marked as a dark area repaints every piece of text inside it without you writing a second rule.
Can I rename the tokens?
Yes. The prefix is a setting, and it changes the names in the stylesheet, the builder variables and the picker together. Update any CSS you wrote by hand against the old names.
What happens to my design if I deactivate the plugin?
The framework stylesheet stops loading, so anything using its tokens falls back to whatever value you gave as a fallback, or to nothing. Builder variables synced into the builder remain in the builder's own collection. Deleting the plugin cleans up properly; see Uninstalling.
Does dark mode need a toggle?
Not necessarily. With the default strategy it follows the visitor's system setting on its own. A toggle is for letting people override that, and the plugin ships one.
Are the class modules required?
No, and they all ship switched off. The framework's job is the tokens; the modules are optional component CSS for people who want it. An unused module costs nothing, in tokens or in bytes.
Can an AI assistant change my design system?
Yes, if you have agents enabled in Breakdance. Five tools let it read the system, change part of it, generate a palette from a brand colour, audit for contrast and consistency problems, and rebuild. Writes are behind the same permission as editing by hand, and two of the tools support a dry run. See Agent tools.
Can I move a design system between sites?
Yes, either through Export and import on the Settings tab or with wp phox export and wp phox import.
Phox Framework · by Phox Elements · Built for Breakdance and Oxygen. For the latest information visit phox-elements.com.
