A growing pile of JavaScript WebGL and Web Audio experiments and games.
Everything is on


Game 5: The Second Good One

Finished on November 10th, 2018.
You've got a tractor beam and a shield, and you can pick up and use any weapons you find.
It's basically Game 2 II, but this has local multiplayer, high explosives, some stealth, and enemies that shoot.

On a keyboard/mouse setup, try the mouse/trackpad plus Z and X (and C to quit), and/or arrows plus N and M (and comma to quit).
On a touchscreen with a friend or three, try sitting across from each other.
[game5 editor]

Game 4: Abandoned multi-player tractor beam stuff

Keyboard mappings are kind of wonky because I tried to fit three players onto one keyboard/mouse.
Try a tablet or smartphone!
Enemies don't really want to hurt you, but their touch is deadly.
[game4 editor]

Game 3: Abandoned rolling platformer

Roll around the test level, using left and right swipes or arrows, and the shift key for turbo if you're using a keyboard.

Game 2: The First Good One

A 2D maze shooter for mobile and desktop, featuring one kind of enemy, two weapons, six levels, about seven sound effects, infinite lives, and fully destructible terrain.

The idea was to complete, multi-level, arcade-ish game with all the little things I took for granted in games until I coded it myself: Startup, player controls, weapons, enemy behavior, explosions, sounds, pause menu, level progression, death, victory, etc.

To make the levels I wrote a game2 editor, for creating and testing levels. It's not connected to the main game; I used it to make levels, then I exported them to JSON, and copied that into the source code. But it's kinda fun to play with on its own.

Game 1: Early Demo

This has one level of basic combat, and infinite digging through destructible terrain.

Terrain Tests

Test 42 - DistGrid

This test shows a 2d canvas slow-motion visualizer for the DistGrid floodfill. The red points are ground, and from there, DistGrid looks at surrounding "space" points and marks each one with the ground point that it is closest to.

Editor Tests

Test 41 - Undo and Redo

This was harder than I expected.
First I made the physics engine stop advancing the world clock when nothing is happening - easy first step.
Then I made a simple undo/redo system where the whole world was copied whenever the user made a change, and the whole world was replaced whenever the user did an undo or redo. But in large levels, the UI would slow down just from recording the world whenever a change ended, and undo/redo slowed down, too.
So, I rewrote it to track changes in terrain, bodies, spirits, timeouts, and the world time. Only the changed things are updated when there's an undo/redo. It's more complex than I wanted, but it seems to be working, and it's fast.

Test 37 - Mouse and Trigger Improvements

Now the cursor follows the mouse, because the Pointer Lock API isn't widely supported, and because I'll need the mouse pointer for menus. You can pan with the mouse button to drag the map, like in most mapping programs. Each action (grab, dig, fill) has its own touchscreen trigger and keyboard trigger, with a cool icon, and onscreen keyboard tips for mouse users.

Test 36 - Save and Load

When you pause the editor, the game is saved to a sharable URL, in a giant hash-fragment. If you open a saved-game URL, it starts playing immediately.
Try this one!

Test 35 - Object Dragging

Now objects can be dragged around. Physics still applies, and the cave is still editable.

Test 34 - Terrain Dragging

Start with the cursor in a tunnel and drag into the earth to extend the tunnel. Or start with the cursor over earth, and drag to make walls or fill in tunnels.

Listens for three kinds of triggers:

Test 33 - Cursor

Move a cursor over a scrolling canvas of terrain and objects.

There are lots of reasons to treat mice, trackpads, and touchscreens like trackballs, for cursor control.

Vertex shaders

Test 32 - Parameterized Distortion

Applies a bunch of shifting distortions at the same time. Includes a position quantizer, a repulsor/attractor, and a wavy flower-ish distortion.

Test 31 - Mesh Distortion

Creates a ring model using a triangle mesh, draws an bunch in a grid, and applies a single hard-coded distortion to them while the camera rushes around all higgledy-piggledy.

User Interface

Test 30 - Trackball

Use a trackpad or touch screen to maneuver with precise, natural control. Inspired by Marble Madness, Crystal Castles, and gay marriage :-D

Test 29 - Full Screen & Pointer Lock

Let the user enter fullscreen mode from the title screen or the PAUSED screen. Fullscreen is supported on all desktop browsers, and in Android, in Chrome and Firefox. Safari on iOS 8 doesn't support it yet.

Request pointer lock when entering PLAYING screen. Exit pointerlock when leaving that screen. Browsers always exit pointerlock when "esc" is pressed, so also re-request it if the user clicks the PLAYING screen. Chrome and Firefox are the only desktop browsers that support pointerlock as of June 2015.

Test 28 - Multiple Screens

