Thursday, December 20, 2012

PDAs, smartphones, and formfactors

My phone, with a custom Alien Bill Gelaskin...
Not that anyone asked, but after playing with my friend's Galaxy S II, I'm wondering if it might be a better formfactor than my iPhone 5, that the more generous screen might be worthwhile so long as it doesn't take too big of a bite out of battery life or mess with the pocketability. (And I've grown to appreciate the iPhone 5's height, especially when using the calendar app, and with the larger landscape mode keyboard.) Also, the back was rounded... personally I think the earlier iPhones were better ergonomically than today's squared off beauties.

I've been a long term PDA user and when I look at the numbers, all but the biggest of today's phones are smaller than the original series of PalmPilots. It's interesting to note how modern smartphones are much more like the 90s' PDAs then they are like 90s' cellphones; when the iPhone was first announced I was struck by the similarity of its shape and homescreen to that of the Palm, not to mention some of the apps, like the datebook and the notepad. (Actually the first iPhone, without copy and paste or a Todo app, was a step down in terms of being an organizer, though obviously "web anywhere" and being a first rate music player made up for that.)
I've always liked to decorate--
Palm IIIc circa 2003


Now is a good time to suggest this excellent piece How Did We Get to the iPhone?-- the author is pretty sharp and while I would put the Palm chronologically before the Windows PDA stuff, and I'm bummed I missed out on the Psion, I saw a lot of my thoughts echoed in his writing. (For what it's worth (not much!) I chronicled my own personal history of devices, circa 2010. I think all I've added since then is an iPhone or two and a MacBook Air...)


Friday, December 14, 2012

speling

It is terrific that the Apache module that can correct "off by one" URL typos is called "mod_speling".

Wednesday, December 12, 2012

chr$

