DebugSwift

Brand Kit Generator

One colour in. A palette you can actually use out.

Ten steps built so the gaps look even to a human eye, each one telling you whether black or white text passes on it. Plus a type scale from a single base size. Copy the CSS and go.

A hex code. Everything below is built from this one value.

The palette

Ten steps built by walking perceptual lightness, so the gaps look even rather than measuring even. Each row says which text colour is legible on it — measured, not guessed.

  • 50#ddffea

    Black 19.57 · White 1.07

    black text passes AA here

  • 100#bbfdd7

    Black 18.14 · White 1.16

    black text passes AA here

  • 200#a7e9c4

    Black 15.10 · White 1.39

    black text passes AA here

  • 300#8ecfaa

    Black 11.66 · White 1.80

    black text passes AA here

  • 400#72b28f

    Black 8.48 · White 2.48

    black text passes AA here

  • 500#569674

    Black 6.01 · White 3.49

    black text passes AA here

  • 600#3e7e5d

    Black 4.35 · White 4.83

    white text passes AA here

  • 700#226344

    Black 2.94 · White 7.15

    white text passes AA here

  • 800#004a2d

    Black 2.02 · White 10.41

    white text passes AA here

  • 900#002c19

    Black 1.37 · White 15.28

    white text passes AA here

Ratios are WCAG 2.1 contrast, computed on the hex above. AA wants 4.5 for body text and 3 for large text — 24px and up, or 19px and up if it's bold. A step with neither black nor white passing is a background for shapes, not for words.

The neutrals

Greys carrying a trace of your hue. Pure greys next to a saturated brand colour read as dirty — a shared hue is what makes a palette look like one family rather than two projects.

  • 50
  • 100
  • 200
  • 300
  • 400
  • 500
  • 600
  • 700
  • 800
  • 900

Which pairs you can actually use

The question a palette never answers: put THIS text on THAT background — does it pass? Every cell is measured. AA needs 4.5 for body text.

Contrast ratio for each text colour on each background colour
Text on →50100Brand 50Brand 500Brand 900900
Neutral 900Aa14.26passAa13.05passAa14.40passAa4.42failAa1.01failAa1.00fail
Neutral 600Aa4.64passAa4.24failAa4.68passAa1.44failAa3.04failAa3.08fail
Brand 700Aa6.60passAa6.04passAa6.66passAa2.05failAa2.14failAa2.16fail
Neutral 50Aa1.00failAa1.09failAa1.01failAa3.22failAa14.10passAa14.26pass

The type scale

Ratio

Confident. Good for marketing pages.

  • Small print14px · 0.875rem · 1.5
  • Body18px · 1.125rem · 1.6
  • Lead paragraph23px · 1.438rem · 1.5
  • Heading 328px · 1.75rem · 1.35
  • Heading 235px · 2.188rem · 1.25
  • Heading 144px · 2.75rem · 1.15
  • Display55px · 3.438rem · 1.05

Take it with you

Paste this straight into your stylesheet. Nothing here needs a build step or a library.

CSS custom properties

:root {
  --brand-50: #ddffea;
  --brand-100: #bbfdd7;
  --brand-200: #a7e9c4;
  --brand-300: #8ecfaa;
  --brand-400: #72b28f;
  --brand-500: #569674;
  --brand-600: #3e7e5d;
  --brand-700: #226344;
  --brand-800: #004a2d;
  --brand-900: #002c19;

  --neutral-50: #eff8f2;
  --neutral-100: #e5eee8;
  --neutral-200: #d1dad5;
  --neutral-300: #b8c0bb;
  --neutral-400: #9ca49f;
  --neutral-500: #808883;
  --neutral-600: #69716c;
  --neutral-700: #505753;
  --neutral-800: #383f3b;
  --neutral-900: #1f2622;

  --text-small-print: 0.875rem;
  --leading-small-print: 1.5;
  --text-body: 1.125rem;
  --leading-body: 1.6;
  --text-lead-paragraph: 1.438rem;
  --leading-lead-paragraph: 1.5;
  --text-heading-3: 1.75rem;
  --leading-heading-3: 1.35;
  --text-heading-2: 2.188rem;
  --leading-heading-2: 1.25;
  --text-heading-1: 2.75rem;
  --leading-heading-1: 1.15;
  --text-display: 3.438rem;
  --leading-display: 1.05;
}

Tailwind v4 theme

@theme {
  --color-brand-50: #ddffea;
  --color-brand-100: #bbfdd7;
  --color-brand-200: #a7e9c4;
  --color-brand-300: #8ecfaa;
  --color-brand-400: #72b28f;
  --color-brand-500: #569674;
  --color-brand-600: #3e7e5d;
  --color-brand-700: #226344;
  --color-brand-800: #004a2d;
  --color-brand-900: #002c19;

  --color-neutral-50: #eff8f2;
  --color-neutral-100: #e5eee8;
  --color-neutral-200: #d1dad5;
  --color-neutral-300: #b8c0bb;
  --color-neutral-400: #9ca49f;
  --color-neutral-500: #808883;
  --color-neutral-600: #69716c;
  --color-neutral-700: #505753;
  --color-neutral-800: #383f3b;
  --color-neutral-900: #1f2622;
}

