Run and edit 20 JavaScript animations - galaxy particles, matrix rain, three.js bloom, CSS 3D. Change the code, see it instantly, download the HTML.
This is a code sandbox, not a gallery of finished videos. Every animation on the page is real source you can read, edit and re-run in place. You get three editable panes — HTML, CSS and JavaScript — a live preview that reloads as you type, a console that catches your errors with corrected line numbers, a set of sliders wired into whatever demo is loaded, and an Explain tab that describes how that particular effect works. Then you can save a PNG, record a video, or download the whole thing as one standalone HTML file.
It all runs in your browser. Your code is never sent anywhere, there is no build step, and there is no account.
Forty demos, grouped by the rendering technique they use, because the technique is usually what you came to learn:
| Technique | Demos | What you learn from them |
|---|---|---|
| Canvas 2D | 19 | Frame loops, particle systems, trails, Verlet physics, pixel readback |
| WebGL | 10 | Raw GLSL fragment shaders — the whole image as one per-pixel function |
| three.js | 5 | Scene graph, materials, post-processing, instanced geometry |
| CSS / DOM | 6 | Transforms, keyframes and 3D effects with no canvas at all |
They range from the recognisable — Matrix rain, a hyperspace starfield, fireworks, confetti, Conway's Game of Life, a double pendulum, a Mandelbrot explorer — to the more instructive: boids flocking, a flow field, falling sand, an L‑system, Verlet cloth you can grab and drag, a sorting visualiser, plasma and caustics and Voronoi shaders, and text that rasterises into particles and reassembles.
Each demo carries a cost label so you can pick sensibly on a laptop: 17 are light, 18 medium and 5 heavy. The heavy ones are mostly the three.js and multi-pass shader scenes; the light ones will run happily on a phone.
Switch between HTML, CSS and JS with the tabs above the editor. The editor has syntax highlighting, Tab inserts two spaces rather than moving focus, and the highlight layer scroll-syncs with the text you are typing.
Auto-run is on by default, so the preview rebuilds shortly after you stop typing. That is convenient for small edits and annoying when you are halfway through writing a function that will throw — uncheck it and drive the preview with the Run button or Ctrl/Cmd + Enter instead. Reset discards your edits and restores the demo's original source. A small "edited" marker in the preview title bar tells you when you have diverged from the shipped version.
Under the preview, the console panel captures console.log, info, warn and error from your code, plus uncaught exceptions and unhandled promise rejections. Error messages carry a line number that has been corrected back to your JS pane — the composed document has a preamble above your code, and the raw browser line number would be offset by it. The message stream is capped so a runaway loop logging every frame cannot lock the page up.
Most demos ship with a controls panel: sliders, toggles, colour pickers and dropdowns specific to that effect. These are not a separate system bolted on top — each control writes a named property into a window.params object that the demo's own code reads every frame. You can see the merge at the top of every demo's JavaScript:
const params = window.params = Object.assign({ speed: 0.5, hue: 140 }, window.params);
Two consequences that matter in practice. First, moving a slider patches the same object the running animation already closed over, so the change lands on the very next frame without restarting the animation — you can steer a simulation while it runs rather than watching it start over. Second, because the defaults are merged in, a demo copied out of this page into a blank file still works with no playground around it: window.params is simply absent and the defaults win.
Some values cannot be patched live — a particle count or an arm count that gets baked into a preallocated array at startup. Those controls are marked internally as rebuild controls, and moving one restarts the preview instead of patching it. That is why some sliders feel instantaneous and others blink.
A shared window.panZoom(canvas, params) helper adds opt-in drag-to-pan and wheel-to-zoom to demos that want it. It is opt-in behind a toggle on purpose: a canvas that swallows wheel events would break the page's own scrolling. It writes zoom, panX and panY into the params bag and the demo applies them itself, so the transform stays visible in the code you are reading rather than hidden inside a framework.
Every one of the 40 demos has a written explanation of the specific technique it demonstrates — not general commentary, but the one idea that makes the effect work and the mistake people usually make instead. Examples of what is in there: why the Matrix rain trail is a translucent wipe rather than a stored history of positions; why Verlet integration stores two positions instead of position-and-velocity, and why that makes constraints trivial; why perspective projection reduces to a single division by depth; how text particles come from reading back the alpha channel of an offscreen render, which is why the effect works with any font and any language.
This is the difference between this and a collection of CodePen embeds. The code, the running result and the explanation of the trick are in one place, and you can break the code to see what the explanation was talking about.
Your code runs inside an iframe created with sandbox="allow-scripts" and no allow-same-origin. That combination puts the document on an opaque origin, which means it cannot read this page's DOM, cookies or storage, and cannot make same-origin requests back to the site. It is genuinely isolated, which is the reason arbitrary editing is safe to offer at all.
The isolation has two visible consequences you will hit if you push on the tool:
three and three/addons/ at a pinned jsDelivr build, so import * as THREE from 'three' works inside a demo. Other bare imports will not resolve — use a full URL to a CORS-enabled ES module host.<canvas> — ask a CSS/DOM demo for a PNG and you get an explicit message saying there is no canvas to capture, rather than a blank file.| Action | Result | Notes |
|---|---|---|
| Save PNG | Single frame as .png | Canvas demos only; sized to the preview |
| Record | Animation as .webm | VP9 or VP8, no audio; canvas demos only |
| Download | Standalone .html | Your HTML, CSS, JS, current slider values and the import map, in one file |
| Copy | Current pane to clipboard | Whichever of HTML/CSS/JS is showing |
| Share | URL with your code in the fragment | Base64-encoded panes; opening the link restores them |
| Fullscreen | Preview fills the screen | The canvas resizes with it — do this before recording for a larger frame |
The downloaded HTML is a complete, working document: open it from your desktop and it runs. It carries the pan/zoom helper and your current control values baked in, so what you saved behaves like what you were looking at, minus the console bridge, which would have nothing to talk to. It does not vendor three.js — the import map still points at the CDN, so a three.js demo saved this way needs a network connection to run.
There is no GIF export and no project saving. Nothing persists after you close the tab, so use Download or Share on anything you want to keep.
ResizeObserver rather than a window resize listener. That matters if you lift the code: a window listener never fires when a container resizes, and it also does not fire the first time, so the canvas can be measured at zero width before layout settles.prefers-reduced-motion and ship a static frame as the fallback.Several of the demos have their own landing pages, which open this same editor directly on that effect: the Matrix Rain Generator, Spirograph Generator, Mandelbrot Explorer, Game of Life Simulator, Sorting Algorithm Visualizer, Double Pendulum Simulator and Voronoi Diagram Generator. If you want one specific effect, start there; if you want to browse the technique, start here, where the full gallery sits above the editor.
| Technique | Best at | Falls over when | Demos here |
|---|---|---|---|
| CSS keyframes / transitions | UI motion, hover states, anything the compositor can handle without JavaScript | You need per-particle logic or physics | Neon 3D Cube, Bouncy Clock, Folding Panel, Acid Glass |
| Canvas 2D | A few thousand independent shapes, trails, cellular automata, text rasterisation | Element counts pass roughly 10,000 per frame | Galaxy Spiral, Matrix Rain, Fireworks, Falling Sand, Character Cloth |
| Raw WebGL | Per-pixel effects where the whole image is a function of position and time | You want objects, cameras and lights rather than pixels | Plasma Shader |
| three.js | Scenes with tens of thousands of points, real 3D cameras, post-processing | A 600 KB dependency is too much for the payoff | three.js Galaxy, Particle Sphere, Holographic Card, Bloom Torus Knot, Shape Morph |
A useful rule: if the thing you are animating already exists as a DOM element and there are fewer than about fifty of them, use CSS. If you are drawing thousands of things that do not need to be clickable, use canvas. If every pixel needs its own calculation, use a shader.
1. The translucent wipe. Painting rgba(0,0,0,0.08) over the canvas instead of clearing it makes every previous frame decay. That single line is the entire trail effect in Matrix Rain, Flow Field and Spirograph Trails. Lower alpha means a longer trail.
2. Additive blending. Setting ctx.globalCompositeOperation = 'lighter' (or THREE.AdditiveBlending) makes overlapping particles sum their brightness instead of covering each other. It is why particle clouds glow at the centre without any lighting calculation.
3. Randomness raised to a power. Math.pow(Math.random(), 3) is still between 0 and 1, but heavily biased toward 0. Multiply it by a spread and you get scatter that clusters tightly near the origin with rare far outliers - which is what makes galaxy arms look like arms rather than a smear. That randomnessPower constant appears in both galaxy demos.
4. Verlet integration. Store a point's previous position instead of its velocity. Velocity is then just current - previous, and you enforce constraints by moving points directly, with the physics correcting itself on the next frame. Character Cloth and Cursor Creature are the same twenty lines with different constraints.
5. Time as the only input. In the Plasma Shader nothing is stored between frames at all: the colour of every pixel is computed from its coordinates and the clock. That statelessness is why shaders parallelise perfectly across thousands of GPU cores, and why the same technique scales to full-screen 4K where a canvas loop would not.
No. The editor and the preview both run entirely in your browser. Your code is executed inside a sandboxed iframe on an opaque origin, which means it cannot read this page, your cookies, or your storage - and it is never transmitted to a server. The Share button encodes the code into the URL itself rather than saving it anywhere.
Yes. Every demo is plain HTML, CSS and JavaScript with no license strings attached - use them, edit them, ship them. Click Download .html to get a single self-contained file that runs by double-clicking it. The three.js demos additionally load three.js from a CDN, which is MIT licensed.
No. The preview declares an import map that resolves the bare specifier three to a CDN copy, which is why the demos can write import * as THREE from 'three' with no bundler. If you download a demo, the same import map ships inside the file, so it keeps working offline-free from disk as long as you have a network connection.
Almost always one of three things: a JavaScript error (open the Console panel - errors show there with a line number), a WebGL context that could not be created (check that hardware acceleration is on in your browser), or an animation that draws off-screen after you changed a coordinate. Hit Reset to restore the original demo and work forward from there.
Canvas 2D gives you an immediate-mode drawing API - you clear and repaint every frame on the CPU, which is simple and flexible up to a few thousand shapes. WebGL runs your code on the GPU as shaders, so it scales to millions of pixels or points but requires writing GLSL. CSS animation is declarative: you describe the start and end state and the browser interpolates on the compositor thread, which is the cheapest option for UI motion but cannot express per-particle logic.
A canvas backing store scales with the square of the pixel ratio. On a 3x display an uncapped canvas renders nine times the pixels of a 1x one, which usually halves the frame rate for no perceptible gain on a particle field or a blurred glow. Capping at 2 is the standard compromise - text and thin lines still look sharp, but fill rate stays affordable.
Do not clear the canvas. Instead of clearRect, paint a translucent rectangle over the whole surface each frame - for example ctx.fillStyle = 'rgba(0,0,0,0.08)' followed by fillRect. Old pixels get darker every frame instead of vanishing, which reads as a fading trail. The alpha value controls the trail length: lower means longer. Matrix Rain, Flow Field and Spirograph Trails in this gallery all use exactly that trick.
Not automatically. requestAnimationFrame fires at the display refresh rate, so a fixed per-frame increment runs 1.7x faster on a 165 Hz monitor than a 60 Hz one. The three.js demos avoid this by multiplying motion by the clock delta. If you write your own, take a delta from performance.now() and scale by it rather than assuming 16.7 ms per frame.
Explore the Mandelbrot set in your browser - zoom, pan, tune iterations, switch to Julia sets, and save a PNG.
Draw spirograph and harmonograph figures in your browser. Adjust the frequency ratio, radii and damping, then save a PNG.
Generate the Matrix digital rain effect in your browser. Tune speed, glyphs, colour and trail length, then export a PNG, video or standalone HTML file.