particle field planning
All checks were successful
deploy / build-and-deploy (push) Successful in 31s
All checks were successful
deploy / build-and-deploy (push) Successful in 31s
This commit is contained in:
parent
ae60a7c856
commit
f4b8e1a7d8
5 changed files with 1685 additions and 0 deletions
138
reference/particle-field-demo/demo.html
Normal file
138
reference/particle-field-demo/demo.html
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
<!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>
|
||||
Loading…
Add table
Add a link
Reference in a new issue