It's all Canvas 2D at the moment. There's no WebGL because when I started this project, three or four years back, it simply wasn't ubiquitous enough. Now I might be able to get away with WebGL (using something like Pixi.js) but the last couple of weeks I really just wanted to finish what I started rather than do a relatively substantial rewrite.
Another quirk is that I'm not using (think Phaser.js, or whatever), because the two main motivations for starting this project were that:
1. I wanted to get better at JavaScript, which I'd always been weak at.
2. I guess 2015/16 was a time when the front-end world felt like it was really going nuts with new frameworks coming out all the time, so I wanted to become familiar with and see what I could do using only APIs built directly into the browser.
Getting back to the point, in terms of effects I've implemented services to keep track of and render lists of particles and "clouds" of vapour. The latter are the translucent circles you see used to render rocket exhaust, and some of the explosion effects.
In fact I just use one service for both and swap in a different renderer for particles or vapours in each service instance, since both behave substantially the same.
Since we're throwing around hundreds or thousands of particles/vapours at a time, and, well, a lot of particles throughout the duration of a single game, and we want to avoid much garbage collection to keep the frame rate steady[1], I implemented an object pool so we're not constantly creating loads of garbage.
Particle types are defined declaratively: colour stops (including transparency), duration, expansion rate for vapours. Instances of particles also have properties like position and velocity.
Explosions are also defined declaratively with an arbitrary number of stops/events at timed intervals which define number and type of particles spawned, angular range through which they should be spawned, initial spread, velocity spread, any sound effect(s) to be played at each stop.
There's a service that manages explosions that you tell call with something like:
This will create an explosion of type "playerExplosion" at the player's position and apply the player's velocity as a drift to all particles and vapours created.
So once I've defined my explosion types it's easy to use them in a variety of different scenarios throughout the game without cluttering the logic too much. The services take care of rendering and particle management so these days I don't have to worry about it too much.
Hopefully that goes some way to answering your question but if you'd like to know anything else, please shout.
[1] GC screwing the frame rate is a genuine issue I ran into with this, particularly on mobile devices.