Until now, each test has had one global world, renderer, and event handler. Now a Screen class encapulates those aspects, so a game can have multiple screens. A main controller class coordinates between the screens, and helps handle transitions.

A game can use this to have a title screen, settings, levels and level transitions, pause screen, "Game Over", "Victory", etc.


Test 27 - Sound Board

Tap the words to make noises.

Test 26 - Touch Tone

Tap the boxes to make noises.

Test 25 - Basic Sounds

Simple sound effects when stuff happens.
And if you want to make your computer get hot: Test 25b - Basic Sounds x100

More Graphics

Test 24 - Pointer

Use the touchscreen or mouse to point at stuff in the world.
Tests the mapping from screen coordinates to world coordinates.

Test 23 - Printer

Easy WebGL text rendering is working now. Once everything is set up, it's
printer.printLine(startMatrix, nextCharMatrix, "DONKEY BATS");

Here's some text, above a waving asteroid field that intersects rose-colored towers.

Test 22 - Renderer

Draws ModelStamps with a standard Renderer class, loaded with a RendererLoader.

Test 21 - Planet X

Tests sphere-building, and distortion.

Test 20 - Glyphs

Builds a whole alphabet in 3D.

Test 19 - F in 3D

Builds a model out of sub-models.

Test 18 - Twirling ghostly obelisks

Tests cuboid models.

Test 17 - A writhing sea of gnome hats

Tests RigidModel and ModelStamp, tools for building and rendering models.

Test 16 - Explosions

I just replaced every circle with an explosion, to work on explosions.

Test 15 - WebGL Renderer

This re-implements the twin-stick shooter renderer from tests 11-13, using WebGL instead of 2D canvas. WebGL seems to be the key to smooth animation on an iPad 2 running iOS 8 - 2D canvas wasn't fast enough. On Android, Chrome and Firefox are buttery smooth on Nexus 5 and 7, KitKat and Lollipop, Chrome and Firefox.

Here are some notes about rendering foregrounds and backgrounds in WebGL, based on what I learned from making test15.

Test 14 - Basic WebGL

A rectangle and a triangle, from, Lesson1, plus some badly-coded animation.

Test 13 - Separate Physics and Drawing Speeds

In this test, the game oscillates between slow-motion and fast-motion every few seconds.

The physics engine has a single queue, sorted by time, to keep track of most events that affect the world:

World-time is independent from JavaScript's To advance world-time, a client needs to consume events from the queue, in time order. That usually causes more events to be inserted at later world-times.

Bodies don't have a currentPosition field. A body has a "path", where position is a function of time, calculated using these fields:

This path only changes when a body accelerates or teleports.

This all makes it easy to separate the speed of world-time from the rendering rate.

Also, in all previous tests, I was guilty of many of the anti-patterns in I had made my canvas fullscreen by using a window.onresize() handler to set canvas.width, canvas.height,, and to the same value as window.innerWidth and window.innerHeight.

Now test13 uses CSS width:100% and height:100% for the fullscreen effect, so those never need to be adjusted by JS. And every frame, test13 compares canvas.clientWidth to canvas.width (ditto for height), to decide when to update canvas.width and canvas.height.

Test 12 - Canvas layers

This is the same as test11, but now the background (the walls) is painted once onto a separate canvas that is bigger than the screen, and that canvas is moved, but not redrawn.


Test 11 - Stick Controls

Twin-stick shooter demo, to test a bunch of "Stick" control classes.
Move with WASD keys, or the left half of a touchscreen.
Fire using IJKL, arrow keys, a mouse or trackpad (using Pointer Lock API), or the right half of a touchscreen.


Test 10 - Rayscan
The RayscanSpirit uses rayscans to see and make decisions.
Test 9 - Spirit
"Spirit" classes animate bodies, bringing them to life.
Test 8 - Collision
Continuous 2D collision detection between bodies shaped like axis-aligned rectangles and circles.


Later this was replaced by BitGrid, but I kept the basic vision of a fingerpaint-like editing UI.
Test 7 - QuadTreeGrid & HallPainter
You can draw a cave map with a mouse or touchscreen.
Test 6 - QuadTree Moon
Demos quadtree editing by adding a circle and deleting a circle, at 60fps

Early graphics

I didn't end up using any of this for the games, but it was fun to write.
Test 5 - Timeshift
Shifts the subtree's time as a function of time. Draws a clock that makes random, uneven progress.
Test 4 - Scale
Changes the size of a drawing tree over time. Looks like a hungry hydra.
Test 3 - Rotate
Rotates the drawing tree over time. Looks like a wiggly sea creature.
Test 2 - Translate
Moves chunks of the drawing tree over time.
Test 1 - Line
Interpolates line endpoints over time.