timetocode.org requires JavaScript.

Please enable JavaScript in your browser
and then reload this page.

springs & pucks

(best with a Chromium-based browser)

Timetocode.org is host to a Python game-physics tutorial, a weather-data application, and the live spring and puck animations on this page.

The game physics animates here using JavaScript, Box2dWeb, and an HTML5 Canvas. Multiplayer games are supported with a peer-to-peer Wi-Fi client developed with Node.js, socket.io, and WebRTC.

Try the tour and then the video walkthrough. The revision history always has a note on what's coming next.

As outlined in this section, take a tour of this application of a physics-engine (and watch the videos):
  • Move objects (pucks) with your mouse or finger. Drag and fling them. Put on the breaks with the f key. Try the g key.

  • Click on the links in the row of letters (under the numbered buttons) to run the variations of the base demos. For example, click on the "5" button and then click on the "d" link to see the falling-dandelions demo.

  • Button #7 starts the Puck Popper game. With multiple players, use #8 for more terrain. For more challenge, try 8c, 8d, and 8e. Here's a how-to video on Puck Popper. Try the Jello: #6.

  • The client interface for multiplayer includes a virtual gamepad for cell phones (or any touch-screen device). Try it. Click the multiplayer option (right panel) to start hosting a game. Type in a room name (left panel), and then click the "Create" button. On your cell phone, from the mini-client page, enter the room name and then touch the "Connect" button. After your connection to the host succeeds, touch the "Two-Thumbs" button.

  • Play some ghost-ball pool.

  • Try an editor feature: select a puck, then resize it with the arrow keys.

  • Then save your edits by clicking the capture button. Replay the capture by clicking the corresponding number key.

Use the numbered buttons in the right panel to start the interactive demos and games. To restart, click the button again (or use the corresponding number key on the keyboard). Each button auto-scrolls this left panel to show corresponding information. The row of letters, below the cluster of numbered buttons, provides links to variations of the base demo or game (captures of edited runs). Clicking one of these links populates the capture box and starts the variation. Clicking the corresponding number button restarts the variation. The "a" link, in this variations row, acts to clear out the capture box and then restart the base demo. The "0" (zero) key resets the demos, clears the capture, exits from full-screen mode, and scrolls this panel to the top.
The "Freeze" button momentarily stops all puck translation while allowing rotation to continue. The neighboring "R" button stops all rotation (use t and shift-t to change the rotation rate of a selected puck).
The "Reverse" button (or ctrl-backspace) flips the velocity and reverses the rotation rate of each puck.
Each of the three mouse buttons has a different spring strength for dragging objects: left click for the normal spring, center click for the weakest spring, right click for the strongest spring and a firmer connection to the larger pucks. (Note that using the right mouse button on the smallest pucks may cause instability in the physics engine; go ahead and try it.) If you're only positioning a small puck (not flinging it), try doing so with the control key down; that will always be stable.
Each demo control has keyboard shortcut letter underlined in its label. That is a keyboard key to use as an alternative to the mouse.
The "COM" (Center Of Mass) toggle controls the position of the selection point. With this on, you will always select the middle of the target object. Turning this off allows you to spin (or stop spinning) the objects.
The "g" (gravity) toggle also controls several associated parameters in Box2D: restitution, friction, and b2_velocityThreshold. Depending on the demo, if gravity is turned off, these settings are used to produce more elastic collisions (low energy loss) so things keep moving and don't stick to the walls. In demo #6, the opposite is done so that collisions are inelastic, reducing chatter when pucks are held in contact with each other under the tension of springs. Note that if you use the editor to change the restitution of a puck, it will remain fixed at that level, independent of the gravity toggle, until the demo is restarted (or the puck is edited again).
The "CV" toggle put a Coronavirus costume on each of the drone pucks in the Puck Popper game, demos 7 and 8. This gives you a safe way to take a swing at this nasty little virus.
The "pause" toggle disables all updates to the canvas. When paused, a stepper button is revealed in place of the fps value; click it to advance a single frame. If the perimeter walls are red, the animation is paused. Uncheck the "pause" control to resume animation. Alternatively use the "p" key to pause and resume. The neighboring "o" key will single step the animation. Hold the "o" key down to repeatedly step at a slow rate.

The combination of the "alt" and "p" keys toggle the canvas eraser on/off. The eraser normally precedes each frame. When toggled off, some drawing features, such as for springs, are inhibited. This feature produces interesting variation of the demos, especially the spinning rectangles of the #4d group (turn gravity off, use the aspect_ratio full-canvas button, and then alt-p), and the expanding color tail of #2e (again, use the full-canvas button, grab the puck with the mouse, shrink it all the way down using the arrow keys, fling it hard, and then alt-p).

