A 2D physics simulation built entirely from scratch using TypeScript and the HTML5 Canvas API.
This project was created as a learning journey into game physics, simulation programming, vector mathematics, and collision systems. Instead of relying on existing physics engines such as Matter.js or Box2D, every major component was implemented manually.
- Real-time Canvas rendering
- Delta-time based simulation
- Custom Vector2D implementation
- Gravity and acceleration
- Wall collision detection
- Ball-to-ball collision detection
- Impulse-based collision response
- Friction and restitution (bounciness)
- Runtime simulation controls
- Collision visualization
- Adjustable physics parameters
This project explores many of the fundamental concepts used in modern game engines and physics systems:
- Vectors
- Magnitude
- Distance calculations
- Normalization
- Dot products
- Position
- Velocity
- Acceleration
- Gravity
- Friction
- Restitution
- Collision normals
- Relative velocity
- Impulse response
- Simulation loops
- Delta time
- Collision systems
- Entity management
- O(n²) collision detection
This project was intentionally developed incrementally.
Started with rendering a single circle using the Canvas API.
Learned:
- Canvas rendering
- Animation loops
- Browser graphics
Introduced:
- Velocity
- Acceleration
- Gravity
Implemented:
velocity += acceleration;
position += velocity;Made the simulation frame-rate independent.
Implemented:
velocity += acceleration * dt;
position += velocity * dt;Created a custom Vector2D class.
Implemented:
- add()
- subtract()
- multiply()
- divide()
- magnitude()
- distance()
- normalize()
- dot()
Added:
- Floor collisions
- Ceiling collisions
- Side wall collisions
Introduced:
- Restitution
- Collision response
Discovered the difference between:
- Surface friction
- Air drag
Implemented friction that only applies while grounded.
Refactored the simulation from:
Ballto:
Ball[]allowing hundreds of simultaneous entities.
Implemented:
distance < radiusA + radiusBfor collision detection.
Learned:
- Pairwise collision checks
- Circle intersection tests
Introduced normalized direction vectors to determine:
- Collision direction
- Separation direction
- Impulse direction
This was the biggest conceptual breakthrough of the project.
Implemented:
- Relative velocity
- Dot products
- Collision impulses
to create realistic collision behavior between balls.
The simulation includes a control panel for modifying parameters at runtime.
| Parameter | Description |
|---|---|
| Gravity | Downward acceleration |
| Speed | Simulation time scale |
| Radius | Ball size |
| Bounciness | Collision elasticity |
| Count | Number of balls |
| Default Color | Normal ball color |
| Collision Color | Collision highlight color |
Clone the repository:
git clone https://github.com/ItsPinion/Bouncing-Balls-Simulation.gitNavigate into the project:
cd Bouncing-Balls-SimulationInstall dependencies:
npm installStart the development server:
npm run devOpen the URL shown in the terminal.
- Launch the simulation.
- Observe the default behavior.
- Adjust gravity and speed.
- Increase the ball count.
- Change bounciness.
- Experiment with different radii.
- Observe how collision behavior changes.
- Study the effects of impulse-based collision response.
Recommended experiments:
- Set gravity to 0.
- Increase ball count dramatically.
- Set bounciness close to 1.
- Slow down the simulation.
Current collision detection uses a naive pairwise approach:
O(n²)
This was intentionally chosen for educational purposes to understand how collision systems work internally.
Future improvements could include:
- Spatial Hashing
- Uniform Grids
- Quadtrees
- Broad Phase Collision Detection
- Ball mass
- Rotational physics
- Angular momentum
- Mouse interaction
- Spatial partitioning
- Constraint systems
- Springs
- Soft-body physics
- Performance optimizations
The purpose of this project was not to build the most advanced physics simulator.
The goal was to understand the underlying principles behind modern physics engines by implementing them manually.
Every feature was built incrementally, from a single bouncing ball to a multi-object impulse-based collision system.
The result is both a working simulation and a documented exploration of fundamental physics-engine concepts.
MIT License