JSON (design tokens)

{
  "color": {
    "brand": {
      "50": {
        "value": "#ddffea",
        "onWhite": 1.07,
        "onBlack": 19.57
      },
      "100": {
        "value": "#bbfdd7",
        "onWhite": 1.16,
        "onBlack": 18.14
      },
      "200": {
        "value": "#a7e9c4",
        "onWhite": 1.39,
        "onBlack": 15.1
      },
      "300": {
        "value": "#8ecfaa",
        "onWhite": 1.8,
        "onBlack": 11.66
      },
      "400": {
        "value": "#72b28f",
        "onWhite": 2.48,
        "onBlack": 8.48
      },
      "500": {
        "value": "#569674",
        "onWhite": 3.49,
        "onBlack": 6.01
      },
      "600": {
        "value": "#3e7e5d",
        "onWhite": 4.83,
        "onBlack": 4.35
      },
      "700": {
        "value": "#226344",
        "onWhite": 7.15,
        "onBlack": 2.94
      },
      "800": {
        "value": "#004a2d",
        "onWhite": 10.41,
        "onBlack": 2.02
      },
      "900": {
        "value": "#002c19",
        "onWhite": 15.28,
        "onBlack": 1.37
      }
    },
    "neutral": {
      "50": {
        "value": "#eff8f2"
      },
      "100": {
        "value": "#e5eee8"
      },
      "200": {
        "value": "#d1dad5"
      },
      "300": {
        "value": "#b8c0bb"
      },
      "400": {
        "value": "#9ca49f"
      },
      "500": {
        "value": "#808883"
      },
      "600": {
        "value": "#69716c"
      },
      "700": {
        "value": "#505753"
      },
      "800": {
        "value": "#383f3b"
      },
      "900": {
        "value": "#1f2622"
      }
    }
  },
  "type": {
    "small-print": {
      "size": "0.875rem",
      "lineHeight": 1.5
    },
    "body": {
      "size": "1.125rem",
      "lineHeight": 1.6
    },
    "lead-paragraph": {
      "size": "1.438rem",
      "lineHeight": 1.5
    },
    "heading-3": {
      "size": "1.75rem",
      "lineHeight": 1.35
    },
    "heading-2": {
      "size": "2.188rem",
      "lineHeight": 1.25
    },
    "heading-1": {
      "size": "2.75rem",
      "lineHeight": 1.15
    },
    "display": {
      "size": "3.438rem",
      "lineHeight": 1.05
    }
  }
}

Why the steps look right

Even numbers aren't even colours.

The usual way to build a ramp is to hold the hue and walk lightness in HSL. It's also why so many generated palettes have muddy middles: HSL's lightness isn't perceptual. Pure yellow and pure blue both sit at 50%, and one of them is blinding.

This builds the ramp in OKLCh instead, a space designed so equal steps in lightness look like equal steps. When a step would be too saturated for a screen to show, the saturation comes down rather than the channels being clipped — clipping is what shifts the hue and gives you a ramp that drifts from orange to brown.

The contrast figures are measured, not estimated. The lightness targets and the line-height suggestions are opinions, and the tool says which is which rather than presenting all of it as fact.

If you need the whole system — logo, type, the rules for using them — that's brand & design systems work, and it starts with a conversation rather than a hex code.

Common questions

What makes this different from other palette generators?

Two things. The ramp is built in a perceptual colour space, so the steps look evenly spaced instead of merely being evenly spaced in numbers — the usual approach produces muddy middles and ends that bunch up. And every step tells you whether black or white text actually passes contrast on it, which is the question you'll hit the moment you try to use the colour.

Are the contrast numbers reliable?

They're the WCAG 2.1 formula computed on the exact hex shown, so yes. Worth being precise about what they cover: contrast between a text colour and a solid background. They say nothing about text over a photo, over a gradient, or at a weight so light it's hard to read at any ratio.

Is this my brand identity, then?

No. It's a starting palette and a type scale — the mechanical part. A brand is what you sound like and what you're for, and no tool derives that from a hex code. This gets you a coherent set of colours to build with instead of picking shades one at a time until they clash.

Why does one of my steps say no text colour passes?

Because it's a mid-tone. Colours in the middle of the lightness range are too dark for black text and too light for white, and no amount of wanting changes that. Use it for a shape, a border, or a chart fill, and put words on the steps that pass.

Beyond the palette

Colours are the easy half.

The hard half is a set of rules everyone actually follows, so the site, the invoice and the van all look like the same company.

Book a free diagnosisTwenty minutes. No pitch, no obligation.

Fixed price agreed before work starts. No hourly billing, no surprises.