add a subtle background animation
All checks were successful
Build and Publish Docker Image / build (push) Successful in 4m15s
All checks were successful
Build and Publish Docker Image / build (push) Successful in 4m15s
This commit is contained in:
8
assets/css/custom.css
Normal file
8
assets/css/custom.css
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#fireflies-canvas {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: -1;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
153
assets/js/fireflies.js
Normal file
153
assets/js/fireflies.js
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
(function () {
|
||||||
|
'use strict'
|
||||||
|
|
||||||
|
var COUNT = 20
|
||||||
|
var MAX_RADIUS = 3
|
||||||
|
|
||||||
|
var PALETTE = [
|
||||||
|
[255, 255, 230],
|
||||||
|
[255, 245, 200],
|
||||||
|
[255, 230, 180],
|
||||||
|
[220, 255, 220],
|
||||||
|
[200, 230, 255],
|
||||||
|
]
|
||||||
|
|
||||||
|
var canvas, ctx, w, h, flies, id, running
|
||||||
|
|
||||||
|
function rand(a, b) { return a + Math.random() * (b - a) }
|
||||||
|
|
||||||
|
function init() {
|
||||||
|
canvas = document.createElement('canvas')
|
||||||
|
canvas.id = 'fireflies-canvas'
|
||||||
|
canvas.setAttribute('aria-hidden', 'true')
|
||||||
|
document.body.prepend(canvas)
|
||||||
|
ctx = canvas.getContext('2d')
|
||||||
|
resize()
|
||||||
|
spawn()
|
||||||
|
running = true
|
||||||
|
tick()
|
||||||
|
addEventListener('resize', onResize)
|
||||||
|
document.addEventListener('visibilitychange', onVisibility)
|
||||||
|
}
|
||||||
|
|
||||||
|
function resize() {
|
||||||
|
w = canvas.width = innerWidth
|
||||||
|
h = canvas.height = innerHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
function onResize() {
|
||||||
|
resize()
|
||||||
|
if (!flies) return
|
||||||
|
for (var i = 0; i < flies.length; i++) {
|
||||||
|
var f = flies[i]
|
||||||
|
if (f.x > w) f.x = w * 0.9
|
||||||
|
if (f.y > h) f.y = h * 0.9
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function spawn() {
|
||||||
|
flies = []
|
||||||
|
for (var i = 0; i < COUNT; i++) flies.push(makeFly())
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeFly() {
|
||||||
|
var c = PALETTE[Math.floor(Math.random() * PALETTE.length)]
|
||||||
|
return {
|
||||||
|
x: rand(0, w),
|
||||||
|
y: rand(0, h),
|
||||||
|
vx: rand(-0.08, 0.08),
|
||||||
|
vy: rand(-0.08, 0.08),
|
||||||
|
r: rand(1.5, MAX_RADIUS),
|
||||||
|
cr: c[0], cg: c[1], cb: c[2],
|
||||||
|
a: rand(0.15, 0.35),
|
||||||
|
phase: rand(0, 6.2832),
|
||||||
|
flashSpeed: rand(0.002, 0.006),
|
||||||
|
wanderPhase: rand(0, 6.2832),
|
||||||
|
wanderSpeed: rand(0.002, 0.008),
|
||||||
|
driftX: rand(-0.002, 0.002),
|
||||||
|
driftY: rand(-0.002, 0.002),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function tick() {
|
||||||
|
if (!running) return
|
||||||
|
update()
|
||||||
|
draw()
|
||||||
|
id = requestAnimationFrame(tick)
|
||||||
|
}
|
||||||
|
|
||||||
|
function update() {
|
||||||
|
for (var i = 0; i < flies.length; i++) {
|
||||||
|
var f = flies[i]
|
||||||
|
f.wanderPhase += f.wanderSpeed
|
||||||
|
var angle = Math.sin(f.wanderPhase) * 1.5
|
||||||
|
f.vx += Math.cos(angle) * 0.004 + f.driftX
|
||||||
|
f.vy += Math.sin(angle) * 0.004 + f.driftY
|
||||||
|
f.vx *= 0.98
|
||||||
|
f.vy *= 0.98
|
||||||
|
var sp = Math.sqrt(f.vx * f.vx + f.vy * f.vy)
|
||||||
|
if (sp > 0.3) {
|
||||||
|
f.vx = (f.vx / sp) * 0.3
|
||||||
|
f.vy = (f.vy / sp) * 0.3
|
||||||
|
}
|
||||||
|
f.x += f.vx
|
||||||
|
f.y += f.vy
|
||||||
|
if (f.x < -40) f.x = w + 40
|
||||||
|
if (f.x > w + 40) f.x = -40
|
||||||
|
if (f.y < -40) f.y = h + 40
|
||||||
|
if (f.y > h + 40) f.y = -40
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
ctx.clearRect(0, 0, w, h)
|
||||||
|
if (matchMedia('(prefers-reduced-motion: reduce)').matches) return
|
||||||
|
|
||||||
|
for (var i = 0; i < flies.length; i++) {
|
||||||
|
var f = flies[i]
|
||||||
|
f.phase += f.flashSpeed
|
||||||
|
var pulse = 0.5 + Math.sin(f.phase) * 0.5
|
||||||
|
var alpha = f.a * pulse
|
||||||
|
if (alpha < 0.01) continue
|
||||||
|
|
||||||
|
ctx.save()
|
||||||
|
|
||||||
|
var glowR = f.r * 4
|
||||||
|
var g = ctx.createRadialGradient(f.x, f.y, 0, f.x, f.y, glowR)
|
||||||
|
g.addColorStop(0, 'rgba(' + f.cr + ',' + f.cg + ',' + f.cb + ',' + alpha + ')')
|
||||||
|
g.addColorStop(0.15, 'rgba(' + f.cr + ',' + f.cg + ',' + f.cb + ',' + (alpha * 0.25) + ')')
|
||||||
|
g.addColorStop(1, 'rgba(' + f.cr + ',' + f.cg + ',' + f.cb + ',0)')
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.arc(f.x, f.y, glowR, 0, 6.2832)
|
||||||
|
ctx.fillStyle = g
|
||||||
|
ctx.fill()
|
||||||
|
|
||||||
|
var coreR = f.r * 1.2
|
||||||
|
var g2 = ctx.createRadialGradient(f.x, f.y, 0, f.x, f.y, coreR)
|
||||||
|
g2.addColorStop(0, 'rgba(' + f.cr + ',' + f.cg + ',' + f.cb + ',' + (alpha * 0.85) + ')')
|
||||||
|
g2.addColorStop(1, 'rgba(' + f.cr + ',' + f.cg + ',' + f.cb + ',0)')
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.arc(f.x, f.y, coreR, 0, 6.2832)
|
||||||
|
ctx.fillStyle = g2
|
||||||
|
ctx.fill()
|
||||||
|
|
||||||
|
ctx.restore()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onVisibility() {
|
||||||
|
if (document.hidden) {
|
||||||
|
running = false
|
||||||
|
if (id) { cancelAnimationFrame(id); id = null }
|
||||||
|
} else {
|
||||||
|
running = true
|
||||||
|
if (!id) tick()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.readyState === 'loading') {
|
||||||
|
document.addEventListener('DOMContentLoaded', init)
|
||||||
|
} else {
|
||||||
|
init()
|
||||||
|
}
|
||||||
|
})()
|
||||||
3
layouts/partials/extend-head.html
Normal file
3
layouts/partials/extend-head.html
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{{ with resources.Get "js/fireflies.js" | resources.Minify | resources.Fingerprint }}
|
||||||
|
<script defer src="{{ .RelPermalink }}" integrity="{{ .Data.Integrity }}"></script>
|
||||||
|
{{ end }}
|
||||||
Reference in New Issue
Block a user