A small browser based Sand Fall physics game
| acid.js | ||
| actions.js | ||
| config.js | ||
| dirt.js | ||
| explosive.js | ||
| fire.js | ||
| grass.js | ||
| ice.js | ||
| index.css | ||
| index.html | ||
| index.js | ||
| lava.js | ||
| oil.js | ||
| physics.js | ||
| plant.js | ||
| README.md | ||
| renderer.js | ||
| smoke.js | ||
| state.js | ||
| steam.js | ||
| ui.js | ||
| water.js | ||
Falling Sand Simulation 🧱✨
A high-performance, modular falling sand physics sandbox built in vanilla JavaScript and HTML5 Canvas. Experience realistic particulate physics, fluid dynamics, thermodynamics, combustion, and chemical reactions running at a silky-smooth 60+ FPS.
⚡ Performance & Engine Architecture
- Direct 32-Bit Pixel Blitter (
Uint32Array/ImageData): Replaces traditional Canvas 2DfillRect/arcdraw calls with direct memory writes into a 32-bit RGBA pixel buffer on an offscreen buffer canvas, delivering a 50x–100x rendering speedup that comfortably handles hundreds of thousands of active particles. - Rapid Fluid Dispersion: Liquids (water, acid, oil) dynamically disperse up to customizable multi-cell horizontal steps per frame, eliminating gelatinous stacking and delivering realistic splashing and surface leveling.
- Oil & Water Emulsion & Separation: Water and oil mix dynamically with diagonal and horizontal swapping before buoyantly separating out according to density.
- Lava & Rock Sinking: Dense molten lava plunges into water, boiling it into rising steam, and solidifies into stone that naturally sinks through liquid to the bottom of the pool.
- Monotonic Frame Counter & Alternating Sweep:
Eliminates the legacy full-grid
updated = falsepass. Cells tracklastUpdated = currentFrame. The simulation loop alternates horizontal scan direction (left-to-right vs. right-to-left) every frame to eliminate asymmetric pile-up bias in liquids and sand. - Zero-Allocation Hot Loop: All neighbor evaluations, directional offsets, and particle physics run with zero heap allocations or closures, preventing garbage collection pauses and stuttering.
- Bresenham Stroke Interpolation: Uses Bresenham's line algorithm between consecutive cursor samples to ensure smooth, gapless lines even when drawing at high speeds.
- Non-Destructive Canvas Resizing: Resizing the window or changing device orientation preserves existing particles on the canvas rather than wiping the simulation.
🧪 Element & Reaction Ecosystem
| Element | Category | Behavior & Unique Reactions |
|---|---|---|
| Sand | Solid | Granular physics; forms realistic dunes; sinks through liquids. |
| Dirt | Solid | Rich earthen soil; supports plant and grass roots; displaceable by explosions. |
| Rock | Solid | Heavy barrier; holds back blasts; naturally sinks through liquids to form riverbeds. |
| Wood | Solid | Rigid structural block; flammable when exposed to fire or lava. |
| Ice | Solid | Crystalline cold block; slowly freezes touching water; melts near heat/fire/lava. |
| Water | Liquid | Flows rapidly; mixes with and separates from oil; turns lava into rock; boils into steam. |
| Lava | Liquid | Heavy molten magma; plunges into water boiling it into steam; cools into solid rock. |
| Oil | Liquid | Viscous flammable liquid; mixes with water and then floats to the surface; catches fire intensely. |
| Acid | Liquid | Corrosive fluid; fast dispersion; sinks through lighter liquids; dissolves organics, metals, and earth. |
| Plant | Organics | Grows upwards towards light; absorbs water; turns into wood under vertical load. |
| Grass | Organics | Colonizes surface dirt and sand; sprouts blades; accelerates with moisture. |
| Fire | Gas / Energy | Dynamic temperature shading (yellow \rightarrow orange \rightarrow red); ignites flammables; spawns smoke. |
| Steam | Gas | Rises through atmosphere and liquids; escapes into the sky or condenses back into water. |
| Smoke | Gas | Produced by fires, explosions, and burning oil; drifts with air turbulence and dissipates. |
| TNT | Energetic | Detonates from fire, lava, or acid; clusters into unified blast waves launching particles kinetically. |
| Eraser | Tool | Clears cells within brush radius; also accessible via right-click drag. |
🎮 Controls & Shortcuts
| Action | Control |
|---|---|
| Draw Element | Left Click + Drag / Touch |
| Erase | Right Click + Drag or select Eraser |
| Brush Size | Mouse Wheel or [ / ] or Drawer Slider |
| Pause / Play | Spacebar or Pause button (⏸ / ▶) |
| Single Frame Step | S or . (Period) or Step button (⏭) |
| Clear Canvas | Clear button in Elements drawer |
⚙️ Configuration & Customization
All simulation and material parameters can be tuned in real time via the Settings ⚙️ drawer:
- Time & Global: Simulation speed (0–20), gravity (-1.0 to 2.0), air drag (0.1 to 1.0).
- Explosive: Blast force, blast reach, plus independent destruction toggles for Rock, Wood, Dirt, Sand, Plant, Grass, Water, Acid, Ice, Lava, and Oil.
- Acid: Dissolve rate, sink rate, spread speed, explode TNT toggle, plus independent dissolve toggles for Rock, Wood, Dirt, Sand, Plant, Grass, Water (infection), Ice, and Oil.
- Water: Flow rate and horizontal spread speed (dispersion).
- Lava: Flow rate, spread speed, cooling rate, and water sink rate.
- Oil: Flow rate, spread speed, burn rate, water sink rate, and oil float rate.
- Ice: Melt rate and freeze rate.
- Fire, Steam & Smoke: Fire decay rate, condensation rate, and smoke dissipation rate.
- Plant & Grass: Growth rate, woodification rate, and burn rate.
- Visuals: Switch between
blocky,fuzzy(filtered bloom), orblobyrendering, and toggle multi-tone grain color noise. - Settings are automatically saved to
localStorageand can be restored using Reset to Defaults.
📂 Project Structure
├── index.html # HTML5 entrypoint with drawers and canvas
├── index.css # Glassmorphic dark UI design and responsive styles
├── index.js # Main initialization loop, event loop, and input wiring
├── config.js # Config defaults, settings persistence, and schema
├── state.js # Grid buffers, canvas dimensions, brush, and frame counter
├── actions.js # Atomic grid operations (move, swap) with frame tagging
├── renderer.js # Fast 32-bit Uint32Array blitter with cursor overlay
├── physics.js # Simulation loop dispatcher and particle generation
├── dirt.js # Granular sand and soil physics with liquid displacement
├── water.js # Fast fluid dynamics, oil mixing/separation, and plant hydration
├── lava.js # Dense molten thermodynamics, water penetration, and rock formation
├── oil.js # Flammable buoyant liquid physics with water emulsion/separation
├── ice.js # Freezing and melting thermal logic
├── acid.js # Fast-spreading corrosive fluid, sinking, and dissolution physics
├── fire.js # Combustion, heat transfer, temperature decay, and smoke emission
├── steam.js # Atmospheric rising and condensation
├── smoke.js # Rising particulate dispersion and decay
├── plant.js # Root propagation, woodification, and phototropism
├── grass.js # Surface dirt colonization and blade growth
├── explosive.js # Clustered BFS blast waves and kinetic shockwaves
└── ui.js # Categorized elements palette, Bresenham strokes, and settings drawer
🚀 Getting Started
No build step or external dependencies are required. Simply serve the directory with any local static HTTP server:
# Using Python
python -m http.server 8080
# Using Node.js (npx)
npx serve .
Open http://localhost:8080 in any modern web browser.