workshop private

← all creations

Dwell

mechanics · created 2026-09-27

Juggling is a booking system with a ballistics problem bolted on. The average of your throws is the ball count — exactly, in all 1270 small patterns checked — so every high throw is a debt you pay in low ones, and from a three-ball cascade a 1 or a 2 is not a throw you are allowed to make. Then the physics: height goes as (balls − dwell)², so at a fixed hand rhythm five balls is four times the height of three and never the 1.67 everyone assumes, and the thing that actually runs out is not the arm. A 300 ms dwell caps a 1.50 m pattern at nine balls no matter how good you are; 100 ms less buys four more, and buying those four with height instead means throwing 3.34 m.

physicsalgorithmssimulationcanvasgame-feel

Juggling looks like a physics problem and is mostly a scheduling one. Before anything leaves a hand there is a question of bookings: a ball thrown now is a promise to catch it on a particular beat, and you have two hands and one beat at a time. Almost everything that makes a pattern hard, and everything that makes a pattern impossible, is decided in that ledger before gravity is consulted.

The whole rule

Write a pattern as the sequence of throws it repeats. A throw is a number: how many beats until that ball comes back down. 3 forever is the three-ball cascade. 531 is a five, a three and a one, over and over.

A throw of t made on beat i books the slot (i + t) mod n. That is the entire legality test:

landings(s) = [ (i + s[i]) mod n  for i in 0..n-1 ]
legal  ⟺  those are all different

No heights, no hands, no gravity. If two beats book one slot, two balls arrive at the same instant and one of them hits the floor.

Out of it falls a fact that feels like it should cost more than it does. The average of the throws is the number of balls. Not a rule of thumb — an identity. The demo checks it the long way round, following each throw to where it lands until the orbits close and counting the orbits, and compares that to the mean, across every legal pattern of period ≤ 4 with ≤ 4 balls. That is 1270 patterns, and the largest disagreement is exactly zero.

The average is a filter, not a proof

Which tempts you into the obvious shortcut: check the average, and if it comes out whole, juggle it. It does not work, and the counterexample is three digits long.

543 averages exactly 4. It also puts every one of its three throws on the same landing:

beat 0 throws 5  →  slot (0+5) mod 3 = 2
beat 1 throws 4  →  slot (1+4) mod 3 = 2
beat 2 throws 3  →  slot (2+3) mod 3 = 2

Three balls, one landing, one pair of hands. Feed 5 4 3 to the demo by hand and it drops on beat 1 — you do not even get to the third throw.

And the shortcut is not close to right in bulk either. Over period-4 sequences of digits 0–9: 2498 of the 10000 have a whole-number average, and 962 of those juggle. The average test throws away three quarters of everything, and then for every pattern it is right about it waves through 1.6 that drop. At period 3 it does better — 334 whole, 226 juggleable, 67.7% — which is exactly the trap, because period 3 is where you would go looking for confidence.

How many patterns there are

The census view enumerates them, and the count that comes back is not the ragged number you would expect from a constraint that awkward:

period n, at most b balls   →   exactly (b + 1)ⁿ patterns

Period 4 with at most 4 balls: 625. Period 5 with at most 4: 3125. The demo checks seven of these by brute force and they land on the nose every time. Subtract to get the ones using exactly that many balls — 625 − 256 = 369 four-ball patterns of period 4. This is a known theorem (Buhler, Eisenbud, Graham and Wright); what the demo adds is watching it come out of an enumeration rather than being told.

(b+1)ⁿ is the number of strings of length n over b+1 symbols. So there are exactly as many juggling patterns as there are ways to write down n digits from a (b+1)-letter alphabet — while the patterns themselves are a thin, scattered subset of the sequences you can actually write. The counting is trivial and the membership is not, which is an unusual way for a set to behave.

Where the game is

Take the hands over — press a digit — and you are feeding throws into the same ledger. Two things immediately bite.

The first is the average, now as a budget rather than a theorem. Your throws must average your ball count, so a 5 is borrowing and something has to repay it. In three balls, a 5 is repaid by a 1.

The second is sharper, and it is the thing nobody tells you. The three-ball ground state has the next three beats already booked:

state  1 1 1 0 0 0 0 0 0        legal throws:  3 4 5 6 7 8 9

From a cascade you cannot throw a 1, and you cannot throw a 2. Beats 1 and 2 are spoken for. The low throws are not something you are bad at; they are unavailable. To make one you first have to throw something high enough to open the slot, which is what 531 actually is — the 5 is what buys the 1, three beats later. That is the loop the mechanic runs on: you can only spend what a previous throw made room for, and the readout of your running average creeping onto your ball count is the receipt.

One more thing the state graph says, which is easy to miss and hard to unsee: throwing never changes how many slots are booked. So 3, 441, 531 and 423 all sit in one state and interchange freely — the transition between them is the empty list, there is nothing to do — while the transition from three balls to four does not exist. Adding a ball is not a juggling move. It is a different pattern, started from scratch.

Then the hands get involved

A beat is a duration. A ball lands D seconds before the beat it is thrown on, is held for D, and is in the air for the rest:

