# Choosing sRGB, Linear RGB, and OkLab for Color Gradients

DevFeed: [Choosing sRGB, Linear RGB, and OkLab for Color Gradients](<https://devfeed.tech/articles/the-current-technology-is-not-ready-for-proper-blending-26117.md>)

Original publisher: [Read original article](<http://blog.pkh.me/p/43-the-current-technology-is-not-ready-for-proper-blending.html>)

Published: 2025-07-18T20:10:43Z

Content type: article

Language: en

Sources: [The Last Static Blog RSS](<https://devfeed.tech/sources/the-last-static-blog-rss.md>)

Topics: [glsl](<https://devfeed.tech/topics/glsl.md>), [color](<https://devfeed.tech/topics/color.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [code](<https://devfeed.tech/tags/code.md>), [color](<https://devfeed.tech/tags/color.md>), [glsl](<https://devfeed.tech/tags/glsl.md>), [graphics](<https://devfeed.tech/tags/graphics.md>), [math](<https://devfeed.tech/tags/math.md>), [prog](<https://devfeed.tech/tags/prog.md>), [technology](<https://devfeed.tech/tags/technology.md>)

## AI overview

This article examines how sRGB, linear RGB, and OkLab behave when generating color gradients. It explains that sRGB can produce muddy midtones, linear RGB models light energy correctly but may look less perceptually suitable, and OkLab generally provides the best perceptual result at a performance cost. It also notes that monochrome gradients produce different tradeoffs.

## Source excerpt

The idea that we must always linearize sRGB gradients or work in a perceptually uniform colorspace is starting to be accepted universally. But is it that simple? When I learned about the subject, it felt like being handed a hammer and using it everywhere. The reality is a bit more nuanced. In this article we will see when to use which, how to use them, and we will then see why the situation is more dire than it looks. Code snippets Before we start, since we are going to use GLSL as language, following are the reference functions we will use for the rest of the article. vec3 s2l(vec3 c) { // sRGB to linear return mix(c/12.92, pow((max(c,0.0)+0.055)/1.055,vec3(2.4)), step(vec3(0.04045),c)); } vec3 l2s(vec3 c) { // linear to sRGB return mix(c*12.92, 1.055*pow(max(c,0.0),vec3(1./2.4))-0.055, step(vec3(0.0031308),c)); } vec3 l2oklab(vec3 rgb) { // linear to OkLab const mat3 rgb2lms = mat3( +0.4122214708, +0.2119034982, +0.0883024619, +0.5363325363, +0.6806995451, +0.2817188376, +0.0514459929, +0.1073969566, +0.6299787005); const mat3 lms2lab = mat3( +0.2104542553, +1.9779984951, +0.0259040371, +0.7936177850, -2.4285922050, +0.7827717662, -0.0040720468, +0.4505937099, -0.8086757660); vec3 lms = rgb2lms * rgb; return lms2lab * pow(lms, vec3(1.0/3.0)); } vec3 oklab2l(vec3 lab) { // OkLab to linear const mat3 lab2lms = mat3( +1.0000000000, +1.0000000000, +1.0000000000, +0.3963377774, -0.1055613458, -0.0894841775, +0.2158037573, -0.0638541728, -1.2914855480); const mat3 lms2rgb = mat3( +4.0767416621, -1.2684380046, -0.0041960863, -3.3077115913, +2.6097574011, -0.7034186147, +0.2309699292, -0.3413193965, +1.7076147010); vec3 lms = lab2lms * lab; return lms2rgb * (lms*lms*lms); } Also, the output of the pipeline will be expected to be sRGB all the time. Color gradients To illustrate how sRGB, linear RGB and OkLab respectively look like, let's interpolate between two colors with each one of them: Color gradients from top to bottom: sRGB, linear, OkLab The 3 stripes were generate