The fullscreen full-screen button stretches the animation canvas into full-screen mode while preserving the original aspect ratio. This provides a nice front-and-center presentation of the demos (a good way to play Puck Popper).

The neighboring aspect_ratio full-canvas button enlarges the canvas to match the size and aspect ratio of the screen (view port). When using this feature, the perimeter fence is enlarged to match the dimensions of the larger canvas (note: the fence is not adjusted for the pool games). Use either the "esc" key or the "0" key to exit from either of the full-screen views. Note that the "0" key clears the capture that is automatically taken when this button is used.

The "remove/add items" select control, provides a way to scrub off the canvas and add elements as needed. If the cursor is moved off an option and onto the canvas (before clicking it) the cursor position can be used to position the new element; after positioning the cursor, press the enter key. If the option is clicked, a default position on the canvas is used.

Use the "Multiplayer" toggle to display the controls for connecting as a host to the node server. Then type a short room name into the red input box (on the left). Optionally, type a nickname for yourself into the chat input box. Then click the "create" button. Wait a few seconds for the server to wake up. Open one (or several) client windows from these links: window, tab. From those client pages, repeat the connection process using the same room name that you specified as the host. Once connected, you will see your mouse and keyboard events rendering to the host canvas (this page). That way multiple users can simultaneously interact with the animated objects in the demo. The question-mark key can be useful for locating your puck in the Puck Popper game (demos 7 and 8). There's more info on the specifics of multiplayer game play in the topics for demos #7 and #8 below.

Optionally, each connected client may initiate a live video stream of the host's canvas. After connecting, click the "Stream" checkbox on the client. This works best if the host and the clients are running their monitors at the same refresh rate. Overall, Chrome is the best browser for producing smooth rendering of the stream on the client. If the client has limited cpu power (like a Raspberry Pi), it's best not to stream. Any client without a video stream has to be in the same physical room to see the rendering on the host's screen.

The Two-Thumbs touch screen interface, a virtual gamepad (see image below), is useful for controlling a game puck from a cell phone in demos 7 and 8 (Puck Popper). From your cell phone, or other touch-screen device, open the mini-client page in Chrome (or the full client). Connect to the host as described above, then click the "Two Thumbs" button. Your left thumb will control the jet direction and intensity (more thrust the farther your touch point is out from center dot). Right thumb fires and aims the shooter. The center rectangle turns the shield on/off.

The colored rectangle, below the shield control, indicates your client color. Touch it, and a large circle will show around your puck (helping you to find it). The small rectangle controls at the bottom require the alt rectangle to be touched first (this prevents accidental firing of these controls when driving the puck). These can be used to: get out of the full-screen mode (esc), freeze the object motion (f), restart the two Puck Popper games (7 and 8). The scope control is located in the bottom right corner of the virtual gamepad. This control precisely rotates the shooter tube and shoots from a fixed position. Touching the center block stops the movement of your puck, and then shoots without recoil (and no rotation). The surrounding two blocks, rotate the shooter tube (ccw or cw). The rotation rate is reduced as the touch point approaches the center block.

Note that you can use the Two-Thumbs interface, even when there is no direct line of sight to the host's screen, by starting up a second client with a video stream.

As described above, the full-screen buttons provide means for presenting the canvas without the help/chat and the controls panels (nice for playing Puck Popper).

There is more information on the Node.js, socket.io, and WebRTC that are used here, including instructions on how to install a local node server on the host computer.

The "Capture" button (or "u" key) records the current state of a demo. The result is written to the neighboring text cell and also to the paste buffer. The capture can be immediately run by clicking the corresponding number button (this will be highlighted yellow). Restart the capture by clicking the yellow button again.

After capturing, the results can be saved for later use by pasting into a text file. To reanimate the capture, paste the result back into the text cell and click the corresponding demo button. The capture result is in formatted JSON. Code editors work well to view and edit the capture with syntax highlighting (JavaScript).

There are links to color-highlighted examples of JSON captures in the help topic for demo #6. These were taken following use of the editing features (see below) to make two circular structures from the Jello matrix.

Captures can be edited. First drag out the lower right corner of the capture text area to better view the capture text. For an editing example, run the 2c demo, and then edit the capture so that one of the pucks has its tail's rainbow parameter set to true. Then click the #2 button.

Editing features can be used to change the characteristics of selected pucks, pins, walls, or springs.

