A biblioteca inteira: 221 espaços, 71 kB com gzip — de qualquer espaço para qualquer outro, nos dois sentidos.
npm install color-space
import space from 'color-space' space.rgb.oklch(255, 128, 0) // → [0.732, 0.186, 53] space.oklch.rgb(0.65, 0.1, 180) // → [56.14, 162.97, 145.41] space.oklch.range // [[0,1], [0,0.4], [0,360]]
Ou um único espaço — o bundle não leva mais nada.
import oklch from 'color-space/oklch.js' oklch.rgb(0.65, 0.1, 180) // → [56.14, 162.97, 145.41]
Tipado: as declarações TypeScript vêm no pacote, para a biblioteca inteira e para cada espaço sozinho.
Para imagens inteiras e buffers longos: 54 espaços, 53 kB com gzip, de 1.4 a 4.8× mais rápido que o lote em JS nas 26 conversões medidas.
import space, { alloc } from 'color-space/wasm'
space.oklch.rgb(0.72, 0.16, 41) // → [246, 125, 79]
const buf = alloc(n) // n×3 Float64Array
space.rgb.oklch(buf) // in place
O módulo não importa nada, então roda onde quer que o WebAssembly rode: navegadores, Node, Deno, Bun — e Python, Rust ou Go via wasmtime ou wasmer.
import struct
from wasmtime import Store, Module, Instance # pip install wasmtime
store = Store() # color-space.wasm: the npm package's dist/
cs = Instance(store, Module.from_file(store.engine, 'color-space.wasm'), []).exports(store)
at = cs['alloc'](store, 1.0) & 0xFFFFFFFF # the buffer: n×3 float64 in the kernel's memory
cs['memory'].write(store, struct.pack('3d', 255, 128, 0), at)
cs['rgb_lrgb_n'](store, 1.0) # in place, edge by edge: rgb → linear rgb → oklab
cs['lrgb_oklab_n'](store, 1.0)
struct.unpack('3d', cs['memory'].read(store, at, at + 24)) # (0.732, 0.112, 0.148)
Espaços rgb, lrgb, xyz, xyz-d50, xyy, lms, p3, p3-linear, rec2020, rec2020-linear, a98rgb, a98rgb-linear, prophoto, prophoto-linear, rec709, hsl, hsv, hwb, oklab, oklrab, oklch, oklrch, lab, lchab, lab-d65, lch-d65, din99o-lab, din99o-lch, luv, lchuv, hsluv, hpluv, cam16, hct, ycbcr-bt709, ycbcr-bt2020, jzazbz, jzczhz, ictcp, ictcp-hlg, ipt, din99d, acescg, acescct, acescc, awg3, logc3, logc4, slog3, vlog, log3g10, clog2, ryb, munsell
Os 221 espaços como funções de shader. Uma conversão para rgb devolve 0–255, como em JavaScript: divida por 255 para uma cor de fragmento.
WebGL e OpenGL: GLSL.
import { glsl } from 'color-space/gl'
import oklch from 'color-space/gl/oklch'
const frag = `#version 300 es
precision highp float;
${glsl(oklch, 'rgb')}
out vec4 color;
void main() { color = vec4(oklch_rgb(vec3(0.7, 0.15, gl_FragCoord.x)) / 255.0, 1.0); }`
WebGPU: WGSL.
import { wgsl } from 'color-space/gl'
const code = wgsl(oklch, 'rgb') + `
@fragment fn main(@builtin(position) p: vec4f) -> @location(0) vec4f {
return vec4f(oklch_rgb(vec3f(0.7, 0.15, p.x)) / 255.0, 1.0);
}`
DirectX, Unity e Unreal: HLSL. Metal: MSL. Ambos gerados a partir do WGSL pelo naga, uma dependência opcional.
import { hlsl } from 'color-space/gl/hlsl' // npm i naga-wasm
import { msl } from 'color-space/gl/msl'
await hlsl('oklch', 'rgb') // float3 oklch_rgb(float3)
await msl('oklch', 'rgb') // metal::float3 oklch_rgb(metal::float3)Converta suas imagens no editor: escolha dois espaços e baixe um .cube para Resolve, Premiere, Final Cut, OBS ou ffmpeg. As conversões de logs de câmera coincidem com as transformações ACES oficiais da Academia.
Leve um espaço para o Photoshop, o gerenciamento de cores do seu sistema, o lcms ou o ImageMagick: baixe-o como perfil .icc. Os espaços RGB servem como espaços de trabalho no Photoshop; os demais convertem por uma tabela de consulta.
Para agentes de IA: eles chamam conversões verificadas em vez de adivinhá-las.
npx -y color-space mcp
// Claude Code
claude mcp add color-space -- npx -y color-space mcp
// VS Code
code --add-mcp '{"name":"color-space","command":"npx","args":["-y","color-space","mcp"]}'
// Claude Desktop · Cursor · .mcp.json
{ "mcpServers": { "color-space": { "command": "npx", "args": ["-y", "color-space", "mcp"] } } }Os preenchimentos e traços da seleção em qualquer um dos 221 espaços — um plano e uma barra por canal, limitados ao gamut do arquivo; copie a cor como CSS.
Todas as cores do arquivo — CSS, Swift, Flutter, Compose, Unity, design tokens — em qualquer um dos 221 espaços, com um plano e uma barra por canal; ao editar, a cor é regravada na sua própria notação.
Um sistema de coordenadas para a cor: eixos, intervalos e uma regra que vincula os números à luz mensurável. A visão humana é tricromática, com três tipos de cones (S, M, L), por isso três coordenadas são o mínimo para descrever qualquer cor que o olho consegue ver. O mesmo laranja é rgb(255 128 0), oklch(0.732 0.186 53) e XYZ [49, 36.7, 4.5]. Uma paleta é um punhado de cores escolhidas; um espaço é uma forma de registrar qualquer cor.
Um modelo de cor define os componentes usados para descrever uma cor: três primárias no RGB, matiz, saturação e claridade no HSL, quatro tintas no CMYK. Um espaço de cor especifica as primárias, o ponto branco e a curva de codificação, para que cada conjunto de valores corresponda a uma cor mensurável. Por isso, rgb(255 0 0) representa vermelhos diferentes em sRGB, Display P3 e Adobe RGB: um modelo, três espaços.
No uso comum, ambos são chamados de espaços, inclusive no color-mix(in hsl, …) do CSS e neste catálogo. Um modelo pode usar um espaço já definido como referência: aqui, HSL e HSV são derivados do sRGB, como no CSS.
Depende da tarefa:
Para ver todos os espaços organizados por tarefa, agrupe o catálogo por finalidade.
OKLCH. Ele mantém os mesmos três parâmetros — matiz, croma, claridade –, mas a claridade dele corresponde à percebida: no HSL, o amarelo em L=50 emite cerca de 13 vezes a luz do azul em L=50, então L igual não significa brilho igual. No OKLCH, significa. O CSS tem suporte nativo a oklch().
Digite ou cole o valor no campo de cor no topo, por exemplo #ff8000. Todos os espaços da página mostram essa cor ao mesmo tempo; em OKLCH os valores são 0.732, 0.186, 53, que o CSS escreve como oklch(0.732 0.186 53). A aba css de cada dossiê traz a forma pronta para copiar, e no código é space.rgb.oklch(255, 128, 0).
Porque são calculados em sRGB codificado com gama, onde tirar a média dos números de duas cores produz uma luz mais escura e mais apagada do que misturar de fato a sua luz produziria. Interpolar no OKLab evita isso; em CSS, fica linear-gradient(in oklab, red, blue). A linha interpolar de cada dossiê mostra a mesma transição em dois espaços, lado a lado, para que você veja a diferença antes de escolher.
Abra o espaço log da sua câmera, como S-Log3, LogC4 ou Apple Log. No bloco LUT dele, escolha Rec. 709 e o seu editor: DaVinci Resolve, Premiere Pro, Final Cut Pro, OBS, ffmpeg e outros. O seu navegador gera o arquivo .cube. É uma conversão técnica, sem mapeamento de tons: as altas luzes acima do branco difuso são cortadas, e o look fica por sua conta.
Uma cor que um espaço consegue descrever, mas outro — ou a sua tela — não consegue mostrar. Um verde vívido do Display P3 não existe no sRGB: converta-o, e os números caem fora da faixa válida. O atlas deixa isso à vista: um ⚠ ao lado da cor atual indica que ela está fora do Limite escolhido, segurar Alt sobre um plano ou uma faixa mostra de qual gamut mais amplo uma cor ali precisa (P3, Rec. 2020), e os trechos fora da faixa aparecem esmaecidos sobre um quadriculado.
Uma tela emite luz; o papel reflete o que suas tintas não absorvem. A tinta sobre o papel reproduz menos cores vivas — azuis, verdes e vermelhos RGB saturados ficam fora do seu gamut — e por isso saem mais apagados. Na pré-impressão, a conversão usa um perfil ICC feito para a impressora e o papel, como o FOGRA39 para papel couché europeu ou o GRACoL nos EUA. O CMYK deste catálogo é a fórmula simples que o CSS usa para device-cmyk() sem perfil: correta nos números, mas não serve como prova de impressão.
Para a web e para compartilhar, sRGB: navegadores e celulares o adotam por padrão quando o arquivo não traz perfil. O Display P3 reproduz mais das cores vivas de uma cena nas telas da Apple e de muitos aparelhos Android, desde que o perfil continue incorporado. Envie em Adobe RGB quando um laboratório de impressão pedir. Reserve o ProPhoto RGB para edição em 16 bits: o gamut dele é tão amplo que arquivos de 8 bits ficam com faixas visíveis.
As conversões são fórmulas fechadas, não aproximações por tabela, e a conversão de ida e volta devolve os valores originais dentro do erro de ponto flutuante. As poucas exceções estão documentadas onde ocorrem: o OSA-UCS não tem inversa fechada, e sistemas de atlas como o Munsell interpolam entre os valores tabelados publicados. A saída em rgb nunca é limitada ao intervalo: uma cor fora do sRGB volta abaixo de 0 ou acima de 255, então limite-a só na hora de exibir.
E são verificadas: cada espaço cita o artigo ou a especificação que implementa, os valores são comparados com os do colorjs.io onde os dois coincidem, e os logs de câmera com as transformações ACES oficiais da Academia. formula-verification.md registra o que foi conferido com o quê — inclusive alguns pontos em que os próprios artigos publicados tinham erros.
Se os números diferem dos de outra biblioteca, compare as faixas: esta mantém as faixas convencionais de cada espaço — RGB 0–255, claridade Lab 0–100, matiz 0–360 — enquanto muitas normalizam tudo para 0–1. Cada cartão mostra suas faixas; no código elas são space.oklch.range.
Nativamente rgb(), hsl(), hwb(), lab(), lch(), oklab(), oklch(), além de color() para Display P3, Adobe RGB, ProPhoto, sRGB linear e XYZ (D65 e D50). O rec2020 do CSS é uma curva gama 2.4 pura, não a curva BT.2020 do Rec. 2020 deste catálogo — os mesmos números corresponderiam a outra cor. A aba css de cada dossiê mostra a cor atual pronta para copiar; os espaços que o CSS não tem são oferecidos como perfis ICC ou LUTs.
Abra Exibição e escolha uma opção em Visão: cegueira ao vermelho (protanopia), cegueira ao verde (deuteranopia) ou cegueira ao azul (tritanopia). O catálogo é redesenhado como esse olho o vê, para você conferir se as cores de uma paleta continuam distinguíveis. Cerca de 1 em cada 12 homens tem deficiência na visão de cores, segundo o NEI.
São produtos licenciados: suas cores são definidas por dados que os proprietários vendem, não por fórmulas publicadas — então não há matemática aberta para implementar, e redistribuir suas tabelas seria ilegal. Sistemas próximos com matemática pública estão aqui: Munsell (a renotação de 1943 é pública) e RAL Design (definido diretamente em CIELAB). Todo sistema cuja matemática tenha sido publicada algum dia tem lugar aqui; sugira um que esteja faltando.
| Ferramenta | Espaços | Logs de câmera | Luma–croma | sRGB | Utilitários | Tamanho | Velocidade | Alvos |
|---|---|---|---|---|---|---|---|---|
| 205 | 31 | 16 | 0–255 | parse mix ΔE contrast CVD | 62 kB | JS, WASM, GL, LUT, ICC, OCIO, MCP, Figma, VS Code, CLI, web | ||
| 30 | – | 1 | 0–1 | parse mix gamut ΔE contrast CVD | 23 kB | JS | ||
| 51 | – | – | 0–1 | parse mix gamut ΔE contrast | 34 kB | JS, web | ||
| chroma-js | 11 | – | – | 0–255 | parse mix ΔE contrast palettes | 17 kB | JS | |
| @texel/color | 16 | – | – | 0–1 | parse gamut ΔE | 9 kB | JS | |
| 128 | 24 | 6 | 0–1 | ΔE CVD | – | – | Python, LUT | |
| 77 | – | – | 0–1 | parse mix gamut ΔE contrast CVD palettes | – | – | Python | |
| 9 | – | – | 0–1 | mix contrast CVD palettes | – | – | R, web | |
| 57 | 11 | – | 0–1 | gamut | – | – | C++, Python, GL, LUT, ICC | |
| 22 | – | – | 0–1, 0–255 | ΔE | – | – | web | |
| 9 | – | – | 0–255 | parse gamut | – | – | web |
Do código-fonte, do pacote ou da página de cada projeto, em 2026-10-18.
@software{Ivanov_color-space_2026,
author = {Ivanov, Dmitry},
license = {CC0-1.0},
month = oct,
title = {{color-space}},
url = {https://github.com/colorjs/color-space},
version = {3.4.0},
year = {2026}
}Ivanov, D. (2026). color-space (Version 3.4.0) [Computer software]. https://github.com/colorjs/color-space
Telas e web
display: a decodificação do display de referência — o que o CSS escreve como color(rec2020 …)
Rec. 2020 display → Linear-light Rec. 2020 → CIE XYZ → sRGB
2011, ITU-R; W3C CSS WG
0.6369580483 0.1446169036 0.1688809752 0.262700212 0.6779980715 0.0593017165 0 0.028072693 1.0609850577
O color(rec2020 …) do CSS: primárias BT.2020 sob a potência 2.4 da BT.1886.
O color(rec2020 …) do CSS; vídeo UHD referido ao display num monitor BT.1886.
Duas curvas respondem pelo nome rec2020: decodificar, em vez disso, com a inversa da curva de câmera BT.2020 (como fazia o colorjs.io 0.5) dá 37% mais luz ao sinal 0.5.
// one space, tree-shaken (0.4-1.5 kB) — its own edge: import rec2020Display from 'color-space/rec2020-display.js' rec2020Display['rec2020-linear'](0.53, 0.53, 0.53) // → [0.2159, 0.2159, 0.2159] // any-to-any, both ways — the wired hub: import space from 'color-space' space['rec2020-display'].rgb(0.53, 0.53, 0.53) // → [128, 128, 128] space.rgb['rec2020-display'](128, 128, 128) // → [0.53, 0.53, 0.53] // route: rec2020-display → rec2020-linear → xyz → rgb