An accessible color palette generator should do more than produce attractive swatches: it should make shade labels meaningful when those colors reach real interfaces. A new free, open-source project called Science Color Palette takes that premise seriously, generating hue ramps whose equivalent steps target the same relative luminance and, therefore, more consistent WCAG contrast behavior.

The project was introduced by Reddit user u/sir__hennihau in r/SaaS as a response to a familiar design-system frustration. Teams often treat labels such as blue-600, yellow-600, and teal-600 as if they represent equivalent visual and accessibility roles. In many popular palettes, they do not. A white label that feels comfortably readable over one hue at the same numeric step may be weak or unusable over another.

Science Color Palette’s central claim is provocative but practical: if a scale is meant to support component decisions, shade numbers should encode a predictable contrast relationship rather than a loose sense of darkness. The tool does not remove the need for UX judgment, typography testing, semantic tokens, or accessibility review. But it offers a more disciplined foundation for making those choices.

The design-system problem: shade numbers often overpromise

Color scales are one of the smallest-looking parts of a design system and one of the easiest to underestimate. A team picks a brand blue, adds a handful of supporting colors, assigns each a 50–900 or 50–950 ramp, and starts building. The real complexity appears later, when designers and developers try to reuse those values consistently across buttons, badges, alerts, charts, empty states, dark mode, and transactional email.

The underlying issue is that hue, perceived lightness, chroma, and measured luminance do not move together in an intuitive way. Bright yellow can look visually intense while being relatively light; saturated blue can look rich and strong while carrying much less luminance. A scale made by applying the same HSL or RGB adjustments to every hue can therefore give steps that look numbered consistently but behave very differently in use.

That distinction matters when teams create rules such as:

  • “Use 600 for primary button backgrounds.”
  • “Use white text on any 700 accent.”
  • “Use 500 for borders and non-text indicators.”
  • “Use 50 as the tinted surface behind an alert.”

Those rules are operationally valuable only if the shade labels are dependable. If yellow-600 and blue-600 produce sharply different contrast outcomes against their matching light surfaces, the component API is hiding an exception rather than expressing a system.

Stripe documented a version of this problem in its widely referenced accessible color-system work. The company described finding that its default text colors did not reliably meet contrast thresholds and concluded that asking every designer or engineer to manually select compliant pairings was not a sustainable system. (stripe.com)

Science Color Palette builds on that same systems-first instinct. Its goal is not to declare a single brand color “accessible.” Colors are not accessible in isolation; foreground/background pairs, text size, weight, rendering, and context all matter. Instead, it aims to make each step in a family more predictable relative to equivalent steps in another family.

What Science Color Palette does

The project is a browser-based palette generator and an open-source codebase. A user starts with one or more colors, and the tool produces a spectrum of related color families, a full shade ramp for each family, and tinted neutrals. The resulting palettes can be exported for use in a design or development workflow.

According to the project documentation, the intended output is a collection of hue families in which a given shade number carries the same contrast meaning across hues. The author explicitly avoids pre-labeling ramps as “success,” “warning,” or “danger,” treating the palette as raw material that a design system can map to semantic roles later. (github.com)

That separation is important. A red ramp is not automatically an error system; it might serve destructive actions, financial loss, a brand accent, a data visualization category, or a decorative illustration. Semantic naming belongs at the token layer, after the product team understands the role, context, and accessibility expectations for that color.

A luminance staircase, not a subjective darkness scale

The core technique is to place shade steps by relative luminance. Under the WCAG 2 contrast model, relative luminance is the quantity used to calculate the contrast ratio between a lighter and darker color. The familiar ratio formula is based on the luminance values of the two colors, not their hue names, saturation labels, or HSL lightness percentages. (w3.org)

In practical terms, Science Color Palette treats every color ramp as climbing the same luminance staircase. If the palette’s blue 600 and yellow 600 share the same luminance, they will produce the same WCAG contrast ratio against the same background luminance. That does not mean the two colors will look identical in intensity or emotional character. It means the numerical shade label has a more reliable accessibility consequence.

