Skip to content

simin75simin/ball-sandbox

Repository files navigation

Ball Sandbox — 2D ball-in-circle physics

A small 2D physics playground inspired by "2^27 balls dropped inside a circle": an offline MP4 renderer plus an interactive Pygame sandbox with multiple container shapes and live-tunable physics.

UI defaults to English; click EN / 中文 in the top-right to switch.

Download for Windows →

Two programs

1. Offline renderer — sim.py

Renders the wall-only "drop balls into a circle" scene to output_nocollide.mp4 using NumPy + Numba.

uv run python sim.py
  • 22 000 balls in a 270 px circle
  • Released simultaneously from a small cluster just below the top of the ring
  • Per-frame colors = current y (top = red, bottom = violet)
  • 10 s @ 60 FPS, ~15 MB

All knobs live in the CONFIG block at the top of sim.py.

2. Interactive sandbox — interactive.py / interactive_app.py

uv run python interactive.py        # dev build (Numba JIT, faster physics)
uv run python interactive_app.py    # pure-NumPy build (no JIT, ships in the .exe)

Four container shapes (circle / square / triangle / ellipse), live sliders for gravity, restitution, damping, ball radius, balls-per-click and container size, plus pause / clear and language toggle.

Controls

Mouse / Key Action
Left click Spawn a cluster of balls at the cursor
Right drag Continuous spray
Scroll wheel Fine-tune the slider under the cursor
Esc Quit

Everything else (gravity / restitution / damping / ball radius / spawn count / container size / shape / pause / clear / language) is on the left panel.

How to get it

Windows — single-file exe (no Python required)

Grab BallSandbox.exe from the latest release. ~20 MB, double-click to run. First launch takes 1-2 s while PyInstaller unpacks to %TEMP%.

From source (any OS with a recent Python)

uv sync                       # creates .venv, installs numpy / numba / pygame-ce / imageio / pillow
uv run python interactive.py

uv is recommended; plain pip install -e . in a venv also works.

Implementation notes

Each physics substep (4× per frame → 240 Hz):

  1. Semi-implicit Euler integrate: v += g·dt; v *= damping; x += v·dt
  2. (offline renderer only) PBD position projection — uniform grid hash, cell = max(2r, 1px), each ball checks its own cell + 8 neighbors
  3. Re-derive v = (x - x_prev) / dt (canonical PBD move)
  4. Wall constraint — project the ball back inside and reflect the normal velocity. Must come after step 3, otherwise the position-derived velocity overwrites the bounce and balls appear to stick to the wall.

Per-shape wall constraints in the interactive sandbox:

  • Circle: project to R - r, reflect radial velocity
  • Square: 4 axis-aligned faces, each handled independently
  • Triangle: equilateral, three outward edge normals + apothem R/2
  • Ellipse: (x/a)² + (y/b)² > 1 → radial-scaling projection, gradient used as the surface normal for velocity reflection

Colors: each frame computes HSV → RGB from the current y coordinate so the ball cloud always reads as a top-red → bottom-violet spectrum.

Rendering:

  • Ball radius ≤ 1 px: pokes pixels directly via pygame.surfarray.pixels3d
  • Larger: per-ball pygame.draw.circle

Scaling toward 2²⁷ balls

134 million balls is well past what this CPU pipeline can do. Practical paths:

  • Taichi / CUDA: port count / scatter / resolve into GPU kernels with ti.atomic_add. An RTX 30-series box can sustain ~10⁷ balls at 30 FPS.
  • NVIDIA Mochi (arXiv:2402.14801): treat balls as spheres in a BVH and trace queries with RT cores; reaches 10⁸.
  • PIC / FLIP: once balls are well under one pixel each, individual collisions stop being visible. Most viral "many balls in a circle" videos are really fluid sims rendered as particles.

Repo layout

File Purpose
sim.py Offline MP4 renderer (Numba)
interactive.py Pygame sandbox, Numba physics — dev build
interactive_app.py Pygame sandbox, pure NumPy — gets packaged into the exe
snapshot.py Dumps PNG keyframes from sim.py
gen_icon.py Procedurally renders icon.ico
snapshots/ Pre-rendered keyframes

References

About

2D ball-in-circle physics sim + interactive pygame sandbox (4 shapes, sliders for gravity/restitution/damping)

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages