pylinka
Menu

Core concepts

The handful of ideas behind every Pylinka effect.

Project → System → Graph

A project is the top-level document. It holds one or more systems, a set of project-wide knobs, and any texture assets. Each system is one particle system: a graph, an emitter, a pool capacity, and a blend mode.

A graph is a typed, acyclic dataflow of nodes joined by edges. Ports carry one of five types — f32, vec2, vec4, color, bool. A system is well-formed when it has exactly one output.spawnPosition and one output.initLife.

Values vs. structure

Every edit falls into one of two buckets, and this is what makes Pylinka feel instant:

Kind of editExampleCost
Valuedrag a number, change a color, move a knobone uniform write, next frame
Structureadd/remove a node or edge, change an easerecompile (~30 ms, debounced)

Unconnected input values are lowered to GPU uniforms, so scrubbing them never recompiles. Only changes to the shape of the generated code do.

Knobs

Any value can be promoted to a knob — a named control like windPower with a range and a linear or log scale. Knobs are shared across a project and driven at runtime:

pylinka.params.set('windPower', 40);   // fans out to every system using it

Promotion is free: the uniform slot already exists, so it never triggers a recompile.

World space & moving emitters

Particles live in the view's local space. The emitter position is consumed only at spawn, so moving the emitter changes where new particles are born while existing ones stay put — a coin flying across the board leaves sparks that hang and fade in place.

This is why you attach the view to a static layer and let the target drive the emitter via follow(). Reparenting the view onto a moving sprite transforms every live particle and defeats world-space simulation.

Emission

Emitters run in one of three modes:

  • flow — a steady rate (particles/second), optionally plus rateOverDistance (particles per pixel the emitter travels) for gap-free trails.
  • burst — a count every interval seconds.
  • once — a single burst on start.

Sub-frame spawn interpolation places particles along the emitter's path within a frame, so fast trails come out continuous rather than clumped.

Pools & lifetime

Each system pre-allocates a fixed capacity of particle slots. When a particle's age reaches its life it dies automatically — there is no kill node for end-of-life. If emission outruns capacity, new particles are dropped (an overflowCount ticks up); the editor warns when rate × maxLife exceeds capacity.

Determinism

Pylinka uses an integer-hash PRNG. Runs are bit-reproducible on the same device, driver, and fixed-step mode. Across different GPUs, float math diverges — expect statistical similarity, not identical trajectories. There are no cross-client sync guarantees.