The project documentation describes fixed target guarantees for key steps measured against the ramp’s own light 50 shade: roughly 3:1 at 500, 4.5:1 at 600, and 7:1 at 700. It also says those checks are performed on the actual exported 8-bit hex values rather than only on idealized mathematical values. (github.com)

That final detail is unusually thoughtful. A theoretical color can cross a threshold, but conversion and rounding to the hex value actually shipped in CSS can move the final contrast slightly. WCAG treats thresholds as thresholds: a computed 4.499:1 does not pass a 4.5:1 requirement simply because it is close. (w3.org)

Why the tool tests against its own light surface

One of the subtler design decisions is measuring key contrast steps against the palette’s own 50 shade rather than pure white. In a real interface, a team may place dark colored text on a subtly tinted notice, card, banner, or status surface—not always on #ffffff.

This is a useful correction to a common workflow mistake. Designers may verify dark text against white, then use it on a lightly tinted component background and unintentionally reduce contrast below the intended target. By grounding the guarantee in the palette’s actual light surface, the generator makes a claim closer to a likely component use case.

Still, that is not a universal safety guarantee. If a product uses a different gray, overlay, gradient, image background, transparency effect, or dark-mode surface, the pair must be checked in that real context. A palette scale can make safe defaults easier; it cannot replace pair-level testing.

Why Oklab and OKLCH are central to the approach

Science Color Palette follows Stripe’s broader idea of constructing an accessible color system but uses Oklab and OKLCH rather than CIELAB as its working color space. That choice reflects how web color tooling has evolved since Stripe published its article.

Oklab was designed by Björn Ottosson as a perceptual color space that predicts perceived lightness, chroma, and hue more usefully than simple device-oriented spaces such as RGB. The model was designed to be numerically practical while providing better perceptual behavior for common graphics and design tasks. (bottosson.github.io)

For a palette generator, the practical advantage is substantial. In RGB, moving a value by the same amount does not create equal-looking changes. In HSL, an identical “lightness” setting can leave a yellow far brighter than a blue. In perceptual spaces, designers can reason more directly about lightness, colorfulness, and hue while still converting the results to the sRGB hex codes that most web products ship.

The chroma-envelope idea

The project also uses a hue-aware chroma strategy. Instead of assigning every hue the same fixed maximum saturation, it calculates how much chroma is possible for that hue at a particular lightness within the displayable gamut.

This is important because color spaces are not boxes where every hue can reach every combination of lightness and vividness. Bright yellow can remain highly chromatic at light values, while blue often carries more vividness in darker territory. Attempting to force every hue to the same saturation curve either creates dull results in one area or out-of-gamut results in another.

The Science Color Palette documentation explains that the tool calculates the available chroma envelope for each hue, allowing yellow to peak in vividness earlier and blue later without special-case, hand-authored rules for specific colors. It also checks the final output against display constraints rather than assuming an abstract color is available on screen. (github.com)

That is a genuine design-system advantage. It respects the physical and perceptual limits of color rather than trying to flatten them into one arbitrary formula. The result may feel less mechanically uniform at a glance, but it should be more coherent in the ways that matter for usable UI scales.

Native CSS is catching up

The approach is also increasingly relevant to front-end engineering. CSS Color Module Level 4 includes oklab() and oklch() color functions, and the CSS Working Group has adopted Oklab/OKLCH for modern color syntax and interpolation-related work. (w3.org)

That does not mean every production system should immediately replace all hex values with OKLCH declarations. Hex remains broadly familiar, easy to inspect, and useful for tool compatibility. But modern CSS now gives teams a more capable vocabulary for authoring, interpolating, and eventually generating colors. A tool that thinks in OKLCH while exporting practical tokens is aligned with where web color standards are heading.

WCAG contrast guarantees: useful, specific, and limited

The most compelling part of the project is its attempt to turn key shade numbers into explicit contrast targets. The author’s proposed landmarks correspond to familiar WCAG 2 thresholds:

  1. 3:1 is commonly associated with large text under WCAG AA and with contrast requirements for certain non-text UI components and graphical objects.
  2. 4.5:1 is the WCAG AA minimum for normal-size text.
  3. 7:1 is the WCAG AAA minimum for normal-size text.

