diff options
Diffstat (limited to 'site/themes/sine/static/js/background.js')
| -rw-r--r-- | site/themes/sine/static/js/background.js | 216 |
1 files changed, 137 insertions, 79 deletions
diff --git a/site/themes/sine/static/js/background.js b/site/themes/sine/static/js/background.js index e9b61a2..174820a 100644 --- a/site/themes/sine/static/js/background.js +++ b/site/themes/sine/static/js/background.js @@ -1,82 +1,140 @@ -document.addEventListener("DOMContentLoaded", () => { - const canvas = document.getElementById("background"); - if (!canvas) return; - const ctx = canvas.getContext("2d"); - - // Grab config from the embedded <script> - const configEl = document.getElementById("background-config"); - const config = configEl ? JSON.parse(configEl.textContent) : {}; - - // Use config values with defaults as fallback - const spacing = config.spacing ?? 24; - const maxRadius = config.maxRadius ?? 8; - const baseOffset = config.baseOffset ?? 120; - const freq = config.freq ?? 0.008; - const speed = config.speed ?? 0.02; - - const baseAmp = config.baseAmp ?? 100; - const env1Freq = config.envelope1Freq ?? 0.002; - const env1Amp = config.envelope1Amp ?? 120; - const env2Freq = config.envelope2Freq ?? 0.0005; - const env2Amp = config.envelope2Amp ?? 200; - - let t = parseFloat(localStorage.getItem("waveProgress")) || 0; - let widthCss = window.innerWidth; - let heightCss = window.innerHeight; - let pixelRatio = window.devicePixelRatio || 1; - - function resize() { - widthCss = window.innerWidth; - heightCss = window.innerHeight; - pixelRatio = window.devicePixelRatio || 1; - - canvas.width = Math.floor(widthCss * pixelRatio); - canvas.height = Math.floor(heightCss * pixelRatio); - canvas.style.width = widthCss + "px"; - canvas.style.height = heightCss + "px"; - ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0); +const canvas = document.getElementById("background"); +const ctx = canvas.getContext("2d"); + +// Resize Handling + +function resizeCanvas() { + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; +} + +resizeCanvas(); +window.addEventListener("resize", resizeCanvas); + +// Custom Math Functions + +function customFunction(x, t, c) { + const centerY = c.height / 2; + + return centerY + (30 + 10 * Math.sin(0.05 * t)) * + Math.sin(0.006 * x - 0.4 * t) + + 20 * Math.sin(0.011 * x - 0.25 * t + 2); +} + +function customFunctionTwo(x, t, c) { + const centerY = c.height / 2; + + return centerY + ( + 40 * Math.sin(0.005 * x - 0.6 * t) + + 25 * Math.sin(0.009 * x - 0.35 * t + 2) + + 15 * Math.sin(0.015 * x - 0.2 * t + 5) + ); +} + +// Math Function Drawing Engine + +// Get time from localstorage if it exists +let time = parseFloat(localStorage.getItem("time")) || 0; + +function drawFunction(fn, color) { + + ctx.beginPath(); + + // Start at left edge + ctx.moveTo(0, fn(0, time, canvas)); + + // Plot function across entire width + for (let x = 0; x < canvas.width; x++) { + const y = fn(x, time, canvas); + ctx.lineTo(x, y); + } + + ctx.strokeStyle = color; + ctx.lineWidth = 2; + ctx.stroke(); +} + +// Starfield Drawing Engine + +function makeStarfield(width, height, count, seed = 1) { + function rng() { + seed |= 0; + seed = seed + 0x6D2B79F5 | 0; + let t = Math.imul(seed ^ seed >>> 15, 1 | seed); + t ^= t + Math.imul(t ^ t >>> 7, 61 | t); + return ((t ^ t >>> 14) >>> 0) / 4294967296; + } + + const stars = []; + + for (let i = 0; i < count; i++) { + stars.push({ + x: rng() * width, + y: rng() * height, + size: rng() * 1.5 + 0.3, + base: 0.5 + rng() * 0.3, + phase: rng() * Math.PI * 2, + speed: 0.5 + rng() * 2.0 + }); + } + + return stars; +} + +function drawStars(ctx, stars, time, color) { + ctx.fillStyle = color; + + for (const s of stars) { + const twinkle = Math.sin(time * s.speed + s.phase) * 0.5 + 0.5; + const alpha = s.base + twinkle * 0.5; + + ctx.globalAlpha = alpha; + ctx.fillRect(s.x, s.y, s.size, s.size); } - window.addEventListener("resize", resize); - resize(); - - function draw() { - const styles = getComputedStyle(document.documentElement); - const fg = styles.getPropertyValue("--fg").trim(); - - ctx.clearRect(0, 0, widthCss, heightCss); - ctx.fillStyle = fg; - - for (let x = 0; x <= widthCss + spacing; x += spacing) { - // envelope: controls crest variance - const envelope = - baseAmp - + Math.sin(x * env1Freq + t * 0.1) * env1Amp - + Math.sin(x * env2Freq + t * 0.05) * env2Amp; - - const waveY = heightCss - (Math.sin(x * freq + t) * envelope + baseOffset); - // const waveY = Math.max(heightCss - 50, heightCss - (Math.sin(x * freq + t) * envelope + baseOffset)); - - for (let y = heightCss; y >= 0; y -= spacing) { - const dist = Math.max(0, y - waveY); - const radius = Math.min(maxRadius, dist / 40); - if (radius > 0.2) { - ctx.beginPath(); - // ctx.arc(x + spacing / 2, y - spacing / 2, radius, 0, Math.PI * 2); - ctx.fillRect( - x + spacing / 2 - radius, - y - spacing / 2 - radius, - radius * 2, - radius * 2 - ); - ctx.fill(); - } - } - } - - t += speed; - localStorage.setItem("waveProgress", t); - requestAnimationFrame(draw); + + ctx.globalAlpha = 1; +} + +// Animation Loop + +let animationId = null; +let lastTime = 0; + +const stars = makeStarfield(canvas.width, canvas.height, 600, 42); + +function animate(timestamp) { + animationId = requestAnimationFrame(animate); + + // First frame setup + if (!lastTime) { + lastTime = timestamp; } - draw(); -}); + // Time difference in seconds + const delta = (timestamp - lastTime) / 1000; + lastTime = timestamp; + + // Advance time + time += delta; + + // save time in localstorage + localStorage.setItem("time", time); + + // Get colors + const styles = getComputedStyle(document.documentElement); + const fgColor = styles.getPropertyValue("--fg").trim(); + + // Clear the canvas + ctx.clearRect(0, 0, canvas.width, canvas.height); + + // Draw Stars + drawStars(ctx, stars, time, fgColor); + + // Draw first custom function + drawFunction(customFunction, fgColor); + + // draw second custom function + drawFunction(customFunctionTwo, fgColor); +} + +animate(0); |
