Skip to content

Instantly share code, notes, and snippets.

@djsnipa1
Created September 12, 2024 17:12
Show Gist options
  • Save djsnipa1/bd20342975f6bfd9b64436e84419adbb to your computer and use it in GitHub Desktop.
Save djsnipa1/bd20342975f6bfd9b64436e84419adbb to your computer and use it in GitHub Desktop.

Revisions

  1. djsnipa1 revised this gist Sep 12, 2024. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Untitled_Project.md
    Original file line number Diff line number Diff line change
    @@ -1,2 +1,2 @@
    # Untitled Project
    A project created by [Chad Boyce](https://gist.github.com/djsnipa1) on [LiveCodes](https://livecodes.io).
    A [project](https://livecodes.io/?x=https://gist.github.com/djsnipa1/bd20342975f6bfd9b64436e84419adbb) created by [Chad Boyce](https://gist.github.com/djsnipa1) on [LiveCodes](https://livecodes.io).
  2. djsnipa1 created this gist Sep 12, 2024.
    2 changes: 2 additions & 0 deletions Untitled_Project.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,2 @@
    # Untitled Project
    A project created by [Chad Boyce](https://gist.github.com/djsnipa1) on [LiveCodes](https://livecodes.io).
    184 changes: 184 additions & 0 deletions script.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,184 @@
    console.clear();

    import {
    converter,
    differenceEuclidean,
    formatHex,
    nearest
    } from "https://cdn.skypack.dev/[email protected]";
    import ColorThief from "https://cdn.skypack.dev/colorthief";

    const colorThief = new ColorThief();
    const toLCH = converter("lch");

    function adjustHue(val) {
    if (val < 0) val += Math.ceil(-val / 360) * 360;

    return val % 360;
    }

    function createScientificPalettes(baseColor) {
    const targetHueSteps = {
    analogous: [0, 30, 60],
    triadic: [0, 120, 240],
    tetradic: [0, 90, 180, 270],
    complementary: [0, 180],
    splitComplementary: [0, 150, 210]
    };

    const palettes = {};

    for (const type of Object.keys(targetHueSteps)) {
    palettes[type] = targetHueSteps[type].map((step) => ({
    mode: "lch",
    l: baseColor.l,
    c: baseColor.c,
    h: adjustHue(baseColor.h + step)
    }));
    }

    return palettes;
    }

    function isColorEqual(c1, c2) {
    return c1.h === c2.h && c1.l === c2.l && c1.c === c2.c;
    }

    function discoverPalettes(colors) {
    const palettes = {};

    for (const color of colors) {
    const targetPalettes = createScientificPalettes(color);

    for (const paletteType of Object.keys(targetPalettes)) {
    const palette = [];
    let variance = 0;

    for (const targetColor of targetPalettes[paletteType]) {
    const availableColors = colors.filter(
    (color1) => !palette.some((color2) => isColorEqual(color1, color2))
    );

    const match = nearest(
    availableColors,
    differenceEuclidean("lch")
    )(targetColor)[0];

    variance += differenceEuclidean("lch")(targetColor, match);

    palette.push(match);
    }

    if (!palettes[paletteType] || variance < palettes[paletteType].variance) {
    palettes[paletteType] = {
    colors: palette,
    variance
    };
    }
    }
    }

    return palettes;
    }

    async function loadImg(url) {
    const img = document.createElement("img");

    img.src = url;
    img.crossOrigin = `anonymous`;

    await img.decode();

    return img;
    }

    async function generatePalette() {
    let colors = [];
    let chosenImg;

    const queries = [
    "red",
    "green",
    "blue",
    "yellow",
    "orange",
    "magenta",
    "pink",
    "purple",
    "turqoise",
    "grey",
    "black",
    "white",
    "indigo",
    "violet",
    "emerald",
    "flower",
    "vibrant",
    "gold",
    "silver",
    "jewels",
    "rainbow",
    "forest",
    "ocean",
    "coral",
    "galaxy",
    "tree",
    "leaf",
    "fish",
    "frog",
    "animal",
    "wildlife",
    "color",
    "paint",
    "paint",
    "abstract",
    "colorful",
    "nature",
    "volcano",
    "sun",
    "ruby",
    "saphire",
    "emerald",
    ""
    ];

    while (colors.length < 4) {
    const url = `https://picsum.photos/200/300?${
    queries[Math.floor(Math.random() * queries.length - 1)]
    }`;
    chosenImg = await loadImg(url);

    colors = await colorThief.getPalette(chosenImg).map((c) =>
    toLCH({
    r: c[0] / 255,
    g: c[1] / 255,
    b: c[2] / 255,
    mode: "rgb"
    })
    );
    }

    const palettes = discoverPalettes(colors);
    document.body.innerHTML = `<div class="content"></div>`;
    document.body.appendChild(chosenImg);

    for (const type of Object.keys(palettes)) {
    const paletteWrapper = document.createElement("div");
    paletteWrapper.classList.add("palette-colors");
    document.querySelector(".content").appendChild(paletteWrapper);

    paletteWrapper.innerHTML = `<p>${type}</p>`;

    paletteWrapper.innerHTML += palettes[type].colors.reduce((html, color) => {
    html += `<div style="background: ${formatHex(color)};"></div>`;

    return html;
    }, "");
    }

    setTimeout(() => {
    generatePalette();
    }, 1000);
    }

    generatePalette();
    60 changes: 60 additions & 0 deletions style.css
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,60 @@
    * {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
    }

    body {
    display: grid;
    min-height: 100vh;
    color: #1d1934;
    place-items: center;
    font-family: system-ui;
    padding: 2rem;
    }

    .palette-colors {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    }

    .palette-colors div {
    flex: 1;
    height: 3rem;
    border-radius: 0.375rem;
    }

    .palette-colors p {
    margin-right: 1rem;
    text-transform: capitalize;
    }

    img {
    position: absolute;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    object-fit: cover;
    z-index: -1;
    filter: brightness(0.75);
    }

    body {
    }

    .content {
    width: 100%;
    display: grid;
    grid-gap: 1rem;
    max-width: 36rem;
    padding: 2rem;
    background: #fff;
    background: hsla(0, 100%, 100%, 0.75);
    -webkit-backdrop-filter: blur(16px) saturate(180%);
    backdrop-filter: blur(16px) saturate(180%);
    box-shadow: 0px 4px 16px 0px hsla(0, 0%, 0%, 0.125);
    border-radius: 1rem;
    border: 1px solid hsla(0, 0%, 100%, 0.9);
    }