W3C guidance states that normal text needs at least 4.5:1 under Success Criterion 1.4.3, while large-scale text can use 3:1. It also makes clear that values should not be rounded up when evaluating a pass/fail threshold. (w3.org)

For product teams, turning those ratios into palette landmarks can simplify handoffs. Instead of every developer asking whether orange-600 is adequate for text over orange-50, a token specification can state the expected contrast relationship directly. That reduces repeated calculations and lowers the chance that a component quietly diverges from the system.

What a 4.5:1 target does not tell you

A WCAG 2 contrast ratio is valuable, but it is not a full readability model. It does not know whether the text is 12px or 32px, whether the font is thin or bold, whether the reader is scanning a dense table, whether the background is textured, or whether the color pairing is light-on-dark versus dark-on-light.

It also does not cover every accessibility concern. A button can pass contrast and still be difficult to understand if color alone communicates state. A chart can have high-contrast lines but remain confusing for color-vision differences. A passing text color can be placed in a tiny, low-weight font that is still uncomfortable to read.

In other words, the tool’s guarantees are best understood as color-pair constraints, not as a declaration that a component is universally accessible. That framing is not a weakness; it is a more honest way to use palette automation.

The APCA debate in the community reaction

The top community critique of the project focused on a real limitation of conventional WCAG 2 ratios: they are polarity-blind. A 4.5:1 ratio treats black text on a light background and white text on a dark background as mathematically equivalent. Many designers and accessibility specialists argue that the perceptual reading experience is not equivalent.

The commenter noted that white text on a dark 600 shade can technically meet 4.5:1 yet feel weaker than the opposite polarity. They suggested APCA—the Accessible Perceptual Contrast Algorithm—as a better model because it evaluates that asymmetry directly.

That criticism is technically well grounded. APCA produces a signed lightness-contrast value and is polarity-aware: the order of text and background matters. Its documentation specifically instructs users to supply text and background in the correct order for accurate prediction, unlike WCAG 2’s symmetric ratio. (git.apcacontrast.com)

The project author agreed with the main point but made an equally practical counterargument: WCAG 2 is still what many teams must use for current compliance work. The author also said the tool includes APCA information in its pair table and reports a minimum value across both polarities, attempting to expose rather than ignore the dark-mode problem.

The right conclusion is “both,” not “either/or”

For SaaS teams, the most useful takeaway is not that WCAG is obsolete or that APCA should be ignored. It is that the two tools answer different operational questions today.

Use WCAG 2 contrast ratios when you need to assess current requirements built around WCAG 2.x success criteria. Use APCA as an additional readability signal, especially for dark themes, light text on saturated surfaces, small typography, and dense data interfaces. APCA remains a developing methodology and should not be casually presented as a universal replacement for all present-day compliance obligations. Its own documentation describes it as a newer algorithm and provides separate guidance for its usage. (git.apcacontrast.com)

A mature workflow can therefore keep the Science Color Palette luminance ladder for predictable WCAG-oriented tokens while using APCA to flag pairings that may be technically compliant but visually fragile. That is much stronger than relying on a single ratio or on designers eyeballing color combinations in a mockup.

How this compares with Tailwind-style color scales

Tailwind’s palette has been enormously influential because it makes color selection fast and offers a recognizable vocabulary for UI work. For many projects, choosing slate-100, blue-600, and rose-700 is more productive than inventing an entire color system from scratch.

But convenience palettes are not necessarily semantic contrast systems. A numeric label can describe a position within a particular hue family without promising that the same number is interchangeable across all families. This is the gap Science Color Palette is designed to address.

The project’s documentation specifically contrasts its approach with popular reference palettes, arguing that values with the same number can differ materially in lightness and contrast behavior across hues. Its example notes that a yellow midpoint and blue midpoint may produce different outcomes against white despite sharing the same numeric suffix. (github.com)

