Design Fundamentals

Building a Colour Palette From One Decision

Five swatches picked separately will fight each other. One hue plus arithmetic will not. A color palette generator that runs entirely in your browser, and the HSL and contrast maths that sit behind it.

Building a Colour Palette From One Decision

You pick a blue you like. Then a green to go beside it, a warm grey for backgrounds, an orange for the buttons, and something for links. Five separate acts of taste. On the screen they refuse to sit together: the green is louder than the blue, the grey looks dead next to both, and the orange button vanishes into the background at exactly the size where it matters.

Nothing is wrong with any of the five colours on its own. What is missing is a relationship between them. A palette that holds together is almost never five choices. It is one choice, and then arithmetic: a hue, plus a small set of rules that derive everything else from it.

The arithmetic is short enough to write out in full, which is what the rest of this article does. Hue, saturation and lightness are three numbers. A palette is what you get when you move one of those numbers at a time and leave the other two alone. There is already a piece on this site about choosing a colour palette without learning colour theory, which is the taste side of the question. This one is the maths side.

One colour in

Type a hex, pick a scheme, and read the explanation afterwards if the result is not doing what you expected. The whole thing is a color palette generator that runs inside the tab: no colour library, no network request, nothing uploaded anywhere. Every swatch below carries its hex, its HSL and its measured contrast against both white and black, and clicking one copies the hex.

Palette generator

Give it one colour and it works out a nine step ramp, a surface, an accent and two tinted neutrals, with the contrast figures for each. All the maths runs in this browser tab, nothing is uploaded.

Hex, rgb() or hsl() all work.

Scheme
Tint and shade ramp
Key colours
60 / 30 / 10 proportion

Roughly 60% surface, 30% base and 10% accent is the split most interfaces settle on.

Interface preview
Surface

A heading in your palette

Body copy sits on the near white, the base colour carries the one action that matters, and the accent turns up once.

Primary action Secondary
Dark

The same palette after dark

On the near black the accent does the work, because the base is often too heavy to sit on a dark ground.

Primary action Secondary
Pick a colour to start

Click any swatch to copy its hex. Contrast follows WCAG 2.1, where 4.5 or more is safe for body text and 3 or more for large text and interface edges.

WunderPaint
The Dynamic Design and Automation Studio
WunderPaint is a layered image editor for your WordPress media library. WunderPaint Studio is the same thing in any browser, free and without an account.

Three numbers, one cylinder

HSL describes a colour as a position in a cylinder. Hue is the angle around the rim, 0 to 360 degrees, running red, yellow, green, cyan, blue, magenta and back to red. Saturation is the distance out from the grey axis in the middle, 0 to 100 percent. Lightness is the height, 0 percent at the black floor and 100 percent at the white ceiling, with the most intense version of any hue sitting at 50 percent.

That is the whole reason to work in HSL rather than in RGB. In RGB no single channel corresponds to anything a designer wants to change: making a colour lighter means moving all three, in a ratio you have to work out first, and getting that ratio slightly wrong drifts the hue. In HSL, lighter is one number going up.

Here is a real pair, so the rotation is not abstract. The blue used throughout this site sits at hue 227, and its complement is what you get by adding 180 degrees to that angle and touching nothing else.

base      #3B66FF    hsl(227, 100%, 62%)
rotate    +180 deg   hue 227 becomes hue 47
accent    #FFD43B    hsl( 47, 100%, 62%)

Saturation and lightness are identical in both rows. The only thing that moved was the angle, and the result is a yellow that belongs to the blue in a way no separately chosen yellow ever quite does. The input field accepts that colour written any of the ways you are likely to have it already: #3B66FF, 3b66ff, the three digit form #f00, an rgb() string with commas or spaces (an alpha value is ignored), or an hsl() string with or without the deg suffix.

Moving one axis at a time

