Can you tell us more about the technologies you used to create this web application [
Fridgemagnets]? I'd love to hear about the process you went through as you envisioned the project, chose technologies, and figured out how you'd code it.
Well, let's start off with the basics. If you look down at the footer, you'll see this line: "inspired by
twittermagents.com and an allergic reaction to all things flash." Now the fact is I love
+GOOD and the design sensibilities they had, but something about twittermagents rubbed me wrong. It wasn't just the Flash, although that was certainly part of it. It was the way the user was forced to create a 'fridgemagnet poem by putting them into a constraining box. People don't have a constraining box for their poems on their refridgerator: they just arrange them wherever they can and hope other people can make sense of them. We recognize a 'fridgemagnet poem by recognizing a meaningful and deliberate arrangement of words.
I already had a (fairly) complete toolbox: I knew that if I wanted to reproduce this in HTML5, I would be writing with HTML, Javascript, CSS, and I would probably be using jQuery. To simulate the "scatter" effect I would need a way to do CSS transform, so I searched for a jQuery plug-in that provided them. I would need jQuery-UI for drag-and-drop. And finally, to get the music effect of the original, I would need an HTML5 equivalent: a little searching and I found Buzz.js.
I don't really code in HTML, CSS, and Javascript anymore: I use HAML, Less, and Coffeescript instead. I like these technologies because they eliminate one whole class of errors. (They can introduce bloat and inefficiency, though, but it's easier to optimize a solution than fix a problem.) So my next step was to create a working environment where those were installed, and then write a Makefile to make converting from these pre-processed languages to their results easier.
I started with the HTML, since that was easiest: I knew I had three regions, a "board", a control panel and a footer. The control panel would have only a few things (volume control for the music, the shuffle button when I get around to it, the tweet button too). The last two had fixed heights. The board would have a "results" section to show the poem as it was being rendered.
I assembled some CSS as I was doing this to give the fixed-height items their necessary space.
At this point, I got stuck: what was I really doing here? At first, I was just throwing stuff at it to see how close I could get. I had some lovely backgrounds, and had some music, but what the heck was I really doing?
I wrote out some notes: The board must be resized when the user changes the size or orientation of their display. Words fill the board on start or shuffle event. A word has a bounding box, which defines how it looks and a larger box... No, that wasn't right: The board is full of tiles which have words on them. When a word is moved, we have to determine if it's part of a poem or not. Italicized words became classes, and bolded ones became events. Some events have to be abstracted: "moved" became "dragged" and "dropped," and had visual side-effects: the "pick up" and "put down" routines.
Now, since every tile has (top, left, height, width), I could theoretically know when two tiles were intersecting. I searched for "How to tell if two boxes are intersecting, naive."
The word "naive" is the key there: if someone uses the word "naive" to explain an algorithm, it's because they're going to show why it's naive and explain how to implement the algorithm correctly. This is what led me to game programming and the Separate Axis Theory. I gave myself a crash course in vector mathematics and wrote an SAT library for javascript over the weekend.
Once that was done, it was a fairly simple matter of (1) creating an object to hold each word, (2) adding the words to the board in a "hidden" way, (3) unmasking some 60 or so of them [Math.random < (60 / no. of words)], and (4) animating them to "fly in." All of these were basic jQuery capabilities.
I knew I need them to be drag-droppable, so I read the drag/drop documentation and added that capability.
This was the real fun. I spent a lot of time thinking about the tiles and collisions, and trying different ways of making sense of the problem until I wrote out
the basic algorithm. Then it was a matter of reasoning about the results: board, poem, and tile. Was the tile in a poem, or had it left a poem? If the poem split in half, what was the poem "now"? None of this had "side effects," so it was all about geometry and decision making: pure functional stuff. So I made up rules: "The poem determination routines all take a poem and a word, and return a new poem." The new poem might be an exact copy of the original, if all you did was move a word slightly, but as long as my functions did exactly that, I knew they weren't going to break anything else.
After that, it was a matter of rendering the side effect: drawing the "found poem" in the lower left corner.
I had never worked with game algorithms like this, but they were only a short stretch from the clock algorithms I'd used for
Arc Experiments. Abandoning my beloved Backbone for a home-made solution was a matter of understanding that I had only one data structure and would save a ton of unneeded code managing it myself. The music API was "just" an API: anyone could use it after reading the documentation.
The biggest insight was the creation of the Dimensioned prototype, which allowed me to use a "write-only DOM" method. I'd learned about that by following the
Javascript Zeitgeist on Delicious. I haven't quite hit it-- as I said, this is a rough draft, but it expresses some essence of the final draft, and I wanted others to see where it was so far. But by using it, I was able to write simple code that said things like "Tell me if these two objects are intersecting," which then made scanning for intersections, and groups of intersections, fairly trivial.
In many ways, programming is more craftsmanship than engineering: we know what tools we have, and we know what things we'd like to do. Sometimes I stretch my skillset out in one direction, and that's what Fridge Magnets does. Reading through the code, you can see little bits that are commented out still: during the "fly in," words aren't supposed to land on top of each other, but they do, because the check just says "they're not colliding," even when they are. It turns out that was okay, visually-- but now I have to say something like "When a user picks up a word, bring its stack order up one so it's 'above' everything else." That may be more visually jarring than sliding it out from under a covering word-- I'll have to see.