That does not make Tailwind “wrong.” Tailwind solves a broad developer-experience problem: it supplies a practical, visually curated starting point. Science Color Palette solves a narrower but consequential system-design problem: it tries to make the numbering itself a reliable accessibility and compositional contract.

When a conventional palette is enough

A conventional palette may be sufficient when:

  • You are building a prototype or internal tool with limited color usage.
  • Your design relies primarily on neutral surfaces and one carefully tested brand color.
  • You use semantic variables that have already been audited in their actual components.
  • Your team is comfortable maintaining explicit exceptions for warning yellow, success green, and other difficult hues.

When a consistent-contrast generator is more valuable

Science Color Palette is more compelling when:

  • You are creating a reusable product design system.
  • Multiple teams need to make safe color choices without asking a designer each time.
  • Your product uses many status colors, data visualizations, tenant themes, or branded variants.
  • You need both light surfaces and dark solid fills across multiple hue families.
  • You want shade labels to become dependable API primitives rather than aesthetic suggestions.

The larger the system, the more expensive color exceptions become. A generator that removes some of those exceptions at the source can be worth more than a beautiful but inconsistent static swatch sheet.

A practical workflow for teams adopting generated palettes

The best way to use an accessible color palette generator is not to export a scale and immediately wire raw values into every component. Treat the output as the foundation for a token system.

Step 1: Start with brand constraints, not only a hex code

Bring in the colors that are genuinely fixed: your core brand mark, required partner colors, category colors, and any established product conventions. Then evaluate whether each needs to be represented as a full interactive ramp or only as an illustrative accent.

A logo color may be ideal for a mark and terrible for body-text links. Preserving it as brand identity does not require making it the primary button fill.

Step 2: Generate the scale, then inspect the difficult hues

Pay special attention to yellow, lime, orange, cyan, and highly saturated blue or violet. These hues often expose the limitations of simplistic scales. Look for abrupt changes in perceived saturation, muddy dark steps, and light steps that no longer feel like part of the intended family.

The purpose of a chroma-envelope approach is to handle those variations systematically, but human review still matters. Check the colors in your actual product environment, not only as isolated swatches.

Step 3: Create semantic tokens

Do not make every component depend on raw tokens such as blue-600. Introduce semantic layers such as:

--color-action-primary-bg: var(--color-brand-600);
--color-action-primary-text: var(--color-brand-50);
--color-notice-warning-bg: var(--color-yellow-50);
--color-notice-warning-text: var(--color-yellow-700);
--color-border-focus: var(--color-brand-600);

This protects the product from future palette changes. If testing later finds that a dark-mode button needs a different pairing, teams can update the semantic mapping rather than search-and-replace a raw shade across the codebase.

Step 4: Test complete pairs in real components

Check foreground, background, border, icon, hover, focus, disabled, selected, and error states. Test text at the actual font size and weight used in the interface. A palette-level target is a strong starting point, but it does not automatically validate translucent layers, gradients, background images, or anti-aliased icon edges.

For email builders, this discipline is especially important. Email clients may alter rendering assumptions, and a visually subtle status banner can be seen in inconsistent environments. Before sending a high-stakes notification, validate the actual recipient addresses with an email address verification tool and validate the message’s final HTML colors in representative clients; deliverability and readable communication are separate but equally important parts of a trustworthy send.

Step 5: Add APCA review for risky text combinations

Use APCA checks as a second pass for small text and reverse-polarity combinations. If a white-on-dark pairing barely clears WCAG 2, consider changing the text, background, font weight, font size, or component treatment rather than treating the pass as the finish line.

This becomes especially important in dark mode. Dark interfaces invite lower-contrast decoration and light text over colorful surfaces, precisely where a polarity-aware readability signal can reveal weaknesses a symmetric ratio will not.

The bigger opportunity: color scales as product infrastructure

The strongest idea behind Science Color Palette is not its specific algorithm. It is the belief that palettes should behave like infrastructure.

