Metodologia

Esta página existe para duas situações: você está comparando geradores de escala e quer saber o que de fato muda, ou precisa justificar uma paleta para um time e quer algo mais específico do que "ficou bom".

Por que composição em vez de interpolação em HSL

A abordagem comum é fixar matiz e saturação e caminhar a luminosidade de quase 100% até quase 0%. É simples, e é por isso que tantas escalas geradas têm um ar de família.

O problema é que a luminosidade do HSL não é uma grandeza perceptual. Nos extremos, manter o S constante enquanto o L se aproxima de 0 ou de 100 espreme o gamut disponível, e as pontas escorregam para uma lavagem da matiz em vez de uma versão escura ou clara reconhecível dela. Dá para ver melhor em laranjas e amarelos saturados.

A composição alfa falha de outro jeito, e por acaso é o jeito mais útil aqui. Colocar a cor sobre branco ou preto é uma interpolação linear em RGB rumo a um ponto fixo, então a matiz é preservada por construção — não existe mecanismo pelo qual ela pudesse escorregar. As pontas são branco tingido e preto tingido, que é normalmente o que um shade 50 ou 950 deveria ser.

O custo, sem rodeio: a claridade percebida entre os passos é irregular, e é irregular de um jeito diferente para cada matiz. Um amarelo 400 é lido como muito mais claro que um azul 400 na mesma opacidade. Se o seu design system depende de o número do shade significar a mesma claridade percebida em todas as cores, esta é a ferramenta errada e um gerador baseado em LCH é a certa.

Cores semânticas, e a checagem que quase ninguém faz

A partir de uma cor de marca, o motor propõe seis papéis semânticos. A restrição interessante não é contraste — é distinguibilidade mútua.

Várias ferramentas checam a razão de contraste contra um fundo, o que responde "dá para ler este texto". Bem poucas checam se o seu vermelho de error e o seu verde de success são distinguíveis entre si para quem tem deficiência de visão de cores no eixo vermelho-verde. Essa é a falha que chega em produção: uma coluna de status em que todas as linhas parecem idênticas para cerca de 8% dos homens.

O motor trabalha em OKLCH, em quatro etapas:

  1. Ancora cada papel numa família de matiz. Error fica em 340–24°, warning em 22–58°, success em 100–165°, info em 192–235° e discovery em 250–300°. Semântica de cor é convenção cultural — sair da família compraria distância perceptual ao preço de uma paleta que ninguém lê corretamente.
  2. Amostra candidatas a cada 3° dentro da família, gerando cada uma já na luminosidade e no croma que a cor final vai usar, para que o ranking avalie exatamente as cores que serão produzidas.
  3. Pontua cada candidata pela distância CIEDE2000 contra todas as cores já reservadas, inclusive a sua cor base.
  4. Faz essa pontuação sob simulação de protanopia, deuteranopia e tritanopia, e guarda o pior dos três resultados. Uma candidata vale o que vale o seu caso mais fraco.

A simulação usa as matrizes de Machado et al. (2009) em severidade máxima, aplicadas sobre sRGB linearizado. O CIEDE2000 entra no lugar da distância euclidiana em RGB porque aproxima a percepção humana — ele pega colisões que a distância em RGB simplesmente não vê.

O limiar de aprovação é ΔE₀₀ ≥ 11, medido como o mínimo entre as três simulações.

Derivadas de #3b82f6
SugeridaProtanopiaDeuteranopiaTritanopia
success56.253.513.9
warning58.261.571.6
error15.019.566.0
discovery4.62.329.2
info16.414.09.2
neutral20.922.816.5
Distância CIEDE2000 até a base sob cada simulação. O menor dos três é o que decide, e um ponto marca os que ficam abaixo de 11.

O que acontece quando duas cores colidem

Às vezes dois papéis ainda caem perto demais — o que é mais frequente quando a sua cor base fica dentro de uma das famílias semânticas, situação comum em marcas azuis e verdes. A tabela acima mostra isso acontecendo: naquele azul, discovery fica a ΔE₀₀ 2,3 da base sob deuteranopia, e info a 9,2 sob tritanopia.

Quando um par fica abaixo do limiar, o motor não desloca a que for mais conveniente. Ele compara o quanto cada cor já se afastou do seu matiz canônico e move a que se afastou mais, preservando no meio da família aquela que ainda está onde o leitor espera. E só aceita a substituição se ela de fato aumentar a distância entre as duas.

É nessa negociação que a paleta deixa de ser uma tabela de consulta. Para uma marca crimson, o vermelho de error sugerido precisa contornar a própria base; para uma teal, o par sob pressão é success e info. As sugestões que você vê são o resultado dessa disputa, e é por isso que mudam a cada cor de entrada.

O que isto não faz

Não checa razão de contraste por você. Uma escala pode ser perfeitamente consistente em matiz e ainda assim reprovar no WCAG para texto corrido no shade que você escolheu — isso depende do fundo, do tamanho e do peso da fonte, e o gerador não sabe nada disso.

Também não modela tricromacia anômala, a forma parcial e bem mais comum de deficiência de visão de cores. A dicromacia completa é a restrição mais dura, então passar nela é uma aproximação razoável — mas é uma aproximação.

E não tem como dizer se o resultado é certo para o seu produto. Só consegue dizer que as cores estão distantes o bastante para serem diferenciadas.