|
All checks were successful
deploy / build-and-deploy (push) Successful in 31s
|
||
|---|---|---|
| .. | ||
| demo.html | ||
| particleNetwork.js | ||
| README.md | ||
particle-network
A canvas animation of drifting particles connected by proximity lines, with opacity modulated by a slowly-rolling fBm (fractal Brownian motion) noise field.
No external dependencies. Pure ES module.
Files
| File | Purpose |
|---|---|
particleNetwork.js |
The module — import this into your project |
demo.html |
Minimal working example (requires a local server for ES module import) |
Quick start
Serve the folder with any static server, e.g.:
npx serve .
# or
python3 -m http.server
Then open demo.html.
Integration
1. Minimal — full-page background
<canvas id="net"></canvas>
<script type="module">
import { ParticleNetwork } from './particleNetwork.js';
const canvas = document.getElementById('net');
// Size the canvas to the viewport yourself, or let the module
// read the parent element's bounding rect (default behaviour).
canvas.style.display = 'block';
canvas.style.width = '100%';
const net = new ParticleNetwork(canvas, null);
net.start();
</script>
2. With field preview (debug / design mode)
<canvas id="net"></canvas>
<canvas id="field"></canvas>
<script type="module">
import { ParticleNetwork } from './particleNetwork.js';
const net = new ParticleNetwork(
document.getElementById('net'),
document.getElementById('field'),
{ count: 60, dimAtMin: 0.5 }
);
net.start();
</script>
3. Bundler / framework
Copy particleNetwork.js anywhere in your src/ tree and import normally:
import { ParticleNetwork } from '@/lib/particleNetwork.js';
No build config changes needed — it uses only standard browser APIs.
Constructor
new ParticleNetwork(mainCanvas, fieldCanvas, options)
| Parameter | Type | Description |
|---|---|---|
mainCanvas |
HTMLCanvasElement |
The particle animation canvas |
fieldCanvas |
HTMLCanvasElement | null |
Optional debug field view |
options |
object |
See below |
Options
All options can be passed at construction time and updated at runtime via
setOption(key, value).
| Key | Default | Description |
|---|---|---|
count |
55 |
Number of particles |
reach |
140 |
Max connection distance in canvas px |
flowSpeed |
2 |
Field drift speed on a 1–10 scale. At 1, motion takes several minutes to traverse the field — clearly present but takes time to perceive. |
fieldScale |
4 |
Noise zoom on a 1–10 scale. Lower = larger rolling blobs. |
dimAtMin |
0.60 |
Opacity reduction at field minimum. 0 = field has no opacity effect. 1 = particles in troughs are fully invisible. |
particleSpeed |
0.35 |
Base particle velocity (px/frame) |
particleMinR |
1.4 |
Minimum particle radius (px) |
particleMaxR |
2.8 |
Maximum particle radius (px) |
fieldUpdateMs |
50 |
How often the noise field recalculates (ms). Lower = smoother but more CPU. |
fieldOctaves |
4 |
fBm octaves. More = finer detail, more CPU. |
bgColor |
'#040e1f' |
Canvas background colour |
lineColor |
'80,160,240' |
RGB string for particle–particle lines |
lineColorMouse |
'160,220,255' |
RGB string for mouse-proximity lines |
canvasAspect |
0.65 |
Canvas height = width × aspect |
timeConstantX |
0.00084 |
Primary axis time advance rate. Halve to slow further. |
timeConstantY |
0.0003145 |
Secondary axis rate — kept at a different ratio for the swirling character. |
Methods
net.start() // begin animation loop
net.stop() // pause (preserves state)
net.setOption(key, value) // update any option at runtime
net.sampleField(x, y) // returns [0,1] field value at canvas coords
net.destroy() // stop loop and remove all event listeners
How it works
Noise field — a 4-octave fBm Perlin noise function is evaluated on a tiny
80×52 offscreen canvas every 50ms, then scaled up via drawImage. This is
~100× cheaper than evaluating at display resolution.
Opacity mapping — each particle's field sample fv ∈ [0,1] maps to an
opacity multiplier via:
multiplier = (1 - dimAtMin) + dimAtMin * fv
At fv = 1 (field peak): multiplier = 1.0 — full brightness.
At fv = 0 (field trough): multiplier = 1 - dimAtMin.
For connecting lines the multiplier is the geometric mean of both endpoint values, so a line straddling a bright and dark zone stays dim.
Distance falloff — cubic: (1 - dist/reach)³, giving a sharp fade near
the connection threshold rather than a linear fade across the full range.
Glow — each particle renders a createRadialGradient halo sized to
r × (2.5 + fieldValue × 1.5), so dots in bright field regions bloom larger.