The Karma Project: Code Less, Teach More

February 18, 2010

Introducing the Karma Lesson Template

Filed under: News — Tags: , , , , , , , , — bryanwb @ 8:19 am

I have created a simple template for individual karma lessons. In this post, I will explain how to use the template and what still needs to be implemented. The template still has some rough spots that I would very much appreciate feedback on.

Before reading on, you should download the lesson template directly or use git to clone the repository.

$ git clone git://

What the Template Provides

  • Layout that matches the XO’s screen resolution
  • Navigation bar – with links to help text, lesson plan, and teacher’s note
  • Viewer for lesson plan and teacher’s note
  • Scoreboard, timer, Start, Stop, Restart buttons all in the footer
  • Helpers to make your lesson event-driven rather than using a single control loop
  • Basic i18n for strings, but this is still in flux

Most Important Files in the Template

These are the files that will modify to create your lesson

  • index.html – the markup for your lesson
  • js/lesson.js – the code for your lesson
  • css/lesson.css – the layout for your lesson

Meet index.html


The html markup in index.html is quite simple

        <div id="kHeader">

	<!-- Put the help text inside #kHelp -->
	<div id="kHelp" title="Help Title"> Help text here</div>
	<div id="feedback"></div>
	<!-- #kMain is where the magic happens, the main frame where your lesson
              its stuff -->
	<div id="kMain">
	  <strong id="itWorks">It Works!</strong>
	<div id="kFooter">

That is very little html for actual page that is rendered. That is because #kHeader, #feedback, and kFooter are just scaffolding that we use to hang jQuery UI widgets on.

Here is a wireframe of index.html that will help you understand the dimensions and layout

As you can see from the wireframe, the lesson has a default width of 1200px and height of 900px. This gives you 1200px X 760px in #kMain to use for your lesson.

This is to match the dimensions of the XO. We could default to a smaller resolution that matches most desktops, like 1024 x 760 or 800×600 and scale up the lesson on the XO. We don’t do this for two reasons. First, scaling up is cpu-intensive and slow as molasses on the XO and second, scaled up raster images (.png, .jpg) ‘pixelate’ and look like crap. If we only used SVG images throughout the template, this would be a non-issue, as SVG scales up and down without performance cost.

I have created a function in the Karma.scaleWindow that will scale down the entire lesson to 950px X 760px. This leaves you only 950px X 460px. Please don’t develop a Karma lesson at this resolution if you intend it to run on the XO. I created this function to scale down your lesson to run on non-XO’s with the resolution 1024 x 760. With a bit of work you can make sure your lesson works at both 1200px X 900px. By far the easiest way to do this is to only use SVG.

Karma.scaleWindow();   /*scales window to 1024 x 760 if current browser window is narrower than 1150px */

If anyone has a better idea how to handle different screen resolutions while still accommodating the XO’s performance issues, please let me know.

Additional files that may be of special interest

  • start.html
  • kDoc.html
  • lessonPlan.html
  • teachersNote.html

The start.html page is an introductory page to the lesson that provides big obvious links to the Lesson Plan and Teacher’s Note. It also indicates very clearly which grade and academic subject the lesson is for. The Lesson Plan describes how to lead the children through the lesson in a classroom. The Teacher’s Note explains what the purpose of the lesson is and where it fits into the curriculum. index.html also has quick links to the Lesson Plan and Teacher’s Note but they are harder to find. The start page may seem unnecessary to some, but the teachers in Nepal tell us that they like it.

I have created a simple viewer kDoc.html for viewing the lesson plan and teacher’s note.
I cannot understate the importance of the lesson plan and teacher’s note. Figuring out how to use educational software effectively with 30+ energetic kids is not a trivial task.


Remember the minimalist markup for kHeader, kFooter, feedback. All three are jQuery UI widgets that have to be attached to HTML <div> elements.

A jQuery UI widget typically consists of a JavaScript file and a CSS file. Here are the widgets and the files that make them up:

  • kHeader — js/ui.kHeader.js and css/ui.kHeader.css
  • feedback — js/ and css/
  • kFooter — js/ui.kFooter.js and css/ui.kFooter.css

