TinyGoon – TowerFall clone in WebGL

I made this game together with Rasmus and Nils at Goo.


It’s a kill ’em all multiplayer game with support for up to 4 players. We used the Gamepad API directly, which means that it doesn’t work perfect in all browsers.

The game uses a new SpriteSystem that I made for Goo Create and the physics is from p2.js.

Here’s the Goo team playing the game when we first presented it. It was buggy but fun! It was the longest presentation of the day since we didn’t want to stop playing.


I made the tile graphics. Should probably start a career as a 2D pixel graphics artist!


Launch the game.

Share Button

Project: Refract

For Goofy day I made a WebGL game that I call Refract. The goal is to guide a laser beam from a starting point to goal. Its core mechanic is based on raycasting from p2.js – this is a perfect use case for the new p2 feature :)

The game was made entirely in Goo Create.

By flipping a boolean script parameter while working on the game in Create, it launches a custom level editor that lets you design levels and export them as JSON. The JSON can then saved back into Create to be included in the levels list.

The backgrounds are procedurally generated on the fly with some randomness added. I used texgen.js for this. I noticed that it uses a bit of CPU while generating large textures, so a future optimization would be to make a custom shader instead.

Because the game is very static when you don’t touch anything, it was possible to pause the render loop fully between interactions. This saves a lot of battery while on mobile.


Launch Refract

Share Button

Fuffr 3D boxing

I made a WebGL demo for the Fuffr hardware. It’s a simple boxing game featuring awesome graphics made by Joakim at Goo, and the new physics components in Goo Create.


The most challenging part about this was to integrate it well with the hardware. Most of the tech part was already sorted – there’s a Fuffr JavaScript lib and a server app. The API is almost exactly like the HTML5 touch API. Easy to get started in other words.

Start Fuffr 3D boxing (also works on ordinary touch screens).

Share Button

Project: Suisse Mania

I was part of making the Suisse Mania project, making a WebGL site for Migros. It’s an experience for all ages about Switzerland and it features 54 attractions around the country.

The app had three versions, a 3D, a lightweight 3D, and a 2D fallback for older devices/browsers. The 2D and the on-top UI was made by Agigen, another techy company here in Stockholm.

The role I had in this project was to do most of the 3D coding. We used Goo Create (of course), and I had a bunch of graphics guys from all of the involved companies to help me do the scene beautiful. Since the UI layer of the app had all the state, it made development of the 3D app quite simple.

  • A few custom shaders, including highlighting, grayscale, particles, icons, etc.
  • Sounds for each monument, including tweaking the distance model equations.
  • Deterministic particle system – that I developed specifically for this project to reduce GPU/CPU communication.

Another thing that I didn’t make but is still very cool is the splatmap shader for the terrain. It uses different channels in a “splatmap” texture to blend other textures in a layered manner. The result is higher quality texturing. The alternative is rendering a very high res texture for the whole terrain, but that would not work on all devices.

Without splatmap shader:

Without splatmap shader.

With splatmap shader:

With splatmap shader

Distance models for sound are used to lower the volume of a sound as its distance from the listener moves from it. I discovered that one of the models in the Audio API, the linear model, was broken in most browsers. But the inverse model worked well enough. The problem was to find good parameters to make sounds die out in the distance but around 100% volume when the camera is near the sound source. I used a graph calculator to get the right parameters for both linear, inverse, and exponential models.

WebAudio API distance models

I’m very happy with the result we got. It was hard work, misunderstandings, mistakes and all that, but it was worth it. I met a lot of nice people and had a really good time working with the Goo and the Agigen team.

Suisse Mania fountain

Retweet this:

Start Suisse Mania.

Share Button

PhysicsToy productivity

I’ll just admit it – I hate writing CSS. Therefore, I baked Twitter Bootstrap into PhysicsToy. The result is prettier and gives more of a tool feeling.

At the same time I shuffled around the menus. Before, all menus were stacked in a hierarchy and it became hard to use. The new version has a context based left menu box, and it is far superior to a hierarchy.

To get the context menu working, I put some work into the selection system. When clicking on the WebGL canvas, the coordinates are converted to physics space, then I do an overlap test to check if something in the physics world was hit. If this is the case, it’s reported to the outer angular app, which adds the item to a selection list. It will update the context menu accordingly, and tell the WebGL renderer to draw borders on the selected items.

If two bodies are selected, the context menu shows buttons for adding a constraint or a spring. This is much more useful than creating a spring and then go through two body lists to find the connected bodies.

Multiple Selection

Mouse dragging does not work yet – however arrow key moving works. Even if several bodies are selected.

