Visualizing Web Design Evolution Using Git
My website here, as of the time of writing this, is still based on a design I made back in 2010, and is rendered using my static site generator that I haven't touched in nearly as long. The site's served its purpose pretty well, but it's kind of a mess; It's unreadable on mobile devices, the CSS causes some weird inconsistencies, and the static site generator is no where near my current standards. So since this is a personal project I have the liberty of throwing it all in the trash and starting over (and learning new things along the way!).
Since my weakest area is front-end (design, Javascript, CSS that doesn't look like it was written by a crazy person, etc.), I decided to jump in there, doing a couple of experiments. I ended up spending the better part of a weekend fiddling with HTML, playing with a couple of CSS frameworks to see what I liked, and incessantly bugging my friend Brian for help. Eventually I got something that I thought looked pretty good and got the 'final' version checked into git.
So you want to know the cool part about git? If you use it right, you have a bunch of commits containing the full history of what you're building! And with a bit of magic you can come up with something like this:
(click on image to see the full size version)
Neat, huh? So how the heck did I manage to pull this off? With some shell scripting wizardry!
Since all of my design is in a single HTML file, index.html
, it's easy to comb through the history with the git log
command. And to get the commit hashes to iterate over them, just add in some grep
, awk
, and tac
to reverse-sort them (from oldest to newest).
git log -- index.html | grep commit | grep -v initial | awk '{print $2}' | tac
Okay, cool, so now we can flip through the history of our index.html
, now how do we make an animated GIF of it? Well, an animation is just a set of images, so we need to figure out how to turn our HTML into an image a bunch of times. This is where wkhtmltopdf comes in handy! The name's kind of a mouthful, but it's a tool that uses WebKit to render HTML and output that to a PDF (or an image). It's super simple to use! Just give it a URL or file name, and then a file to output to, and it does the rest.
wkhtmltoimage --width 1920 --height 1080 index.html index${NUM}.png
Alright, now we've got a bunch of images, how do we string those together into a GIF? For things like this, I always turn to ImageMagick's convert
tool, which is the swiss-army-knife of image manipulation. It turns out that if you pass it a bunch of still images and a filename that ends in .gif
, it just knows to make a GIF! Incredible! Since we want it to slowly go through the changes so you can play spot-the-difference, we add in a -delay 100
to the command to tell it to wait 100 tens of milliseconds between each frame.
convert -delay 100 index*.png progress.gif
Add in some hackery to remove duplicates (because the rendered page may not change if you change the HTML) and to add a pause of the last frame, and this is what I came up with:
#!/bin/bash
# requires that imagemagick and wkhtmltopdf are installed
mkdir -p progress
git checkout master
mkhtmltoimage --crop-w 1920 --crop-h 1080 https://nickpegg.com progress/0000.png
count=0
commits=$(git log | grep commit | grep -v initial | awk '{print $2}' | tac)
for commit in $(echo $commits | xargs); do
git checkout "$commit"
i=$((++count))
wkhtmltoimage --crop-w 1920 --crop-h 1080 index.html "progress/$(printf "%04d" "$count").png"
done
# Magical one-liner to remove duplicates
md5sum progress/* | \
sort | \
awk 'BEGIN{lasthash = ""} $1 == lasthash {print $2} {lasthash = $1}' | \
xargs rm
# Add an artificial pause by copying the last file a few times
for i in $(seq $((count+1)) $((count+5))); do
cp progress/$(printf "%04d" "$count").png progress/$(printf "%04d" "$i").png
done
convert -delay 100 progress/*png progress.gif
git checkout master