Skin generator

Start from a skin that already works, change what you care about, and let the rest follow. The export is a complete, valid [data-skin] block — every colour a light-dark() with both halves literal, no placeholders, nothing left to look up.

Identity

Becomes the selector: [data-skin="mine"]

Loads that skin's values — both modes — into every control below. Anything you have already changed is overwritten.

Editing
Which mode the controls below are editing

Every colour below has a light value and a dark one; this picks which of the two the controls are editing. The other half is kept and exported untouched. It also sets which way the derived hover and active states move: darker on light, lighter on dark.

There is no color-scheme control, because a skin must never set it. That is rule 1 of the contract.

Change --color-primary and its four relatives follow. Edit one of them by hand and it stops following — the generator will not overwrite a decision you made.

On, to match the shipped skins. Off if you want your skin to sit outside the library's layer and win over it unconditionally.

Typography 4

Four families. Which is used where is a component decision.

Surfaces and content 8

Borders 3

Brand roles 12

Each with a hover, an active and a foreground.

Status roles 12

A solid colour, a foreground for it, and a tinted surface.

Utility 4

Shape 8

Shape roles optional

derived, override only to change the relationship. These are derived in tokens/shape.css from the radius scale above, so a skin inherits them. Override one only to change the relationship — square boxes with pill-shaped fields — not merely the radii, which the scale already handles.

Live preview

Surfaces and text

Primary text sits on the page surface. Muted text is secondary, and subtle text is a placeholder.

Raised surface

A card, a popover, anything above the page.

Sunken: inputs, wells, inset regions.
primarysecondaryaccent
info — surface, solid and foreground.
success — surface, solid and foreground.
warning — surface, solid and foreground.
danger — surface, solid and foreground.
selectorfieldboxelevation 2

Inverse block, for high contrast.

Contrast

WCAG 2 ratio for every foreground token against the surface it is meant to sit on, in both modes — contract rule 3, and the reason a dark mode is never an inversion. 4.5 is the floor for body text, 3 for large text and for the edges of a control.

    Export

    Then hand-edit it

    The derived values are arithmetic, and arithmetic does not know that your warning yellow needs more lightness than the formula gave it, or that the tint behind a danger banner is one step too loud. That is the point of exporting literals rather than a function call: every number is yours to move, and moving one does not silently move four others.

    Paste the block into your own stylesheet, set data-skin on <html>, and you are done. The mode follows the reader unless you also set data-theme. There is nothing to register and nothing to rebuild.