WoofJS — making JavaScript learnable

“I’m done with Scratch,” my students tell me. “Now what?” I’ve been trying to answer this question for the past two years: what’s the programming language to learn after Scratch?

Scratch is amazing. With it, any eight-year-old can learn how to make video games in just a few hours. With any other programming language, teaching sequential evaluation, parameters, events, parallel programming, conditionals, loops, Boolean algebra, variables, and lists would take dozens of agonizing hours. In Scratch a student joyously becomes familiar with these concepts through making their first game. As a co-founder of The Coding Space, a NYC after-school and summer program, I have watched students spend thousands of hours in Scratch. It’s magical to see.

However, all good things must come to an end. Despite having an incredibly low barrier to entry, Scratch has a ceiling that limits what types of games students can build. Multiplayer is impossible, and so are full screen and mobile games.

Requirements

  1. Motivating. As video games, animations or stories, Scratch projects are worth sharing. Students never ask, “why are we learning variables?” because they are self-motivated to learn variables to make the score counter work in their racing game.
  2. Shareable. Every Scratch project is immediately shareable via a URL. There’s drastically less motivation to make something that you can’t easily show your friends or family.

These constraints knock out almost every programming language right off the bat. Ruby, Python, Java, and C++ projects can’t easily be shared via a URL, nor can you easily build motivating projects with them (unless you find the Fibonacci sequence or REST APIs motivating).

Web Programming

This is a big jump from Scratch. Not only do students have to learn how to translate their Scratch coding knowledge to JavaScript, but they also have to learn two additional languages, HTML and CSS. Considering this is an 11-year-old’s first experience with text-based coding, three new programming languages all at once is a nightmare. So let’s simplify.

ProcessingJS

Despite many novel features, ProcessingJS and Khan Academy’s programming environment are far from ideal. Bret Victor makes a comprehensive study of these flaws in his essay “Learnable Programming.”

I searched for a JavaScript graphics framework that didn’t have the drawbacks of Processing. I couldn’t find one, so I built it.

WoofJS

It meets our requirements:

  1. Motivation. Like Scratch, Woof’s lends itself incredibly well to games and animations, which are highly motivating.
  2. Shareable. Built for the web, Woof works seamlessly in all browsers, mobile and desktop, full-screen and fixed-screen. You can even bookmark your game on your home-screen like an app.

And it does one better: Woof closely mimics Scratch.

Because Woof commands directly correspond to Scratch blocks, they allow students to focus solely on syntax translation. Students don’t have to learn new metaphors and paradigms at the same time they’re picking up their first text-based syntax. Going from move 10 steps in Scratch to car.move(10); in Woof is a small enough jump that students familiar with Scratch can pick it up in just a few hours.

WoofJS & ProcessingJS

Is meaning transparent? Is meaning explained in context, by showing and telling?

In Woof, all object properties can be set explicitly as named-parameters in the constructor or through dot-notation. It’s transparent what new Rectangle() does, as well as what each of its properties do.

// WoofJS// set optional parameters explicitly by name
var r1 = new Rectangle({x: 100, y: 200, width: 30, height: 40});
// set properties by name
r1.color = "blue";

Is time visible and tangible?

// ProcessingJSvar x = 0;
var y = 0;
draw = function() {
background(255, 255, 255);
ellipse(x, y, 30, 30);
x++;
y++;
};

In Woof, (like ReactJS) rendering is taken care of for you. You don’t have to add effectful code to your draw() method to make things move. Instead, you cause state to change in response to events or intervals. This means you don’t even have to think about how your view layer works — it just does. And in Woof, time is much more tangible with commands like forever(), after(), when(), and repeatUntil().

// WoofJSvar circle = new Circle();forever(function() {
circle.x++;
circle.y++;
});

Does the environment show the data? Is hidden state eliminated?

// ProcessingJSfill(252, 60, 115);         // set the color pink
rect(100, 160, 20, 80); // create a pink rectangle
fill(84, 98, 255); // set the color blue
ellipse(280, 200, 80, 80); // create a blue circle

In Woof, there’s no hidden view-layer state. If you make one rectangle pink, only that one rectangle is pink. As an added bonus, Woof makes it easy to examine all internal state in real-time.

// WoofJSnew Rectangle({color: "pink"});
new Circle({color: "blue"});
var counter = 0;
forever(function() { counter++; });
new Text({text: function() { return counter; } })

Is something on screen as soon as possible?

// ProcessingJSellipse();                   // nothing on the screen
ellipse(200); // nothing on the screen
ellipse(200, 200); // nothing on the screen
ellipse(200, 200, 30); // nothing on the screen
ellipse(200, 200, 30, 30); // circle appears on the screen

In Woof, simply start off by typing new Circle() and you’ll see a circle on the screen. If you want to make it bigger, you can add a radius. Want to move it to the right? No problem!

// WoofJSnew Circle();                      // circle appears on the screen
new Circle({radius: 30}); // circle appears with radius 30
new Circle({radius: 30, x: 200}); // circle appears at x 200

Can the programmer start concrete, then generalize?

  1. Start constant, then vary

As we demonstrated in the Is time visible and tangible? section above, Processing has a large cognitive gap between a stationary circle and a moving circle, while Woof’s cognitive gap is almost as small as Scratch’s.

2. Start with one, then make many

As we’ll show in the Can the programmer put diverse pieces together? section below, Processing makes it difficult to group code into reusable chunks, which makes it tricky to start with one and then make many without unforeseen side-effects.

