<!-- tsParticles container -->
<div id="tsparticles"></div>
<canvas id="field"></canvas>
<!-- https://github.com/matteobruni/tsparticles -->
<div class="github">
<a class="btn btn-link" href="https://github.com/matteobruni/tsparticles" title="Find more info on GitHub">
<img class="img-fluid" id="gh-mark" src="https://cdn.matteobruni.it/images/particles/GitHub-Mark-120px-plus.png" alt="">
<span id="gh-project">Made with tsParticles</span>
</a>
<div>
<a class="github-button" href="https://github.com/matteobruni/tsparticles" data-icon="octicon-star" data-show-count="true" aria-label="Star matteobruni/tsparticles on GitHub">Star</a>
<a class="github-button" href="https://github.com/matteobruni/tsparticles/fork" data-icon="octicon-repo-forked" data-show-count="true" aria-label="Fork matteobruni/tsparticles on GitHub">Fork</a>
<a class="github-button" href="https://github.com/matteobruni/tsparticles/releases/tag/tsparticles%401.17.9" data-icon="octicon-download" aria-label="Download matteobruni/tsparticles on GitHub">Download</a>
</div>
</div>
<script async="" defer="" src="https://buttons.github.io/buttons.js"></script>
/* ---- reset ---- */
body {
margin: 0;
background: #000;
}
canvas {
display: block;
vertical-align: bottom;
}
/* ---- tsparticles container ---- */
#tsparticles {
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
z-index: 1;
}
#field {
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
z-index: 0;
}
.github {
bottom: 10px;
right: 10px;
position: fixed;
border-radius: 10px;
background: #fff;
padding: 0 12px 6px 12px;
border: 1px solid #000;
z-index: 1000;
}
.github a:hover,
.github a:link,
.github a:visited,
.github a:active {
color: #000;
text-decoration: none;
}
.github img {
height: 30px;
}
.github #gh-project {
font-size: 20px;
padding-left: 5px;
font-weight: bold;
vertical-align: bottom;
}
let noiseZ;
let size;
let columns;
let rows;
let w;
let h;
let field;
let canvasField = document.getElementById("field");
let ctxField = canvasField.getContext("2d");
function setup(container) {
size = 20;
noiseZ = 0;
reset(container);
window.addEventListener("resize", reset);
}
function initField() {
field = new Array(columns);
for (let x = 0; x < columns; x++) {
field[x] = new Array(columns);
for (let y = 0; y < rows; y++) {
field[x][y] = [0, 0];
}
}
}
function calculateField() {
for (let x = 0; x < columns; x++) {
for (let y = 0; y < rows; y++) {
let angle = noise.simplex3(x / 50, y / 50, noiseZ) * Math.PI * 2;
let length = noise.simplex3(x / 100 + 40000, y / 100 + 40000, noiseZ);
field[x][y][0] = angle;
field[x][y][1] = length;
}
}
}
function reset(container) {
const pxRatio = window.devicePixelRatio;
w = canvasField.offsetWidth * pxRatio;
h = canvasField.offsetHeight * pxRatio;
canvasField.width = w;
canvasField.height = h;
noise.seed(Math.random());
columns = Math.floor(w / size) + 1;
rows = Math.floor(h / size) + 1;
initField();
}
function drawField(ctx) {
ctx.clearRect(0, 0, canvasField.width, canvasField.height);
for (let x = 0; x < columns; x++) {
for (let y = 0; y < rows; y++) {
let angle = field[x][y][0];
let length = field[x][y][1];
ctx.save();
ctx.translate(x * size, y * size);
ctx.rotate(angle);
ctx.strokeStyle = `hsla(${(angle * 180) / Math.PI}, 100%, 50%, 1)`;
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(0, size * length);
ctx.stroke();
ctx.restore();
}
}
}
tsParticles
.load("tsparticles", {
fpsLimit: 120,
particles: {
number: {
value: 200,
density: {
enable: true,
value_area: 800
}
},
color: {
value: ["#5bc0eb", "#fde74c", "#9bc53d", "#e55934", "#fa7921"]
},
shape: {
type: "circle"
},
opacity: {
value: 0.7,
random: {
enable: true,
minimumValue: 0.2
},
animation: {
enable: true,
speed: 1,
minimumValue: 0.2
}
},
size: {
value: 7,
random: {
enable: true,
minimumValue: 3
},
animation: {
enable: true,
speed: 5,
minimumValue: 3
}
},
line_linked: {
enable: false,
distance: 150,
color: "#ffffff",
opacity: 0.4,
width: 1
},
move: {
enable: true,
speed: 5,
direction: "none",
random: false,
straight: false,
outMode: "out",
bounce: false,
warp: true,
noise: {
enable: true,
delay: {
value: 0.01
}
},
trail: {
enable: false,
color: {
value: "#000"
},
length: 30
}
}
},
interactivity: {
detect_on: "canvas",
events: {
resize: true
}
},
detectRetina: true,
pauseOnBlur: true
})
.then((container) => {
container.setNoise({
init: function () {
setup(container);
},
update: function () {
calculateField();
noiseZ += 0.005;
drawField(ctxField);
},
generate: function (p) {
const pos = p.getPosition();
const px = Math.max(Math.floor(pos.x / size), 0);
const py = Math.max(Math.floor(pos.y / size), 0);
if (!field || !field[px] || !field[px][py]) {
return { angle: 0, length: 0 };
}
return {
angle: field[px][py][0],
length: field[px][py][1]
};
}
});
container.refresh();
});