Move lightness alone and you get a ramp: the same colour from a near white tint down to a deep shade, all of it recognisably one family because the hue and the saturation never changed. This is the ladder every design system ships, usually labelled 100 at the top and 900 at the bottom. The generator builds nine of these steps at fixed stops running from 95 percent lightness down to 15 percent.

Move saturation alone and you get the same colour, quieter. This is the axis that decides whether a page is comfortable to sit in front of. A colour at 100 percent saturation has one RGB channel pinned at its maximum and one at its minimum, so there is no headroom left in it. Over a large area that causes two problems: an accent works by being more intense than its surroundings, and nothing beats a background already sitting at the edge of the gamut; and the eye adapts to a strong colour field within seconds, so anything laid on top starts drifting towards the opposite hue. Hence a desaturated surface rather than the base itself.

Move hue alone and you get the schemes. Analogous rotates a little way in each direction and stays in the same emotional register. Complementary goes to the far side of the wheel and gives you maximum separation. Triad and split complementary sit in between, with the split version pulling back from the exact opposite to take some of the harshness out of it. Monochrome does not rotate at all, which leaves it with no hue to work with, so the generator moves its accent 26 lightness points instead of rotating it. That is a compromise, and the tool shows you the result rather than pretending otherwise.

The set the generator derives

From one base colour and one scheme, the output is a ramp of nine steps, a surface, an accent, and two tinted neutrals. Analogous, triad and split complementary produce a second accent because those schemes define two angles; monochrome and complementary define one, so they produce one.

Table showing what a palette generator derives from one base colour: a nine step ramp at 95 to 15 percent lightness, a surface at 94 percent with saturation capped at 14, an accent rotated by the scheme angle, a near white at 97 percent capped at 10, and a near black at 9 percent capped at 16, followed by a second table of scheme rotations, monochrome none, analogous plus and minus 30, complementary 180, triad 120 and 240, split complementary 150 and 210.

One detail is worth knowing before it surprises you. The ramp stops are absolute rather than relative to your base, so a base at 62 percent lightness falls between two steps and is not itself a step. The generator flags the nearest one instead of bending the ramp to fit, because a ramp whose spacing shifts with every base is useless as a system: you could not swap the brand colour later and expect the same nine tokens to behave the same way.

Why pure grey looks unfinished

Mid grey is #808080, which is hsl(0, 0%, 50%): a hue of zero, a saturation of zero, and no connection to anything else on the page. Put it next to a near white that carries a trace of the base hue and the pure grey reads as a different material, as though it had been cut out of another design and pasted in.

The reason is that we read a page as a lit surface. Under one light, every material picks up some of the same colour, so a set of neutrals that all carry a trace of the same hue reads as one scene. Zero saturation says the opposite: this surface is lit by nothing. It is the difference between a wall photographed in a room and a wall sampled from a colour chart.

So the three neutrals here are tinted rather than grey. The surface sits at 94 percent lightness, the near white at 97 percent and the near black at 9 percent, and each takes the base saturation scaled down and capped, at 14, 10 and 16 respectively. Scaled down, not set: this matters, because it means a grey base still gives you a grey palette. Feed the tool #808080 and you do not get an invented hue back, which is the failure mode of every generator that hard codes a tint value.

Sixty, thirty, ten

Four colours in a list are not a design. Four colours in a proportion are. The old decorator’s ratio, 60 percent of the area to one colour, 30 percent to the second and 10 percent to the third, is the step that turns the output above into something you can actually build with: the surface takes the 60, the base takes the 30, the accent takes the 10.

The reason the ratio works is that it destroys the tie. Two colours at equal area have no figure and no ground, and the eye receives no instruction about where to look. Push one of them out to 60 percent and it becomes the ground by default; everything else is then read against it. The accent surviving at 10 percent is the only thing left that can act as a signal, which is exactly why it has to stay at 10. An accent applied to six different elements is not an accent any more, it is a third background. This is the same argument as the one behind white space in composition: the emphasis comes from the ratio, not from the ingredient.