flight(t) = t·beat − D        height = g·F²/8

With two hands taking turns, a hand is busy for D and idle for V = 2·beat − D, and those four durations are locked together by an identity Claude Shannon wrote down while building a juggling machine:

(flight + dwell) · hands  =  (vacant + dwell) · balls

The demo holds it across 1890 combinations of ball count, tempo and dwell, to 3.5 × 10⁻¹⁶ relative — it is bookkeeping, not a model, and it is the reason you can only ever trade these things against each other.

Five balls is four times as high

Hold your hand rhythm fixed and add a ball. Flight time goes up by one beat, so height — which goes as flight squared — goes as (n − d)², where d is the dwell as a fraction of a beat. Not as n. At a one-beat dwell the numbers come out whole:

3 balls  →  ×1
5 balls  →  ×4.00
7 balls  →  ×9.00
9 balls  →  ×16.00

At a gentler 0.75-beat dwell it is ×3.57 for five, and with no dwell at all — an instantaneous hand, which nobody has — the best case is still ×2.78. There is no dwell anywhere that makes five balls ×1.67 of three. Everyone’s first instinct is the dashed grey line in that panel, and the orange curve leaves it immediately.

This is also why the scene goes off the top of the screen when you load 97531: at the tempo that suits a cascade, its nine peaks at 6.5 m. The demo draws where three balls would reach on the same hands as a dashed line near the floor, so the spike means something. Press N and it solves for the tempo that would put that nine at 1.5 m instead, which is the only other thing hands can do.

What actually runs out

Here is the part worth taking away. Fix the height you are willing to throw — say 1.50 m, which is 1106 ms of flight. Vacant time cannot go negative, because a hand cannot be in two places, and that alone caps the pattern:

N ≤ hands · (flight + dwell) / dwell

dwell 400 ms  →   7 balls
dwell 300 ms  →   9
dwell 200 ms  →  13
dwell 100 ms  →  24

A 300 ms dwell caps a 1.50 m pattern at nine balls, and no amount of arm fixes it. Take 100 ms off the dwell and you get four more. Try to buy those same four balls with height instead, keeping the slow hand, and you need to throw 3.34 m — ×2.22 as high — for the identical result.

So the limiting organ is the hand, not the arm. The thing you would train is not throwing power and not even catching accuracy; it is how briefly you can hold a ball and still control where it goes. That is a strange conclusion to reach from a gravity problem, and it is the one Shannon’s identity forces.

And the precision bill

There is a second cost, and it compounds. A throw with a relative error σ in launch speed has a proportional error in flight time — δF = σ·F — because F = 2v/g is linear in speed. Flight time grows with the pattern. The catch window does not. So:

60 ms window, 0.75-beat dwell:
3 balls  needs throws inside 3.17%
7 balls  needs throws inside 1.14%       ×2.78 more consistent

Simulated rather than asserted: the same hands, throwing at a fixed 2% error, last 3994 beats on three balls — against a 4000-beat cap, so essentially forever — 92 on five, and 10 on seven. The pattern does not get harder gradually. It falls off a cliff, because a constant relative error is an absolute error that grows.

Driving it

Three views, V cycles. hands runs a pattern — the scene, the ladder (every throw an arc from the beat it left to the beat it lands on, so a collision would be two arcs touching down on one dot), and the live landing schedule with the legal throws marked. wall is the two physics panels. census is every pattern of a period, with X mixing in the near-misses that pass the average test and drop anyway.

In hands: 0–9 throws, and the first digit you press takes the hands off the autopilot; A gives them back. [ ] change pattern, ↑ ↓ the tempo, ← → the dwell, N solves for the tempo the pattern would really need, space runs and pauses. In census: ← → move the cursor, [ ] the period, ↑ ↓ the ball cap, Enter sends the selected pattern to the hands.

What the model does not do

Reusing it

src/dwell.mjs is framework-free and has no DOM in it. Seconds, metres, m/s.

import { parse, isValid, mean, ballCount, census, stateOf, legal, schedule, shannon, ceiling } from './dwell.mjs';

isValid(parse('531'));            // true
isValid(parse('543'));            // false — average 4, three balls on one slot
ballCount(parse('97531'));        // 5, found by following orbits, not by averaging
census(4, 4).length;              // 625 = (4+1)^4

legal(stateOf(parse('3'), 9));    // [3,4,5,6,7,8,9] — no 1, no 2
schedule(parse('531'), { beat: 0.28, dwell: 0.21 });   // timed throws with heights
shannon({ balls: 5, beat: 0.28, dwell: 0.21 }).vacant; // what the hand has left
ceiling({ flight: 1.106, dwell: 0.3 });                // 9.37 balls, hard stop

The scheduling half is useful well away from juggling: stateOf / legal / advance is a small bounded-resource allocator — a window of future slots, a move that books one, and a legality test that is just “is it free” — and transition is breadth-first search over those states. Anything that has to place work on a timeline without double-booking it has the same shape.

node scripts/screenshot-demo.mjs boots the demo in a real Chromium, drives it through its own hooks, and checks all 47 of the claims above against the running code before it writes a single screenshot.