Thomas Fuchs
Hi, I'm Thomas Fuchs. I'm the author of Zepto.js, of script.aculo.us, and I'm a Ruby on Rails core alumnus. With Amy Hoy I'm building cheerful software, like Noko Time Tracking and Every Time Zone and write books like Retinafy.me.
   Want me to speak at your conference? Contact me!

Apple-style carousel with scripty2

May 1st, 2010

Prototype Core team member Sébastien Gruhier has an Apple store carousel with scripty2 example up at his site (and of course the code that it took to implement it!).

Plus, there’s a second example of how to use it to build a 37signals “Sortfolio” like carousel, with just one line of code. Awesome.

The code & examples are available on Github.

Build a Flash-like game with scripty2

April 30th, 2010

Flash games are facing stiff competition from JavaScript. You’ll see why when you follow along with this tutorial to create your first JavaScript-based game. How about a game of memory?

Naturally, we’re talking about animations here. The bar has never been higher in terms of interactivity in games. Games that don’t move are just no fun. Happily, in 2010, games built in JavaScript can be just as shiny, interactive, and fluid as games built in Flash.

All you need is a little help from a few open source tools.

For the visuals, we’ll use my Scripty2 animation framework, the successor to script.aculo.us. You’ll learn about easings, how to use and combine its built-in effects, and how to write your own. It’s easier than you think.

We’ll also use the Prototype JavaScript framework to write shorter, cleaner code, especially when managing the data structures and game logic. Like Scripty2, Prototype can change the way you think about JavaScript (and yes, we’re giving the latest and great version of Prototype a spin, which is available as Prototype 1.7 Release Candidate 1).

The best thing about learning to develop games is that the skills are useful even if you don’t want to be a game developer. Animations, easings, and the programming logic that drives them can help you make your “regular” web apps more useful and compelling. JavaScript as a technology has come so far, now it’s time for the interfaces built with it to catch up.

Check out the demo and play a game of memory!

Before proceeding, please download the tutorial files, and fire up a text editor of your choice to follow along!

1. Set up HTML skeleton

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <title>scripty2 Memory!</title>
    <link href="memory.css" media="screen" rel="Stylesheet" type="text/css" />
  </head>
  <body>
    <div id="field">
      <div class="card"><img src="back.png"/></div>
      <!-- 16 times -->
    </div>
  </body>
</html>

Our little memory game requires a playing field with 16 playing cards, a score field (1 point for each revealed pair) and a number of tries field (increments for each revealed card, regardless if a pair is found or not). It’s good style to add a DOCTYPE (we’ll use XHTML 1.0 Transitional) and define the character set as UTF-8.

2. Include JavaScript libraries

<script type="text/javascript" src="prototype.s2.min.js"></script>
<script type="text/javascript" src="memory.js"></script>

For fast loading, the best practise is to include JavaScript files at the bottom of your HTML, just before the closing tag. The tutorial demo code comes with all the files you need. Include the minified prototype.s2.min.js file, and the demo code in memory.js (which is not minified and heavily commented for easier comprehension).

3. Prepare card pair graphics

Fire up your graphics editor of choice and design 1 square card back graphic and 8 designs for the front (our memory game will use 16 cards, so it’s 8 pairs), resolution 140×140 pixels. The tutorial code comes with prefabricated graphics for this, with the scripty2 logo for the back and the numbers 1 to 8.

4. Shuffling cards

var cards = $$('div.card');
cards = cards.sortBy(Math.random);

To shuffle, first grab an array of all 16 card elements with var cards = $$('div.card') (memory.js, line 8), then use cards.sortBy(Math.random) (line 35) to randomly reorder. Array#sortBy is a Prototype JavaScript library function, to easily sort arrays. Feeding it JavaScript’s Math.random function is a handy shortcut. The expression returns a new array with the elements in random order.

5. Exporting internal functions for development

Object.extend(window, { shuffle: shuffle, win: win });

In Line 154 of memory.js, the shuffle and win functions are exported to the global namespace, for easy testing (no need to play through a complete game when you just want to tweak the winning animation timings). In the actual code, 'object' refers to the argument given to the outer wrapper function, which is 'window' (line 157), and'object' is the global namespace object when JavaScript is executed in a web browser.

