Perceptual Brightness Preview
by Ben Gillbanks
December 18, 2024
HTML
<h1>Perceptual Brightness Viewer</h1>
<p>See original colors and their perceptual equivalents.</p>
<p>Perceptual brightness is how dark colours appear to the eye, as opposed to how bright they are mathematically (when described with hsl for example).</p>
<div class="palette" id="palette"></div>
CSS
body {
font-family: Arial, sans-serif;
padding: 20px;
line-height: 1.6;
}
h1 {
line-height: 1.1;
}
.palette {
display: flex;
}
.swatch {
display: flex;
flex-direction: column;
align-items: center;
flex-grow:1;
margin-bottom: 10px;
}
.color-box {
width: 100%;
height: 80px;
}
JavaScript
// Input colors
const colors = [
"#0A0C1F", // Very dark blue - almost black. The darkest colour.
"#263264", // Dark blue
"#A0ABB6", // Mid grey
"#B2EFEB", // Light blue
"#3FB0F1", // Mid blue
"#3548A3", // Blue
"#420241", // Dark red/ purple
"#6A3E49", // Brown
"#C22D44", // Red
"#E08355", // Orange
"#FFC763", // Yellow
"#A7D171", // Light green
"#30AB62", // Green
"#1E7F82", // Dark Green
"#FF76D7", // Pink
"#F4F4F4", // Off white
];
// Constants for sRGB luminance
const rY = 0.212655;
const gY = 0.715158;
const bY = 0.072187;
// Inverse of sRGB "gamma" function
function invGamSRGB(ic) {
const c = ic / 255.0;
return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
}
// sRGB "gamma" function
function gamSRGB(v) {
v = v <= 0.0031308 ? v * 12.92 : 1.055 * Math.pow(v, 1.0 / 2.4) - 0.055;
return Math.round(v * 255);
}
// Perceptual brightness (gray value)
function perceptualBrightness(r, g, b) {
const luminance = rY * invGamSRGB(r) + gY * invGamSRGB(g) + bY * invGamSRGB(b);
return gamSRGB(luminance);
}
// Convert hex to RGB
function hexToRGB(hex) {
const bigint = parseInt(hex.slice(1), 16);
return {
r: (bigint >> 16) & 255,
g: (bigint >> 8) & 255,
b: bigint & 255,
};
}
// Convert RGB to hex
function rgbToHex({ r, g, b }) {
return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`;
}
// Generate swatches
function generateSwatches(colors) {
const palette = document.getElementById("palette");
// Sort colors by perceptual brightness
const sortedColors = colors.map((color) => {
const rgb = hexToRGB(color);
const brightness = perceptualBrightness(rgb.r, rgb.g, rgb.b);
return { color, brightness };
}).sort((a, b) => a.brightness - b.brightness);
sortedColors.forEach(({ color }) => {
const rgb = hexToRGB(color);
const perceptualRGB = {
r:...