This is my personal playground where I implement various bonker things to get better at visualizations and physics simulation. Expect experiments, small games, and visualization-first simulations.
- Left Click: Spawn big balls
- Sliders: Gravity, speed, particle count
- Text Box: Max particle cap
- ESC: Exit
This project uses a set of pragmatic, GPU-friendly approximations to produce visually interesting behavior while remaining performant at large particle counts. Below are the main formulas and the implementation notes showing how they map to the code.
We use a softened inverse-square style influence computed pairwise and accumulated using vectorized GPU ops.
Vector form (conceptual):
Practical scalar form used in code (softening in denominator):
Notes:
- A small softening term
$\varepsilon$ prevents singularities at short ranges. - Forces are accumulated per-particle using GPU tensors (see
simulation/physics_torch.py).
Collisions are resolved pairwise using the collision normal and the relative velocity along that normal.
Unit normal:
Relative velocity:
Classical instantaneous impulse magnitude (elastic model):
Velocity updates (impulse application):
Implementation notes:
- The code uses a mass-weighted impulse factor and an adjustable restitution (near-elastic for large masses) to produce lively collisions while remaining stable on the GPU.
- After impulses, overlapping pairs are separated to prevent sticking:
We use semi-implicit (symplectic) Euler integration:
$\mathbf{v} \leftarrow \mathbf{v} + \mathbf{a},\Delta t$ $\mathbf{x} \leftarrow \mathbf{x} + \mathbf{v},\Delta t$
With additional safeguards:
- Small-ball speeds are clamped to a configured maximum to keep visuals coherent.
- Bounce responses apply velocity sign flips with damping at boundaries.
- Add small epsilons to denominators (e.g.,
$|\mathbf{r}|^2 + \varepsilon$ ) to avoid divisions by zero. - Use vectorized tensor operations and accumulation (e.g.,
scatter_add/index-add patterns) to handle multiple collisions affecting the same particle in one timestep. - Defer mutations to the global active mask until after per-frame accumulation so array shapes remain consistent during GPU writes.
- Big balls carry a scalar
healthand aconsec_non_owncounter. - Same-color small-ball collisions:
- Heal the big ball by +1
- Absorb and deactivate the small ball
- Non-own-color collisions:
- Decrease big ball health by 1
- Increment
consec_non_own - If
consec_non_own >= 50the big ball "explodes" into several small balls (spawned from the inactive pool)
Implementation mapping:
- Health, consec counters and spawn logic are implemented in
simulation/physics_torch.py(collision loop and post-collision spawn), and helper spawn routines insimulation/particle_utils.py.
For a concise code-to-formula guide, see the comments near the collision and attraction loops in simulation/physics_torch.py. If you want, I can add a short inline table mapping each equation above to the exact line ranges in that file. Would you like that?
- PyTorch (CUDA) : physics & vector math on the GPU (
simulation/physics_torch.py,simulation/gpu_setup.py). - Pygame : visualization, UI, event handling (
simulation/visualizer.py,simulation/ui_components.py). - CuPy (optional) : alternate GPU compute backend.
- numpy : utility conversions and CPU fallbacks.
| Component | Requirement |
|---|---|
| OS | Windows / Linux / macOS (dev-tested on Windows) |
| Python | 3.10+ |
| GPU | NVIDIA GPU with CUDA (recommended) |
| CUDA | 12.x (matching PyTorch/CuPy build) |
| RAM | 8 GB+ |
A CUDA-capable GPU is strongly recommended for interactive experiments at high particle counts.
pip install -r requirements.txtRequires: Python 3.10+, NVIDIA GPU with CUDA
Note: This simulation requires CUDA 12.x (CUDA 12.0+ builds). If your system has a different CUDA major version installed, install CUDA 12.x and matching CuPy/PyTorch wheels. The project enforces CUDA 12.x only.
Install (inside a virtual env):
python -m venv .venv
# Windows PowerShell
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txtRun headless benchmark:
python ball_sim.py --particles 100000 --duration 60Run interactive visualization:
python ball_sim.py --visualize --particles 50000- 3D visualization backend
- More physically-accurate integrators & collision handling
- Mini-games and interactive scenarios
- Improved UI and in-app presets
See CONTRIBUTING.md give ideas, suggest more good things, submit experiments, or collaborate.
This repository is available under the MIT License.
Have fun experimenting, this is a sandbox for trying computationally-interesting visual ideas.

