Files
server-configs/httpserver/data/main.js
2026-03-22 00:54:28 -07:00

92 lines
2.6 KiB
JavaScript
Executable File

fetch('./ddate-now')
.then(r => r.text())
.then(d => { document.getElementById('ddate').textContent = d.trim(); })
.catch(() => { document.getElementById('ddate').textContent = ''; });
const canvas = document.getElementById('warp');
const ctx = canvas.getContext('2d');
let w, h, cx, cy, stars = [], animId = null, active = false;
const prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
const isMobile = window.innerWidth < 768 || window.innerHeight < 600 || /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
const starCount = isMobile ? 200 : 400;
const speed = prefersReduced ? 0.01 : 0.02;
function resize() {
w = canvas.width = window.innerWidth;
h = canvas.height = window.innerHeight;
cx = w / 2;
cy = h / 2;
}
class Star {
constructor() { this.reset(); }
reset() {
const angle = Math.random() * Math.PI * 2;
const radius = Math.random() * Math.max(w, h);
this.x = Math.cos(angle) * radius;
this.y = Math.sin(angle) * radius;
this.z = Math.random() * w;
this.pz = this.z;
}
update() {
this.pz = this.z;
this.z -= speed * this.z;
if (this.z < 1) this.reset();
}
draw() {
const sz = 1 / this.z, spz = 1 / this.pz;
const sx = this.x * sz * w + cx, sy = this.y * sz * h + cy;
const px = this.x * spz * w + cx, py = this.y * spz * h + cy;
const r = Math.max(0, (1 - this.z / w) * 2);
ctx.beginPath();
ctx.strokeStyle = `rgba(255, 255, 255, ${r})`;
ctx.lineWidth = r * 2;
ctx.moveTo(px, py);
ctx.lineTo(sx, sy);
ctx.stroke();
}
}
function init() {
resize();
stars = [];
for (let i = 0; i < starCount; i++) stars.push(new Star());
}
function animate() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
ctx.fillRect(0, 0, w, h);
for (let i = 0; i < stars.length; i++) {
stars[i].update();
stars[i].draw();
}
animId = requestAnimationFrame(animate);
}
function startWarp() {
if (active) return;
active = true;
canvas.classList.add('active');
init();
animate();
}
function stopWarp() {
if (!active) return;
active = false;
canvas.classList.remove('active');
if (animId) cancelAnimationFrame(animId);
}
document.addEventListener('click', (e) => {
if (e.target.classList.contains('warp-trigger')) {
e.preventDefault();
active ? stopWarp() : startWarp();
}
});
window.addEventListener('resize', () => {
if (active) resize();
});