6. Handling the click event

function dispatchClick(event, element){
  // the "element" argument contains the card that was clicked on!
  // now do stuff!
}

$('field').on('click', 'div.card', dispatchClick);

There’s two ways the clicking can be handled, either be registering event handlers on each card invidually, or using a dispatcher pattern. Opting for the latter is a good choice for games, as it allows tighter control. The dispatchClick function (lines 107 to 153) is registered on the “field” DIV, and detects which card was clicked on, by using Prototype 1.7’s handy new “on” function (line 151).

7. Add game logic

if(!element.retrieve('picture_revealed')){
  var id = reveal(element);
  
  $('tries').innerHTML = (++tries);
      
  // second card revealed, check if we have a matching card pair
  if(currentId){
    blocked = true;
    // yes, up score and run nice animation to remove the cards
    if(currentId == id){
      score++;
      updatescore.delay(1);
      
      (function(){
        cards.findAll(function(card){
          return card.retrieve('picture_id') == id;
        }).each(function(card){
          card.morph('opacity:0',{
            transition: 'pulse', duration: 1
          });
        });
        blocked = false;
      }).delay(0.5);
      
      if(score==8) win.delay(1.5);
    // no, hide all cards (after 1 second)
    } else {
      (function(){ 
        cards.each(function(card){ hide(card); });
        blocked = false;
      }).delay(1);
    }
    currentId = null;
  // first card revealed
  } else {
    currentId = id;
  }
}

There are two distinct possible states in the game when the player clicks a card:

  1. No card is currently revealed: reveal the card that is clicked on
  2. One card is already revealed: reveal the card that is clicked on and compare both shown cards, if a pair is found, remove those cards and update the score. Otherwise turn both cards on their back.

If the score reaches 8, the player wins the game.

8. Score keeping

// in dispatchClick, when a pair was revealed
score++;
updatescore.delay(1);

For each revaled pair, add a score point (line 121, 122). delay is a Prototype function that delays a function call for the given time, so the updating of the HTML is done a second later.

function updatescore(){
  $('score').update(score).setStyle('color:#77a638').morph('color:#aaa', 2);
}

The updatescore function sets the HTML, gives the new score a green color and then animates the color to fade to gray (line 85).

function shuffle(duration){
  $('score').innerHTML = score = 0;
  $('tries').innerHTML = tries = 0;
  // ...
}

Shuffling resets the score and number of tries counts (line 23, 24).

9. Add shuffling animation

// animate cards to go to new positions
cards.inGroupsOf(4).each(function(group, x) {
  group.each( function(card, y){
    flip(card, 'back.png');
    card.morph('opacity:1;left:'+(x*SIZE)+'px;top:'+(y*SIZE)+'px', {
      duration: duration || 0.5, transition: 'easeInOutQuint'
    });
  });
});

In the shuffle function, the movement of cards to a new position is achieved with just a few line of JavaScript, mostly to define animation options (lines 43 to 45). One key to good use of animation is to keep the duration short, as the animation should visually indicate that shuffling takes place, but shouldn’t feel sluggish or too drawn-out.

10. Basic easings

Easings are a mathematical function describing a change in timing. By default, Scripty2 runs effects with easing, so movements accelerate at the start of the effect, and decelerate smoothly at the end of the effect. There’s several predefined easings available, some of them taken from Flash game programming. Learn more and play around over at the scripty2 documentation.

11. Flip card animation

function flip(element, image){
  var img = element.down('img');
  img.morph('width:0px;left:70px;', {
    duration: .2, transition: 'easeInCubic',
    after: function(){
      if(image) img.src = image;
      img.morph('width:140px;left:0px', {
        duration: .2, transition: 'easeOutCubic'
      });
    }
  });
}

When revealing cards and hiding them again (when no matching pair was found), a “card flip” animation . To do this, two animations are chained: 1. the width of the image is gradually reduced to 0 (while keeping the height), accelerating troughout, 2. the card images is switched, and the width is expanded back to 140, decelerating.

12. Found a pair animation with advanced transitions

