Tuesday, December 23, 2014

modern web tricks

I made my annual virtual advent calendar again, and this year I focused on the work of Ed Emberley. I'll do a "director's commentary" for the 25 puppets once they've all been unlocked, but for now I'd like to talk about some of the little tricks I used in assembling the main launch page for this year's calendar.

(It has been drawn to my attention that some of my work online is older, and doesn't exemplify best web coding practices, and so going into the future I'm determined to always try and put my best face forward with this stuff (and shake some old functional-but-ugly habits I picked up along the way.))

Ed Emberley has a series of books teaching kids and grownups how to draw things one simple shape (a square, a circle, maybe a letter) at a time. I highly recommend them!

My first idea for the layout was with a wide, highly horizontal view for each day.
It did a good job of reflecting the layout of the books, where the construction of the animal is shown as new shapes  in a kind of landscape format. However, it didn't look very calendar-like; I "user tested" the early draft with some friends and the response was along the lines of "what is this?" So I switched back to my traditional 5x5 grid.

Another idea that came from my "beta testers" (Jeremy Penner) was this:
I definitely think it'd be nice to show which days you've visited. Perhaps by showing the animal it becomes? Right now it's pretty tough to go "I wanna play with the whale again", but I see the appeal in getting a surprise when you open up a present.

Great thought, and obvious in retrospect. I made a screen capture for each puppet, so before you had seen it, you see all the pieces that make it in a square (with a day # overlay), but once you've played with it, the abstract list of pieces is replaced with a playfully cropped portrait.

I really think this adds to a sense of discovery and progress in the site. As previously blogged I used browser Local Storage to remember what puppets the user had seen, and then set the day to the portrait if it had been viewed already. Games and some sites use similar techniques, and I really like how the pile of portraits grown. Of course it's limited to only working if you consistently use the same browser, but I couldn't see away around that without offering an account system or tie-in to facebook or some such, which would be overkill (and risks a sense of "well why do they want THAT"). Local Storage was a good compromise.

I decided to display each puppet in a modal dialog (using jqModal.) In previous years I had made each day its own page, but keeping it as a single page app felt better to me. I thought about using a hash/anchor for back button support and bookmarkability, but the small advantages were outweighed by the potential for confusion.

I was still worried about the "what the heck is this" factor, so I did a 26th puppet, a bird, to display at the top, in both deconstructed and puppet form. The thing is, I was shy about having a processing.js app running all the time (especially with some of the heavier puppets, running two things at once wouldn't have been a good idea for performance and battery life reasons) but I still wanted a sense of playful animation, so I converted a series of a screenshots to an animated GIF using ImageMagick. I made the output not loop, and then had the onmouseover reset the src, retriggering the animation when the mouse was moved over it:

<img src="img/shakeATailFeather.gif" onmouseover='this.src="img/shakeATailFeather.gif"'>

I also used setTimeout to trigger the same thing at random intervals, in case the user didn't try hovering.

Each puppet has 3 images associated with it: the portrait, the deconstructed pieces, and then a grayed out, locked deconstructed. (I also used ImageMagick to make the grayed out version.) Assuming I wanted to precache, that would be a lot of roundtrips to the server, so I constructed a CSS sprite sheet for all 75 images. Each was 160x160 and so I set up an explicit .img class (I probably could have been more sophisticated and used different css selectors) for plucking it out of the sheet:
.img {
    background-image: url('spritesheet.png');

The ImageMagick syntax for generating the sheet was

convert image1.png image2.png [...] imageN.png -append spritesheet.png

That makes a big vertical strip, and I made a perl script to construct the CSS for each image, something like

snake .img.seen{
       background-position: 0px -320px

The pattern there is that the y offset is (-1 * size of image * image number).

Finally I could tackle the appearance of each day. I used the css nth-child() selector to alternate red and green, and used a .5 opacity for the number overlay. (For the unlocked days, at least. For locked entries I had a starker white number that was over the greyed out deconstructed pieces image) I wanted to draw attention to the current day, so I decided to have it flash gold (well yellow) using a CSS animation:
.advcal .day.today.unpicked {   
    animation-name: homeCycle; 
@keyframes homeCycle {
  50% {color:yellow}
(I also put in webkit version of these properties.)

For an increased sense of playfulness and interaction, I used CSS transition for the :hover over the squares.

I was glad to have the opportunity to practice CSS animations and transitions, since it's a relatively new technology. I had a little trouble finessing some of the states via classes alone, though, so while I didn't use jQuery for the color cycling I did use it for some of the image showing and hiding.

After launch, I added sharethis.com's widgets for social media sharing and some light view tracking. (In retrospect, I might have had a conflict with their use of the URL anchor hash had I been using that to follow the opening of the puppets.)

You can see the results on the live web site or in the github project page. As you can see, there's a lot of things that a mobile web engineer should be familiar with, and he or she should always be willing to experiment with different layout ideas, and test them with friends.

No comments:

Post a Comment