The strip under the swatches shows that split at real proportions, and the two preview cards below it, one light and one dark, put the palette into a tag, a heading, a paragraph and two buttons, so you can see whether it survives contact with an interface. On screens narrower than 700 pixels the strip drops its inline labels, since none fits inside a 10 percent segment, and the sentence underneath carries the numbers instead.

Contrast is a measured number

The one part of this that is not taste is contrast, and it has a formula. Convert each sRGB channel back to linear light, weight the three channels and add them up to get relative luminance, then compare two luminances with a fixed ratio.

relative luminance
  L = 0.2126 * R + 0.7152 * G + 0.0722 * B
  R, G, B linearised from sRGB, each 0 to 1

contrast ratio
  (L_lighter + 0.05) / (L_darker + 0.05)
  range 1:1 (identical) up to 21:1 (black on white)

Two thresholds are worth memorising, both from WCAG 2.1. A ratio of 4.5:1 or more is safe for body text. A ratio of 3:1 or more is the bar for large text, meaning roughly 18pt, or 14pt when it is bold, and it is also the bar for the non-text parts of an interface: input borders, icons, the edge of a button. Below 3:1 you are guessing. The generator colours every contrast reading on that scale, green at 4.5 or more, amber at 3 or more, red below.

Each swatch is measured against white and against black, because you rarely know in advance which ground a colour will end up on. Most colours pass one test and fail the other. The blue above is unusual: #3B66FF comes out at 4.64:1 on white and 4.53:1 on black, so it clears the body text bar either way. Its complement does not. #FFD43B is 1.43:1 on white and 14.73:1 on black, which means it is a colour you can set black text on and nothing else. If you ever wondered why a bright yellow call to action with white lettering looks wrong, that is the number saying so, and the same measurement is what decides whether text stays readable over a photograph.

There is exactly one place where the tool overrules its own palette. The secondary button in each preview card is darkened or lightened in 2 point steps until it clears 4.5:1 against the card it sits on, so the preview never shows you unreadable text and calls it a demonstration. Everywhere else the palette is reported as it is, contrast failures included.

Where HSL lies to you

HSL is the right space for deriving a palette and the wrong space for judging one. Its lightness value is a geometric position in that cylinder, not a measurement of how much light the colour actually emits, so two colours can sit at identical lightness and be nowhere near each other in brightness.

Table comparing six fully saturated hues all set to 50 percent HSL lightness, with their hex values, relative luminance shown as proportional bars, and WCAG contrast ratios against white and black. Yellow reaches 0.9278 luminance and 1.07 to 1 on white, blue only 0.0722 and 8.59 to 1 on white. Below, the three luminance coefficients: red 0.2126, green 0.7152, blue 0.0722.

Pure yellow is hsl(60, 100%, 50%) and pure blue is hsl(240, 100%, 50%). Same saturation, same lightness. Their relative luminances are 0.9278 and 0.0722, a factor of nearly thirteen. The reason is sitting in the formula above: yellow is red plus green at full strength, so it collects 0.2126 plus 0.7152, which is 0.9278 exactly. Blue collects the 0.0722 term and nothing else. The weights are not arbitrary, they follow how sensitive human vision is to each part of the spectrum, and they make the middle of the lightness axis a fiction.

Three consequences follow. A step labelled 500 is not a fixed perceived brightness across hues, so a yellow 500 and a blue 500 are not interchangeable in a component. You cannot rotate a hue and assume the contrast comes with it, which is why the generator measures the accent afresh rather than inheriting the base reading. And two colours picked at matching HSL lightness will not look like a matched pair, because one of them is doing most of the shouting.

What to do about it is simple enough. Read the measured number on each swatch rather than trusting the step label. Expect yellow, green and cyan hues to need a much darker step before text on them passes, and expect blue and violet hues to pass on white at a lightness where a yellow would not come close. If you genuinely need a ramp whose steps are perceptually even, that is what LAB and OKLCH exist for, and this tool deliberately does not go there: it stays in the one space that maps directly onto the numbers people actually type into a stylesheet.