The transition system can be used for advanced scripting of the effects, for example for making an animation swing from or to a position, bouncing elements, pulsating or throbbing or even for random flickering. An effect often used in games is pulsating or blinking to grab the player’s attention.

card.morph('opacity:0',{
  transition: 'pulse', duration: 1
});

When a matching pair of cards is found by the player, fade those cards out, but use a pulsate transition when doing so.

This makes the cards “blink” smoothly and communicates the idea of accomplishment to the player (play a round of any jump and run video game and you’ll find similiar animations).

13. Winning animation

function win(){
  cards.each(function(card){
    card.morph('opacity:1');
    flip(card, urlForId(card.retrieve('picture_id')));
    card.store('picture_revealed', false);
    card.morph('top:0px;margin-left:'+((Math.random()*50) - 25)+'px', {
      propertyTransitions: {
        opacity: 'easeInOutQuart',
        marginLeft: 'pulse',
        top: 'bounce'
      },
      delay: 0.4+Math.random()*5,
      duration: 3+Math.random()*7
    }).morph('opacity:0;top:-100px;margin-left:0',2);
  });
  
  shuffle.delay(17);
}

Remember the animation when you win a round of Solitaire on Windows? You can do better! The example code shows a combination of several animations. First, all cards are shown with the numbers revealed, next there’s a smoke-like upwards movement and finally the cards disappear. Use win() on the console (or win the game!) to see this. After a slight delay the game is reset.

14. Preloading card graphics

// preload images $R(1,8) is like [1,2,3,4,5,6,7,8] (for this purpose)
$R(1,8).each(function(id){
  var img = new Image();
  img.src = urlForId(id);
});

function urlForId(id){ 
  return 'picture_'+id+'.png'; 
}

Because only the card backs are initially shown, preloading the card images makes sure there are no messed up card flipping animations.

15. Tweaking animation timings

The single most important thing with games is that everything should feel just right. Spending time on choosing the right transition animations, durations and delays is very important. This “motion design” is similiar to trying variations in graphic design. Don’t be shy and try out various settings and have fun fooling around. I’ll leave this step up to you!

16. Fix opacity on IE8

<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE7" />

Internet Explorer 8 is a bit peculiar when it comes to support CSS opacity. It still doesn’t support the ‘opacity’ property like any other browser, but also breaks support for ‘filter: alpha(opacity=XX)’, which worked fine in IE6 and IE7. To work around this, insert above meta element in the HEAD section of the HTML.

17. Avoiding “stuck” cards

