Compare commits
18 Commits
3f99b8b62f
...
b3038644ad
Author | SHA1 | Date | |
---|---|---|---|
|
b3038644ad | ||
|
fb5a4675f8 | ||
|
fe51090807 | ||
|
24af3c33ac | ||
|
8d08d145c4 | ||
|
bf5321eec5 | ||
|
6b165f24da | ||
|
c0e4424257 | ||
|
89263b1495 | ||
|
e937b17e17 | ||
|
63971cb860 | ||
|
5b0d2d108a | ||
|
d9b18cdb9e | ||
|
1a519a1d55 | ||
|
e52855f954 | ||
|
507c5f6e38 | ||
|
b410e55915 | ||
|
bcfe64f427 |
81
.gitattributes
vendored
Normal file
81
.gitattributes
vendored
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
# Common settings that generally should always be used with your language specific settings
|
||||||
|
|
||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
# https://www.davidlaing.com/2012/09/19/customise-your-gitattributes-to-become-a-git-ninja/
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
#
|
||||||
|
# The above will handle all files NOT found below
|
||||||
|
#
|
||||||
|
|
||||||
|
# Documents
|
||||||
|
*.bibtex text diff=bibtex
|
||||||
|
*.doc diff=astextplain
|
||||||
|
*.DOC diff=astextplain
|
||||||
|
*.docx diff=astextplain
|
||||||
|
*.DOCX diff=astextplain
|
||||||
|
*.dot diff=astextplain
|
||||||
|
*.DOT diff=astextplain
|
||||||
|
*.pdf diff=astextplain
|
||||||
|
*.PDF diff=astextplain
|
||||||
|
*.rtf diff=astextplain
|
||||||
|
*.RTF diff=astextplain
|
||||||
|
*.md text
|
||||||
|
*.tex text diff=tex
|
||||||
|
*.adoc text
|
||||||
|
*.textile text
|
||||||
|
*.mustache text
|
||||||
|
*.csv text
|
||||||
|
*.tab text
|
||||||
|
*.tsv text
|
||||||
|
*.txt text
|
||||||
|
*.sql text
|
||||||
|
|
||||||
|
# Graphics
|
||||||
|
*.png binary
|
||||||
|
*.jpg binary
|
||||||
|
*.jpeg binary
|
||||||
|
*.gif binary
|
||||||
|
*.tif binary
|
||||||
|
*.tiff binary
|
||||||
|
*.ico binary
|
||||||
|
# SVG treated as an asset (binary) by default.
|
||||||
|
*.svg text
|
||||||
|
# If you want to treat it as binary,
|
||||||
|
# use the following line instead.
|
||||||
|
# *.svg binary
|
||||||
|
*.eps binary
|
||||||
|
|
||||||
|
# Scripts
|
||||||
|
*.bash text eol=lf
|
||||||
|
*.fish text eol=lf
|
||||||
|
*.sh text eol=lf
|
||||||
|
# These are explicitly windows files and should use crlf
|
||||||
|
*.bat text eol=crlf
|
||||||
|
*.cmd text eol=crlf
|
||||||
|
*.ps1 text eol=crlf
|
||||||
|
|
||||||
|
# Serialisation
|
||||||
|
*.json text
|
||||||
|
*.toml text
|
||||||
|
*.xml text
|
||||||
|
*.yaml text
|
||||||
|
*.yml text
|
||||||
|
|
||||||
|
# Archives
|
||||||
|
*.7z binary
|
||||||
|
*.gz binary
|
||||||
|
*.tar binary
|
||||||
|
*.tgz binary
|
||||||
|
*.zip binary
|
||||||
|
|
||||||
|
# Text files where line endings should be preserved
|
||||||
|
*.patch -text
|
||||||
|
|
||||||
|
#
|
||||||
|
# Exclude files from exporting
|
||||||
|
#
|
||||||
|
|
||||||
|
.gitattributes export-ignore
|
||||||
|
.gitignore export-ignore
|
||||||
|
.vscode export-ignore
|
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
!.vscode/numbered-bookmarks.json
|
||||||
|
*.code-workspace
|
||||||
|
|
||||||
|
# Local History for Visual Studio Code
|
||||||
|
.history/
|
||||||
|
|
||||||
|
# compiled CSS
|
||||||
|
css-review
|
||||||
|
css
|
21
index.html
Normal file
21
index.html
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>animated particles</title>
|
||||||
|
<link rel="stylesheet"
|
||||||
|
href="css/index.min.css"
|
||||||
|
crossorigin="anonymous"/>
|
||||||
|
</head>
|
||||||
|
<body onload='particles(avoidMouse=false)'>
|
||||||
|
<canvas id="particles"></canvas>
|
||||||
|
<!-- javascript -->
|
||||||
|
<script
|
||||||
|
src="js/particles.js"
|
||||||
|
crossorigin="anonymous"
|
||||||
|
async>
|
||||||
|
</script>
|
||||||
|
<!-- end javascript -->
|
||||||
|
</body>
|
||||||
|
</html>
|
194
js/particles.js
Normal file
194
js/particles.js
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
function particles(){
|
||||||
|
/* create particles animation
|
||||||
|
based on the amazing tutorial by 'Franks Labratory'
|
||||||
|
https://youtu.be/d620nV6bp0A
|
||||||
|
*/
|
||||||
|
|
||||||
|
// handle parameters
|
||||||
|
particles = (
|
||||||
|
typeof particles !== 'undefined'
|
||||||
|
&& Number.isFinite(particles)
|
||||||
|
) ? particles : 1;
|
||||||
|
sizeMultiplier = (
|
||||||
|
typeof sizeMultiplier !== 'undefined'
|
||||||
|
&& Number.isFinite(sizeMultiplier)
|
||||||
|
) ? sizeMultiplier : 3;
|
||||||
|
speed = (
|
||||||
|
typeof speed !== 'undefined'
|
||||||
|
&& Number.isFinite(speed)
|
||||||
|
&& (1 <= speed && speed <= 1000)
|
||||||
|
) ? (speed / 100) : 0.5;
|
||||||
|
avoidMouse = (
|
||||||
|
typeof avoidMouse !== 'undefined'
|
||||||
|
&& typeof avoidMouse === 'boolean'
|
||||||
|
) ? avoidMouse : true;
|
||||||
|
hover = (
|
||||||
|
typeof hover !== 'undefined'
|
||||||
|
&& typeof hover === 'boolean'
|
||||||
|
) ? hover : true;
|
||||||
|
|
||||||
|
// read css colour variables from root element
|
||||||
|
const particleColour = getComputedStyle(document.documentElement).getPropertyValue('--col-particle');
|
||||||
|
const strokeColour = getComputedStyle(document.documentElement).getPropertyValue('--col-particle-stroke');
|
||||||
|
const strokeHoverColour = getComputedStyle(document.documentElement).getPropertyValue('--col-particle-stroke-hover');
|
||||||
|
|
||||||
|
// get canvas element, set context and size
|
||||||
|
const canvas = document.getElementById('particles');
|
||||||
|
const canvasContext = canvas.getContext('2d');
|
||||||
|
canvas.width = window.innerWidth;
|
||||||
|
canvas.height = window.innerHeight;
|
||||||
|
|
||||||
|
let particlesArray;
|
||||||
|
|
||||||
|
// get mouse position
|
||||||
|
let mousePosition ={
|
||||||
|
x: undefined,
|
||||||
|
y: undefined,
|
||||||
|
radius: (canvas.height / 80) * (canvas.width / 80)
|
||||||
|
};
|
||||||
|
|
||||||
|
// add mouse position event listener
|
||||||
|
window.addEventListener('mousemove', function(event){
|
||||||
|
mousePosition.x = event.x;
|
||||||
|
mousePosition.y = event.y;
|
||||||
|
});
|
||||||
|
|
||||||
|
// create particle class
|
||||||
|
class Particle{
|
||||||
|
constructor(x, y, directionX, directionY, size, colour) {
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.directionX = directionX;
|
||||||
|
this.directionY = directionY;
|
||||||
|
this.size = size;
|
||||||
|
this.colour = colour;
|
||||||
|
}
|
||||||
|
// method to draw individual particles
|
||||||
|
draw(){
|
||||||
|
canvasContext.beginPath();
|
||||||
|
canvasContext.arc(this.x, this.y, this.size, 0, Math.PI * 2, false);
|
||||||
|
canvasContext.fillStyle = particleColour;
|
||||||
|
canvasContext.fill();
|
||||||
|
}
|
||||||
|
// check particle position, mouse position, move particle and draw it
|
||||||
|
update(){
|
||||||
|
// check if particle is still within canvas
|
||||||
|
if (this.x > canvas.width || this.x < 0){
|
||||||
|
this.directionX = -this.directionX;
|
||||||
|
}
|
||||||
|
if (this.y > canvas.height || this.y < 0){
|
||||||
|
this.directionY = -this.directionY;
|
||||||
|
}
|
||||||
|
|
||||||
|
// avoid the mouse if avoidMouse = true (default)
|
||||||
|
if (avoidMouse){
|
||||||
|
let dx = mousePosition.x - this.x;
|
||||||
|
let dy = mousePosition.y - this.y;
|
||||||
|
let distance = Math.sqrt((dx * dx) + (dy * dy));
|
||||||
|
if (distance < mousePosition.radius + this.size){
|
||||||
|
if (mousePosition.x < this.x && this.x < canvas.width - this.size * 10){
|
||||||
|
this.x += 10;
|
||||||
|
}
|
||||||
|
if (mousePosition.x > this.x && this.x > this.size * 10){
|
||||||
|
this.x -= 10;
|
||||||
|
}
|
||||||
|
if (mousePosition.y < this.y && this.y < canvas.height - this.size * 10){
|
||||||
|
this.y += 10;
|
||||||
|
}
|
||||||
|
if (mousePosition.y > this.y && this.y > this.size * 10){
|
||||||
|
this.y -= 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// move particle
|
||||||
|
this.x += this.directionX * speed;
|
||||||
|
this.y += this.directionY * speed;
|
||||||
|
|
||||||
|
// draw particle
|
||||||
|
this.draw();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create particle array
|
||||||
|
function init(){
|
||||||
|
particlesArray = [];
|
||||||
|
let numberOfParticles = (canvas.height * canvas.width) / 9000;
|
||||||
|
for (let i = 0; i < numberOfParticles * particles; i++){
|
||||||
|
let size = (Math.random() * sizeMultiplier) + 1;
|
||||||
|
let x = (Math.random() * ((innerWidth - size * 2) - (size * 2)) + size * 2);
|
||||||
|
let y = (Math.random() * ((innerHeight - size * 2) - (size * 2)) + size * 2);
|
||||||
|
let directionX = (Math.random() * 5) - 2.5;
|
||||||
|
let directionY = (Math.random() * 5) - 2.5;
|
||||||
|
let colour = '#8c5523';
|
||||||
|
|
||||||
|
particlesArray.push(new Particle(x, y, directionX, directionY, size, colour));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if particles are close enough to connect to eachother
|
||||||
|
function connect(){
|
||||||
|
let opacityValue = 1;
|
||||||
|
for (let a = 0; a < particlesArray.length; a++){
|
||||||
|
for (let b = a; b < particlesArray.length; b++){
|
||||||
|
let distance = ((particlesArray[a].x - particlesArray[b].x) * (particlesArray[a].x - particlesArray[b].x)) + ((particlesArray[a].y - particlesArray[b].y) * (particlesArray[a].y - particlesArray[b].y));
|
||||||
|
if (distance < (canvas.width / 10) * (canvas.height / 10)){
|
||||||
|
opacityValue = 1 - (distance / 20000);
|
||||||
|
// change colour on 'hover' if hover = true (default)
|
||||||
|
if(hover){
|
||||||
|
let dx = mousePosition.x - particlesArray[a].x;
|
||||||
|
let dy = mousePosition.y - particlesArray[a].y;
|
||||||
|
let mouseDistance = Math.sqrt((dx * dx) + (dy * dy));
|
||||||
|
if (mouseDistance < 200) {
|
||||||
|
// change colour if mouse is close
|
||||||
|
canvasContext.globalAlpha = opacityValue;
|
||||||
|
canvasContext.strokeStyle = strokeHoverColour;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// use regular stroke colour
|
||||||
|
canvasContext.globalAlpha = opacityValue;
|
||||||
|
canvasContext.strokeStyle = strokeColour;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
canvasContext.globalAlpha = opacityValue;
|
||||||
|
canvasContext.strokeStyle = strokeColour;
|
||||||
|
}
|
||||||
|
canvasContext.lineWidth = 1;
|
||||||
|
canvasContext.beginPath();
|
||||||
|
canvasContext.moveTo(particlesArray[a].x, particlesArray[a].y);
|
||||||
|
canvasContext.lineTo(particlesArray[b].x, particlesArray[b].y);
|
||||||
|
canvasContext.stroke();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// animation loop
|
||||||
|
function animate(){
|
||||||
|
requestAnimationFrame(animate);
|
||||||
|
canvasContext.clearRect(0, 0, innerWidth, innerHeight);
|
||||||
|
|
||||||
|
for (let i = 0; i < particlesArray.length; i++){
|
||||||
|
particlesArray[i].update();
|
||||||
|
}
|
||||||
|
connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
// resize event
|
||||||
|
window.addEventListener('resize', function(){
|
||||||
|
canvas.width = innerWidth;
|
||||||
|
canvas.height = innerHeight;
|
||||||
|
mousePosition.radius = ((canvas.height / 80) * (canvas.width / 80));
|
||||||
|
init();
|
||||||
|
});
|
||||||
|
|
||||||
|
// mouse-out event (mouse leaving the window)
|
||||||
|
window.addEventListener('mouseout', function(){
|
||||||
|
mousePosition.x = undefined;
|
||||||
|
mousePosition.y = undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
init();
|
||||||
|
animate();
|
||||||
|
}
|
7
scss/_palette.scss
Normal file
7
scss/_palette.scss
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// colours used thoughout site
|
||||||
|
:root {
|
||||||
|
--col-bg-canvas: #2c2830;
|
||||||
|
--col-particle: #ebe7c5;
|
||||||
|
--col-particle-stroke: #692e50;
|
||||||
|
--col-particle-stroke-hover: #9aa68b;
|
||||||
|
}
|
82
scss/_reset.scss
Normal file
82
scss/_reset.scss
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/* based on Eric Meyer's CSS Reset 2.0 (http://meyerweb/eric/tools/css/reset/)
|
||||||
|
modified for easier implementation of REM font-sizing with default set to
|
||||||
|
62.5% or 10px on most browsers by default. Media-queries adjusts this base conversion.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@media only screen and (max-width: 640px) {
|
||||||
|
:root {
|
||||||
|
font-size: 42.5%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (min-width: 641px) and (max-width: 1024px) {
|
||||||
|
:root {
|
||||||
|
font-size: 50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (min-width: 1025px) {
|
||||||
|
:root {
|
||||||
|
font-size: 62.5%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
:root {
|
||||||
|
height: 100%;
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
width: 100%;
|
||||||
|
body {
|
||||||
|
font-size: 2.2rem;
|
||||||
|
height: 100%;
|
||||||
|
line-height: 2.2rem * 1.25;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
html, body, div, span, applet, object, iframe,
|
||||||
|
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||||
|
a, abbr, acronym, address, big, cite, code,
|
||||||
|
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||||
|
small, strike, strong, sub, sup, tt, var,
|
||||||
|
b, u, i, center,
|
||||||
|
dl, dt, dd, ol, ul, li,
|
||||||
|
fieldset, form, label, legend,
|
||||||
|
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||||
|
article, aside, canvas, details, embed,
|
||||||
|
figure, figcaption, footer, header, hgroup,
|
||||||
|
menu, nav, output, ruby, section, summary,
|
||||||
|
time, mark, audio, video {
|
||||||
|
border: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: inherit;
|
||||||
|
font: inherit;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HTML5 display-role reset for older browsers */
|
||||||
|
article, aside, details, figcaption, figure,
|
||||||
|
footer, header, hgroup, menu, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol, ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote, q {
|
||||||
|
quotes: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
blockquote:before, blockquote:after,
|
||||||
|
q:before, q:after {
|
||||||
|
content: '';
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
16
scss/index.scss
Normal file
16
scss/index.scss
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/* styles of index */
|
||||||
|
|
||||||
|
/*
|
||||||
|
import partials
|
||||||
|
*/
|
||||||
|
@import 'reset';
|
||||||
|
@import 'palette';
|
||||||
|
|
||||||
|
#particles {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: var(--col-bg-canvas);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user