What it refuses to do

Bad input is refused rather than guessed at. Type something the parser cannot read and the field turns red, the message tells you it is keeping the last valid colour, and the palette does not move. An empty field is not treated as an error, because clearing a field is the normal first step in retyping one. Leaving the field normalises whatever is in it back to the current base hex. An out of range hsl() is wrapped on the hue and clamped on saturation and lightness, so hsl(400 120% 150%) resolves rather than failing.

The rest of the omissions are deliberate. There is no alpha channel, so translucent overlays are outside its scope. There is no CMYK or LAB output, which means it will not tell you what any of this does on paper, and what changes between screen and print is a separate problem with its own arithmetic. It does not auto-fix the palette itself: if your base fails on white, it says so and leaves the decision to you, because silently shifting somebody’s brand colour is worse than reporting the failure. And nothing is saved between visits, which follows from the fact that nothing leaves the browser in the first place. Copy the CSS variables or the JSON before you close the tab.

Working from one decision

The point of deriving instead of picking is not that arithmetic has better taste than you do. It is that arithmetic is consistent, and consistency is most of what people mean when they call a palette designed. Nine ramp steps built from one hue always relate to each other. Nine steps chosen by eye across three sessions do not, and no amount of later adjusting fixes it, because the problem is not any individual colour.

So the decision that is left to you is a smaller one, and a better one: which hue, and how far around the wheel the accent should go. Everything after that is a rule you can restate in a sentence. Move lightness for the ramp, cut saturation for the neutrals, rotate hue for the accent, and split the area 60, 30 and 10. Check the two contrast thresholds before you commit to anything a visitor has to read.

Interfaces are the easy case, because you control every colour in them. Photographs are not: the colour arrives with the picture and has to be steered rather than specified, and colour grading in five moves covers that side of the same problem. The measurement is identical either way, and a palette you can defend with numbers is one you can hand to somebody else without a paragraph of explanation attached.

Building a Colour Palette From One Decision

Table of Contents

Learn it by building something

Every week one thing you can make the same afternoon, from dynamic templates to 3D type. Written down step by step.

One mail a week, and then it ends.
Unsubscribe in one click.

Developer Tools

Dummy Text Generator: Lorem Ipsum That Behaves Like Real Copy

Lorem ipsum has a longest word of thirteen letters and no umlauts at all, so a layout tested with it is tested with the easiest text it will ever hold. What placeholder text should actually prove, and a generator that produces it.

Photo Editing

Cutting Things Out: Selections, Masks and the Art of the Edge

Amateur cut-outs are not spotted by their shape. They are spotted by a halo of the old background and hair that has been shaved off in a curve no head ever had.

Developer Tools

Favicon Generator: The Icon Files a Site Actually Needs

The favicon is the one image on your site nobody checks at the size everybody sees. Here is the short list of files a site still needs, the two measurements that decide whether your mark survives a browser tab and an Android mask, and exactly where the WordPress site icon stops.

Security & Privacy

Stopping WordPress Hotlinking Without Breaking Image Search

Hotlinking is another site's HTML pointing at your image URL, so your server pays for their page. Prove it from the access log before you block anything, then write a referrer rule at the web server level that still lets crawlers, CDNs and link previews through.

Photo Editing

Spend your JPEG bits where the eye looks, not evenly across the frame

An encoder gives the hedge behind your subject as many bits as the subject. A saliency model knows better, but a browser will not let you set quality per region, so the encoder is not steered: its input is prepared instead. On the sample that was 41 per cent off the file at an unchanged quality setting.

WordPress Images

WordPress Image Sizes Explained: Every File Created From a Single Upload

One upload becomes eight or more files. Here is what WordPress actually creates, why some sizes are missing, and what to do about it, with numbers measured on a real site.

Download the free WunderPaint Plugin for WordPress

The WunderPaint workspace with the layers panel, adjustment sliders, text style presets and the asset library along the bottom