Select a single object by clicking in the canvas area and then dragging the cursor over the object (or by directly clicking on the object).

Summary of the single-select commands:
  • control key
    • mouse drag: hold the "ctrl" key down and mouse drag the object. Puck position and other characteristics are displayed in this mode.
    • rotation: hold down the "ctrl" and "shift" keys and drag the object using the mouse. You'll see the ghost (outline) of the source puck as you drag.
    • shoot a puck: the rotation move (above) leads to a billiards shot by releasing the mouse button. For more on this, try demo 3d, the Ghost-Ball Pool game. Note that the game has the "ctrl" and "shift" keys locked down; ctrl-shift-l toggles this lock. Use the "alt" key to reverse the direction of a shot.
  • arrow keys: resize a single object
    • up/down keys: change a rectangular object's height
    • left/right keys: change a rectangular object's width
  • "-" and "+" keys: change the surface friction (tackiness)
  • "[" and "]" keys: change the puck's restitution (elasticity)
  • "<" and ">" keys: change the linear damping (drag). Use while holding down the "alt" key to change a puck's rotational damping.
  • ctrl-v: replicate the object (includes navigation pins) near the original
  • ctrl-x: delete

To repeat the resizing operations keep holding the corresponding key down.

By default, walls and pins (stationary spring anchors), are not selectable unless you check the "Edit walls & pins" box. This default protects them from moving around under normal mouse-drag situations. To mouse-drag walls and pins, you must also hold down the "ctrl" key.

Check the "Edit walls & pins" box to change the characteristics of the static terrain for any of the demos. This includes perimeter and interior walls (even rotating ones). Refer to the next section, on Multi-select, for commands to rotate objects.

Demo #8 was constructed using the editing features and the state-capture feature. Modify demo #8 to create your own battle field: edit, then capture it.

Multi-select allows you to select single or multiple objects. This is the only method by which springs can be selected (by selecting their connected pucks and pins).

Hold the shift key down to select multiple objects during mouse drag (turn off "Select COM" to select off-center points). Hold down the alt key for box-based selection.

Selected objects are indicated by yellow dots; springs are dashed. To unselect an object, RIGHT click and drag, still using the shift (or alt) key. Note that right clicking with shift down in FireFox yields a context menu when you release the click; ignore it, try using the alt key with FireFox, or use Chrome.

To completely reset the multi-selection, release the shift (or alt) key and click on any empty space in the canvas area.

Summary of the multi-select commands:
  • control key: group drag
    • hold the control key down, then click and mouse drag any body in the multi-select group causing the whole group to drag
  • control and shift keys (or control and alt): group rotation
    • hold both the control and shift keys down, then click and mouse drag any body in the multi-select group causing the whole group to rotate about the center of the group
    • hold both the control and alt keys down to cause each body to rotate about itself
  • arrow keys: resize single or multiple objects
    • holding down the "s" key directs resizing (or damping) operations at selected springs. In the default mode ("s" key up), operations are directed at selected pucks and walls.
    • up/down keys change the object's length
    • left/right keys change the object's width (and strength if it's a spring)
    • left/right keys, while holding down "s" and "alt", changes spring width without affecting spring strength
  • t (and shift-t): incrementally change the rotation rate.
  • "-" and "+" keys: change the surface friction (tackiness)
  • "[" and "]" keys: change the restitution (elasticity)
  • "<" and ">" keys: change the damping (drag) on selected pucks
    • Use while holding down the "alt" key to change the rotational damping (drag) on pucks.
    • Use while holding down the "s" key to change the damping characteristics (shock absorbers) of selected springs.
  • ctrl-x: deletes single or multiple objects
    • the first ctrl-x operation deletes the selected springs, a second ctrl-x deletes selected pucks and pins
  • ctrl-c: copy a single spring (must have ONLY the two connected pucks or pins selected). Press ctrl-c a second time, with no selected pucks or pins, to stop using this spring as the source for paste operations.
  • ctrl-s: paste a single spring (onto two selected pins or pucks)
  • ctrl-v: replicate a selected group of objects to the cursor location. Note: client pucks and navigation pins are excluded.

Altering the characteristics of objects in a multi-select group, such as resizing, affects all members of the group. If a status message is displayed, it indicates the changing value of the last object selected in the group. All member values are scaled with the same factor (increments of 5 or 10%).

Copy and paste can be used to place a spring onto a pair of selected pucks or pins:
  1. use multi-select to select ONE spring (two pucks/pins)
  2. copy it (ctrl-c)
  3. use multi-select to select a new pair of pucks/pins (turn off "Select COM" to select off-center points)
  4. paste the spring (ctrl-s)