See the API documentation online or at docs/index.html in the template

Attaching a widget to a page

var $kFooter = $('#kFooter').kFooter();  //where #kFooter is a <div> element

Using different initialization parameters

var $kFooter = $('#kFooter').kFooter({'winningScore': 6, timer: true, scoreboard: false,
						pauseButton: true, startButton: true});

Notice that II assigned the result of the kFooter method to the variable $kFooter. This variable is cached reference that I can use to call new methods on the kFooter later and it is much faster than using a fresh jQuery selector each time like $('#kFooter').kFooter(/* some method */);. The naming convention for such variables is to prefix them with the ‘$’ character to signify the variable refers to a jQuery object.

All three widgets have their own methods that you can use to interact with them. The kFooter widget, for example, has methods getScore(), inc(), dec(), setScore(), startTimer(), stopTimer(), and more to manage its built-in scoreboard and timer

Calling methods on jQuery UI widgets is bit different. You pass the method name as an argument in order to call it. Here are examples of calling methods on the kFooter widget:

$('#kFooter').kFooter('inc');   //increments the score
//or if u have a reference

// To pass arguments to the method, simply append them as additional arguments
$kFooter.kFooter('inc', 2);  //increment score by 2 rather than the default of 1

Event-Driven User Interface

When you create your first lesson, it is very tempting to use a loop like


  if(/* user does X */){
       exit the loop


This code, while well-intentioned will cause your browser to display the horrible “Unresponsive script” message. The code also makes the user interface sluggish and generally unresponsive.

You can avoid this terrible message by making your code event-driven. This is a big word for using events and flags to control the behavior of your lesson.

Here is some code that look event-driven but actually is just a modified for loop and should be avoided. It can also cause the dreaded “Unresponsive script” message.

var timerId;

var game = function(){
      /* do stuff */
      timerId = setTimeout(game, 10);

if(/* user wants to quit */){

Here is a good example of event-driven code, modified code take from ui.kFooter.js

var timerRunning = true;
var runTimer = function(){
	if (timerRunning) === false){
	    return;  /* setting timerRunning to false stops the timer */
        /* code for manipulating the time displayed */
	timerId = setTimeout(runTimer, 1000);

//start the timer

//to stop the timer, set the flag timerRunning to false
timerRunning = true;

Things to Remember:
* Use setTimeout rather than setInterval
* Set flags to stop a background animation or timer rather than clearInterval()

Triggering custom Events and listening for them

If you initialize the kFooter widget with a winning score, it will emit a custom event “kFooterWinGame” event when that score is reached.

var $kFooter = $('#kFooter').kFooter({'winningScore': 6});

//show congratulations message when kFooterWinGame event is emitted

The API documentation details the events that each widget emits.

Unresolved Issues

Here are some unresolved issues that I will continue working on and would most appreciated help with.

  • Scaling – scaling and raster graphics (.png, .jpg files) just don’t play well together
  • Icons – jQuery UI icons are all png’s, which means they scale poorly. They are also too small and hard to override
  • Sound plays poorly on chromium on linux — pls up vote this issue in the chromium bug tracker to encourage the chromium guys to fix it.
  • internationalization — still in flux, doesn’t integrate with pootle
  • Firefox 3.6 performance is pretty sluggish on the XO. We really need to figure out how to get chromium running on the XO. I believe it will be at least 2x faster.

Internationalization is still very much in flux – I have created a basic jQuery plugin for handling it but it leaves much to be desired. I just recently discovered google chrome’s i18n mechanism for chrome extensions and I believe that it is far superior. I hope to port it to jQuery, which should take some time. I really think that chrome, jQuery, and Firefox’s jetpack should agree on a common API for i18n. Integration with pootle will be a pain but there more incentive for others to integrate with it if all three platforms used the same tooling.


January 15, 2010

Get Started with Jake, a Rake clone in JavaScript

Filed under: News — Tags: , , , , — bryanwb @ 8:33 am

In my last post, I gave an introduction to narwhal, a standard library for JavaScript. This time I will explore Jake, a Rake clone in JavaScript. I have been using it for the repetitive tasks in the Karma project like generating documentation, cleaning up temporary files, and checking out the latest version and packaging it for deployment. You may want to take a look at my Jakefile before you work through this tutorial.

What Jake doesn’t have

  • XML files
  • Special syntax

Jake only has pure JavaScript. This is a good thing. (mental) Context switching is expensive, particularly for utility scripts you might only look at once every few months.

Why use *-ake?

Managing a software project, especially web development projects, I find myself needing to do a number of repetitive and mind-numbing tasks that often, but not always, need to be done in a certain order. When packaging a new release of Karma, I usually want to check out the latest code from several repositories, put all the files in a temporary directory, remove unnecessary files, minify the source, and copy common JavaScript and CSS files to a common directory. Sometimes, I just want to check out the latest code. Sometimes I just want to minify the source and not move around the JavaScript and CSS files.

Here are the Tasks

  1. Check out files from version control
  2. Copy files to a temporary build/ directory
  3. Copy Common JS and CSS to a common directory, change references to new paths
  4. Remove files not needed for deployment to the server like docs, tests, utilities
  5. Minify JS and CSS files
  6. Optionally, compress project files into a tarball or zip file

Here is how those same tasks map to Jake tasks

  1. Check out files from version control ==> jake checkout
  2. Copy files to a temporary build/ directory  ==> jake build-dir
  3. Copy Common JS and CSS to a common directory, change references to new paths  ==>jake move-common-files
  4. Remove files not needed for deployment to the server like docs, tests, utilities ==> jake repack
  5. Minify JS and CSS files ==> jake minify
  6. Optionally, compress project files into a tarball or zip file  ==> jake package

Now some of these tasks depend on previous tasks so I shouldn’t be able to run them unless the previous tasks have been completed. But if they have been completed, I don’t want to rerun them. This is what buildmasters call <em>build dependencies</em>.

There is a task I haven’t yet specified, <code> jake build </code> which depends on tasks 1-6. I will show you an example build task later in the tutorial. Now let’s go back to creating basic tasks.

First Steps with Jake

Next, let’s set up jake. Narwhal has a package manager called tusk, which is comparable to ruby’s gem and Python’s easy_install.

$ tusk install jake
you@computer$ jake
No Jakefile found (looking for: jakefile, Jakefile, jakefile.js, Jakefile.js, jakefile.j, Jakefile.j)

Jake, like its siblings Rake and Make, requires a Jakefile that contains jake tasks.

Here is a very simple Jakefile

//import the jake module
//This is equivalent to python's "import" statement
var  JAKE = require("jake");
// JAKE.task('taskname', [ dependencies ], function(){});
JAKE.task('hello', function(){
      print('hello world');

Like Rakefiles, Jakefiles contain pure JavaScript. You should see a number of commands that are specific to narwhal. It is beyond the scope of this tutorial to cover those. I recommend you take a look at the narwhal documentation here.

To execute this simple hello task, run the following in the same directory as the Jakefile

$ jake hello

Now let’s do something more interesting. I frequently need to regenerate the documentation for karma.js using a long shell command that I can never remember all the switches for. I use the excellent jsdoc-toolkit.

JAKE.task('docs', function(){
        var path = './tools/jsdoc-toolkit';
             var cmd = 'java -jar ' + path + '/jsrun.jar ' +
                 path + '/app/run.js ' + './js/karma.js -d=docs/ ' +
         } else {
             print("The folder ./tools/jsdoc-toolkit isn't present " +
                   "you need it to generate documentation");


May prefer passing an array to OS.system rather than a string.

var cmd = [
   'java', '-jar', path + '/jsrun.jar',
   path + '/app/run.js', './js/karma.js',
   '-d=docs/', '-t=tools/jsdoc-toolkit/templates/jsdoc/'

One task that I run quite quickly is “jake clean” which I use to get rid all the temporary files created by text editors. Importing the submodule jake/clean automatically adds the “clean” task to your Jakefile. The next step is to add regular expressions that I want cleaned. The syntax for regular expressions here is not what I am used to. If may look odd to you too.

var CLEAN_LIB = require('jake/clean');  //adds the tasks clean and clobber
//include the temporary files created by text editors
CLEAN.include('**/#*#', '\.#*' , '**/\.tmp*',"**/\.*\.*\.swp");
CLEAN.exclude('\.git');    //don't touch my .git directory!

The regular expressions in the CLEAN.include() statement may look odd and that is because they are not regular expressions at all. Rather they are glob expressions.

Now, let’s run the clean task

$ jake clean

Here I tell the clobber task to delete my entire build-dir/ directory


Often during a build process you find yourself checking if a particular file or directory exists and creating it if it doesn’t. Jake’s filedir() method is great shorthand for this. JAKE.filedir() which runs the task’s action if a) the target file (passed as the task name) doesn’t exist, or b) any of the dependencies’ timestamps are newer than the target’s timestamp.

filedir ("build-dir", ["debug", "release"], function()

Now let’s go back to the 6 build tasks I outlined earlier in this article. Let’s create the build meta-task. We can specify dependencies for the build task as an array for the second argument to Jake.task. The dependencies will be run before the the build task if they are not up-to-date.

JAKE.task('build',['checkout', 'build-dir', 'move-common-files', 'repack', 'minify', 'package'],  function()
    /* do any finishing touches */

I have just scratched the surface of what Jake can do. You may want to look through my Jakefile for ideas. Cappuccino’s Jakefile is also a great example of what can be done with Jake.

Jake is a great tool and narwhal is a very useful platform. While quite young, narwhal is quite a stable and feature-rich platform. The biggest drawback that I have found working with narwhal is that documentation is quite lacking. Hopefully this will be resolved shortly.

December 20, 2009

Karma version 0.2 Released

Filed under: News — Tags: , , , — bryanwb @ 4:23 pm

We are proud to release Karma version 0.2 today. You can test out the demos here. You need Firefox 3.5 or Google Chrome/Chromium to run the demo. You can download the Karma-2.xo bundle here. We now have a well-documented API and a four part tutorial.

The Karma Project aims to create high-quality open-source educational software using openweb technologies, with special emphasis on the Sugar desktop educational environment. karma.js is a javascript library for manipulating HTML 5 and SVG in any context.

New Features:

Features that didn’t make it into Release 0.2:

  • Internationalization mechanism for inline text
  • new browsing layout (Chakra)

I am particularly proud of the Karma version of “Conozco a Uruguay”. You can try it out online right away.

If you are interested in Karma, the first step is to join our Google Group and to look through our four-part tutorial series.

  1. Introduction to karma.js
  2. Comparing HTML 5 Canvas and SVG
  3. Digging into Inkscape
  4. JavaScript and SVG

OLE Nepal and SugarLabs deserve special thanks for their continued support of the Karma Project.

September 15, 2009

Karma version 0.1 Released

Filed under: News — Tags: , , , , — bryanwb @ 7:35 am

We are proud to release Karma version 0.1 today. Please download the code and try it out for yourself. You can also test out the demo here. You need Firefox 3.5 to run the demo and you will need to tweak Firefox 3.5 on the XO or you can download this Karma XO bundle Karma-1.xo


  • Chaining of operations
  • Wrappers for drawing functions
  • API documentation
  • simple mechanism for pre-loading images and audio

Known Bugs:

  • You cannot access the Adding_Up lesson from google chrome or chromium. It does work if you have the lesson stored on your local machine. This is because chromium does not yet support loading media over HTTP.
  • Knavbar with adding up.
  • The links on ‘kstart’ page to Teacher’s Note and Lesson Note don’t go anywhere
  • The css on stages 2 and 3 of Chakra are all screwed up

Features that didn’t make it into Release 0.1:

  • Internationalization mechanism
  • SVG manipulation
  • Addition of knavbar to adding_up_to_10
  • A refactored version of the Quadrilaterals lesson


  • Bryan Berry
  • Felipe Lopez Toledo
  • Christoph Derndorfer
  • Om Prakash Yadav
  • Rabi Karmacharya
  • Roshan Karki
  • Saurav Dev Bhatta
  • Devendra Khadka
  • Pavel Mocan

Please test out Chakra and our first lesson “Adding up.” We would most appreciate it if you report any bugs you find to our bugtracker on launchpad

Blog at