BrianHicks / elm-particle / Particle.System


type System a

Hold and simulate all your particles at once! This is a whole lot easier than managing all the subscriptions and emitters yourself.

init : Random.Seed -> System a

Get a System given a seed. So, why do I need that? Well, it's much nicer to generate random particles if we can do it synchronously, so I keep track of a seed so we can do everything in one call to your update! If you don't really care about the seed, you can initialize it like this:

init (Random.initialSeed 0)

If you want one that's actually pseudo-random, get a random seed with the Random.independentSeed generator or pass the current time in when you initialize your app from JavaScript.

hasParticles : System a -> Basics.Bool

Are there any living particles in the system? Useful for conditionally showing or hiding the view, or letting effects finish gracefully before moving on to the next part of your app.

Gimme some particles!

burst : Random.Generator (List (Particle a)) -> System a -> System a

Make a burst of a bunch of particles at once! Use this for things like confetti or fireworks. We use randomness here because 100 particles all doing exactly the same thing tends to be uninteresting.

If you haven't used the Random library before, check the docs at the top of Particle.

We could make a burst of 50 confetti particles like this:

burst (Random.list 50 confettiParticles) system

Simulate Particles


type Msg a

Get me from sub and pass me to update!

update : Msg a -> System a -> System a

Update all the particles by one step. Use it in your update function whenever you get a Msg. Probably like this:

update msg model.system

view : (Particle a -> Svg msg) -> List (Html.Attribute msg) -> System a -> Html msg

View all the particles in the system. You'll need to provide a rendering function for each particle—the same one you'd give to Particle.view—as well as a list of attributes on the SVG element itself.

For example, if you wanted a full-screen particle display, it would look like this:

view viewConfetti
    [ Html.Attributes.style "width" "100%"
    , Html.Attributes.style "height" "100vh"
    ]
    system

viewHtml : (Particle a -> Html msg) -> List (Html.Attribute msg) -> System a -> Html msg

Do the same thing as view but render HTML instead of SVG.

viewCustom : (Particle a -> renderedParticle) -> (List renderedParticle -> wrapper) -> System a -> wrapper

Do the same thing as view but render your own custom wrapper type instead of SVG. You will want this if you are using something like Html.Styled or TypedSvg, for example.

If you use this we do not know how to position the particle. Please use Particle.leftPixels and Particle.topPixels to do that yourself.

sub : List (Basics.Float -> Random.Generator (List (Particle a))) -> (Msg a -> msg) -> System a -> Platform.Sub.Sub msg

Subscribe to the right events in the browser. In this case, that's requestAnimationFrame deltas. You don't have to worry about how to hook up the right functions, just stick this in the subscriptions of your app and call update with the Msg you get.

The first parameter here is a list of emitters. These are different than bursts in that they continuously spout particles. This can create particle effects like water or fire. They live in the subscription so that we can manage our subscriptions intelligently. It also means that you don't have to store generators—which contain functions—in your model. So maybe you want to turn a stream of water on and off, or control the pressure? That's great! You can store those parameters in your model, and use them to make your generators.

Each emitter gets the time since the last frame in milliseconds so that it can calculate how many particles to emit. So, for example, a water emitter that emitted 60 drops per second may look like this:

waterEmitter : Float -> Generator (List (Particle Droplet))
waterEmitter delta =
    Random.list (ceiling (delta * (60 / 1000))) dropletGenerator

Then you'd use this in your subscription like this:

sub [ waterEmitter ] ParticleMsg model.system

If this doesn't make sense, go read the Water.elm example, which ties all of this together.