A few things to try with multi-select:
  • Dissect (or add to) the jello matrix in demos #6 and #8.
  • Select a compound object (like the triangle in demo #5) and change the connecting spring lengths while it's spinning.
  • Delete some of the pucks in demo #3. Select and delete without using the freeze button. Notice how the new holes in the puck grid propagate after wall collisions.

Demo #1 presents several circular puck animations. The 1a version is a simple mix of large and small pucks, no gravity. These pucks have some surface friction, tackiness, affecting collision and rotational behavior. If gravity is toggled on, their tacky surface, allows these to be combined (stacked) into rolling trios. Try toggling off the "COM" (center of mass) selection and then mouse drag to apply a torque to one of these pucks. Surface friction of selected pucks can be changed via the editor (+,- keys).

1b illustrates the capability of Box2D to model multiple objects in contact that can settle under gravity to form a stacked pile.

1c presents an unusual method for calculating the first two digits of pi (31) using two elastically colliding pucks. Wait as the large puck is repelled by collisions with the smaller puck (and wall). The collision count will stop, eventually, as the two pucks both move in the negative y direction, the large puck slightly faster than the smaller one. This 31-count case occurs when the larger puck has 100 times the mass of the smaller. If the mass of the two pucks are changed to be equal (you can try this by editing the capture), this demo will yield the first digit of pi (3), three collisions, two kisses and one wall bounce.

This 3Blue1Brown video tells the counting-to-pi story.

More pi digits can be found in this way at higher mass ratios, where the ratio is 100 to some power of n. You'll need to use a dedicated 1D physics engine like this one written in Python. The 1D algorithm is also implemented here in demos 1d (3 digits of pi, n=2) and 1e (5 digits, n=4).

The "v max" value captures the highest velocity for the smaller puck during the pi-counting series. This peaks at the point when the larger puck has transfered all its kinetic energy to the smaller puck and reverses its direction. A closed-form solution to this can be derived by equating the kinetic-energy expressions for the two pucks. For 1e:

Demo #2 is a sound-field simulation where two of the pucks are emitting at 60Hz (or the refresh rate of your computer and monitor). The width of the canvas represents 6 meters. Every second a single wave is colored white (others are gray) so you can see that waves are propagating out from the puck. The propagation speed can be changed in the capture (propSpeed_ppf_px). The set of waves are stored in a FIFO buffer. The set size can be changed in the capture (length_limit). This gives the appearance of a tail as the puck is dragged. If you fling the puck so it moves faster than the wave speed (Mach > 1) you will see a shock-wave.

The 2c version of this demo illustrates object motion at Mach speeds of 1.00, 1.41, and 2.00. These speeds produce corresponding Mach angles of 90°, 45°, and 30° (view the capture).

When using the single-frame stepper, you'll see that the 'white' wave is colored red for even more visibility. Pause it when the white wave is visible, then click the "step" button. Notice that the center of the red circle never moves, even if the puck is moving.

2e has a rainbow tail, as characterized in the HSL (Hue, Saturation, Lightness) color space. Saturation and lightness percentages are editable in the capture.

Demo #3 presents examples of order and disorder and are intended for use with the "reverse" button (or ctrl-backspace).

3a illustrates the effect of a disorderly influence on a grid of pucks colliding with each other and the walls. Try reversing the puck motion shortly after the start of the disorder. You'll see that it doesn't take long before this becomes non-reversible. The Playing Catch video (second) in the Perfect Kiss topic, demonstrates a much more reversible puck-puck collision calculation.

3b and 3c have puck-puck collisions inhibited, leaving only wall collisions. This makes for a very reversible collision process even minutes into the demo.

If you try demo 3d you might smell the smoke and beer from your local pool hall.

Demo #3d is the 9-ball version of the Ghost-Ball Pool game (here are racks for 8-ball and simple rotation). Instructions are displayed at the start and in the outline below. Press the "v" key or click here to go full-screen (you'll see the cue ball on the right). The "esc" key returns you to normal view. For listing on the leaderboard, enter: here.
  • To aim a shot, select the cue ball with the mouse, then drag the ghost ball so as to touch it to an object ball or cushion. This will display alignment lines. After colliding, the object ball travels along the solid yellow line, cue ball along the solid white.
  • Shoot the cue ball by releasing the mouse button. Shot speed is initially set at 20. Release over the cue ball to cancel the shot. Use the "alt" key to reverse the direction of the shot.
  • Adjust the shooting speed by tapping the "z" key while dragging the ghost. The value is based on the separation between the ghost and the ball. Optionally, adjust with the mouse wheel.
  • Move any of the balls by dragging with the "ctrl" key down, useful for setting up trick shots and ball-in-hand positioning after a foul.
  • Restart the game with the "3" key.
  • The "b" key disengages the ghost-ball from the target (temporarily turns off finemoves), or toggles it, on/off, in other demos.
  • "alt-b" and "alt-n" step you through the shot history.
  • The "m" key toggles between this help and the chat panel where the leaderboard reports are displayed.
For multiple players, the desktop client supports all the keyboard and mouse commands needed. Try a three-device setup: two players on laptops, connected to a host computer, and viewing the pool game on the host's screen. Use the full-screen mode on clients and host.

A cell phone (touch screen), also, can be used as a client device (to aim a shot). Open the desktop client on your phone and connect as usual to the host. Then use the client's full-screen button (after which you'll get a blank gray screen). Touch and drag to aim a shot; release the touch point to shoot. Release over the cue ball to cancel the shot. Starting a second touch point adjusts the speed lock (like the "z" key described above). Triple tapping, with one finger, toggles ball-in-hand mode (so you can move any ball). Starting a fourth touch point restarts the game (four fingers).

