summaryrefslogtreecommitdiff
path: root/site/themes/sine/static/js/background.js
diff options
context:
space:
mode:
Diffstat (limited to 'site/themes/sine/static/js/background.js')
-rw-r--r--site/themes/sine/static/js/background.js216
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);