jb-website/reference/particle-field-demo/demo.html
Josh Bairstow f4b8e1a7d8
All checks were successful
deploy / build-and-deploy (push) Successful in 31s
particle field planning
2026-07-23 23:14:04 +10:00

138 lines
3.6 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Particle Network — demo</title>
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body {
background: #040e1f;
color: #a0c4f0;
font-family: system-ui, sans-serif;
font-size: 13px;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 16px;
padding: 24px;
}
.canvases {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 8px;
width: 100%;
max-width: 960px;
}
.canvas-wrap {
position: relative;
border: 0.5px solid rgba(80, 140, 220, 0.25);
border-radius: 8px;
overflow: hidden;
}
canvas { display: block; width: 100%; }
.label {
position: absolute;
top: 10px; left: 12px;
font-size: 11px;
color: rgba(120, 180, 255, 0.45);
pointer-events: none;
}
.controls {
display: flex;
flex-wrap: wrap;
gap: 8px 20px;
align-items: center;
width: 100%;
max-width: 960px;
}
.controls label { color: rgba(160, 200, 255, 0.6); }
.controls input[type=range] { width: 100px; accent-color: #5090d0; }
.dim-row {
display: flex;
align-items: center;
gap: 10px;
width: 100%;
}
.dim-row input { flex: 1; max-width: 300px; }
.dim-row span { min-width: 36px; }
</style>
</head>
<body>
<div class="canvases">
<div class="canvas-wrap">
<canvas id="mainCanvas"></canvas>
<div class="label">particle network</div>
</div>
<div class="canvas-wrap">
<canvas id="fieldCanvas"></canvas>
<div class="label">noise field</div>
</div>
</div>
<div class="controls">
<label>nodes</label>
<input type="range" id="sCount" min="20" max="100" value="55" step="1">
<label>reach</label>
<input type="range" id="sReach" min="60" max="260" value="140" step="1">
<label>flow</label>
<input type="range" id="sSpeed" min="1" max="10" value="2" step="1">
<label>scale</label>
<input type="range" id="sScale" min="1" max="10" value="4" step="1">
<div class="dim-row">
<label>dim at minimum</label>
<input type="range" id="sDim" min="0" max="100" value="60" step="1">
<span id="sDimOut">60%</span>
</div>
</div>
<script type="module">
import { ParticleNetwork } from './particleNetwork.js';
const net = new ParticleNetwork(
document.getElementById('mainCanvas'),
document.getElementById('fieldCanvas'),
{ count: 55, reach: 140, flowSpeed: 2, fieldScale: 4, dimAtMin: 0.60 }
);
net.start();
// Wire up controls
document.getElementById('sCount').addEventListener('input', e =>
net.setOption('count', parseInt(e.target.value)));
document.getElementById('sReach').addEventListener('input', e =>
net.setOption('reach', parseInt(e.target.value)));
document.getElementById('sSpeed').addEventListener('input', e =>
net.setOption('flowSpeed', parseFloat(e.target.value)));
document.getElementById('sScale').addEventListener('input', e =>
net.setOption('fieldScale', parseFloat(e.target.value)));
const dimSlider = document.getElementById('sDim');
const dimOut = document.getElementById('sDimOut');
dimSlider.addEventListener('input', e => {
const v = parseInt(e.target.value);
dimOut.textContent = v + '%';
net.setOption('dimAtMin', v / 100);
});
</script>
</body>
</html>