Story

Connect4Story = Story([
  [
    {
      setup: function() {
        Story.write('game', new Connect4(5,5));
      },
    }, Story.Ignore(Story.Loop(
      { setup: function() {
        DrawGame("Red's turn", Story.read('game'), Story.read('target'));
        $('.column', Story.read('target')).each(function(index) {
          $(this).unbind('click').click(Story.callback(function() {
            var game = Story.read('game');
            if(game.can_move(index)) game.move("red", index);
            this.moved = true;
          }));
        });
      }, update: function() { 
        return !this.moved; 
      }, teardown: function() { 
        Story.read('target').contents().remove(); 
      } },
      { setup: function() {
        DrawGame("Blue's turn", Story.read('game'), Story.read('target'));
        $('.column', Story.read('target')).each(function(index) {
          $(this).unbind('click').click(Story.callback(function() {
            var game = Story.read('game');
            if(game.can_move(index)) game.move("blue", index);
            this.moved = true;
          }));
        });
      }, update: function() { 
        return !this.moved; 
      }, teardown: function() { 
        Story.read('target').contents().remove(); 
      } }
    )), function() {
      var winner = Story.read('game').winner();
      if(winner) Story.write('winner', winner);
      return !winner;
    }
  ], 
  function() {
    var target = Story.read('target');
    DrawGame(Story.read('winner') + ' won!', Story.read('game'), target);
    jQuery('<button/>')
      .text("Play Again?")
      .click(function() {
        Connect4Story.tell({ target: target });
      })
      .prependTo(Story.read('target').find('.connect4'));
  }
]);

Lightweight, simple, scalable, modular metascripting. Linearizes and abstracts callback chains. Makes complex flow simple.

Story is a modular framework for handling asynchronous events.

To learn more, please see the API docs.