The Image Editor & Design Studio

Everything described here can be done in the browser, on your own site. The live demo runs the full editor with nothing to install.

Free

Chaos Art

Autonomous painters make one-of-a-kind abstract art in 3D space - gestures, art movements, painterly media, and embeds that paint a new original for every visitor.

Pro

Particle Strokes

Paint with swarms of light: twenty-two movements, a stamp you draw yourself, and curves that give a stroke a shape - the swarm keeps painting for a few seconds after you let go.

Pro

City Diorama

Any place on earth as a miniature you could hold: real streets, water and building footprints raised into a 3D diorama - or wrapped around a sphere as your own tiny planet.

Free

Papercut Art

Layered paper pictures with real depth - a photo sliced along its actual depth into up to twenty layers, parametric landscapes, animals and clouds you can shape, letters with real counters, and a look that runs on three dials.

Pro

3D Earth Studio

A hyperrealistic globe - day and night with city lights, live clouds, atmosphere halo, country borders and highlights, click-to-place markers with flight-route arcs, satellite orbits, seamless rotation video and a live website embed.

Free

Mystic Studio

Turn a birth date into wall art - a real natal chart with houses and aspects, the moon of that night, zodiac and Chinese zodiac posters, numerology cards and a synastry wheel for two, in eight artful themes.

Free

Marble Bath

Marble paper on a virtual water bath - drop, rake and comb real Ebru patterns with gestures, flowers and classic recipes, razor-sharp at any size and re-editable as a layer.

Free

Day Ring

Turn a day into a beautiful circular schedule - colour-coded time blocks as arcs around a 24-hour clock, with concentric rings for overlaps, emoji, templates and a legend.

Free

Code Shot

Turn code into a gorgeous, share-ready image - syntax highlighting, editor themes, window frames and diff highlighting - then drop it into your design as a re-editable layer.

Pro

3D Solar System Studio

Build a date-accurate 3D solar system - real planet positions for any date, photoreal textures and one slider from artistic to true scale - then drop it into your design as an editable layer.

Pro

3D Molecule Studio

Build a real 3D molecule - from a curated library, the periodic table or a SMILES string - then style it, measure it and drop it into your design as an editable layer.

Pro

3D Textile Studio

Drop your design onto cloth that behaves like the material you pick: silk falls soft, felt holds its shape, flag fabric snaps in the wind. Hang it, blow it and drape it, then lay the finished drape back into your document as a picture.

Pro

3D Particle Studio

Point the engine at any layer and it becomes a cloud of particles that keeps its colours, flowing through a sphere, a galaxy or your own outline. Keep the frame you like as a still, or embed the running engine so it keeps moving on your page.

Free

Origami

Put your own picture on the paper and watch that very sheet fold itself into a crane or a box. Every step is a station you can stop at and turn around in 3D, which is exactly where printed diagrams leave you alone.

Pro

3D Flip Studio

A hardcover you can leaf through, a limp magazine, a strewn pile of sheets, a sticker peeling off its backing. The curl is real geometry, so the print never slides across the paper.

Free

Handwriting Fonts

Draw the alphabet here or fill in a printed sheet and photograph it. What comes out is a genuine font family, installed into your site and available in every picker.

Pro

Step Guides

Turn any picture into an instruction. Every mark is pinned to a place in the image, so arrows still point at the right thing after the callout has been dragged somewhere else.

Free

Text Art

One studio, sixteen art types: ASCII and emoji art, brick, dice, cube, sticky-note, LED, ceramic and keycap mosaics, word portraits, text flows, silhouettes, element tiles and more.

Free

Photo Mosaic

The classic photomosaic, computed in your browser: your main image emerges from many media-library photos via true structure matching - never a cheap overlay.

Free

Puzzle Sheets

Generate printable puzzle sheets: word search, mazes in eight shapes, sudoku with unique solutions, criss-cross, cryptograms and number pyramids.