Randomly reordering doesn’t guarantee that a card is in different positions on each shuffle (e.g. card #13 might be in position #6 on both random shuffles). To avoid this, set up a loop that keeps reshuffling until all card positions are swapped. Use Prototype’s zip and any functions to keep the code short and concise.

// randomize cards and reposition them randomly, in a 4x4 grid
// 1. make sure all positions change place
// this can take several iterations
// [].concat() is used to create a copy of an array
var currentOrder = [].concat(cards), matches = true;
while(matches){
  // zip combines two arrays into one
  // [1,2].zip(['a','b']) --> [[1, "a"], [2, "b"]]
  // this can be used to compare two arrays (in this case, find "any" matching pairs)
  cards = cards.sortBy(Math.random);
  matches = cards.zip(currentOrder).any(function(pair) { return pair[0] === pair[1]; });
}

18. Final touches

It’s a good idea to harden your code, both against user intervention (wildly clicking on things!) and programmatically (wrapping it in its own namespace or JavaScript closure). In the demo code the “blocked” boolean is flipped when click events should be suppressed (lines 9, 109, 118, 132, 140), and everything is wrapped in a JavaScript closure pattern (lines 4, 157).

That’s it. Awesome browser games. No Flash required.


About the author

Thomas Fuchs has been writing hard-core JavaScript since waaaaay back in the late 1990s.

His famous script.aculo.us framework was created during the development of one of the most highly interactive applications the Web had ever seen. He’s continued to push the boundaries of what is possible with JavaScript, with Scriptaculous and its successor, Scripty2.

Script.aculo.us has gone on to be used in such web sites & applications as CNN.com, NASA.gov, Me.com and more.

In addition to being a Prototype core member and Rails core alumnus, Thomas is one of the world’s top JavaScript and rich web app performance experts. He is also the author of Textorize, an automated tool that brings beautifully anti-aliased image text to the web (and beats the pants off Photoshop).

He is a self-described “artsy wanker.”

Prototype 1.7rc1 released

April 9th, 2010

A few days ago, Prototype 1.7rc1 was released and introduces some really cool new features and updates!

Perhaps most importantly, we now rely on middleware for the CSS selector engine. It defaults to Sizzle (used in jQuery among others), but you can also plug in others that might work better for your specific application. A good alternative is NWMatcher, a VERY fast selector engine. You might also find this useful in cases you do not need to support some older browsers, or if you want to use Prototype for specific platforms like iPhone Safari, to cut down on unwanted code.

The coolest new feature is Element#on, an encapsulation of the event delagation pattern that is so helpful in cutting down on the number of event handlers:

$("messagelist").on("click", "li.active", function() {
  // handle click on li elements with class "active"
});

Plus, Prototype 1.7 introduces a the new Element.Layout measurement methods, that allow for easy measuring of all sorts of CSS properties, automatic conversion to pixels of arbitrary CSS units plus measuring of hidden (display:none) elements.

Read the post at the Prototype blog for details!.

I Can’t Believe It’s Not Flash!

February 19th, 2010

Here’s my slide deck from my presentation at Webstock 2010 in Wellington, New Zealand, with me ranting about Flash (just a little!), and showing all sorts of up- and coming awesome web technologies (like HTML5 video, Canvas, SVG/VML and WebGL). Plus you can’t go wrong with a JavaScript-based C64 emulator.

Note that it’s really full of videos, something you regrettably can’t see when viewing the deck, but I do hope that the video of this talk will be up soon (will keep this post updated!).

Emile.js talk (video & slides)

January 28th, 2010

My talk from Fronteers in Amsterdam last year, about my 50-line of code CSS animation framework Emile!

Watch the video

If you like, grab the slides and the code at my previous post.

My next appearance will be in beautiful New Zealand, at the ever-amazing Webstock conference in Wellington (Feb 14-19). If you’re around and don’t have your tickets yet, you’re missing out majorly. I’d even go so far and call it a MAJOR FAIL. So do come there and join Amy and me at our Performance Bootcamp and our talks on “I can’t believe it’s not Flash!” and “Shift+Cmd+R: Hard Refresh Your Design”!

vienna.js Vienna JavaScript User Group

January 15th, 2010

User Groups are fun! And a JavaScript group was really missing in Vienna! So we founded one. 🙂 Everyone is welcome, just bring enthusiasm and open minds (and laptops!).

The first meetup will be on February 10, 2010, at Metalab.

If you like to join us for our first meetup, please RSVP!

We’re looking for a presentation of something awesome & JavaScripty, so any volunteers please step forward for fame and glory (please mail me at thomas@fesch.at!).

More information and updates on http://viennajs.org/ and on Twitter @viennajs.

JavaScript Master Class Vienna, March 2010

January 14th, 2010

Amy Hoy and I proudly present our fourth JavaScript Master Class, this time it’s where we live, in beautiful Vienna, Austria!

Do you…

  • know all the ins and outs of JavaScript’s object model by heart?
  • eat prototypes (‘little p’) for breakfast?
  • use closures and anonymous functions—but only in a memory-safe way?
  • secure internal code from API users, when necessary? (without obfuscation?)
  • curry functions?
  • practice safe namespacing?
  • dream about DOM reflow?
  • crawl through the DOM tree with practiced ease?
  • bubble or capture events from scratch—without peeking at the manual?
  • architect your large projects like a pro?
  • manage your code with an iron fist?
  • build your deployment process with tools other than FTP?
  • test your JavaScript with a unit testing framework?

Don’t worry if you don’t—yet. You will after you put yourself through our JavaScript Master Class, whether you use Prototype, jQuery, Mootools, or just your own naked cleverness.

The day is half about JavaScript the language, with topics ranging from functional programming patterns, closures and anonymous functions, object-orientation and prototypes all the way to building domain-specific languages and APIs in JavaScript; and half about the ecosystem, encompassing code organization, getting deployment right, creating great documentation, and having proper unit testing in place.

Our full-day class is limited to 20 seats, so you get to to pick Amy and my brains to the fullest (and afterwards we’ll socialize over a beer or two!).

Head over to http://javascriptmasterclass.com/ to learn more and register!

PS, we’re expecting to sell out! We’d hate to hear from you that you wanted to come but didn’t get a seat in time, so if you want to attend, please don’t hesitate! Register early!

Web development’s next decade

January 7th, 2010

Goodbye 2000’s, hello 2010’s. What does the next decade on the web have in store for us?

Let’s start by looking at what happened in the last decade.

In the Year 2000…

At the beginning of the year 2000 (shiver!), the current version of Internet Explorer was 5.0. (Though people were largely still using version 4.) IE’s market share was approximately 75% for all versions, slightly more than today.

Netscape had a market share of about 20%, thanks to a rapid decline following its last release (version 4.08 in November, 1998).

There were no alternatives in sight.

Flash was at version 4 (and didn’t get video support until mid-2002!), and JavaScript was at 1.3 (1.5 was released later in 2000).

Front-end web development was a horrible, evil mess. There were almost no debugging tools available for HTML or CSS. Forget about debugging JavaScript. (Though browsers were already pretty powerful, that power was largely wasted on tickers and animated cursors).

Many people took ActiveX seriously.

Snap back to the present—and the future

Here are some predictions of how I think the Web and development tools will keep progressing through the next decade:

First of all, most web sites/apps will suck most of the time. Still. This is not a problem technology can solve, only devotion and effort on the behalf of people who make web sites.

Furthermore, we’ll still see lots of compatibility problems. But nothing like what we have today, much less 5 years ago.

Browser Marketshare

And that’s despite the fact that Internet Explorer’s market share will continue to drop, to maybe 20-40% by the end of the decade. This will be caused largely by a shift to more specialized browsing devices (mobile phones, tablets), with IE used mainly for in-house legacy “web” business applications.

Conversely, Firefox will gain some more market share, but it will eventually yield to WebKit-based browsers, with many more WebKit-based browsers from various vendors being released. (You can see this trend now with Apple’s Safari, Google Chrome, Nokia’s Starlight project, and more.)

Interactive Environments & Developer Tools

JavaScript, CSS animations, and related graphics & I/O systems will take over. (Graphics will include Canvas, WebGL & SVG, but possibly also things we don’t foresee yet.)

We’ll see IDEs for development with JavaScript-based Flash-like graphics engines, that will use Canvas and WebGL, and SVG (Microsoft just announced it joined the SVG working group). Plus, these IDEs will also target non-browsers, by compiling the results into a browser runtime with deployment to various mobile platforms.

There will also be a dramatic increase of hybridized local/web software, such as Single Serving Browsers (SSBs), and “real” desktop-land software that syncs to, and interacts with, cloud services.

Browsers will eventually stop supporting Flash (at least out of the box), but Flash will stay as a development platform for mobile devices.

Mobile Devices

On the mobile side of things, I fully expect the landscape to be utterly different from now. The iPhone is just 3 years old now and changed pretty much everything in the “smartphone” space, and who knows what Tablet goodness 2010 will bring.

Language Dominance

And of course, JavaScript will continue to be the world’s #1 programming language, being supported (exclusively!) by anything that runs/is based on a web browser runtimes.

We’ll also see dramatically increasing use of server-side JavaScript technologies as well.

Translation: If you aren’t already comfortable with JavaScript as a language, you better learn it now.

Computers

I’m pretty certain that the basic form factor of computers that most people use today (laptops) won’t change that much (my 2002 Titanium PowerBook was not that much different from my current-generation MacBook Pro, except for speed/storage increase).

It is quite possible that desktop computers will experience a renaissance, with people switching to a desktop machine at home/work and tablets to lug around.

Disclaimer

And yeah, I’m probably horribly wrong. 🙂

(Big thanks to Amy for the input and some added sections on this article!)