<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.2/p5.js" integrity="sha512-U9A2hkdqQwJaC2PgtQYCAZl6OkYhJOvF86X9ibqKw1bsYnn3txJAyeRQzYwSD0qRgBUzKXdhzGUGIYzuoh4JEA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.11.2/addons/p5.sound.js" integrity="sha512-TU9AWtV5uUZPX8dbBAH8NQF1tSdigPRRT82vllAQ1Ke28puiqLA6ZVKxtUGlgrH6yWFnkKy+sE6luNEGH9ar0A==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
             
body {margin:0px; padding:0px; overflow: hidden}
#code {
  position: absolute;
  top: 0;
  left: 0;
  font-family: monospace;
  z-index: 1000;
  color: #ffffff;
  padding: 8px;
  white-space: pre-wrap;
  font-size:10px;
}
let program;
function setup() {
   pixelDensity(1);
   smooth();
   createCanvas(windowWidth, windowHeight,WEBGL);
  program = createShader(vert,frag);
	rgb = [0.5, 0.5, 0.5];
	xyz = sRGBtoXYZ(...degamma(...rgb));
	//lab = sRGBtoLAB(...degamma(0.5,0.5,0.5));
	console.log("xyz", xyz);
	console.log("rgb", XYZtoSRGB(...xyz));
	lab = XYZtoLAB(...xyz);
	console.log("lab", lab);
	console.log("xyz", LABtoXYZ(...lab));
	
	
	//console.log(lab);
	//console.log(gamma(...LABtoSRGB(...lab)));
}



function XYZtoSRGB(x,y,z) {
    return [
			3.2404542 * x -1.5371385 * y -0.4985314 * z,
    	-0.9692660 * x + 1.8760108 * y + 0.0415560 * z,
   		0.0556434 * x -0.2040259 * y + 1.0572252 * z
			];
}

function sRGBtoXYZ(x,y,z) {
    return [
			0.4124564 * x + 0.3575761 * y + 0.1804375 * z,
    	0.2126729 * x + 0.7151522 * y + 0.0721750 * z,
   		0.0193339 * x + 0.1191920 * y + 0.9503041 * z
			];
}

function LABtoXYZ(l,a,b){
	const EPSILON = 216.0 / 24389.0;
	const KAPPA = 24389.0 / 27.0;
	const whitePoint = {x:0.9504492182750991, y:1.0, z:1.0889166484304715}; // D65
  const fy = (l + 16.0) / 116.0;
  const fx = a / 500.0 + fy;
  const fz = fy - b / 200.0;
	const rx = pow(fx, 3.0) > EPSILON ? pow(fx, 3.0) : (fx * 116.0 - 16.0) / KAPPA;
	const ry = l > KAPPA * EPSILON ? pow((l + 16.0) / 116.0, 3.0) : l / KAPPA;
	const rz = pow(fz, 3.0) > EPSILON ? pow(fz, 3.0) : (fz * 116.0 - 16.0) / KAPPA;
	return [whitePoint.x * rx, whitePoint.y * ry, whitePoint.z * rz]
}

//http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Lab.html
function XYZtoLAB(x, y, z){
	const EPSILON = 216.0 / 24389.0;
	const KAPPA = 24389.0 / 27.0;
	const whitePoint = {x:0.9504492182750991, y:1.0, z:1.0889166484304715}; // D65
	const xr = x / whitePoint.x;
	const yr = y / whitePoint.y;
	const zr = z / whitePoint.z;
  const fx = (xr > EPSILON) ? Math.pow(xr, 1.0/3.0) : (KAPPA * xr + 16.0)/116.0;
  const fy = (yr > EPSILON) ? Math.pow(yr, 1.0/3.0) : (KAPPA * yr + 16.0)/116.0;
  const fz = (zr > EPSILON) ? Math.pow(zr, 1.0/3.0) : (KAPPA * zr + 16.0)/116.0;
  return [(116.0 * fy) - 16.0, 500.0 * (fx - fy), 200.0 * (fy - fz)]
}

function LABtoSRGB(l,a,b) {
	return XYZtoSRGB(...LABtoXYZ(l,a,b));
}

function sRGBtoLAB(x,y,z) {
	return XYZtoLAB(...sRGBtoXYZ(x,y,z));
}

function degamma(r,g,b) {
	return [pow(max(0, r), 2.2), pow(max(0, g), 2.2), pow(max(0, b), 2.2)];
}

function gamma(r,g,b) {
	return [pow(max(0, r), 1/2.2), pow(max(0, g), 1/2.2), pow(max(0, b), 1/2.2)];
}

