a.github-corner(href='//github.com/meodai/color-names', target='_blank', aria-label='View source on Github')
svg(width='80', height='80', viewbox='0 0 250 250', aria-hidden='true')
path.triange(d='M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z')
path.octo-arm(d='M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2', style='transform-origin: 130px 106px;')
path.octo-body(d='M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z')
.options
label
span.label List
select(data-list)
option(value="default") Color Name List
option(value="bestOf") Best of
option(value="short") Short Names
option(value="basic") Basic Colors
option(value="html") HTML / CSS
option(value="wikipedia") Wikipedia
option(value="french") French Colors
option(value="spanish") Spanish Colors
option(value="japaneseTraditional") Japanese Traditional
option(value="chineseTraditional") Chinese Traditional
option(value="leCorbusier") Le Corbusier
option(value="nbsIscc") NBS-ISCC
option(value="ntc") NTC.js
option(value="osxcrayons") OSX Crayon
option(value="ral") RAL color
option(value="ridgway") Ridgway's Nomenclature
option(value="sanzoWadaI") Sanzo Wada
option(value="thesaurus") Thesaurus
option(value="werner") Werner's Nomenclature
option(value="windows") MS Windows
option(value="x11") x11
option(value="xkcd") xkcd survey
label
span.label Model
select(data-model)
option(value="rgb") rgb
option(value="xyz") xyz
option(value="cat02") cat02
option(value="jab") jab
option(value="luv") luv
option(value="yuv") yuv
option(value="lab") lab
option(value="oklab") OK lab
option(value="lch") lch
option(value="hsv") hsv
option(value="hsl") hsl
option(value="hsi") hsi
option(value="hwb") hwb
option(value="hcg") hcg
button
span toggle darkmode
strong.
<svg xmlns="http://www.w3.org/2000/svg" width="184" height="184" viewBox="0 0 184 184">
<g>
<path class="line" d="M43.27,54.49A7.93,7.93,0,0,0,54.49,43.27l-8.33-8.33A7.93,7.93,0,0,0,34.95,46.16Z" transform="translate(-8 -8)"/>
<path class="line" d="M159.45,167.38a7.93,7.93,0,0,0,5.61-13.54l-8.33-8.33a7.93,7.93,0,0,0-11.21,11.21l8.33,8.33A7.9,7.9,0,0,0,159.45,167.38Z" transform="translate(-8 -8)"/>
<path class="line" d="M46.16,165.05l8.33-8.33a7.93,7.93,0,1,0-11.21-11.21l-8.33,8.33a7.93,7.93,0,1,0,11.21,11.21Z" transform="translate(-8 -8)"/>
<path class="line" d="M151.12,56.81a7.91,7.91,0,0,0,5.61-2.32l8.33-8.33a7.93,7.93,0,0,0-11.21-11.21l-8.33,8.33a7.93,7.93,0,0,0,5.61,13.54Z" transform="translate(-8 -8)"/>
<path class="line" d="M15.93,107.93H27.71a7.93,7.93,0,0,0,0-15.86H15.93a7.93,7.93,0,0,0,0,15.86Z" transform="translate(-8 -8)"/>
<path class="line" d="M164.36,100a7.93,7.93,0,0,0,7.93,7.93h11.78a7.93,7.93,0,0,0,0-15.86H172.29A7.93,7.93,0,0,0,164.36,100Z" transform="translate(-8 -8)"/>
<path class="line" d="M100,164.36a7.93,7.93,0,0,0-7.93,7.93v11.78a7.93,7.93,0,0,0,15.86,0V172.29A7.93,7.93,0,0,0,100,164.36Z" transform="translate(-8 -8)"/>
<path class="line" d="M100,35.64a7.93,7.93,0,0,0,7.93-7.93V15.93a7.93,7.93,0,0,0-15.86,0V27.71A7.93,7.93,0,0,0,100,35.64Z" transform="translate(-8 -8)"/>
<path class="circle" d="M100,153.09A53.09,53.09,0,1,0,46.91,100,53.15,53.15,0,0,0,100,153.09Zm0-90.33A37.23,37.23,0,1,1,62.77,100,37.27,37.27,0,0,1,100,62.77Z" transform="translate(-8 -8)"/>
</g>
</svg>
.currentColor
#container
View Compiled
$c-black: #202124;
$c-white: #fff;
$bg: $c-white;
:root {
--dark: $c-black;
--light: $c-white;
--background: var($c-black);
--foreground: var($c-white);
}
// <link href="https://fonts.googleapis.com/css?family=Inconsolata" rel="stylesheet">
//@import 'https://fonts.googleapis.com/css?family=Inconsolata';
//$t-code: 'Inconsolata', ipm, Menlo, 'Courier New', monospace;
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@200&display=swap');
$t-code: 'Inter', sans-serif;
//@import 'https://fonts.googleapis.com/css?family=Space+Mono';
//$t-code: 'Space Mono', ipm, Menlo, 'Courier New', monospace;
body {
overflow: hidden;
background: $c-black;
background: var(--background);
font-family: $t-code;
color: #fff;
color: var(--foreground, #{$c-white});
}
.github-corner {
position: absolute;
top: 0; right: 0;
transform: translate3d(0,0,0);
transition: 333ms transform cubic-bezier(.7,.3,.25,1.15) 1200ms;
will-change: transform;
svg {
width: 4rem; height: 4rem;
}
path {
will-chrange: fill;
}
.octo-arm,
.octo-body {
fill: $c-black;
fill: var(--background, #{$c-black});
}
.triange {
fill: $c-white;
fill: var(--foreground, #{$c-white});
}
}
.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}
button,
select {
position: absolute;
font-family: $t-code;
box-sizing: border-box;
appearance: none;
-webkit-appearance: none;
border: none;
color: $c-white;
color: var(--foreground, #{$c-white});
background-color: transparent;
cursor: pointer;
}
select {
position: relative;
//max-width: 10rem;
}
.options {
position: absolute;
bottom: 0;
right: 0;
padding: 1rem;
}
button {
bottom: 1rem; left: 1rem;
padding: 0;
outline: none;
padding: 0 0 0.5em 0.3em;
span {
display: none;
}
stonrg {
display: block;
}
svg {
display: block;
width: 2rem; height: 2rem;
}
path {
fill: currentColor;
}
.line {
display: none;
}
}
.isDark {
button {
.line {
display: block;
}
}
}
select {
font-size: 1.5rem;
//text-decoration: underline;
appearance: none;
-webkit-appearance: none;
border-radius: 0;
color: turquoise;
//text-decoration-color: pink;
padding: 0.25em 1.2em 0.25em 0.3em;
background-color: rgba(#202124,.5);
background-size: auto 25%;
background-repeat: no-repeat;
background-position: calc(100% - .7rem) 55%;
background-image: url('data:image/svg+xml,%3C%3Fxml%20version%3D%221.0%22%20encoding%3D%22utf-8%22%3F%3E%20%3C%21--%20Generator%3A%20IcoMoon.io%20--%3E%20%3C%21DOCTYPE%20svg%20PUBLIC%20%22-//W3C//DTD%20SVG%201.1//EN%22%20%22http%3A//www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd%22%3E%20%3Csvg%20width%3D%22512%22%20height%3D%22512%22%20viewBox%3D%220%200%20512%20512%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20xmlns%3Axlink%3D%22http%3A//www.w3.org/1999/xlink%22%20fill%3D%22%23ffffff%22%3E%3Cpath%20d%3D%22M%2096.00%2C96.00l-96.00%2C96.00l%20256.00%2C256.00l%20256.00-256.00l-96.00-96.00L%20256.00%2C256.00L%2096.00%2C96.00z%22%20%3E%3C/path%3E%3C/svg%3E');
transition: 150ms background-color;
&:focus {
outline: none;
}
&:hover {
background-color: rgba(#202124,.8);
}
}
label {
display: inline-block;
}
@media (max-width: 480px) {
button {
left: auto;
right: 1rem;
bottom: 7rem;
}
select,
label {
width: 100%;
}
}
.label {
font-size: .7em;
display: block;
padding: 0 0.5em;
}
.currentColor {
pointer-events: none;
position: absolute;
left: 1.5rem;
top: 1rem;
text-shadow: 0 1px 10px #202124;
h2 {
margin: 0;
}
span {
display: block;
margin-top: .1em;
&::before {
position: relative;
top: -.2em;
display: inline-block;
margin-right: 0.25em;
color: var(--color);
content: '⬤';
font-size: .9em;
}
}
}
View Compiled
console.clear();
import * as THREE from 'https://threejsfundamentals.org/threejs/resources/threejs/r110/build/three.module.js';
import { OrbitControls } from 'https://threejsfundamentals.org/threejs/resources/threejs/r110/examples/jsm/controls/OrbitControls.js';
let cam, scene, root, renderer, controls, layers,
objects = [], cubeSize = 100, dotSize = 1.25,
width = window.innerWidth + 1,
height = window.innerHeight + 1,
$select = document.querySelector('[data-model]'),
$selectList = document.querySelector('[data-list]'),
cDark = '#202124', cLight = '#ffffff',
bg = cDark, colorMode = 'rgb', spaceCube, isDark = true;
const colorModes = {
hsv: {
func: 'hsv',
x: [0, 360],
y: [1, 1],
z: [2, 1]
},
hsi: {
func: 'hsi',
x: [0, 360],
y: [1, 1],
z: [2, 1]
},
hsl: {
func: 'hsl',
x: [0, 360],
y: [1, 1],
z: [2, 1]
},
rgb: {
func: 'rgb',
x: [0, 255],
y: [1, 255],
z: [2, 255]
},
xyz: {
func: 'xyz',
x: [0, 95.047],
y: [1, 100],
z: [2, 108.883]
},
'cat02': {
func: 'cat02',
x: [0, 95.047],
y: [1, 104],
z: [2, 108.883],
},
jab: {
func: 'jzazbz',
x: [0, .2],
y: [1, .16, -.16],
z: [2, .16, -.16],
},
luv: {
func: 'luv',
x: [0, 100],
y: [1, 224, -134],
z: [2, 122, -140],
},
lab: {
func: 'lab',
z: [0, 100],
y: [1, 127, -128],
x: [2, 127, -128]
},
oklab: {
func: 'oklab',
z: [0, 1],
y: [1, .3, -.3],
x: [2, .35, -.35]
},
lch: {
func: 'lch',
z: [0, 100],
y: [1, 100],
x: [2, 0, 360]
},
yuv: {
func: 'yuv',
z: [0, 255],
y: [1, 255],
x: [2, 255]
},
hwb: {
func: 'hwb',
x: [0, 360],
y: [1, 1],
z: [2, 1]
},
hcg: {
func: 'hcg',
x: [0, 360],
y: [1, 1],
z: [2, 1]
}
};
init();
function onWindowResize() {
width = window.innerWidth + 1;
height = window.innerHeight + 1;
cam.aspect = width / height;
cam.updateProjectionMatrix();
renderer.setSize(width, height);
}
let colorList = [];
function fetchList (listname='default') {
fetch(`https://api.color.pizza/v1/?list=${listname}`).then(d => d.json()).then(d => {
colorList = d.colors;
addParticles(colorList, colorMode);
})
}
fetchList()
let part;
function createCanvasMaterial(color, size = 256) {
var matCanvas = document.createElement('canvas');
matCanvas.width = matCanvas.height = size;
var matContext = matCanvas.getContext('2d');
// create exture object from canvas.
var texture = new THREE.Texture(matCanvas);
// Draw a circle
var center = size / 2;
matContext.beginPath();
matContext.arc(center, center, size / 2, 0, 2 * Math.PI, false);
matContext.closePath();
matContext.fillStyle = color;
matContext.fill();
// need to set needsUpdate
texture.needsUpdate = true;
// return a texture made from the canvas
return texture;
}
let pMaterial, particles;
function addParticles(colorNames, cMode) {
// create the particle variables
const particleCount = colorNames.length;
if (particles) {
particles.dispose();
}
particles = new THREE.Geometry();
if (pMaterial) {
pMaterial.dispose();
}
dotSize = 255/Math.sqrt(colorNames.length/3) * .4;
dotSize = Math.max(Math.min(dotSize, 4), 1.25);
pMaterial = new THREE.PointsMaterial({
vertexColors: THREE.VertexColors,
size: dotSize,
alphaMap: createCanvasMaterial('#ffffff', dotSize * 100),
flatShading: true,
//fog: false,
//depthWrite: false,
transparent: true,
alphaTest: .5,
//sizeAttenuation: true,
});
let colors = [];
const mode = colorModes[cMode];
colorNames.forEach((col, i) => {
let colorComp;
let color = new Color({
"color": col.hex,
"type": "hex"
});
if (mode.func === 'oklab') {
colorComp = linear_srgb_to_oklab(chroma(col.hex).rgb());
} else if (mode.func === 'yuv') {
colorComp = yuv(chroma(col.hex).rgb());
} else if (mode.func === "luv") {
colorComp = color.luv;
} else if (mode.func === "xyz" || mode.func === "cat02" || mode.func === "jzazbz") {
colorComp = color.xyz;
if (mode.func === "jzazbz") {
colorComp = Jzazbz(colorComp);
}
if (mode.func === "cat02") {
colorComp = xyz2cat02(colorComp);
}
} else if (mode.func === 'hwb') {
const [hsvH, hsvS, hsvV] = chroma(col.hex).hsv();
colorComp = [
hsvH,
(1 - hsvS) * hsvV,
1 - hsvV
]
} else {
colorComp = chroma(col.hex)[mode.func]();
if (mode.func === 'hcg') {
colorComp = [colorComp[0],colorComp[1] / 100,colorComp[2] / 100];
}
}
let pX = translate(colorComp[mode.x[0]], mode.x[2] || 0, mode.x[1], -cubeSize * .5, cubeSize * .5),
pY = translate(colorComp[mode.y[0]], mode.y[2] || 0, mode.y[1], -cubeSize * .5, cubeSize * .5),
pZ = translate(colorComp[mode.z[0]], mode.z[2] || 0, mode.z[1], -cubeSize * .5, cubeSize * .5);
if (mode.func === 'hsl' || mode.func === 'hsv' || mode.func === 'hsi' || mode.func === 'hcg') {
let theta = Math.PI * colorComp[mode.x[0]] / 180;
let r = colorComp[mode.y[0]] * cubeSize;
if (mode.func === 'hsi') {
r *= colorComp[mode.z[0]] * 0.75;
/*
let intensity = colorComp[mode.z[0]];
let factor = Math.min(intensity, 1 - intensity) * 0.75;
r *= factor;
*/
} else if (mode.func === 'hsv') {
r *= colorComp[mode.z[0]] * 0.5;
} else if (mode.func === 'hcg') {
r *= .5;
} else {
r *= colorComp[mode.z[0]] < 0.5 ? colorComp[mode.z[0]] : 1 - colorComp[mode.z[0]];
}
pY = r * Math.cos(theta);
pX = r * Math.sin(theta);
}
if (mode.func === 'lch') {
let theta = Math.PI * colorComp[mode.x[0]] / 180;
let r = translate(colorComp[mode.y[0]], 0, mode.y[1], 0, cubeSize * .5);
pY = r * Math.cos(theta);
pX = r * Math.sin(theta);
}
let particle = new THREE.Vector3(pX, pY, pZ),
Tcolor = new THREE.Color(col.hex);
colors.push(Tcolor)
// add it to the geometry
particles.vertices.push(particle);
});
// create the particle system
const particleSystem = new THREE.Points(
particles,
pMaterial
);
particleSystem.name = 'colors';
particles.colors = colors;
// add it to the scene
objects.push(particleSystem)
scene.add(particleSystem);
part = particleSystem;
}
renderer.render(scene, cam);
animate();
function setSceneColor(color) {
scene.background = new THREE.Color(color);
scene.fog = new THREE.Fog(color, 150, 300); //new THREE.FogExp2(0x000000, 0.0007);
}
/*
var aspect = window.innerWidth / window.innerHeight;
var d = 20;
camera = new THREE.OrthographicCamera( - d * aspect, d * aspect, d, - d, 1, 1000 );
camera.position.set( 20, 20, 20 ); // all components equal
camera.lookAt( scene.position ); // or the origin
*/
function init() {
cam = new THREE.PerspectiveCamera(75, width / height, 1, 500);
cam.position.z = cubeSize * 1.5;
scene = new THREE.Scene();
setSceneColor(bg)
root = new THREE.Object3D();
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(width, height);
addCube();
controls = new OrbitControls(cam, renderer.domElement);
// controls.addEventListener( 'change', render ); // remove when using animation loop
// enable animation loop when using damping or autorotation
controls.enableDamping = true;
controls.dampingFactor = .75;
controls.enableZoom = true;
controls.zoomSpeed = .25;
controls.autoRotate = true;
controls.autoRotateSpeed = 2.0;
controls.maxDistance = cubeSize * 1.75;
controls.maxPolarAngle = Math.PI * 4;
//controls.minPolarAngle = 0;
controls.maxAzimuthAngle = Infinity;
controls.minAzimuthAngle = -Infinity;
controls.noPan = true;
controls.noKeys = true;
//controls.noZoom = true;
const container = document.querySelector('#container');
container.appendChild(renderer.domElement);
window.addEventListener('resize', onWindowResize, false);
document.querySelector('button').addEventListener('click', toggleDarkMode, false);
}
function toggleDarkMode() {
isDark = !isDark;
document.querySelector('body').classList.toggle('isDark');
var newColor = isDark ? cDark : cLight;
setSceneColor(newColor);
var colorspace = scene.getObjectByName('colorspace');
scene.remove(colorspace);
addCube(isDark ? '#ffffff' : cDark);
document.documentElement.style.setProperty('--background', newColor);
document.documentElement.style.setProperty('--foreground', isDark ? '#ffffff' : cDark);
}
function addCube(color) {
let geometryCube = cube(cubeSize);
//geometryCube.computeLineDistances();
const material = new THREE.LineBasicMaterial({
color: color || 0xffffff,
linewidth: 1,
linecap: 'round', //ignored by WebGLRenderer
linejoin: 'round' //ignored by WebGLRenderer
});
const colorspace = new THREE.LineSegments(
geometryCube,
material
);
colorspace.name = 'colorspace';
objects.push(colorspace);
scene.add(colorspace);
spaceCube = colorspace;
}
function cube(size) {
const h = size * 0.5;
const geometry = new THREE.Geometry();
geometry.vertices.push(
new THREE.Vector3(-h, -h, -h),
new THREE.Vector3(-h, h, -h),
new THREE.Vector3(-h, h, -h),
new THREE.Vector3(h, h, -h),
new THREE.Vector3(h, h, -h),
new THREE.Vector3(h, -h, -h),
new THREE.Vector3(h, -h, -h),
new THREE.Vector3(-h, -h, -h),
new THREE.Vector3(-h, -h, h),
new THREE.Vector3(-h, h, h),
new THREE.Vector3(-h, h, h),
new THREE.Vector3(h, h, h),
new THREE.Vector3(h, h, h),
new THREE.Vector3(h, -h, h),
new THREE.Vector3(h, -h, h),
new THREE.Vector3(-h, -h, h),
new THREE.Vector3(-h, -h, -h),
new THREE.Vector3(-h, -h, h),
new THREE.Vector3(-h, h, -h),
new THREE.Vector3(-h, h, h),
new THREE.Vector3(h, h, -h),
new THREE.Vector3(h, h, h),
new THREE.Vector3(h, -h, -h),
new THREE.Vector3(h, -h, h)
);
return geometry;
}
function render() {
const time = Date.now() * 0.0001;
renderer.render(scene, cam);
//controls.update();
objects.forEach(object => {
//object.rotation.x = 0.25 * time * ( i%2 == 1 ? 1 : -1);
object.rotation.x = 0.25 * time;
object.rotation.y = 0.25 * time;
})
}
function animate() {
requestAnimationFrame(animate);
render();
}
$select.addEventListener('change', e => {
colorMode = $select.value;
objects = [];
const colorspace = scene.getObjectByName('colorspace');
scene.remove(colorspace);
const colors = scene.getObjectByName('colors');
scene.remove(colors);
addParticles(colorList, colorMode);
addCube(isDark ? cLight : cDark);
}, false);
$selectList.addEventListener('change', e => {
const listName = $selectList.value;
objects = [];
const colorspace = scene.getObjectByName('colorspace');
scene.remove(colorspace);
const colors = scene.getObjectByName('colors');
scene.remove(colors);
fetchList(listName);
//addParticles(colorList, colorMode);
addCube(isDark ? cLight : cDark);
}, false);
function translate(value, low1, high1, low2, high2) {
return low2 + (high2 - low2) * ((value - low1) / (high1 - low1));
}
const PQ = function perceptual_quantizer(X) {
const XX = Math.pow(X*1e-4, 0.1593017578125);
return Math.pow(
(0.8359375 + 18.8515625*XX) / (1 + 18.6875*XX),
134.034375);
};
function Jzazbz([X, Y, Z]) {
const
Lp = PQ(0.674207838*X + 0.382799340*Y - 0.047570458*Z),
Mp = PQ(0.149284160*X + 0.739628340*Y + 0.083327300*Z),
Sp = PQ(0.070941080*X + 0.174768000*Y + 0.670970020*Z),
Iz = 0.5 * (Lp + Mp),
az = 3.524000*Lp - 4.066708*Mp + 0.542708*Sp,
bz = 0.199076*Lp + 1.096799*Mp - 1.295875*Sp,
Jz = (0.44 * Iz) / (1 - 0.56*Iz) - 1.6295499532821566e-11;
return [Jz, az, bz];
}
function cat022hpe(l,m,s) {
var lh = ( 0.7409792 * l) + (0.2180250 * m) + (0.0410058 * s),
mh = ( 0.2853532 * l) + (0.6242014 * m) + (0.0904454 * s),
sh = (-0.0096280 * l) - (0.0056980 * m) + (1.0153260 * s);
return {lh: lh, mh: mh, sh: sh};
}
function xyz2cat02([x,y,z]) {
const l = ( 0.7328 * x) + (0.4296 * y) - (0.1624 * z),
m = (-0.7036 * x) + (1.6975 * y) + (0.0061 * z),
s = ( 0.0030 * x) + (0.0136 * y) + (0.9834 * z);
return [l, m, s];
}
function yuv(rgb) {
return [
/*Y*/ rgb[0] * .299000 + rgb[1] * .587000 + rgb[2] * .114000,
/*U*/ rgb[0] * -.168736 + rgb[1] * -.331264 + rgb[2] * .500000 + 128,
/*V*/ rgb[0] * .500000 + rgb[1] * -.418688 + rgb[2] * -.081312 + 128
]
}
function f(x)
{
if (x >= 0.0031308)
return (1.055) * x^(1.0/2.4) - 0.055
else
return 12.92 * x;
}
function linear_srgb_to_oklab(rgb)
{
rgb = rgb.map(comp => comp / 255);
let l = 0.4121656120 * rgb[0] + 0.5362752080 * rgb[1] + 0.0514575653 * rgb[2];
let m = 0.2118591070 * rgb[0] + 0.6807189584 * rgb[1] + 0.1074065790 * rgb[2];
let s = 0.0883097947 * rgb[0] + 0.2818474174 * rgb[1] + 0.6302613616 * rgb[2];
l = Math.cbrt(l);
m = Math.cbrt(m);
s = Math.cbrt(s);
return [
(0.2104542553*l + 0.7936177850*m - 0.0040720468*s),
(1.9779984951*l - 2.4285922050*m + 0.4505937099*s),
(0.0259040371*l + 0.7827717662*m - 0.8086757660*s),
];
}
let rayCaster = new THREE.Raycaster();
document.querySelector('body').addEventListener('mousemove', onDocumentMouseMove);
const $currentColor = document.querySelector('.currentColor');
let currentColorTimer;
function showColor(name, hex) {
clearTimeout(currentColorTimer);
$currentColor.innerHTML = `<div><h2>${name}</h2><span>${hex}</span></div>`
$currentColor.style = `--color: ${hex}`;
currentColorTimer = setTimeout(() => {
$currentColor.innerHTML = '';
}, 3000);
}
// Highlight a color name using a raycaster at some point
function onDocumentMouseMove(event) {
let mousePosition = {};
event.preventDefault();
mousePosition.x = (event.clientX / renderer.domElement.clientWidth) * 2 - 1;
mousePosition.y = - (event.clientY / renderer.domElement.clientHeight) * 2 + 1;
rayCaster.setFromCamera(mousePosition, cam);
var intersects = rayCaster.intersectObjects([scene.getObjectByName('colors')], false);
if (intersects.length > 0) {
var descriptions = [];
for (var i = 0; i < intersects.length; i++) {
//Only display those points we can SEE due to the near clipping plane.
//Without this check, the ray caster will list them all, even if they're clipped by the near plane.
//".distance" is relative to the camera, not absolute world units.
if (intersects[i].distance > cam.near) {
var description = " " + colorList[intersects[i].index].name + ", ";
description += " " + colorList[intersects[i].index].hex + ", ";
description += " Distance: " + intersects[i].distance.toFixed(2) + ", ";
description += " Ray to point dist: " + intersects[i].distanceToRay.toFixed(2) + ", ";
description += " Index: " + intersects[i].index + ", ";
description += " Coords: [" + intersects[i].point.x.toFixed(2) + ", " + intersects[i].point.y.toFixed(2) + ", " + intersects[i].point.z.toFixed(2) + "]";
descriptions.push(description);
showColor(colorList[intersects[i].index].name, colorList[intersects[i].index].hex);
break;
}
if (descriptions.length > 0) {
console.log("Mouse pointer intersected the following points, closest to furthest: ");
for (var v = 0; v < descriptions.length; v++)
console.log(descriptions[v]);
}
}
}
}
View Compiled
This Pen doesn't use any external CSS resources.