Hyper Flow pixels are fine points, not large retro blocks. Every built-in field returns normalized 3D coordinates. The renderer transforms, projects and depth-sorts them before painting one of ten Canvas 2D shapes.
Built-in fields
| Mode | Character |
|---|---|
pulse |
A breathing spherical point cloud |
orbit |
Four independently tilted trajectories |
orb |
Layered orbital shells made for fine line particles |
wave |
A rippling spherical surface |
helix |
Three interlaced strands |
vortex |
A rotating spiral search field |
constellation |
A sparse linked thought map |
scatter |
A cloud that breaks and reforms |
lattice |
A rotating volumetric point grid |
ribbon |
Seven parametric strands moving as one surface |
tunnel |
Rings traveling through perspective depth |
stream |
Parallel animated signal lines |
torus |
A rotating ring volume with layered bands |
rose |
A parametric field of layered petals |
swarm |
An organic coordinated point cloud |
grid-wave |
A spatial grid displaced by travelling waves |
burst |
Radial signals travelling from the center |
infinity |
Several strands woven into a continuous loop |
import { createParticleFlow } from "@scorpion7slayer/hyper-flow";
const field = createParticleFlow("#field", {
mode: "orb",
density: 1.8,
speed: 0.65,
size: 0.8,
radius: 0.39,
depth: 1,
perspective: 3.2,
shape: "line",
lineLength: 5.4,
lineWidth: 0.65,
viewport: { padding: 0.1, clip: true },
colors: ["#101c31", "#2454d4", "#0c3699"],
opacity: [0.2, 0.96],
rotation: { x: -0.18, y: 0, z: 0 },
interaction: { mode: "rotate", strength: 0.42 },
});Choose a particle primitive
The default renderer supports circles, squares, diamonds, triangles, lines, crosses, rings, dashes, stars and configurable polygons. size scales every point without changing field density.
field.update({
shape: "polygon",
size: 0.8,
density: 1.6,
shapeOptions: {
sides: 7,
fill: false,
strokeWidth: 0.7,
rotation: Math.PI / 7,
aspect: 0.72,
},
});
field.update({
shape: "line",
lineLength: 7,
lineWidth: 0.55,
});The DPR is capped at 2 by default. Set pixelRatio to a number when a capture or display needs an explicit value.
Constrain the drawing viewport
Use fractional viewport padding to keep perspective projection and custom rendering inside a demo, card or product surface.
field.update({
viewport: {
padding: 0.12,
clip: true,
},
});clip: true also confines beforeRender, renderer and afterRender drawing to the padded rectangle.
Add trails and compositing
trail controls how much of the previous frame remains. 0 clears every frame and 0.98 approaches a persistent trace. Combine it with any Canvas 2D blendMode.
field.update({
mode: "ribbon",
shape: "line",
trail: 0.82,
blendMode: "lighter",
});Keep trails below 0.9 for interfaces where the field must settle quickly after pointer input.
Configure connections
connections: "auto" preserves the default links for constellation, lattice and grid-wave fields. Set false to remove them, true for standard links on any topology, or pass exact values:
field.update({
connections: {
distance: 0.14,
opacity: 0.16,
width: 0.55,
color: "#2454d4",
maxPoints: 320,
},
});Change pointer behavior
The pointer can rotate the whole field, repel nearby points or attract them. smoothing controls how quickly the force catches up with the pointer.
field.update({
interaction: {
mode: "repel",
strength: 0.34,
radius: 1.15,
smoothing: 0.08,
},
});Pass interaction: false for a purely ambient field.
Compose the field inside the canvas
Use origin to move the projection center, scale to stretch individual axes and jitter to add controlled organic displacement.
field.update({
origin: { x: 0.7, y: 0.48 },
scale: { x: 1.25, y: 0.72, z: 1 },
jitter: 0.018,
});Use parameters to change time and spatial behavior across built-in and custom fields. The standard keys are frequency, phase, amplitude, spread, and twist. Any additional numeric key is passed to custom field functions unchanged.
field.update({
speed: -0.7,
parameters: {
frequency: 1.4,
amplitude: 0.72,
twist: -0.5,
customNoise: 0.18,
},
});Write a field function
mode accepts a function. It runs once per point and per frame:
createParticleFlow("#field", {
parameters: { curl: 1.4 },
mode: ({ index, count, time, parameters }) => {
const progress = index / count;
const angle = progress * Math.PI * 12 + time * (parameters?.curl ?? 1);
return {
x: Math.cos(angle) * progress,
y: progress * 2 - 1,
z: Math.sin(angle) * progress,
color: index % 3,
size: 0.8 + progress,
opacity: 1 - progress * 0.35,
};
},
});Transform a built-in field
Use one transform or an array when the built-in topology is useful but its geometry needs local rules. Returning false culls the point for that frame.
import { createParticleFlow, particleTransforms } from "@scorpion7slayer/hyper-flow";
createParticleFlow("#field", {
mode: "wave",
transform: [
particleTransforms.twist(0.4),
particleTransforms.ripple(0.05, 7),
({ opacity = 1 }) => opacity < 0.25 ? false : undefined,
],
});Replace point painting
Use renderer(context, point, frame) to replace the built-in painter. Projected screenX, screenY, renderSize, and resolved colorValue values are included on point. Canvas state such as globalAlpha already reflects depth and point opacity.
Use beforeRender(frame) and afterRender(frame) to paint a background grid, mask or foreground treatment inside the same clipped frame. Pass null through update() to remove a transform, renderer or hook.
See Customization recipes for complete orb, ribbon, connection and renderer examples.
Performance and accessibility
- Automatic density scales with the shorter canvas side and defaults to a 1,200 point maximum.
particlescan set an exact count or a custom range up to 4,000. - The DPR defaults to the device value, capped at 2.
ResizeObserverkeeps the backing buffer aligned with CSS size.IntersectionObserverand page visibility pause offscreen work.reducedMotion: "respect"renders a stable frame instead of a continuous loop.destroy()removes observers, pointer listeners and the animation frame.
Set autoPause: false or reducedMotion: "ignore" only when the application has a specific reason.
Stepped DOM motion
The earlier CSS-style pixel timing remains available for DOM targets through flow():
flow(".sprite", {
from: { x: -31, opacity: 0 },
to: { x: 0, opacity: 1 },
duration: 560,
pixel: { steps: 7, snap: 4 },
});This DOM option changes easing and transform snapping. It is separate from the Canvas particle engine.