There is a recent book about a simple, simple program for the Commodore 64. The title of the book is the program itself, namely:
10 PRINT CHR$(205.5+RND(1));:GOTO 10
This program generates a maze-like structure by printing a series of randomly selected forward or back slashes (technically, slash-like characters from the computer's character graphic set.) When the screen is filled, the "maze" scrolls up two lines and keeps on drawing.

You can get a free e-copy of the book at 10print.org (They also have links to purchase physical copies). The text was a collaboration and goes into the history of C=64 one liners, the culture of computers that booted into BASIC, the meaning of (pseudo-)randomness, the legacy of mazes and labyrinths, etc etc. (Slate.com also had a nice review)

It's an inspiring book! Using processing.js, I created a slight variant on their "mazewalker" program, a variant that sends a little circle to wander the maze thus created:


There are some interesting nuances in how the maze walker works... although the "slashes" act as the walls, the walker is always "over" a slash, in a sense... but if you know which direction it was last traveling (and what type of slash it's over) you know which way it be deflect, and implicitly which section of the hallway it was travelling in.

My code for that is big and geared at readability, but Processing creator Casey Reas tweeted this tiny Processing version, from this processing forum challenge:
void draw(){int x=frameCount%20*5;int c=int(random(2))*5;line(x+c,89,x+5-c,94);if(x==95)set(0,0,get(0,5,100,x));} 
The end result of that is this:

So clever! It's very true to the spirit and feel of the original, though it has to do more work because the C=64 would keep track of the cursor and move the screen automatically.

Saturday, December 8, 2012

ObHacks and fun with giant stretchy backgrounds

So, "back in the day", before the web had really entered the popular consciousness, there was Usenet, a vast collection of discussion groups. Unlike today's forest of web-based forums where each has its own UI and culture, Usenet offered a single login, B.Y.O.interface, and semi-universal set of "basic netiquette" guidelines to talk about a huge array of different topics-- not to mention sporting a generally smart and net-savvy userbase. Its a bit of 'Net culture I miss.

One of my favorite newsgroups was "alt.hackers". It was "self-moderated" and you had to do a certain trick in order to post there. (This was of course using the original meaning of "hack": a clever, technically adept stunt, as opposed to the other meaning of "breaking into someone else's system".) There was a tradition there where if your primary content wasn't about hacking, you would include an "ObHack" (Ob as in Obligatory), some small little feat you had accomplished. Sadly, I haven't posted on alt.hackers for a long time (in part because I didn't have a good alternative when my alma mater gave up its Usenet feed) but I bring it up to say the following would have been a good ObHack (or two...)

The background is: A while ago the comic artist James Harvey was accepting commissions and I had him do a take on my personal avatar, Alien Bill. He's been my "signature" character for over twenty years now... usually he looks like
or even
but Harvey turned him into this magnificent Strider o'er the Earth:


I love that, especially at larger sizes, so I decided to use it as the backdrop at my portfolio site http://alienbill.com/, with this img tag

<img class="stretch background" src="bigbill/bigbill.jpg">

and this CSS to make it fill the complete width of the browser window:


.background {
    width: 100%; 
    position: absolute; 
    left: 0px; 
    top: 0px; 
    z-index: -1;
}

I was pretty happy with the result!  I was inspired by some uses of oversized images I've seen on other sites, but I think in general designers shy away from them, possibly concerned about load times. Still, a 1000x1500 image is only 200K and can look pretty good stretched larger than its natural size.

I had one problem though, which is if the browser is narrow relative to its height, the image ends, and you see the background color. For a while I punted and just had the background be a nice sky blue, so that as the image first loaded, the transition from background to image would be minimized. Still, it looked ugly at the bottom where the image ended and the "sky" picked up again. The ObHack, then, was the following code:

$(document).ready(function(){
$(".stretch.background").load(
function(){
$("body").css("background-color","#ABF36B");
}
);
});

So now the background starts blue, but when the image finishes loading, the background changes to the green, so it's a nice grassy area beneath. I also chopped the image and touched it up so the transition from image to flat color was masked. (Come to think of it, I could have considered a grassy repeating pattern for the background, but I think the flat green works well enough.)

Monday, December 3, 2012

advent-ures in processing.js

Presenting, the 2012 alienbill advent calendar, http://advent.alienbill.com/! 25 interactive toys and games for the holiday season.

All the entries are in processing.js... mostly ports of previous year entries I wrote in processing, but I made sure the interactions were tablet friendly, and I doubled the screen size. It's really fun watching stuff work on iOS devices...

Monday, November 26, 2012

flip this

There are many jQuery libraries out there for generating a "Flip" transition effect, as if a card was flipping over.  Flip!'s page is polished, but the effect is marred by the content disappearing during the flip. (Also I didn't like how it encourages the back content to be generated programatically, rather than living with the rest of the content.) QuickFlip 2 does a better job keeping the content present, but the visual effect is rather lackluster. However I have found an excellent, easy to use library that has a high "hey, wow!" factor and only a few things to watch out for: Zachstronaut's rotate3Di. Here it is an action:

This is a trivial example, but the content inside can be any html, including images.

It took me a bit to wrap my head around how it works: it's some CSS transform magic with skewY() and scale() being animated in sync for the nifty 3D illusion. The front of the card/back of the card bit is really interesting: if you want different content for the front and back, you make a function for the sideChange parameter. This function is called halfway through the flip with a boolean argument that indicates if the front is showing. Your function is then responsible for show()ing the appropriate side and hide()ing the other (which makes sense: with a flat object, only one side is visible at a time... Amusingly, the defaults without this function are to show the content reversed.)

So for this example, I had this HTML:

<div class="flippable" id="flipExample">
    <div class="front">Click To Flip</div>
    <div class="back">The Back</div>
</div>

decorated with this CSS (some parts omitted for brevity, feel free to view source.)

.flippable {
    height:150px;
    width:150px;
    padding:1px;
}
.flippable .front {
    background-color:#ffcccc;
}
.flippable .back {
    display:none;
    background-color:#ccccff;
}

The code then was pretty easy...
$('#flipExample').click(
    function(){
        $(this).rotate3Di('toggle', 1000,
            {
                sideChange:function(isFront){
                    if(isFront) {$(this).find(".front").show();$(this).find(".back").hide();}
                    else  {$(this).find(".front").hide();$(this).find(".back").show();}
                }
            });
    }
);

So like I mentioned, the things to watch out for were pretty minor: one was that the container (which is what is actually being rotated, but maybe shouldn't have content of its own outside of what's in your front and back side content) needed 1 pixel of padding, otherwise some odd lines showed up during the animation in chrome. And also, you need to include 2 js files, not just 1: jquery-css-transform.js and rotate3Di.js. The Transform one is needed for IE9 tweaking, which brings us to IE in general: it doesn't work for IE8 or earlier, but it degrades gracefully into an untransitioned swap of the front with the back.

So, a nice effect, and easy to put into place.

Tuesday, November 20, 2012

trunKit: how to deal with too much text...

As a UI developer, I'm sometimes given a visual spec to implement that doesn't really stretch: designs with elements that are fixed sized, regardless of the content meant to be lincluded inside (such as a long title or description.)

One solution for this is to show an abbreviated version of the title, possibly ending with a "...", and then let "hover" (in an increasingly touchscreen world, hover is often deprecated, though iOS tends to let a quick tap act as a hover) show the full title.  While refactoring our "activity tiles" at Alleyoop, I decided to wrap our solution to this issue as a jQuery plugin, So I introduce to you:
 trunKit.alienbill.com
I've posted an example of it in action below, but more information is there on the project site or its github repository.

Wrapping the functionality as a jQuery was easy: I'd recommend jMar's simple guide. The short of it is using a tiny bit of boilerplate, you're implementing an "each()" function (so your code can be daisy-chained) and then there's a nice method to allow for a hash of configuration options, but with sensible defaults.

Here it is in action:
 
This is the first example that I am placing here
My second example is not much different from the first
but by placing three examples, we will experiment with different colors.
But this is short.
There's likely dozens of similar plugins already out there, but this is mine, and I learned a bit from making it and packaging it as a plugin...

Thursday, November 1, 2012

wiki-dy wiki-dy wack

I like wikis, but tend to dislike wiki markup. As a note to my future self, {code}...{code} can be used to mark off some coding type stuff especially if said code has ${template stuff} like that in it.

Wednesday, October 17, 2012

safety second - encoding URLs


Just a note to my future self: you need to be not so blasé about building and then encoding URLs. And you can't just use javascript's encodeURI()on the whole thing, things like & will all be escaped inside of it. Instead, use encodeURIComponent() on the separate bits of it.

Again, kind of no-brainer but I got a slightly singed by it this week.

Friday, October 12, 2012

safety first with "global" javascript variables

This might be a "well duh!" for some of my audience, and I admit my need for this indicates some underengineering in my company's javascript component structure, but sometimes it's useful to pass information into one of our embedded components from the enclosing page via a global variable. ("Gasp!")

For a long time we were making this harder than it needed to be, because if you plan to have the page set something like

var global_hideFooter = true;

and then later do something in a component function like

if(global_hideFooter) { //do something 
}

it will break badly if called from another page that didn't set global_hideFooter one way or the other-- all the code in that block after the call to the non-existent variable will not be run.

However, if we realize that when you set a global in a browser (either by something like "var foo=" outside of any scope, or just start setting "foo =" anywhere) it gets implicitly included as a key/value on the "window" object. That means we can safely do

if(window.global_hideFooter) { //do something 
}

and it won't break if a page doesn't set it (and handily, in this case an unset value would act like false in a boolean context... defaults to false is a pretty natural coding paradigm.)

Tuesday, October 9, 2012

jquery data

Like I've written about previously, Javascript scoping can be tough to wrap your head around, and in general I try to avoid situations where I have to use CreateDelegate in order to have the context I'd "expect", especially during a click or similar event.

Yesterday I realized I had been forgetting about a very powerful tool in the anti-CreateDelegate, let-DOM-objects-carry-the-context-they-need front: jQuery's ".data()"  function. This little beauty lets a developer put key/value pairs "into" the DOM object for easy retrieval later.

Here's a version of some broken code I made yesterday:

for(var i = 0; i < data.length;i++){
    var jqo = $(".templateWrapper .modelTile").clone(true);
    var foo = data[i].value;
    jqo.click(function(){
        alert.text(foo);

    });
    $("#container").append(jqo);
}

The problem was because of the scoping, the text being alert()d was whatever the last value of foo had been, for all the tile objects.

I knew I could make use CreateDelegate object to carry the context, but that seems slightly less robust. Instead, I went back to use the .data() function:

for(var i = 0; i < data.length;i++){
    var jqo = $(".templateWrapper .modelTile").clone(true);
    jqo.data("val", data[i].value);
    jqo.click(function(){
        alert.text(
$(this).data("val"););
    });
    $("#container").append(jqo);
}

That worked and felt great! I'm not sure why I've been shy about using the .data() function; it's easier than CreateDelegate and less hacky than hidden form elements or rereading the content of visible DOM objects.

Friday, September 28, 2012

fullscreen iOS html5 apps and pretty clouds

Recently I remade an old art project of mine, "Virtual Sisyphus", as an html5 canvas work using Processing.js:


The viewer plays the role of Sisyphus, condemned to drag a rock up a mountain for eternity. Every time you try and fail to do so, the rock scores a point. (It's an existentialist joke, and like the PHB in the Dilbert cartoon series said, it has a certain sense of playfulness, if you look at it from the rock's point of view.)

I exhibited this as a work at my company's employee art show by using an iPad as a kind of virtual frame, you can see it on the left here:


I programmed the piece to have adjustable width and height, so it could fill its container, and scale itself to make good use of the space. Then, to make it as a nice fullscreen app (and make sure all the finger moving got interpreted as clicks and mouse drags in the Sisyphus world, rather than as scaling or resize) I did the following:

In the processing.js code setup, I started with:
size(document.documentElement.clientWidth, document.documentElement.clientHeight);

Then in the html file I had the following meta tags:

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name = "format-detection" content = "telephone=no"/>
<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width;" />
<meta name="apple-mobile-web-app-capable" content="yes" />

Just to be sure, I set padding and margin to 0px for both the body and the canvas tag processing.js uses.

(The apple-specific tag is kind of neat, adding that meant I could send the webpage to the homescreen from Safari, and then when I launch it from the home screen, it just has a minimal black bar at top, and skips the usual Safari address bar and what not.)

BONUS: HOW TO MAKE CLOUDS
I ended up being pleased with how nicely my cloud algorithm came out, using stretched ovals to get  a nicely organic/cartoony feel. Here was my Cloud class:

class Cloud {
  float x,y;
 ArrayList<Fluff> fluffs; 
  Cloud(){
      y = random(0,height * 3 / 8);
      fluffs = new ArrayList();
      int count = round(random(2,8));
      for(int i = 0; i < count; i++){
      fluffs.add(new Fluff());
      }
      x = width - getLeftmost();
      
 } 
   void move(){
      x -= random(.1,.5);
   }   
   float getLeftmost(){
       float lowest = 9999;
     for(Fluff f : fluffs){
       float side = f.getLeftmost();
       if(side < lowest) lowest = side;
     }
     return lowest;
   } 
   
   float getRightmost(){
       float highest = -9999;
     for(Fluff f : fluffs){
       float side = f.getRightmost();
       if(side > highest) highest = side;
     }
     return highest;
   } 
   
   void draw(){
     stroke(0);
     noStroke();
     fill(200);
     pushMatrix();
     translate(x,y);
   for(Fluff f : fluffs){
      f.draw(); 
   }
   popMatrix();
   }
  
}


class Fluff{
  float w,h,x,y;   
  Fluff(){
          w = random(width/9,width /3);
     h = random(height/24, height / 8);  
     x = random(-w/3,w/3);
     y = random(-h/3,h/3);
    
   }
   
   float getLeftmost(){
     return x-w/2;
   }  
   float getRightmost(){
     return x+w/2;
   }  
   
  void draw(){
   ellipse(x,y,w,h);
   w += random(-.1,.1);  
   h += random(-.1,.1);  
   x += random(-.1,.1);  
   y += random(-.1,.1);  

}

(Much  of the code was just getting the maximum left and right extents, so I would know when it was safe to remove a cloud from the world, and making sure it appeared off the right side of the screen.)

My main cloud generating loop was:

Cloud cloudToKill = null;

  for(Cloud c : clouds){
     c.move();
    c.draw(); 
    if(c.x + c.getRightmost() < 0){
     cloudToKill = c; //only one but it doesn't matter
    }
  }
  if(cloudToKill != null) clouds.remove(cloudToKill);
  
  if(clouds.size() < 5){
     if(random(250) < 1){
        clouds.add(new Cloud());
     } 
  }
  
It could only remove one cloud per frame, but that wasn't such a problem. And it maxed out at 5 clouds at a time.

So, that was it! Let me know if you ever manage to drag that rock to the top!


Monday, September 24, 2012

utm, no escape and irregular expressions


If you're doing work online and hang around marketing people enough, at some point "utm" might enter your world. Your landing pages will get hit with URL parameters like

utm_source=google&utm_medium=cpc&utm_term=some%25252Bgreat%25252Bkeywords&utm_campaign=Program

Beautiful, huh? ("UTM" stands for "Urchin Traffic Monitor", as Urchin was an early Google purchase and is at the core of their marketing tools.)

We were trying to use the utm_term variable, grabbing the keywords that triggered our ad (that the user then clicked) to appear on a web search. We wanted to parse the keywords to plug into our own local search engine.

I was aware aware of the %2B encoding... that's the hex code for a plus, and a plus is used to represent a space character, since URLs aren't supposed to have spaces. The double encoding (space to plus to hex) seemed a bit of overkill, but whatever...

But it wasn't enough! Searches were failing and it wasn't clear why... using our log browsing tool "Splunk" (what a name!) I grabbed log data to get the actual URLs, and found they our primitive "replace %2B with space" routine wasn't cutting it, because of beauties like "%252B" and even "%25252b" showing up. %25 is the code for the percent sign itself. So these guys weren't just doing double encoding, but triple and quadruple encoding!  Yeesh. (Meme: "Yo Dawg, we heard you like encoding, so we encoded your encoding so you can escape while you escape!")

I'm not sure if there's a handy library that would more properly do the un-escaping, but a bit of playing with javascript and actual data leads me to believe this regex should do the trick:

function removeDoubleEncodedSpaces(val){
return val.replace(/\%(25)*2b/gi," ");
}
So the pattern was a literal percent sign, 0 or more "25"s, then ending with a literal "2b", and I wanted to replace all of those with space, and do it in a case insensitive way. (Sometimes being an old Perl geek has its advantages.)

UPDATE: a coworker pointed out I could use decodeURIComponent(), a javascript built in. But I'd have to apply it 3 or 4 times in this case... I'm not sure if there's a while loop that would make sure all the encoding was taken care of.

Thursday, September 20, 2012

more html5 sound toys and games goodness

Last night I gave a brief presentation about my lowLag.js audio library at the Boston HTML5 Game Dev Meetup. I was able to show off the project's playground page with its new drum machine mini-app:

I got some nice feedback about the project from people. Brian Shim mentioned a trick of setting up a mic and getting a sound clip that has both the sound of the tap and the actual sound replay, so you can quantify the lag more precisely.

Admittedly, my humble project was a bit eclipsed by Tristan Jehan's talk about The Echo Nest. To brutally over simplify, part of their core is similar to what Pandora and the Musical Genome project do, but they use big data to get there, and when combined with an open API (and a number of music hackathons) they get some amazing stuff done... not just charting the relations between artists and songs in a metadata kind of way, but chopping and splicing and analyzing the song files themselves. Here were some of the projects mentioned:
Some of the others tools using the API seem to not be (or no longer online), like
Finally, we witnessed the launch of the Brainworth Kickstarter. The idea is a platform that teaches html5 game programming by playing games. It looks to have crazy fun social elements and general flexibility.

Monday, September 3, 2012

empower everyone: a new old paradigm for social software

Ok, enough of the in-the-trenches HTML5 audio gridning: lets talk about something a bit more abstract.

Recently I noticed a parallel in the solutions to problems faced by Google in their Hangouts app and by Apple with their AppleTV AirPlay photo sharing.

Google Hangouts is a group voice chat. That social technology often has a problem where one's person microphone is causing a problem for everyone else: either delay-echoing the main conversation, or making feedback, or having an on-device microphone amplify the typing sound of that person as they multitask during the chat, or some kind of intrusive background noise. Those sounds can be very disruptive to the group. But with Google Hangouts, everyone is empowered to mute anyone else. And they don't just mute that person for themselves, they mute that person for everyone!

If it ended there, a typical engineer might thing "That's censorship! How can that work? We should designate a conversation leader and only that person has such power!" But Google added two additional features that make it make sense: a public announcement of the muting is made on the Google Hangouts screen. ("Fred muted Barnie", for example). And a person who is muted is always empowered to unmute themselves. So while the potential for mute/unmute wars certainly exists, overall the experience makes sense.

I saw a similar problem and solution with AppleTV's AirPlay feature. We were over at our friend Sam's  house during our Labor Day vacation, and each of us had some pictures of the past few days on our iPhones that we'd like to show each other. The UI for this was breath-takingly simple in its "it just works" factor: in the iPhone photo app, hit the sharing button and then "AppleTV". And the rule is "last one in wins"; anyone can override what other people are looking at.  The stakes are pretty low, and anyone can replace what anyone else has beamed to the screen. Simplicity trumps authority!

But of course, there's nothing new under the sun, and this idea of empowering everyone has been around for a while. Here's an excerpt from Steven Levy's Hackers, Heroes of the Computer Revolution   about the ITS (Incompatible Time-Sharing System), an OS for the PDP-6:
ITS, in contrast [to Multics where hackers would prove their mettle by crashing the robust system], had a command whose specific function was crashing the system. All you had to do was type KILL SYSTEM, and the PDP-6 would grind to a halt. The idea was to take all the fun away from crashing the system by making it trivial to do that. On rare occasions, some loser would look at the available commands and say, "Wonder what KILL does?" and bring the system down, but by and large ITS proveed that the best security was no security it all.
Now it's not clear that this type of communal empowerment is always appropriate... like Alfred Pennyworth says in The Dark Knight, "some men just want to watch the world burn" and so the community needs to be able to reject such griefers with the scorn they deserve.  Still, it's a powerful idea to keep in mind for community UX.

Thursday, August 30, 2012

sounds good: hacking through the jungle of html5 audio

Audio is a more difficult thing for computers to get right. Even the humble(?) task of providing low-latency (i.e. quick response) audio clip playback is a challenge for some systems (I saw this first with using the minim library in Processing). And I'm talking basic audio, not heavily processed stuff, or even strictly "real time"-- enough so that in a game you can easily tell what onscreen event triggered the noise, not that you can base a "Guitar Hero" clone off of it.

tl;dr: Introducing lowLag.js Sounda simple wrapper for low-latency, high-compatibility, html5-friendly audio. 

It gives you three comands: init(), load(), and play(), and provides nice speedy sound across most browsers. See its official homepage or its github page for more.

The background:

I asked my buddy Darius Kazemi if had a recommendation- he helped Subatomic Studios make an HTML5 port of their iOS game Fieldrunners (You might want to his New Game 2011 Post Mortem on the porting process) and his quick answer was
Soundmanager2 is the standard. Definitely use that.
SoundManager 2's turned out to be a decent recommendation, thanks in part to the online documentation: even though the primary download seems to be a whole source tree, you just need to pluck a few files out for use, as outlined on the template example page (the API and Demo code page was also helpful.)

So SoundManager2 (with its two-fisted Flash-object with html5 fallback) worked on most browsers, it had much lag, especially on Chrome. I mentioned this to Darius and he told me that on chrome he usually goes straight to the Webkit Audio API, and sent me his example page.

So now I had 3 different techniques for audio. I made 3 test pages: one for the <audio> tag cloning technique, one using soundmanager2, and one using webkitAudio. Each page has a high pluck sound button, a low pluck sound button, and a button to play both at once.

Anyway, the webpage shows the detailed work I did in finding out what techniques worked best in which browsers, and then how I wrapped those in a single easy-to-use wrapper js object. I know I'm going to use it on upcoming game projects.

Enjoy!

Thursday, August 16, 2012

simple labeled percentage bars in CSS

So at work the spec called for a percentage complete bar... one of my coworkers came up with something like the following (I reinvented the CSS, but the idea was his)

The css and HTML is a bit more fiddly than I like, but I've seen worse:

<style>
.percentage {
width:200px;
height:20px;
background-color:#CCCCCC;
text-align:center;
color:black;
position:relative;
font-family:tahoma,arial,sans-serif;
}
.percentage .bar{
position:absolute;
top:0px;
left:0px;
overflow:hidden;
width:100px;
}
.percentage .inner{
width:200px;
background-color:#000055;
color:white;
}
</style>

<div class="percentage">
<span class="val">50%</span>
<div class="bar">
<div class="inner"><span class="val">50%</span></div>
</div>
</div>


The basic idea is to have 3 nested divs. The outer div has a fixed width and the percentage, with a dark text color. The middle div is set to the desired visible width of the bar (multiplying the current percent value times the width of the outer bar, divided by 100) It has its overflow set to hidden, so that the final inner div (set to the full width of the outer bar) displays its darker shade, lighter text for only as far as it needs to-- then the duplicate text of the outermost div shows behind it. The innermost bar obviously doesn't have to be a set color, it can be a repeating background image or whatever.

I then added a demonstration of an animation technique. As far as I know, there's no easy way of knowing how far along a jQuery animation is (for updating the % text) so I used setTimeout with a function that incremented the value and then called itself (in something a bit like tail recursion) until finally the displayed value was the same as the goal value.

(Wrapping this as a jQuery object or applying it to a specific need is left as an exercise for the reader...)

So that was the UI side of things. On the UX side, I thought we had a problem. At work we are introducing a point-and-level system and were using the progress bar to to show the user's current level along with how the points total and how long until the next level. The display for that was something like this:
 Level 3 was achieved at 700 points, and at that point I had 850. Take a look and answer this question: about how many points do I need to be at Level 4? 




To me it looks like Level 4 is around 2500 or so -- the bar indicates that I'm only 1/3 of the way there. But that's not the case. Level 4 is 1200 points, and what the bar is showing me is that I'm about 1/3 of the way up from when I hit Level 3.

So, I found that counter-intuitive, and unlike how other point systems (like the unlock system in the game Just Cause 2) do things. Instead, I thought this display was more clear:

Here, it looks like I am most of the way to the next milestone, which is in fact the case.

An alternate display might be something like:

I think this does a clearer job than the first example of showing Level 3 as a baseline, and that Level 4 as what is being worked to.

The jury is still out on which display we'll use. It deserves some user testing, but I'm pretty sure either of the alternatives are a better form of data visualization than the original setup.

Friday, August 10, 2012

js singleton boilerdish

(Improved version as of early 2014)

This is mostly just for future reference for myself (hence the cutesy name "boilerdish" that I can Google on...)

There are several patterns for making JS objects. One of my favorites is:

var someObject = new function(){
    this.someVariable = undefined;

    this.init = function(){
        alert("started up");
        someObject.someVariable = true; //don't rely on meaning of "this" too much!
    };
}

$(document).ready(someObject.init);

(Also sometimes I like to throw in the diagnostic logging stuff I wrote about here)

Caveats: this pattern doesn't provide much "privacy" for members, so it's not good for defensive coding. It's also kind of assuming a "singleton" use, but I find that pretty common and useful. (Also, given how frustrating "it depends on what this 'this' is this time" can be, the fall back of being able to refer to  "someObject.someVariable" out of the global space, rather than relying on delegates so that something like "this.someVariable" can work, is extremely helpful...) It does mean that there can just be a single entry in the generic Window namespace, which is always a plus.

Monday, August 6, 2012

processing.js porting gotchas

I've been porting entries from my Java Advent Calendars (both the 2009 and 2011 editions) into HTML5, via the wonder that is Processing.js. The original Processing (a Java based IDE and API, geared at students and artists) is amazing enough -- I really credit it with enabling me to make some really fun stuff in folks' browsers (not to mention effortlessly generated native Windows and Mac apps) but it feels like applets are kind of on their way out. So Processing.js allowing what is basically straight Java code to be run as Javascript (using the Canvas object) is super amazing. I don't know what black magic preprocessing they do to get 90% of my Java classes to work in a Javascript context, but it's great work, and less problematic than I thought.

Still, there are lots of gotchas, so here's my list of things to look out for, as determined by my personal experience. (Which involved some Processing code against the older version of Java that didn't use typed collections, and might not be using the latest and greatest release of Processing.js.)

Environment Gotchas

  • Speed. Some of my code that runs fine as an applet runs a bit slow in the browser, or at least with  some browsers javascript engines. I haven't yet isolated what operations slow things the most, but it seems like the line drawing isn't as quick.
  • Error messages. When you're coding up new stuff, the error messages can be a bit opaque, and generally don't have the line number of the original .pjs file. 
  • Chrome and running things locally. Chrome tends to balk at running code loaded locally from the file system. (Might be a good excuse for that Python webserver trick I mentioned earlier.)
  • 3Dness. One of my first attempts at porting a simple 3D app ended in failure, I haven't researched if there's an easy way around this.
Coding Gotchas
Most of the coding problems I've run into involve collections.
  • Collections & Inheritance. I had a big problem with this early-on, with an overly ambitious engine project I was doing for the Boston HTML5 Gamejam. It used a lot of object subclassing, and it seems like items in a heterogeneous collection of subclasses weren't being cast to quite the right types when it came time to call function names that they had in common.
  • The .removeAll() function for Collections is late to the party. I'm not sure if later version of the library fix this, but it was a known issue.
  • HashSet is not implemented. I liked to use HashSets for collections where order didn't matter but I wanted to be able to remove specific member items efficiently. ArrayList is a pretty good substitute.
  • In the bad old days of Java, before it's implementation of "foreach", you had to use iterators, and the best way to remove an item if you were in the loop itself was through the Iterator.remove() method (which removes it from the container the iterator is based off of.) .remove on the Processing.js iterator doesn't seem to propagate up to the main collection. (Combined with the .removeAll() lack, this was a little annoying.)
  • Apparently in Processing,
    ArrayList<SomeClass>things = new ArrayList<SomeClass>();
    is fine, but Processing.js gets confused, and wants spaces before the collection name. (For a while this led be to be unfairly pessimistic about the porting from Java, because the error message wasn't clear, and I was writing lines like that without spaces all over the place.)
So despite this list, in practice I've been increasingly impressed with what Processing.js can do. It's an awesome set of training wheels for people looking to go from Java to Javascript, and sometimes I wonder if it might not be a solid tool in its own right, as crazily ambitious as "run Java classes in Javascript" seems.

Followup: one other class of error involve java being strict about its types, but js being loose:

 int spotToYcoord(int s){
     return s / 3;
   }
This returns int values only in Java, but the equivalent of floats in javascript. (In this case the fix was to explicitly return floor(s/3) instead.

Wednesday, August 1, 2012

png compression for windows

Previously I wrote about ImageMagick, a Mac-only wrapper for several different near-lossless image compression programs. Today I discovered PNGGauntlet which is a PNG-only version for Windows. (I think it will also convert JPGs etc to PNGs, which might not be what you're looking for.

Thursday, July 26, 2012

a hack is still a hack

One problem with using divs with background images instead of proper imgs is divs don't have an exact equivalent of the "alt" tag, for screen readers and webcrawlers.

I found a coworker using "text-align:-9999px;" for the div -- this moved the text off the page but allowed him to use an image instead. (He was concerned about some of the nuance of the font and character rendering.)

It's a clever idea, but I think not a good practice. It smelled a bit off to me, and as I research it I see some bots like Google consider it a bit of a red flag.

A good trick to know of, but I'm not recommending it.

Sunday, July 22, 2012

the alleyoop "ignite" hackathon

the design for the hackathon shirts-- best
corporate shwag ever?
In June, my company ran a hackathon. It was modeled after the "startup weekends" that many of us in the company had been involved in. (In fact, our Product Director Matthew Mamet is heavily involved with some of the ones in Boston.)

The schedule for such a hackathon was/is as follows:

  • The week before: people think of an improvement or new feature for our site/product.
  • Wednesday afternoon: people give 2 minute pitches for their idea, and everyone has three votes (represented by a post-it to attach to the pitch's title sheet). Each of the top 4 post-it getters than have a crossfunctional team formed for it, captained by the person who pitched the idea.
  • Next 48 hours: people discuss, code, and user survey like crazy to validate the concept and see how much of it they can put into action. We had students in to user test and give feedback, and various Mentors to provide constructive criticism.
  • Friday late afternoon: each of the 4 teams gives a 5-minute presentation and has 5 minutes of Q+A. Then, the judge (Patrick, our President) goes out to mull over what he's seen and pick a winner, and also each participant gets to vote for any team except there own as a "People's Choice" winner.


I pitched an idea: TTT, "Typing Topic Targetting" (letter expanded to 4 "T"s to include Textbooks)... and my idea got picked by my peers. It was right-sized to be able to get big bang for the buck, fast (my experience with other hackathons and gamejams has taught me the value of aiming... well, not low, but in a way that assure you get value for money.)

The rationale of TTT was that since earlier word clouds had shown that visitors on the site were able to type in just what were looking for, math-help-wise, we should leverage that ability to get them more quickly to the topic they wanted help on, rather than forcing them to navigate through the hierarchical taxonomy of math that the site had to offer.

 My team was appropriately small, consisting of me (as captain and coder), Ari (who is interning here this summer) and Vincent-- we also had design support from Tom. We came up with mockups quickly to put in front of the students who were coming in to test things, and then did online surveys with Survey Monkey and click/label tests with Verifyapp.com. I also toiled away on a functioning prototype for the final presentation -- experience had shown that functioning demos impress judges.
search on keywords, hover for a view of the topic
After early discussions we decided on the importance of taking advantage of the topic screenshots that were already part of the site. We also realized that if we had a text search capability we could manually type in the table of contents of a student's textbook and then be able to synch our sites info with what the student was actually studying. 

We ended up building a nice interface for that, where you could either scroll through the table of contents and click your current section, or type in a page number and it would do the scrolling and clicking for you. We also showed a concept that would take the user directly to the first recommended activity, the core idea being the quicker we get people to what we have to offer in the context of just what they're looking for, the better off everyone is.

On the final day, we had a bit of time to polish up our presentation. Ari made a slick Prezi presentation, and we rehearsed until we had our 5 minutes down cold, explaining the benefits of our feature in terms of user onboarding and retention, a summary of the research we had done, and showing off our demo of the tech. (Part of the trick is to cut away all the extraneous padding, and then have one person pick up RIGHT when the other person drops off, a trick a mentor suggested as the "Radiolab" treatment.)

In the end, I'd say Team TTTT was a big success. We didn't score as the first place judge's pick, but we did get the second place "People's Choice" award - not bad for a plucky little 3 person team. (The winning team had 8 or so folks from all parts of the company, a beautifully faked online demo, and an intriguing idea.) Plus, all 4 ideas are being integrated into the real site.

Other groups in Pearson have showed interested in the hackathon, both the results (especially in my take on search UI) and in the process itself. I learned that a UI coder shouldn't build his or her own search engine under a tight deadline...

Anyway, I purposefully made the tech demo portable, and you can see and play with it on my personal website. The search and textbook sections are active, though there's a fair amount of fakery going on. ("Any sufficiently advanced technology is indistinguishable from a rigged demo ") I like the way kinetics of the search came out, and Tom did a nice job with the look and feel.

Not bad for half a week's work!

Tuesday, July 10, 2012

simple buttons for simple minds

Just a random note, as long as you don't mind cutting off IE8, you can get pretty decent button-looking divs in CSS now, with something like

<style>
.simpleButton{
box-shadow: 0 0 3px 3px #888888 inset;
border-radius: 7px 7px 7px 7px;
width:150px;
text-align:center;
}
</style>
You can get
Testing
It even works as a button:

Attractive, and easier and more flexible than using a background image.

Wednesday, June 27, 2012

quick note on tables

I've been slammed at work and not updating this site as much, though I have two biggish posts planned: a followup to my previous discussion about table layout, and the results from a hackathon my company ran the other week.

So I have put out arguments that tables solve more problems than they cause, but the accursed IE8 through up a counterargument... in short it looks like using colspans on rows before rows with items that have set widths may lead to frustrating results. A temporary fix was moving the "offending" colspan to its own table, but I refer my future self to this stackoverflow discussion that describes how setting "table-layout:fixed;" and a placeholder row explicitly setting widths, before the colspan, seems to lead to the correct behavior.

Tuesday, June 5, 2012

a sinking feeling about floating

I sometimes worry that I'm making what an old boss coined a CLM (career-limiting-move) by publicly declaring my irritation with floating divs vs tables.

My preference for tables is a a hangover from my paleolithic web roots, I'm afraid, but I'm not convinced modern html5-based design provides a solid alternative for flexible grid-based design. Floated divs certainly have advantages (in flexiblity, readability, division of form from content) but "always having things stay where you'd expect them to" isn't among them. 

Case in point: here is some CSS and its rendered result when applied to a wrapper div and 6 children, color coded for your convenience:

<style>
    .floater_wrapper {
        background-color:#cccccc;
        width:160px;
        height:58px;    
    }
    .floater_wrapper div{
        float:left;
        width:40px;
        height:20px;
        margin:4px;
        text-align:center;
    }
    .floater_wrapper div:hover{
        margin:2px;
        border:2px solid white;
    }
</style>



1
2
3
4
5
6

Simple enough, right? Float divs, and add a border when hovered. And in general it works ok... except on Firefox and Chrome, if you happen to have changed the page zoom (like by pressing ctrl-+) up a notch. In that case when you hover over 3 the floating changes, the box 4 jumps to underneath 3, and 5 and 6 get pushed down a row, outside of the box.

I'm not sure exactly what's going on, in terms of why the "4" thinks "2" is lower than "3" and so it floats against that-- I assume the screen zoom is putting in rounding errors. This particular case is easily remedied by not changing the margin when hovered and giving the non-hover state a transparent border, rather than assuming a 2px border plus a 2px margin is the same as a 4px margin.

So this case had a simple fix, but the non-intuitiveness and obscurity of the error (in terms of the page zoom) gives me pause. A radical change in structure like that is just not something you would have seen in a table-as-layout solution.  Just to get it out of my system, I'd like to write a few more advantages caveman-tables-for-layout have over floating divs. (Which is the fairest way of putting it, I think: people who say the argument is "tables vs css" are being grossly unfair.)

Eric Meyer, in 2009, put it pretty well:
All this is why the old “only use tables for layout” argument keeps coming up over and over: strip away the overheated rhetoric and obvious link-baiting, and you find the core of a real need. Because as powerful as CSS can be, table cells do certain things very easily that CSS makes very, very hard. Cells stretch vertically, keeping equal heights as a matter of their intrinsic nature. They stay out of each others’ way, while still being allowed to sit next to each other and use any sizing dimensions. They tie their layout to their parent elements, and vice versa.
I'd love to hear if the situation has changed much since then.

I can see the advantages that floated divs can have: like in today's example I didn't need to pollute the numbered divs with table structure layout, and programmatically it would have easier to just keep on adding in divs, rather than having to coordinate the row structure. (and yeah yeah yeah, tables are for tabular data and using them for layout is the anti-thesis of proper html5 semantic thinking.)

But on the flipside, the wrapper in this example had a fixed height, in part because a container div will collapse if all its contents are floated (hence things like the clearfix hack... and don't get me started about some of the disgusting stuff I've seen to get columns to line up!)

Finally, beside my love of colspans and rowspans and what not, it's a lot easier to throw a "border" onto a misbehaving table you're trying to construct than to get a visualization of errantly interacting floating divs!

I'm swimming against the tide of design history here, I know, but until I learn of a better way to get grid-like behavior on a webpage, tables are going to be part of my web design arsenal.

(Quick followup as I ponder this a bit more: I do realize responsive design is generally a lot harder with tables, because of the mix of form and content. Most of what I really count on tables for, though, is not in the "whole page" style of layout, but for individual smaller widgets, where you really don't want things jumping around, and for them to keep their general relative positions. That's actually one of the paradoxes of responsive design: usually you want layout things to stay the same, no matter how the content changes, but with responsive design you finally want things to shift when the content seems to big for the space allotted...)

Tuesday, May 29, 2012

choking on cookies

Just a note: if you are designing an integration using iframes (like where your content shows up in an iframe on some other domain's site) you need to be aware of some pretty deep browser-specific issues involving cookies. IE will block cookies until some privacy blahblah is set; Safari has similar issues, but it's issue is about cookies on pages that haven't been directly navigated to (i.e. they've only shown up in an iframe, rather than the domain having ever been seen in the URL bar.)

There might be some further differences between the two cases; it seems like IE will allow cookies over the life of the page, at least, which is more than we got from Safari (which was a big issue because our pattern was to authenticate in one endpoint call, and then do further requests for more data) but don't quote me on that. The short of it is: you have to do a lot more QA on cross-brower issues if they involve iframes and other sites, and in fact the problem are so significant you should be thinking about them as you architect your embedded pages (and possibly doing rapid prototypes to make sure you can get to the cookies you need to when you need them.)