pylinka
Menu

Pylinka

A node-based particle system for PixiJS that runs on the GPU. You wire a typed graph, it compiles to WGSL or GLSL, and particle state stays in GPU memory for as long as the effect plays. WebGPU first, WebGL2 everywhere else.

What you get

Particles never round-trip to the CPU while an effect is running. Each system costs one emit pass, one update pass and one instanced draw per frame, whatever the particle count.

Every unconnected number in the graph becomes a GPU uniform, so dragging a value updates the running effect on the next frame with no recompile. Give a value a name and your game can drive it at runtime as a knob. Only structural edits, adding a node or swapping an ease, rebuild the pipeline.

The backend follows the host. A PixiJS WebGL app gets the WebGL2 simulation inside the same GL context, a WebGPU app shares the device, and either way the particles interleave correctly with the rest of your scene: behind the symbols, above the background.

A trail in a few lines

Attach the system to a static VFX layer and let a moving target drive the emitter:

import { createPylinka } from '@pylinka/core';
import project from './coin-spark-trail.pylinka.json';

const pylinka = await createPylinka(project, { renderer });
vfxLayer.addChild(pylinka.systems.sparks.view);

// follow a flying coin: the sparks hang and fade in world space
pylinka.systems.sparks.follow(coinSprite);

// live knob, no recompile
pylinka.params.set('windPower', 40);

app.ticker.add((t) => pylinka.update(t.deltaMS / 1000));

Things that push back

Particles can react to the world around them. field.obstacle is a body moving through the field, with a soft push, a swirl and a drag term that produces a bow wave in front and a wake behind. Bind its centre to a knob and a cursor or a flying sprite drives it live. The output.collide* nodes give you floors, walls, boxes and discs with bounce and friction.

Play with both in the standalone interaction lab, or read how they work in Core concepts.

Scope

Pylinka is 2D. Simulation state is vec2 and there is no vec3. It compiles particle graphs and nothing else, so you get analytic force fields and simple solid bounds rather than a real physics solver. For anything heavier, run your own solver and feed Pylinka the positions.

Start with Getting started, then skim Core concepts. The node reference lists everything you can wire.