(My dad had a good eye for the game; remembering the times we shared shooting pool in our basement.)

Demo #4 shows Box2D's capability for modeling the rotation and collisions of non-spherical objects. This is a good one to try the editing features. Copy one of the rectangles and then change its width and length. Make some copies of your copy.

The 4b capture (view it) looks a bit like a flying drone. Try using multi-select to select the whole drone (alt-key and mouse drag), then use the right arrow key to change the length of the rotors. If you make them long enough they will collide and stop spinning. Angular momentum is conserved and causes the drone body to start spinning. In a similar way, you can cause the rotors to collide by changing the length of the springs (select the whole drone, hold the s key down, then up/down arrow keys).

For an editing exercise, enable wall and pin edits (click the checkbox). On the left side of the canvas, a spring is mounted on two pins. This can be used to produce a copy (shift key, then carefully mouse-drag over the pins, without selecting the wall, then ctrl-c) and paste it onto a pair of pucks (with the shift key down, mouse-drag over two pucks, then ctrl-s).

The "Freeze" (stop translation) and "R" (stop rotation) buttons are especially useful here.

The 4c capture shows a rectangular puck, elastic and with no surface friction, initialized to have no y component of momentum. The wall collisions, without friction, offer no impulse in the y direction, so it's center of mass continues to travel along the same line. The wall collisions do provide a rotational impulse, so the puck's energy transfers back and forth between rotational and translational forms.

4d shows the release of potential energy associated with tall blocks.

Demo #5 introduces pins, springs, and revolute joints. The spring objects model both springiness and damping behaviors. Revolute joints allow two objects to rotate about a hinge point. Pins are stationary anchor points to which springs and revolute joints can be attached.

With demo 5a, try using the "F" key to stop the orbiting behavior. The pucks in the triangle group and the large tethered-to-a-pin puck are all characterized as inelastic so they play well together under tension. Try to get the large puck inside the triangle group. Notice that the triangle group can be flattened out if gravity is on. Turning gravity off will often result in the flattened triangle popping up and moving. Try this a few times under the dangling large puck (might have to lower the two pins of the large puck, get it closer).

This is another good place to try the editing features. Use multi-select to select the three springs on the triangle (hold shift (or alt) key down then mouse over the three pucks), then adjust their length, as a group, using the "s" and the up/down arrow keys. Use the "s" key and the "[" and "]" keys to change their damping coefficients. Try copying and pasting a spring.

5b is a Rube Goldberg type variation of this (view the capture). The editing features were used to build this compound spring-puck group and adjust the spring characteristics (length, spring constant, and damping).

5c is a simple spring pendulum that is tuned to show its two natures: vertical spring bounce and pendulum swing (view the capture). Give it a little time and you'll see it change back and forth between the two modes.

5d is like watching dandelion seeds gently land on the ground. Use the right mouse button while holding down the "ctrl" and "shift" keys to launch a dandelion. The puffy dandelions have high translational drag in contrast to the much lower drag of the pucks dangling underneath. Here is a large-canvas version where the ctrl-shift lock has been applied; just drag and release to shoot. Here's a handy link to fullscreen viewing.

5e incorporates the revolute joint type of Box2D to produce a wall-mounted pulley and a chain-link loop. The revolute joint is a sister to the spring in the Box2D family of joints. Note the "add revolute joint" and "add chain" options of the "remove/add items" select control in the right panel.

