import { prefersReducedMotion } from "../shared/media.js"; export function initPageMeshBackground() { if (prefersReducedMotion()) return; const root = document.documentElement; let rafId = 0; let showMarkers = false; const markers = []; function createMarker(label) { const el = document.createElement("div"); el.textContent = label; el.style.position = "fixed"; el.style.zIndex = "10000"; el.style.width = "18px"; el.style.height = "18px"; el.style.borderRadius = "999px"; el.style.background = "#000"; el.style.color = "#fff"; el.style.fontSize = "11px"; el.style.fontWeight = "700"; el.style.lineHeight = "18px"; el.style.textAlign = "center"; el.style.pointerEvents = "none"; el.style.boxShadow = "0 0 0 1px rgba(255,255,255,0.55)"; document.body.appendChild(el); return el; } function setMarker(el, xPct, yPct) { el.style.left = `calc(${xPct}% - 9px)`; el.style.top = `calc(${yPct}% - 9px)`; } markers.push(createMarker("A")); markers.push(createMarker("B")); markers.push(createMarker("C")); const markersToggle = document.querySelector("[data-mesh-markers-toggle]"); if (markersToggle instanceof HTMLInputElement) { showMarkers = markersToggle.checked; markersToggle.addEventListener("change", () => { showMarkers = markersToggle.checked; markers.forEach((m) => { m.style.display = showMarkers ? "block" : "none"; }); }); markers.forEach((m) => { m.style.display = showMarkers ? "block" : "none"; }); } const hero = document.querySelector(".hero"); const spots = [ { x: 2, y: 2 }, { x: 50, y: 2 }, { x: 98, y: 2 }, ]; const update = () => { rafId = 0; const heroHeight = hero instanceof HTMLElement ? Math.max(hero.offsetHeight, 1) : Math.max(window.innerHeight, 1); const heroProgress = Math.min(window.scrollY / heroHeight, 1); const opacityMaxRaw = getComputedStyle(root).getPropertyValue("--mesh-opacity-max").trim(); const opacityMinRaw = getComputedStyle(root).getPropertyValue("--mesh-opacity-min").trim(); const opacityMax = Number.parseFloat(opacityMaxRaw); const opacityMin = Number.parseFloat(opacityMinRaw); const safeOpacityMax = Number.isFinite(opacityMax) ? opacityMax : 1; const safeOpacityMin = Number.isFinite(opacityMin) ? opacityMin : 0; const opacityNow = safeOpacityMax - (safeOpacityMax - safeOpacityMin) * heroProgress; root.style.setProperty("--mesh-opacity-current", `${Math.max(opacityNow, safeOpacityMin).toFixed(3)}`); spots.forEach((p, idx) => { const key = ["a", "b", "c"][idx]; root.style.setProperty(`--mesh-${key}-x`, `${p.x.toFixed(2)}%`); root.style.setProperty(`--mesh-${key}-y`, `${p.y.toFixed(2)}%`); if (showMarkers) setMarker(markers[idx], p.x, p.y); }); }; const onScroll = () => { if (rafId) return; rafId = window.requestAnimationFrame(update); }; window.addEventListener("scroll", onScroll, { passive: true }); window.addEventListener("resize", onScroll, { passive: true }); update(); }