date: 2017-09-05 tags: - linux - git title: 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](http://github.com/nickpegg/posty) 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](https://bokstuff.com) 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: [![Progress so far](/media/img/design_vis/progress.small.gif)](/media/img/design_vis/progress.gif) (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](https://wkhtmltopdf.org/) 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 ```