A fully client-side 2D physics sandbox built with vanilla HTML5 Canvas and JavaScript. No external frameworks or build tools required.
- Semi-implicit Euler integration with configurable substeps
- Gravity, drag, collision detection and response
- Circle-circle, circle-box, and box-box collision support
- Spatial hash grid for efficient broadphase collision detection
- Handles thousands of bodies at 60 FPS
- Circles: Full physics bodies with mass, restitution, friction
- Boxes: Axis-aligned rectangles
- Particles: Lightweight circles optimized for large quantities
- Click & Drag: Spawn entities with initial velocity
- Shift + Drag (or Middle Click): Pan viewport
- Mouse Wheel: Zoom in/out
- Space: Play/Pause simulation
- Period (.): Step one frame
- 0: Select tool
- 1: Circle tool
- 2: Box tool
- 3: Particle brush
- Delete/Backspace: Remove selected entity
Load pre-built demonstrations:
- Particle Fountain: 1000+ particles in fountain pattern
- Box Stack: Pyramid with gravity
- Newton's Cradle: Momentum conservation
- Rain: Particles with wind effect
- Pinball: Bumpers and bouncing balls
- Save scenes to browser localStorage
- Load saved scenes
- Export/Import scenes as JSON files
- Adjust gravity (X and Y components)
- Change drag coefficient
- Modify time scale (0.1x to 2.0x)
- Select entities and edit properties live:
- Mass
- Restitution (bounciness)
- Friction
- Color
- Static/Dynamic toggle
- Show velocity vectors
- Show entity IDs
- Show collision contacts
- Show world grid (when paused)
- Dark theme toggle
- Open
index.htmlin a modern web browser - Click a tool button (Circle, Box, or Particles)
- Click and drag on the canvas to spawn entities
- Watch them interact with physics!
The project is organized into modular ES6 modules:
src/
├── engine/ # Core physics engine
│ ├── core.js # Game loop and world management
│ ├── math.js # Vector operations and utilities
│ ├── physics.js # Physics simulation
│ ├── spatialHash.js # Collision optimization
│ ├── entities.js # Entity factories
│ ├── render.js # Canvas rendering
│ ├── input.js # Input handling
│ └── plugins.js # Plugin system
├── ui/ # User interface
│ ├── panel.js # Control panel
│ ├── toolbar.js # Top toolbar
│ └── hud.js # Heads-up display
├── persistence/ # Scene save/load
│ └── storage.js
└── scenes/ # Example scenes
└── examples.js
- Target: 60 FPS with 500+ particles
- Spatial hash grid reduces collision checks from O(n²) to ~O(n)
- Fixed timestep ensures consistent physics
- Device pixel ratio awareness for crisp rendering
- Minimal per-frame allocations
Works in all modern browsers that support:
- HTML5 Canvas
- ES6 Modules
- requestAnimationFrame
- localStorage
Feel free to use, modify, and distribute this code for educational or personal projects.