Revolute joints (and systems using them) can be captured and also replicated using the multi-select features. For example, use box select (alt-key and drag) to select the whole chain-pulley system and then ctrl-v to paste a copy.

You can also break the chain, by selecting two links (shift-key and drag) and then ctrl-x to delete the revolute joint (a second ctrl-x will delete the two links). Reconnect the two links by selecting their ends (turn "COM" off first) and then using the "add revolute joint" option from the "remove/add items" select control.

Note the wall-mounted pulley was created by "add pin", then enabling "edit walls & pins", then selecting the pin and a puck (with "COM" on), and finally "add revolute" joint to mount the puck on the pin.

Traditional spring models are not native to Box2D and are developed here as external objects that apply forces to things modeled in Box2D. Erin Catto uses a soft-constraints approach to spring modeling (distance joints) in Box2D. Here is his presentation on this. When using distance joints, I use the equations on page 45 to translate from k and c to frequency and damping ratio. (see updateB2D_spring method of the Spring prototype in the constructorsAndPrototypes module).

The 5f demo contrasts these two spring types: traditional springs on the left (yellow), and distance joints (cyan) on the right.

Most of the springs at timetocode.org, including the cursor spring, use a default spring-nature setting as they are being instantiated (e.g. when re-animating a capture, pasting a copy of a spring, or adding a spring using the "remove/add items" select control). Use shift-s to toggle this default setting between soft-constraints or a traditional spring nature. After changing the default, you can then (you must) re-run a demo, or paste the new spring, to see the change in behavior.

Note that any capture with springs having a softConstraints key specified, will override attempts to use the shift-s feature. You must remove the softConstraints key (edit the capture) to let the spring have a variable nature and respond to the shift-s command. Any new capture will have a softConstraints key specified for each spring.

The capture for 5f explicitly specifies the spring nature (see "softConstraints" key, set true or false, in the capture). So, in this case, soft will stay soft, traditional will stay traditional.

The advantage of the soft constraints is added stability: strong spring (or strong damping) forces on small masses will be more stable. But the improvement in stability is small (as implemented here), and it seems that the traditional springs give a better feel, especially in compound groups. So I continue, for now, to leave the default set to traditional springs, and most of the springs in the demos without a softConstraints key.

Demo #6a, Jello-Madness, is based on the corresponding game from the J-term course. The demo starts with a mildly tangled block of jello, it's spinning, and the tangle-timer is running. Straighten out the block and the tangle timer stops. The idea here is to severely tangle up the block for a game (drag perimeter pucks into the middle using the right mouse button). Use the capture button to record a good tangle. Then pass the mouse and keyboard to your friend and see if they can untangle the mess; they start by clicking the #6 button (or 6 key). The shortest untangle time wins. The right mouse button, the freeze control (f key), and possibly the gravity control are useful in this game. Hints: one of the interior pucks is colored differently and also note the diagonal springs are all yellow.

Try 6d, a more severely tangled piece of jello. Start with a spinning fling, using the right mouse button... If you're lucky, you can get the whole thing straightened out with one move.

Here are links to JSON captures of editor-modified versions of this demo: 6b (view the capture), and 6c (view). To get some practice with pasting and running a capture, open a view-it link here, copy everything, then paste into the text area under the "Capture" button. Then click the #6 button to run the capture.

Demo #7a is a small version of Puck Popper. The object of this game is to be the last controlled puck remaining (all other player and drone pucks have been popped). The center black puck is outfitted with the client controls needed to play the game. Multiple network clients can play (see multiplayer topic above). All network clients should first connect, then the host should click the #7 button.
  • 7b: two drones
  • 7c: four drones (difficult to shoot your way out of this one)
  • 7d: one drone on a 2-pin path (an easy one)
The w-a-s-d group of keys controls the jet that is used to move your puck. The "w" key fires the jet. The "a" and "d" keys rotate the jet clockwise and counterclockwise. The "s" key is used to turn the jet to a direction opposing the current motion of the puck. This can be useful in breaking (stopping). Subsequent "s" presses rotate the jet in 90-degree clockwise steps. Firing the jet, "w", resets this pattern so the flip operation results with the next "s" press.

The i-j-k-l group of keys controls your gun. The "i" key shoots bullets. The "j" and "l" keys rotate the gun clockwise and counterclockwise. The "k" key rotates the gun in 90-degree clockwise steps (shift-k steps counterclockwise).