Because everything in Woof is an object (or sprite), it’s easy to start with one object and then expand to as many objects as you want. Each object is responsible for its own data and can travel. You can even store them in a list. (In Processing, the closest thing to keeping track of many things of a similar type would be a list of functions.)

// WoofJSnew Circle({x: randomX(), color: randomColor()}) // start with onevar circles = []                                 // then make many
every(1, "second", function() {
circles.push(new Circle({x: randomX(), color: randomColor()}));
});

Is the computer’s world connected to the programmer’s world?

Processing’s core metaphor is the ‘painter’s algorithm’ — the computer places a series of shapes on the screen, like drawing on paper. Because this metaphor carries no computational power (you cannot compute by filling in pixels), all computation occurs outside the bounds of the metaphor…

// ProcessingJSvar x = 0, y = 50, dy = 0;
draw = function() {
x+=4
y+= dy;
if (y > 185) {
dy = -dy
ellipse(x, 190, 36, 25)
}
else {
dy = dy * 0.98 + 3;
ellipse(x, y, 30, 30)
}
};

The simulated properties of the ball (position) are not associated with the picture of the ball onscreen. They are computed and stored abstractly as “numbers” in “variables”, and the ball is merely a shadow that is cast off by this ethereal internal representation. The ball cannot be picked up and moved; it cannot be told how to interact with other objects. It is not a “living thing”, and the simulation cannot be understood or thought about in any way other than “numbers in variables”. This is a very weak way of thinking.

Woof steals Scratch’s and Smalltalk’s everything-is-an-object (or sprite) metaphor. Woof also steals LOGO’s movement, angles, turning and pen anthropomorphic metaphors. This way, the x- and y- position of your objects (or sprites) are stored within the objects themselves. If you tell them to .move() or .turnLeft() they’ll listen to you like a dog would. This makes it much easier to mentally think through an algorithm, because you can pretend your code is giving someone orders or that you yourself are in the object’s shoes and are carrying out orders yourself.

// WoofJSvar dog = new Image({url: "http://i.imgur.com/SMJjVCL.png"});dog.penDown = true;dog.turnLeft(90)dog.move(10)

Can the programmer break down her thoughts into mind-sized pieces?

// ProccesingJSdraw = function() { doStuff1(); };         // ignoreddraw = function() { doStuff2(); };         // overwrites doStuff1()onMouseDown = function() { doStuff3(); };  // ignoredonMouseDown = function() { doStuff4(); };  // overwrites doStuff3()

In Woof, you can have infinitely many forever() and other control loops. You don’t have to funnel all of your code through the same top-level events that forces you to build tangled code. As an added benefit, sprites (or objects) have their own events, and can listen to as many of them as you want.

// WoofJS forever(function() { doStuff1() })           // stuff1 happens!forever(function() { doStuff2() })           // stuff2 happens!car.onMouseDown(function() { doStuff3() })   // stuff3 happens!car.onMouseDown(function() { doStuff4() })   // stuff4 happens!

Can the programmer put diverse pieces together?

Processing’s lack of modularity is a major barrier to recomposition. The programmer cannot simply grab a friend’s bouncing ball and place it alongside her own bouncing ball — variables must be renamed or manually encapsulated; the “draw” and mouse functions must be woven together, and so on. One can easily start from an existing Processing program and modify it, but the language does not encourage combining two programs.

In Woof, because all view-layer state is encapsulated into objects, it allows you to easily build modular and functional code without worrying about side effects. No need to interweave top-level events — your events and your friend's events can coexist happily side-by-side.

// WoofJS// take a friend’s stem code
new Rectangle({y: minY, height: height, color: "green"});
new Circle({y: minY / 2 - 20, x: -20, radius: 20, color: "green"});
new Circle({y: minY / 2 +40, x: 20, radius: 20, color: "green"});
// and add your petal code, no problem
for (var i = 0; i < 10; i++){
new Rectangle({width: 100, height: 100, color: "red", angle: 36 * i});
}

Early Reception

It took one of our 13-year-old students just a few minutes pick up Woof and make a circle that grows with your mouse:

var circle = new Circle();
forever(() => {
circle.radius = circle.distanceTo(mouseX, mouseY);
});

One of our 11-year-old GirlCode summer students was able to pickup JavaScript and Woof within a week, producing numerous games including a Flappy Bird clone (space key to play). Before Woof, even my advanced 13-year-olds could barely build a clone of sometimesredsometimesblue.com after weeks of struggling, so this is progress.

A few teachers at The Coding Space have contributed to various games and demos:

v1.0.0 and beyond

If you’re a coding teacher, you can get your students started by having them re-make one of their existing Scratch projects in Woof. Because they’re starting with algorithms they already know, your students will be able to focus solely on the tricky problem of syntax translation from Scratch to JavaScript. From there, it’ll be easier for them to create new projects directly in Woof.

Down the line, I think it would be interesting to integrate Woof with either Pencil Code’s Droplet editor or Google’s Blockly to make the transition from Scratch to Woof even easier. Ping me at steve at thecodingspace.com if that sounds like a project you’d like to help with!

In the meanwhile, I encourage you to check out our documentation, play with some demos, and build your own games and animations. Even better, go find a 12-year-old that’s ready to move on from Scratch and show her what’s next.

Acknowledgements

Shameless plug for The Coding Space: We’re hiring full-time and part-time teachers so please reach out if you’re in NYC, love working with children, and are excited to shape the future of coding education.

Enabling computational thinking by building tools for thought at futureofcoding.org. Co-creator of thecodingspace.com and woofjs.com

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store