One Year Of Design — In Colors

One Year Of Design — In Colors

This post is about how I built Colors — a data-driven collection of beautiful color palettes 🌈.

During the past year I've been working on Klart.co — a bookmarking service for designers and I've been using the service myself since then. A couple of months ago I decided to launch Pixels a collection of beautiful designs, which was basically designs I already collected for myself. I just thought it'd be useful for others too.

Anyway, given all this data (roughly 800 designs) I thought that it would be pretty cool to generate color palettes from this. I could see some issues though, and I was not convinced they would look good. Problems like gradients, photographic backgrounds etc, could generate weird palettes. But I decided to give it a try anyway, and it turned out pretty great (spoiler 😛). Let me walk you through it.

Expanding the current platform

The current platform for Klart was a Node.js application backed by MongoDB and Redis running on Digital Ocean. I was pretty happy with this setup and it had handled the traffic well so far so I decided to keep it simple and run Colors in the same application. After a couple of hours coding, I had an API endpoint for serving color palettes and another route serving the view for the Colors application in production.

I use Webpack to handle all my static assets so creating a bundle for Colors was as simple as adding another entry-point and push to production.

First design

After lessons learnt building the first version of Pixels, I was settled on a basic grid layout for Colors. I was thinking about whether I should have a two or three column grid and decided that displaying 5 colors in each palette needed some space, so I went with three. Initially it looked like this:

First grid layout

My first idea was to show the hex codes directly in the grid view, but I changed my mind and used a modal as detail view instead. This makes sharing much easier since each palette gets it's own URL.

Modal view

I though it would be nice to automagically copy the hex code when a color was clicked. This can be a bit tricky since you need to use hidden text forms etc. Luckily I found a nice library to handle this for me (Clipboard.js 🙏).

Another tricky part was how to dynamically set the text color of the hex to blend well with the background. After testing out different solutions using both CSS only and JS I ended up with the following giving the best results on most cases:

export default function shadeColor(color, percent) {
  const f = parseInt(color.slice(1), 16);
  const t = percent < 0 ? 0 : 255;
  const p = percent < 0 ? percent * - 1 : percent;
  const R = f >> 16;
  const G = (f >> 8) & 0x00ff;
  const B = f & 0x0000ff;
  return `#${(0x1000000 +
    (Math.round((t - R) * p) + R) * 0x10000 +
    (Math.round((t - G) * p) + G) * 0x100 +
    (Math.round((t - B) * p) + B))
    .toString(16)
    .slice(1)}`;
}

Credit to this fellow 👌.

Iterating

When I was happy with the detail view I decided to go back to the grid and work on it some more.

I thought that it would be cool to add some kind of interaction to be able to measure which palettes are more popular but I didn't want to force users to sign up. A simple like-button using local storage and an endpoint to collect the data would do the job without being a pain to implement.

Another thing that I'd thought would be useful was a link back to the design the palette was extracted from. I didn't really know what the best icon for this would be, but Font Awesome helped me out a bit with fa-external-link. That sounded good.

I also added some hover effects using shadows, color and scale.

New list view

Shuffling

A super appreciated feature on Pixels was the ability to randomly organize items by hitting space. It made a lot of sense to add this to Colors as well.

Shuffling

Meta data

Being a good citizen, I want my sites to look good on social media. At the current state, when palettes was shared by URL, people would just see the Klart logo and the description of the site. Boring.

I decided to add images for each palette. But the problem is, these images didn't exist, palettes was generated by HTML and CSS. I was thinking about this for a while and I've previously made dynamic sharing images using rendered HTML and CSS screenshotted by a headless browser like PhantomJS. But thinking more about the nature of these images I realized I could do something simpler.

I decided to create a thumbnail endpoint for each palette that would dynamically generate an SVG and then serve that as the meta image. Great.

Only problem with this approach is that Twitter et al don't support SVG images. Damn.

Luckily, there is an awesome tool called GraphicsMagick that allows me to take my generated SVG, convert it to a Buffer and then to a PNG that I would be able to serve. Pretty neat. This is what I ended up with.

  let svg = '<?xml version="1.0" encoding="utf-8" standalone="yes"?>';
  svg += '<svg xmlns="http://www.w3.org/2000/svg" height="500" width="600">';
  snap.colors.forEach((hex, idx) => {
    svg += `<rect x="0" y="${idx * 100}" width="600" height="100" style="fill:${hex};" />`;
  });
  svg += '</svg>';
  res.set('Content-Type', 'image/png');
  return gm(new Buffer(svg), 'svg.svg').stream('png', (err, stdout, _stderr) => {
    stdout.pipe(res);
  });

Some caching would probably do me good here, but I decided to save it for later since it wasn't critical for the first launch 🚀.

And this is the end result:
Dynamic meta image in Twitter card preview

I realized that the images are supposed to be of specific ratios for different sites, so my images ended up a bit cropped. The result was still way better than a generic share link though, so I decided to move on 😏.

The result — Beautiful and data-driven color palettes

The result was pretty awesome. Most palettes turned out to look really good and some are a bit ... funky 🙈. It's also pretty cool that I can keep collecting awesome designs for Pixels and this site will automagically keep up with it ✨.

This is what Colors looks like now 🌈:
Colors today

Final thoughts

The biggest surprise to me was the overall quality of the color palettes. Even from hard conditions such as gradients and full page photographic backgrounds, beautiful palettes were generated. That's pretty awesome.

Extra big thanks to all makers out there that makes this possible ❤️.

Don't forget to subscribe to Pixels to get the best designs and color palettes to your inbox every week.