Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

recstudio-particles

A tiny, MIT-licensed starter for GPGPU particle scenes in the browser — the kind of interactive particle work you see on Awwwards sites. 65,536 particles simulated entirely on the GPU, drifting on divergence-free curl noise, stirred by your pointer, and springing into any word or any silhouette PNG you hand it.

No build step. No dependencies to install. Clone it, serve the folder, open the page.

The particle field

Drift, then a word, then a shape


Quick start

git clone https://github.com/odedbahiri-arch/recstudio-particles.git
cd recstudio-particles && npx serve .

Then open the URL it prints (usually http://localhost:3000).

Any static server works — python -m http.server, the VS Code Live Server extension, whatever you already use. It does need to be a server: the demo is ES modules, so opening index.html from the filesystem will not work.

Controls: move the pointer to stir · hold the mouse for a shove · 1 drift · 2 word · 3 shape · space autoplay on/off


Make it yours with Claude Code

The whole kit is steered by one CONFIG object at the top of index.html. That is deliberate — it means you can point Claude Code at it and describe what you want in a sentence. Copy any of these:

1 — install and run it

Clone https://github.com/odedbahiri-arch/recstudio-particles into this folder, start a static server in the repo root, open the page in my browser, and tell me if there are any console errors. It is a no-build ES-module project — do not add a bundler, a package.json, or npm dependencies.

2 — your word, your colour

In index.html, set CONFIG.morph.text to AURORA and change CONFIG.colors.fast to my brand colour #7cf2c8, keeping colors.slow dark and cool so the contrast still reads. Then reload and screenshot the "word" mode (press 2) so I can see it.

3 — your shape, your mood

Put my-logo.png in shapes/, point CONFIG.morph.image at it, and make the whole scene calmer: raise CONFIG.motion.damping, lower CONFIG.motion.noiseStrength, and soften CONFIG.pointer.strength and CONFIG.pointer.swirl. If the shape comes out inside-out, flip CONFIG.morph.imageInvert.

For a wilder scene, invert prompt 3: lower damping, raise noise strength and pointer swirl.


The config surface

Everything below lives in index.html. These are the knobs worth knowing:

Key Does
particles.textureSize Particle count is this squared. 128 → 16,384, 192 → 36,864, 256 → 65,536.
particles.size / .opacity Sprite size and brightness. Particles are additive, so opacity stacks into glow.
colors.slow / .fast The colour ramp. Slow particles get slow, fast ones (and particles held in a shape) get fast.
colors.accent / .accentRatio A sparse second colour. Past ~0.02 it reads as confetti.
field.shellRadius / .shell The spheroid the drifting cloud is kept inside, and how firmly.
field.flatten / .spin Squash the cloud into a disc; turn it slowly.
motion.noiseScale / .noiseSpeed / .noiseStrength The curl-noise drift: eddy size, how fast the field evolves, how hard it pushes.
motion.damping Drag while drifting. Low = long smooth streaks, high = calm.
pointer.radius / .strength / .swirl Reach, push, and stir of the pointer. swirl is what makes it feel liquid.
morph.text / .font The word. Hebrew, Arabic and CJK all work — the text is drawn to a canvas, so whatever your OS can render, the particles can form.
morph.image / .imageInvert Path to a silhouette PNG. Transparent PNGs use the alpha channel; fully opaque images fall back to brightness, so a black shape on white also works.
morph.spring / .damping How eagerly particles snap to their target, and how hard they are braked once there. Roughly damping ≈ 2 × √spring is crisp; much less and the letters blur.
timeline.steps The autoplay loop. Reorder, retime, or set autoplay: false.

How it works

Four ideas, and that is the whole kit:

  1. State lives in textures. Each particle owns one pixel of a floating-point texture: xyz is its position, another texture holds xyz velocity plus a per-particle random seed. 65,536 particles is a 256×256 texture.
  2. Ping-pong. Each frame renders a fullscreen quad that reads the current state texture and writes the next one, then swaps the two. The CPU never touches a particle. (src/simulation.js)
  3. Forces. The velocity shader adds curl drift, a spring toward the morph target, soft containment, and the pointer force, then applies drag. (src/shaders.js) The drift uses bitangent noise — the cross product of two noise gradients, which is divergence-free, meaning the flow has no sources or sinks and particles swirl forever instead of piling up.
  4. Targets are just pixels. A word is drawn to an offscreen 2D canvas; a PNG is drawn to one too. Either way the opaque pixels are scattered across the particles as target positions. Anything you can draw to a canvas can be a shape. (src/targets.js)
index.html          the demo page + the CONFIG object (start here)
src/main.js         scene, camera, input, render loop
src/simulation.js   the ping-pong GPGPU simulation
src/shaders.js      all the GLSL
src/targets.js      text and PNG → particle target positions
src/vendor/         three.js r185 and atyuwen's bitangent noise, both MIT
shapes/             sample silhouettes — drop your own PNG here

Requirements and performance

  • WebGL2 with EXT_color_buffer_float (every current desktop and mobile browser). The page tells you plainly if the GPU cannot do it instead of failing silently.
  • Measured here: 65,536 particles at 170 fps, 1440×900, Chrome, RTX 4070 Super. The simulation cost is per-particle, so if a weaker machine struggles, drop textureSize to 192 or 128 — 16,384 particles still looks good.
  • Zero console errors, zero network requests after load — three.js is vendored in the repo.

Credits

Built with Claude Code by RecStudio.

MIT licensed. Use it in client work, ship it, sell it — no attribution required (though it is always nice).

About

A tiny MIT-licensed GPGPU particle starter for the browser: curl-noise drift, pointer forces, and morph-to-any-word-or-PNG. No build step.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages