Show HN: Making a Falling Sand Simulator

This page summarizes the projects mentioned and recommended in the original post on

Our great sponsors
  • Appwrite - The Open Source Firebase alternative introduces iOS support
  • SonarLint - Clean code begins in your IDE with SonarLint
  • Scout APM - Less time debugging, more time building
  • falling-turnip

    falling sand game with regular parallel arrays.

    If you want more performance, falling sand simulators can further be made parallel by implementing them using Margolus Neighbourhoods, as in Falling Turnip:

    The idea is that a single iteration divides the world into 2x2 squares and then applies effects sequentially within each square, but not between the squares. This means each square can be processed independently. In the next iteration, the division into squares shifts right and down by one cell each direction. This does mean you need more steps than in a sequential implementation, but I found it to be quite a principled approach to parallelizing cellular automata when I first read about it. One interesting side effect of this design is that falling particles end up being separated by blank space, as shown here: I wonder if that is fixable.

  • sand.js

    A falling sand game as a cellular automaton, powered by WebGL.

    Another way to do this (albeit without simple support for fluids) is to use the Moore neighborhood and use a left and right "bias" to decide which direction a grain should fall towards if it can't fall straight down. This works pretty well as a shader, and has the same side effect with the horizontal lines.

  • Appwrite

    Appwrite - The Open Source Firebase alternative introduces iOS support . Appwrite is an open source backend server that helps you build native iOS applications much faster with realtime APIs for authentication, databases, files storage, cloud functions and much more!

  • CAM6

    Cellular Automata Machine (CAM6) Simulator

    Typically a cellular automata simulation will have some edge condition like wrapping or mirroring an adjacent cell.

    A nice optimization trick is to make the cell buffers 2 cells wider and taller (or two times whatever the neighborhood radius is), and then before each generation you update the "gutter" by copying just the wrapped (or mirrored) pixels. Then your run the rule on the inset rectangle, and the code (in the inner loop) doesn't have to do bounds checking, and can assume there's a valid cell to read in all directions. That saves a hell of a lot of tests and branches in the inner loop.

    Also, the Margolus neighborhood can be defined in terms of the Moore neighborhood + vertical phase (even/odd row) + horizontal phase (even/odd column) + time phase (even/odd time). Then you can tell if you're at an even or odd step, and which of the four squares of the grid you're in, to know what to do.

    That's how the CAM6 worked in hardware: it used the x/y/time phases as additional bits of the index table lookup.

    Here's how my CAM6 emulator computes the Margolus lookup table index, based on the 9 Moore neighbors + phaseTime, phaseX, and phaseY:

                        function getTableIndexUnrotated(

NOTE: The number of mentions on this list indicates mentions on common posts plus user suggested alternatives. Hence, a higher number means a more popular project.

Suggest a related project

Related posts