Bootstrap grid system explained

One of my co-workers ran across an article called “The Subtle Magic Behind Why the Bootstrap 3 Grid Works“. It’s worth mentioning here, partly so I have a good place to find the link again.

The article does a very good job of laying out two things: how Bootstrap’s grid system works (for those of you, like me, who are geeks and want to know how everything works), and — far more importantly — how to use Bootstrap’s grid system correctly (for those of you, like me, who wished the Bootstrap documentation did a better job on that score).

The “how to make it work” is vital. The first time I tried to use Bootstrap’s grid system, I tried to follow the documentation, finally gave up in disgust, and just did a View Source to see what classes the documentation page actually used, and dorked around with it until I figured out how many of those I really needed. If you read this article, you won’t have to do that. It lays out, very clearly, what classes you need to put where, and what you can safely nest inside what. The illustrations are also quite helpful.

Well worth the read.

Angular street cred

Today at work, a couple of my co-workers flagged me down to help them figure out a problem with an Angular app they were working on.

Now, my only experience with Angular has involved playing with it in my spare time (and trying to write a video game with it) — whereas these are people who have been doing Angular development as their day job for the past month or so.

Of course, I did volunteer to give the team a lunch-and-learn presentation, back when they started on this project, to help introduce them to Angular. So I guess I already had some Angular street cred. Plus, they’ve known me for years — enough to know how I like to dig into the details and figure out how things tick.

But still, I thought that was pretty cool — that even in my spare time, I’ve picked up enough Angular knowledge that they called me over to help.

(And yes, I was able to help get their code working.)

ng-rpg: Trying to scroll the world map with Angular animations

I’ve talked before about how I’m writing a Final Fantasy-style roleplaying videogame in AngularJS. As is my wont, I’m actually trying to write a reusable framework that other people could use to build their own console RPGs; my game will just be a proof-of-concept for the framework.

(I’m calling dibs on the name “ng-rpg”.)

One of the most basic things that a Final Fantasy-style RPG needs to do is let you walk around the map. Angular has animation support baked in, and I had some ideas on how I could implement “walk around the map” with animation and databinding, as crazy as that sounds. But I needed to do some testing to make sure I’d get good results.

Let’s say the user hits the left arrow on the keyboard. I always show the in the center of the screen, so for the hero to move left within the map, the map needs to slide to the right. I scale the tiles based on screen size, but let’s say the map needs to move 100 pixels. Once it’s moved 100 pixels, I need to check to see whether the left arrow is still held down; if so, I kick off the animation again, and the hero keeps moving smoothly westward through the (scrolling) map.

Angular can do a bunch of this. I could use databinding to add a CSS class to the “map” div, and as long as I’ve defined the animations in my CSS, Angular would automatically kick off a nice animation to move everything 100 pixels.

I also need to know when the animation is done, so I can’t just use the built-in ngClass binding — it has no way to give a “done” notification. Instead, I need to write my own directive, and have it use the $animate service to add the class and specify a “done” callback. Then in the callback, I can decide whether I need to restart the animation, or perhaps start a different animation, or just stop. So far so good.

The question is, if the callback restarts the animation, what will the user see? Will the transition be seamless and continuous, or will there be a tiny pause before the animation restarts?

To find out, I put together this proof-of-concept plunk. It just has a box that you can move left and right using a couple of buttons, and each time you tell it to move, it does two animations in a row, so you can see whether there’s a seam between them.

The results were disappointing. With Angular 1.2, Chrome’s animation is smooth and seamless; you can’t even tell it’s chaining two animations end-to-end. But in both FireFox and IE, there’s a noticeable pause before it starts the second animation, so the animation is choppy instead of continuous. And in the Angular 1.3 beta (plunk), I haven’t had any luck getting this technique to work at all — if I remove and re-add the class in the “done” event, the animation doesn’t restart.

So it looks like pure-Angular animations won’t really work for RPG maps (though I expect they’ll be pretty slick for battle animations). But that’s okay; my next map-animation proof of concept showed more promise. Stay tuned.

Using ImageMagick for palette-swapping

A common thing in console RPGs is palette-swapped monsters, where the same image is given a different set of colors, so an Imp becomes an Imp Captain, Dark Imp, etc. without the need for brand-new artwork. I used this technique to generate the various hair colors in my Ponytail and Plain hairstyles that I posted on OpenGameArt and contributed to the Universal LPC Spritesheet.

You can do palette swaps fairly straightforwardly with the ImageMagick command line. You pass something like the following to the convert command line:

-fill #FFFF00 -opaque #999999

This replaces all light gray pixels (#999999) with eye-searing yellow (#FFFF00). Note that it’s target color first, then source. You can repeat this pair of commands as often as you like.

It gets a little odd when you get to semitransparent colors. Say your source image has some pixels that are #9C59919C (that’s ImageMagick’s oddball RGBA syntax, with the alpha at the end). If you try to replace #9C5991 with some other color, it won’t affect the semitransparent pixels — -opaque does an exact match, and #9C59919C is not an exact match for #9C5991[FF]. So you need to explicitly specify the source and target alpha with each semitransparent color:

-fill #FF00FF9C -opaque #9C59919C

Note for GIMP users: If you use ImageMagick to replace semitransparent colors, and then open the output file in GIMP, GIMP may not show the semitransparency. This seems to be a GIMP-specific bug with indexed-color images (i.e., those stored with a palette). Just switch GIMP to Image > Mode > RGB and it’ll display correctly.

Combine this with the trick we saw last time to remove the embedded create/modify dates and you get something that looks like this (though all on one line):

convert
    infile.png
    -fill #FFFF00 -opaque #999999
    -fill #FF00FF9C -opaque #9C59919C
    +set date:create +set date:modify
    outfile.png

Using ImageMagick to write PNGs without embedded create/modify dates

I’m writing some Rake tasks to generate a bunch of PNGs to check into version control, and ran into a problem: every time ImageMagick generated the files, they showed up as diffs in Git, even if the pixel content was identical. The files’ hashes were different each time I generated them.

I did some hunting, and found a discussion thread “create/modify-date written into file”, but its fix (adding +set modify-date +set create-date to the command line before the output filename) didn’t work for me — if I generated the same content twice, the two files were still different.

So I looked at the output of identify:

identify -verbose generated.png

Which spews out quite a lot of output, but in it was this:

  Properties:
    date:create: 2014-01-12T08:01:31-06:00
    date:modify: 2014-01-12T08:01:31-06:00

Maybe they just renamed the properties in a later version of ImageMagick? (The thread was from IM 6.4; I’m on 6.8.7.) So I tried adding +set date:create +set date:modify.

And that did it: I could generate the same file twice, and the two files were binary equal.

file 'generated.png' => ['infile.png', 'Rakefile'] do
  sh "convert infile.png[64x64+0+0] infile.png[64x64+128+0] +append " +
    "+set date:create +set date:modify generated.png"
end