Good infrastructure reduces repeated decision-making. A well-designed API means developers do not need to remember incidental details. A good component library lets teams compose layouts without rebuilding controls. In the same way, a robust color scale should let a team infer likely contrast behavior from the token itself instead of re-solving the color problem in every feature.

That can improve speed and consistency in several ways:

  • Fewer visual regressions: equivalent color steps are less likely to create surprising contrast failures between hue families.
  • Clearer documentation: teams can describe what a shade is safe for, not only what it looks like.
  • More resilient theming: tenant or campaign colors can be turned into usable ramps rather than patched manually.
  • Better designer-developer handoff: numeric values gain shared meaning across Figma files, CSS variables, and component code.
  • Less accessibility debt: teams catch structural contrast issues while defining tokens rather than during late-stage audits.

For founders and product leads, this also changes the economics of design quality. Accessibility work is often framed as a review task that arrives near launch. But systematic palette generation shifts some of that work upstream, where it is cheaper to make changes and easier to apply them everywhere.

Limitations to keep in mind before adopting it

The project is promising, but it should be evaluated as an open-source design tool—not as a compliance certificate.

First, a uniform luminance scale does not guarantee perceptual uniformity in every UI context. Font rendering, text size, adjacent colors, motion, screen brightness, and user vision all affect the final experience.

Second, WCAG contrast is not the same thing as usability. A 4.5:1 pair can technically pass while still being a poor choice for a dense dashboard, low-weight text, a bright outdoor setting, or an older audience. Conversely, an excellent palette cannot fix unclear interaction language or a workflow that relies only on color to communicate errors.

Third, gamut handling deserves testing on the environments your users actually have. The project checks output against displayability, but products may use wide-gamut assets, browser-specific rendering, CSS blending, screenshots, native wrappers, or exported PDFs that alter the visual result.

Finally, generated palettes still need brand judgment. Sometimes a mathematically disciplined ramp will reveal that a company’s preferred color simply cannot support all intended roles. That is useful information, even if it is not the answer stakeholders hoped for.

Conclusion: make shade labels earn their meaning

Science Color Palette is a thoughtful contribution to a problem that most design teams recognize but often work around manually. Its core proposition—that the same shade number should mean the same luminance and contrast relationship across hue families—makes intuitive sense for anyone building a scalable interface system.

The tool’s use of OKLCH, gamut-aware chroma limits, final-hex verification, and WCAG-based landmarks gives it more substance than a typical palette picker. The Reddit discussion also highlights the necessary caveat: WCAG 2 contrast ratios are not polarity-aware, so teams should use APCA and real-component testing to assess reverse-polarity text, dark themes, and borderline choices.

For builders, the practical lesson is straightforward. Stop treating 600 as a decorative label. Treat it as an interface contract. If a palette can make that contract more consistent, it can reduce design debt long after the swatches have been exported.

FAQ

What is an accessible color palette generator?

An accessible color palette generator creates color ramps while considering measurable accessibility properties, especially contrast between foreground and background colors. The strongest tools help teams generate consistent design tokens rather than only visually pleasing swatches.

Does a 4.5:1 contrast ratio guarantee readable text?

No. It is an important WCAG 2 threshold for normal text, but readability also depends on font size, weight, text polarity, surrounding content, screen conditions, and the reader’s visual needs. Use the ratio as a baseline, then test the real component.

Why can yellow-600 and blue-600 have different contrast?

Different hues can have very different relative luminance even when they share the same numeric shade label. Yellow is naturally much lighter than blue in many conventional color scales, so identical-looking labels do not necessarily produce identical contrast outcomes.

What is the difference between WCAG contrast and APCA?

WCAG 2 uses a symmetric contrast ratio based on relative luminance. APCA uses a polarity-aware lightness-contrast model, meaning it distinguishes dark text on light backgrounds from light text on dark backgrounds. WCAG 2 remains important for current conformance work, while APCA can add useful readability insight.

Should teams use raw palette tokens directly in components?

Usually no. Use raw tokens to build semantic tokens such as --color-button-primary-bg or --color-alert-warning-text. This makes your system easier to audit, theme, and update when palette testing reveals a better pairing.