Holding down the spacebar turns on a shield that protects you from the bullets of an opponent (you can't shoot when your shield is up). Target pucks will pop after 10 hits, client-controlled pucks pop after 20 hits.

The "friendly fire" checkbox (visible when the "Multiplayer" control is checked) controls whether bullets from real Puck Popper players can affect the health of other real players. If unchecked, human bullets can only impact the drones. In this mode multiple players act as a team to scrub out those nasty drones. Nice.

The blue pucks are drones. They try to get you (it's time to start using the spacebar to turn your puck shields on). The drones follow a path established by the blue pins. Turn on the editor to see the navigation path. When the editor is on, you can drag these navigation pins to change the drone path. These pins can also be copied and deleted using the features of the editor.

The multi-select features of the editor can be used to detach the drone from the navigation path (delete its spring). First, check that wall and pin edits are enabled. Box selection (click and drag with the alt key down) is useful for selecting the spring between the drone and the navigation pin. If you've used the ctrl-q feature to disable (sleep) the drone's movement and shooting, it will come to rest over its current pin, making it hard to select both pin and drone using the shift-key approach. The box selection method allows pin, drone, and spring to be selected in one action, the box drag. Then ctrl-x deletes the navigation spring.

In a similar way, you can reattach a drone by copying (ctrl-c) the spring from another drone and pasting (ctrl-s) it onto the free drone and a blue navigation pin. Remember, ctrl-q toggles drone shooting and navigation on/off, useful when detaching and reattaching them.

Drones can be copied, to produce a free floating drone: mouse-drag over a drone, then ctrl-c. Attach it to the navigation path using the methods above.

A single drone, attached to a navigation pin, can be generated by depressing the shift, d, and p keys together (shift-d-p). The drone and pin will appear at the current location of the local host's cursor. If wall/pin edits are enabled, you can then extend this drone's navigation course by copying and dragging the pin (single-select operation, ctrl-c).

Navigation forces are rendered as jets when the editor is off (rendered as springs when the editor is on).

The drones use raycasting to find puck targets. To hide from the ray, move behind a wall, behind another puck, or beyond the length of the ray.

After finding a puck, they point their gun to "lead" the target. This anticipates where the moving-target puck will be when the bullets arrive. You'll see the gun is angled slightly ahead of the raycast line when the target is moving. The algorithm also accounts for the motion of the drone.

The controlled pucks are inelastic and with some drag to make them a bit easier to drive (bullets and regular pucks are elastic and with no drag).

Scoring in Puck Popper (demos 7 and 8):
  • +200 for last puck-player standing
  • +100 for popping client and drone pucks
  • +50 for popping a regular puck
  • +10 for hitting a puck with one of your bullets
  • -10 for getting hit by a bullet
  • -1 for shooting a bullet that expires before it hits another puck
A score summary for each player is reported in the chat panel at the end of the game (one puck left).

A leaderboard report, the top 15 scores, is displayed below the game-score summary table. The report consists of two query results, one table sorted by time, the other by score (click the link to toggle between the two tables). The backend of the leaderboard, a Google sheet, is queried depending on the version of the Puck Popper game (e.g. demo #7 results are reported separate from #8). Custom versions of Puck Popper, made using the capture feature, are reported separately as distinguished by a unique identifier in the capture. Game results where the mouse was used (in the Canvas area) or the drones are "sleeping", are filtered out of the reports.

From the host page, you can establish a nickname (without connecting to the multiplayer server) by typing the nickname into the chat field before starting demos #7 or #8. That nickname will be used when reporting to the leaderboard.

Demo #8a is a larger version of the Puck Popper game. This is similar to #7 in that a controlled puck is created for the local client, each network client, and for each of the four drones (they will try to find you). For more on the drones refer to demo #7. In multi-player mode all network clients should first connect, then the host should click the #8 button.

To play without drones, use ctrl-q to stop the drone navigation. Use the editor features to select and delete them. Then capture the drone-free course for repeated play.

The starting position and velocity for each human-controlled puck is fixed (to be the same each time the game starts). These positions can be edited in the startingPosAndVels object of a capture.

8a is intended to be a template that can be edited and captured for later use.

Try shooting at the pucks in the spring matrix (jello). The editor's multi-select feature is useful for carving/slicing up the jello. Hold the shift key down, then mouse over pucks in the jello grid. A first ctrl-x will delete selected springs, a second ctrl-x will delete the selected pucks.

For 8a, 8b, and 8c, the controlled pucks are inelastic and with some drag to make them a bit easier to drive. Bullets are elastic and with no drag; regular pucks are inelastic and with no drag.

There are elastic collisions and no drag in 8d and 8e. These versions of Puck Popper are the most challenging to play. This optimizes the capability of the drone pucks to anticipate (and lead) for the motion of the human-controlled pucks. 8e has no gun recoil.

Demo #9 animates the additive mixing of three colors: red, green, and blue. The blending features of the HTML5 canvas facilitate the color mixing. The globalCompositeOperation attribute is set to a value of 'screen'.

The three balls are coupled together with three distance joints (aka springs, with damping). Each ball is also lightly coupled to a corresponding stationary pin and has some linear damping (fluid drag). When "Edit walls & pins" feature is enabled (checked), the pins and springs are visible.

Puck-puck collisions are inhibited by using the collideConnected attribute of the distance joint. If pucks are copied, they will collide with any pucks not coupled to them with a distance joint.

Normal editing and capture features apply here. Use the box-selection feature (alt key) for an easy way to copy or modify the three-puck group. To include the pins in copy operations, the "Edit walls & pins" feature must be enabled. The 9b version was made with the editor.

This demo runs most efficiently in Google Chrome. Frame rates will dip below target for other browsers, especially if the "Edit walls & pins" feature is enabled.

These demos try to run at a frame rate that is equal to the refresh rate of your display. This frame rate is reported to the right of the "pause" control. The value should be about 60fps if your display's refresh rate is set to 60 Hertz. Cell phones will generally not be able to reach 60fps for most of the demos.

Below the "pause" control is a selection control used in establishing a fixed timestep for the physics-engine (inversely related to framerate). This is automatically set (based on an observation of your framerate) whenever the page is refreshed.

Generally this will get set to 60 Hertz unless you have a DVI or Display Port connection to a monitor that can render at higher rates. Note that the longer timestep of the 30 Hertz setting will be unstable in demos that incorporate springs.

Direct mouse drag (and rotation) of single or multiple objects will produce instability when editing spring systems at rates of 60 Hz or less. At 100 Hz or higher these operations work the best.

If you do have high-refresh-rate gear, try setting your monitor to a refresh rate that the demos can easily match. If a demo is running slower (fps) than your monitor's refresh rate, try reducing your monitor's rate (in Windows 10, right click on the desktop, then "display setting", then "advanced display setting", then "display adapter properties", then "monitor" tab, then change the "screen refresh rate"). Then, after you have dialed back your monitor to the point that the demos can match it, set the timestep control to agree with that value (or refresh the page to set it automatically).

At the beginning of the timestep select list, you'll see the option "variable". This lets the physics timestep (framerate) float along with the refresh rate of your monitor. This can be handy for observing the fps performance of your system. Generally it's best to only use this to test. Then set a similar fixed-timestep value.

Overall, Chrome is the best browser to use here. (You may want to stop reading about browsers and simply use Chrome.) However, Firefox is a close second to Chrome, and, depending on the hardware, I sometimes prefer its rendering e.g., demo #2 when running on my laptop.

Firefox has a "feature" that conflicts slightly with one of the editing features here. Right-clicking with the shift key down will always bring up a context menu in Firefox when the click is released, apparently overriding attempts to disable it. Chrome and Edge do a better job listening.

Firefox also has distinctive alt key behaviors. The alt key is used here to start a box-based selection. If this is played by the book (hold alt key down, then click and drag the mouse) all goes well. But if you tap the alt key (down then release) this will trigger the menu bar to be displayed. Any click and drag operations that follow will appear to be stuck in box-select mode. To reset this do two complete cycles of the alt key (down-up-down-up) without any mouse clicks in the middle.

Microsoft Edge is now based on Chromium (like Chrome). It works very well here, pretty much identical to Chrome.

MS Internet Explorer is not functional here.

Testing is very thin on macOS. Chrome looks good there; all the multiplayer functionality (including WebRTC) works. Safari looks ok except for some minor rendering issues relating to object borders and dashed lines. For GhostBall Pool (#3d), Safari doesn't go to fullscreen well; use the full-canvas button instead.

Testing on the Raspberry Pi showed that Chromium looks good there and the multiplayer works fine. RPi makes an excellent non-streaming client but is very underpowered as a host. The right-side alt key is required for box selecting objects.

A Chromebook makes a good streaming and non-streaming client. As a host it is somewhat underpowered. The touchpad differs from Windows. Because of the way this site uses the alt key (for box-based object selection), you must use a mouse to get right-click features like the strongest mouse springs.

For the curious, here are the JavaScript modules behind this page. The code is colorized (syntax highlighted). Note that the server-side code for the leaderboard is not included here.


























Pause (0fps)


Demos and Games:

Edit walls & pins