function draw() {
  const margin = 32;
  const side = min(width, height) - margin * 2;
  background(0);
  fill(255);
  shader(program);
  const loopLen = 360;
  program.setUniform("mouseY", (mouseY - (height - side) * 0.5) / side);
  program.setUniform("rect", [(width - side) / 2, (height - side) / 2, side, side]);
  rect(-side * 0.5, -side* 0.5, side, side);
  resetShader();
}

const vert=`
#ifdef GL_ES
precision highp float;
precision highp int;
#endif

attribute vec3 aPosition;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;
uniform mat3 uNormalMatrix;
void main() {
  gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aPosition, 1.0);
}`;

const frag=`
#ifdef GL_ES
precision highp float;
#endif

uniform float mouseY;
uniform vec4 rect;

mat3 transpose(mat3 m) {
  return mat3(
    m[0][0], m[1][0], m[2][0],
    m[0][1], m[1][1], m[2][1],
    m[0][2], m[1][2], m[2][2]);
}

mat2 inv(mat2 m) {
	float a = m[0][0];
	float b = m[1][0];
	float c = m[0][1];
	float d = m[1][1];
	float det = (a * d - b * c);
	if (det != 0.0) {
		return mat2(d, -b, -c, a) / det ;
	} else {
		return mat2(0.0, 0.0, 0.0, 0.0);
	}
}

vec3 XYZtoSRGB(vec3 xyz) {
	return transpose(mat3(
			3.2404542, -1.5371385, -0.4985314,
    	-0.9692660, 1.8760108, 0.0415560,
   		0.0556434, -0.2040259, 1.0572252)
			) * xyz;
}

vec3 LABtoXYZ(vec3 lab){
	float EPSILON = 216.0 / 24389.0;
	float KAPPA = 24389.0 / 27.0;
	vec3 whitePoint = vec3(0.9504492182750991, 1.0, 1.0889166484304715); // D65
  float fy = (lab.x + 16.0) / 116.0;
  float fx = lab.y / 500.0 + fy;
  float fz = fy - lab.z / 200.0;
	float rx = pow(max(0.0, fx), 3.0) > EPSILON ? pow(max(0.0, fx), 3.0) : (fx * 116.0 - 16.0) / KAPPA;
	float ry = lab.x > KAPPA * EPSILON ? pow((lab.x + 16.0) / 116.0, 3.0) : lab.x / KAPPA;
	float rz = pow(max(0.0, fz), 3.0) > EPSILON ? pow(max(0.0, fz), 3.0) : (fz * 116.0 - 16.0) / KAPPA;
	return vec3(whitePoint.x * rx, whitePoint.y * ry, whitePoint.z * rz);
}

void main(void)
{
  vec2 crd = ((gl_FragCoord.xy - rect.xy) / rect.zw - vec2(0.5)) * 2.0;
	float px = 1.0 / max(rect.z, rect.w);
	float sqrt3 = sqrt(3.0);
	
	float yTh = clamp((1.0 - mouseY) * 2.0, 0.0, 1.0);
	float x = 0.0, y = 0.0, z = 0.0;
	if (crd.x < 0.0) {
		vec2 lCrd = crd - vec2(-sqrt3 * 0.5, -0.5);
		mat2 mat = inv(mat2(sqrt3, 0.0, -1.0, 2.0) * 0.5);
		lCrd = mat * lCrd;
		x = lCrd.x;
		y = lCrd.y;
	} else {
		vec2 lCrd = crd - vec2(0.0, -1.0);
		mat2 mat = inv(mat2(sqrt3, 0.0, 1.0, 2.0) * 0.5);
		lCrd = mat * lCrd;
		x = 1.0;
		z = lCrd.x;
		y = lCrd.y;
	}
	if (y > yTh) {
		vec2 lCrd = crd - vec2(-sqrt3 * 0.5, -0.5 + yTh);
		mat2 mat = inv(mat2(sqrt3, sqrt3, -1.0, 1.0) * 0.5);
		lCrd = mat * lCrd;
		x = lCrd.x;
		y = yTh;
		z = lCrd.y;
	}
	
	vec3 xyz = LABtoXYZ(vec3(y * 100.0, (x - 0.5) * 256.0, (z - 0.5) * 256.0));
  vec3 lrgb = XYZtoSRGB(xyz);
	vec3 rgb = pow(clamp(lrgb, vec3(0.0), vec3(1.0)), vec3(1.0/2.2));
	vec4 color = vec4(rgb, 1.0);	
	
	float mx = max(x, max(y, z));
	float mn = min(x, min(y, z));
	color.rgb = mix(color.rgb, vec3(0.0), smoothstep(0.0, px, -mn));
	color.rgb = mix(color.rgb, vec3(0.0), smoothstep(0.0, px, mx - 1.0));
	
  gl_FragColor=color;
}`;


Run Pen

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.