Slabtype algorithm now a jQuery plugin

Algorithms, Digital Humanities, Graphic Design, jQuery, Source Code, Typography
1/17/12

image

Slabtype, the text rendering algorithm I developed for Public Secrets, has been adapted by web developer Brian McAllister as a jQuery plugin. If you’re interested, you can read details about the inner workings of the original algorithm. Very gratifying to see past work live on in new forms!

 

Postmortem: “Swing” at LAFlashapaloozastock III

Events, Flash, Flex, Interactive Design, LA Flash, Music, Typography, Wii
12/9/08

Swing projected on a brick wall next to the Wii menu

“Swing" was briefly installed outside next to a Wii running
Wii sports, but otherwise spent most of its time inside.

LAFlashapaloozastock III was another well put-together event—I enjoyed Ralph Hauwert’s talk on Flash effects and 3D as it was one of the best at bringing some perspective outside of the immediate world of Flash. Hauwert wove Escher, Pink Floyd, and the Amiga demoscene into the mix in a talk that otherwise would have just been a sequence of “ooh, cool!” demos (though they were quite cool… fluid dynamic bump maps on 3D objects, for instance...).

It was a challenge getting people comfortable enough with “Swing” to try it out—I had only one song request ("This Is How We Do It” by Montell Jordan) and that came early in the day, before a lot of folks started showing up. Over the course of the day I started calling the piece “karaoke for introverts” since no singing was required, but all the same people seemed reticent to pick a song and give it a go, just as if I had brought a real karaoke machine to the proceedings.

A student asked if I had considered adding greater variety to the visuals (color, etc.)—a valid question, given the apparent simplicity of the display. I explored this both during the original development of the piece and for this new version, but in both cases found that adding additional visual elements or processing made the experience too complex cognitively. While the YouTube video makes it look easy, trying to synchronize motions, syllables and pre-recorded music is actually a pretty challenging task for a novice, and glitz just makes it harder.

All in all, I came away with three keys to a successful “Swing” experience:

  • You’ve got to feel comfortable
  • You’ve got to love the song you’re performing and know it inside and out
  • You’ve got to be tuned into the rhythmic implications of whether your text is broken down into words or syllables

All of these things are easier to realize at home than in an installation space, so I’m planning to post the new version of Swing (which will now run in a browser for both Mac and PC users) soon, probably after Ruben & Lullaby is released.

Speaking of which, I met a lot of great folks during the event and got a lot of interest in Ruben & Lullaby (my upcoming iPhone/iPod touch game). I’ll be putting the finishing touches on over the next week or so, so stay tuned…

 

New version of Swing, the Wii Remote typographic karaoke Flash experience, to debut this Saturday

Animation, Announcements, Events, Flash, Flex, Fun, Interactive Design, iPhone, LA Flash, Music, Typography, Wii
12/5/08

image

For those in the Los Angeles area, stop on by LAFlashapaloozastock III in Venice this weekend for a full day of Flash goodness, including the debut of a new version of Swing. Swing has evolved into a typographic karaoke experience—we’ll use online services to stream your choice of song, download the lyrics, and get you waggling your way to Wii happiness. I’ll also have a number of “tuned” song/lyric combinations for you to play (yes, your dream of finally seeing a type animation of every single “ee-oh-oh” in Every Little Thing She Does Is Magic is about to be realized).

I’ll also be handing out postcards and generally talking up my upcoming iPhone game “Ruben & Lullaby,” which should be released in the next few weeks and has already garnered notice in TouchGaming. For more information visit opertoon.com.

Hope to see you there at LAFLashapaloozastock!

 

The slabtype algorithm, Part 4: Final layout and source code

Algorithms, Flash, Graphic Design, Interactive Design, Source Code, Typography
1/30/08

This is the final installment of a four-part graphical dissection of the “slabtype” text layout algorithm I developed for Public Secrets. For an introduction to the algorithm, visit The slabtype algorithm, Part 1: Background. To review some calculations that set the stage, visit Part 2: Initial calculations. To get into the real meat of the algorithm, visit Part 3: Iterative line splitting.

In this post, we’ll wrap things up by doing our final layout of the text, followed by the source code for the algorithm. The iterative sequence we explored in the previous installment successfully turned our original text:

Original text

into seven separate lines:

All seven lines

We’re almost done. Our next task is to assemble these lines into a slab by scaling them all to an identical pixel width:

Scaled lines

And finally, to scale the entire slab to fit inside the original box, allowing for a minimum amount of padding on each side:

Scaled lines inside slab

And with that, the algorithm has run its course. In conjunction with the treemap algorithm, the slabtype algorithm allows us to dynamically lay out the entire contents of a screen like this

A screen full of slabtype

using only a collection of quotes as a starting point. Due to randomization in the input to the treemap algorithm, even identical collections of quotes are never laid out in exactly the same way. Within Public Secrets, you can briefly see the dynamism of the slabtype algorithm in action when a box containing a quote resizes as it moves from one location to another—the text inside shifts around to keep pace with the changing dimensions of its enclosing rectangle.

This algorithm was included in Public Secrets as a method called formatInscription, which is reproduced below (AS 2.0). I hope this has been a useful exercise—I’d love to get your feedback, questions, or suggestions for improvement.


    /* -- formatInscription : formats the text to fit the slab dimensions -- */
    public function formatInscription(rect:Rectangle, useMargin:Boolean):Void {
       
        // calculate height of the ’ideal’ line
        var idealLineAspectRatio:Number = PS.fontInfo.altGoth3D.aspectRatio * PS.fontInfo.altGoth3D.idealLineLength;
        var idealLineWidth:Number = rect.width;
        var idealLineHeight:Number = idealLineWidth / idealLineAspectRatio;
        var lineCount:Number = Math.floor(rect.height / idealLineHeight);
        var idealCharPerLine:Number = Math.min(60, Math.max(Math.round(this._inscription.length / lineCount), 1));
       
       
        // segment the text into lines
        var words:Array = this._inscription.split(“ ”);
        var lineBreaks:Array = new Array();
        var preText,postText,finalText:String;
        var preDiff,postDiff:Number;
        var wordIndex:Number = 0;
        var lineText:Array = new Array();
       
       
        var counter:Number = 0;
       
        // while we still have words left, build the next line
        while (wordIndex < words.length) {
            postText = “”;
           
            // build two strings (preText and postText) word by word, with one
            // string always one word behind the other, until
            // the length of one string is less than the ideal number of characters
            // per line, while the length of the other is greater than that ideal
            while (postText.length < idealCharPerLine) {
                preText = postText;
                postText += words[wordIndex]+“ ”;
                wordIndex++;
                if (wordIndex >= words.length) {
                    break;
                }
            }
           
            // calculate the character difference between the two strings and the
            // ideal number of characters per line
            preDiff = idealCharPerLine - preText.length;
            postDiff = postText.length - idealCharPerLine;
           
            // if the smaller string is closer to the length of the ideal than
            // the longer string, and doesn’t contain just a single space, then
            // use that one for the line
            if ((preDiff < postDiff) && (preText.length > 2)) {
                finalText = preText;
                wordIndex--;
               
            // otherwise, use the longer string for the line
            } else {
                finalText = postText;
            }
           
            lineText.push(finalText.substr(0, finalText.length-1));
        }
       
        lineCount = lineText.length;
       
        // create inscription clip
        this._inscriptionClip.removeMovieClip();
        this.createEmptyMovieClip(“inscriptionClip”, 10);
        this._inscriptionClip = this[“inscriptionClip”];
       
        // build the text fields
        var curY:Number = 0;
        this._lines = new Array();
        for (var i:Number=0; i<lineCount; i++) {
            this._inscriptionClip.attachMovie(“altGoth3DText”, “line”+i, 10+i);
            this._lines.push(this._inscriptionClip[“line”+i]);
            this._lines[i].content.text = lineText[i];
           
            // scale this line so it exactly fits with width of the rect
            this._lines[i]._yscale = this._lines[i]._xscale = (rect.width / this._lines[i].content.textWidth) * 100;
           
            this._lines[i]._y = curY;
            curY += this._lines[i]._height * .59;
        }
       
        this._inscriptionWidth = rect.width;
        this._inscriptionHeight = curY;
        this._inscriptionAR = this._inscriptionWidth / this._inscriptionHeight;
       
        if (useMargin) {
            var margin:Number = this._margin;
        } else {
            var margin:Number = 0;
        }
       
        // calculate the scaling to apply so the total inscription fits inside the rect
        // centered, with the given margin
        var clipScale:Number;
        clipScale = ((rect.width-(margin * 2)) / rect.width) * 100;
        if (this._inscriptionHeight > rect.height) {
            clipScale = ((rect.height-(margin * 2)) / this._inscriptionHeight) * 100;
        }
        this._inscriptionClip._yscale = this._inscriptionClip._xscale = clipScale;
        this._inscriptionClip._x = (rect.width - (rect.width * (clipScale / 100))) / 2;
        this._inscriptionClip._y = (rect.height - (this._inscriptionHeight * (clipScale / 100))) / 2;
        GraphicUtil.changeColor(this._inscriptionClip, this._colorScheme.text_color);
           
    }


 

The slabtype algorithm, Part 3: Iterative line splitting

Algorithms, Flash, Graphic Design, Interactive Design, Typography
1/28/08

This is the third in a four-part graphical dissection of the “slabtype” text layout algorithm I developed for Public Secrets. For an introduction to the algorithm, visit The slabtype algorithm, Part 1: Background. To review the calculations that set the stage for this post, visit Part 2: Initial calculations.

In this post, we’ll take up the real workhorse of the slabtype algorithm—iterative line splitting—followed by the final layout of the text.

Our initial calculations provided us with a single very important number: 8, our ideal character count per line. This number gives us a target to aim for as we split our text into individual lines. We start by dividing our text into its constituent words:

Word splitting

Next, we execute the following iterative sequence:

  1. Create two containers for words. One will hold the next word of the text, the other will hold the next two words of the text.
  2. Keep adding subsequent words to both containers until the character length of one container is less than or equal to the length of the ideal character count per line, while the character length of the other container is greater than the ideal character count per line.
  3. Store the contents of the container whose character count is closest to the ideal character count per line.
  4. Repeat.

Here’s a diagram of how we arrive at our first line using this sequence:

First line

In this example, our two word containers initially hold the words “I and “I WISH. Neither of these exceed the ideal character count per line, so we continue adding words, giving us “I WISH and “I WISH IT. The latter is ten characters long, two characters longer than our ideal character count per line of eight. Since the former is seven characters long, resulting in only a one-character difference between its length and the ideal, we store “I WISH as the contents as the first line of the slab.

Here’s how we arrive at the next line:

Second line

Here, we have a very similar case. Neither IT nor IT WAS exceed the ideal character count, so we proceed to IT WAS and IT WAS THAT. IT WAS is only two characters off the ideal, compared to three characters for IT WAS THAT, so we pick the former.

Third line

The third line plays out a bit differently.  With THAT and THAT SIMPLE, we find that THAT SIMPLE’s character count of eleven is nearer the target of eight than THAT’s character count of four, so we go with the latter.

The fourth line plays out much like the first two:

Fourth line

While the fifth pass chooses the first of the two text containers:

Fifth line

The sixth finds ERASE MY matching the ideal character count per line exactly:

Sixth line

Leaving PAST” as our only remaining word, which becomes a line unto itself.

Seventh line

Since we have exhausted our available words, the iterative part of the algorithm ends, resulting in our original text being split into seven lines:

All seven lines

For the final installment, we’ll turn our attention to laying out the text within the target box (source code will be provided).

Coming soon: The slabtype algorithm, Part 4: Final layout and source code

 

Page 1 of 2 pages  1 2 >