I also added duplication – useful if you need to create many similar bodies.


All of these new features speeds up the workflow in PhysicsToy. Go create something.

Share Button

TapTruck – I made an Android game in a day

Been thinking of releasing a game on Google Play for a while and I finally did it! I made the game in Goo Create during the last goofy friday and released it as an app the day after.

The game is called Tap Truck and the goal is to drive a monster truck to the finish line without tipping over.


Get the app on Google Play or play it in your browser.

And now the tech part. I exported the project from Create as a webpage. Slightly modified it and uploaded it to Ludei online compiler. I got an .apk file back which I could sign and upload to Google Play.
Should make a tutorial for this. Let me know if you’d like that!

Share Button

New projects page!

I found myself showing Vines when trying to elevator pitch myself. Mini videos are great for show the gist of a product. Therefore, I compiled most of my recent Vines to gif and collected them here.

Skärmavbild 2015-03-22 kl. 14.08.47

Share Button

Making Vines on OSX

I recently got a few questions on how I make and upload my screencaps to Vine. Here’s the recipe!

1. Screencap using QuickTime

QuickTime on OSX has support for video screencaps. Open QuickTime and go to File / New screencap. Pick a part of your screen and press record. Make sure that your screen selection is nearly square for the best vine experience! Also, make sure that width >= height, otherwise Vine won’t accept it.

To get an almost square selection, I resize my browser window with Chrome devtools open until I see that the inner browser width equals the inner height. Then I make the screen selection for the video.

Making a square screencap

2. Trimming

It’s easy to trim the video in QuickTime. Just press command+t and you can use the UI to trim your video. Make sure that the total time of the video is less than 6.5 seconds.

QuickTime trimming

3. Exporting

Usually it’s okay to export in 1080p, but make sure that you don’t pass the max file size of 5Mb. Click File / Export / 1080p… and see what you get.

Note that if you choose to remove the sound from the video (see next step), the file size will be very small.

4. Optional: removing sound

Sometimes sound is not needed in the Vine. I use ffmpeg with the following command to lower the volume to zero:

ffmpeg -i in.mov -af 'volume=0' -strict -2 out.mov

5. Upload to Vine using VineClient

You can upload the Vine using the VineClient add-on for Google Chrome. Install, log in, press Upload and follow the instructions.

Note that if you check the “Keep aspect ratio” checkbox, you’ll get black stripes at top and bottom of your Vine. Uncheck it if you know that your video is nearly square.

6. Sharing on Twitter

Don’t make the mistake of sharing to Twitter via VineClient. In that case your Vine will not get displayed inside your tweet. The reason for that is because VineClient uses an own Vine URL that Twitter doesn’t recognize. Instead, go to vine.co, find your Vine there and share it.

Vine in Twitter

Note that the Vine URL in the tweet got hidden! This only happens if you put the URL last in your tweet.

That’s all! Now go make some awesome Vines.

Share Button

p2.js progress!

My 2D physics engine has gone a long way since I started the project on github. It’s been integrated in one of the biggest 2D HTML5 game frameworks, Phaser. It’s been starring in the official Google IO experiment for 2015. I’m just very happy and wanted to express it.

Share Button

PhysicsToy – halfway there…

Recently, I’ve been working on a 2D physics editor called PhysicsToy. It makes it possible to create these kinds of simulations, without coding:


Silly car

Before I get bored and want to start a new cool hobby project, I wanted to report the current status of the web app.

Frontend: Angular.js and Pixi.js

I used the p2.js debug renderer and polished it up a bit. Then I added some Angular.js magic. I’ve wanted to learn Angular for a while, and PhysicsToy was a great project to use it in. I hooked up Angular and connected it to a simple list-like menu. Then added some code for updating the p2.js world as the angular data changes. Viola, PhysicsToy was born.

Backend: Node.js and Postgres on Heroku

Another thing I wanted to try was Postgres. I’ve been using MySQL in other projects, but why not try something new, and at the same time choose open source.
Postgres didn’t let me down. It offered a JSON data type, which is convenient for my Angular scene data. Postgres seems more consistent and in general more thought through than MySQL, even though they are based on the same SQL language.

Before pushing the data to Postgres, I do some validation using JSON-schema. I use an interesting solution for version handling of the JSON: I store the scene data as it is and never upgrade it in the database, but I do on-the-fly upgrading when serving to the clients. The benefits of this solution are that the original scenes can be in all servers forever. And it’s ideal when the app is under development, with a constantly changing data model. The only bad part is that the upgrading takes some server juice.

Had a fun time coding this, I hope that it will grow to something big!

Share Button