/* AnwarPi — WebGL light-beam background + scroll reveal. Loads deferred on every page; no-ops gracefully if WebGL is unavailable. */ (function () { "use strict"; var reduced = false; try { reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches; } catch (e) {} var staticMode = false; try { staticMode = new URLSearchParams(location.search).has("static"); } catch (e) {} /* ================= WebGL beam field ================= */ function initWebGL() { var canvas = document.createElement("canvas"); canvas.id = "anwarpi-bg"; canvas.setAttribute("aria-hidden", "true"); var first = document.body.firstChild; if (first) document.body.insertBefore(canvas, first); else document.body.appendChild(canvas); var gl = canvas.getContext("webgl", { antialias: false, alpha: false, depth: false, stencil: false }) || canvas.getContext("experimental-webgl"); if (!gl) { canvas.parentNode.removeChild(canvas); return; } var vertSrc = "attribute vec2 p;void main(){gl_Position=vec4(p,0.0,1.0);}"; var fragSrc = [ "precision highp float;", "uniform float uTime;", "uniform vec2 uRes;", "uniform vec2 uMouse;", "float hash(float n){return fract(sin(n*127.1)*43758.5453);}", "void main(){", " vec2 uv = gl_FragCoord.xy / uRes;", /* y: 0 bottom -> 1 top */ " float t = uTime * 0.06;", " float v = 0.0;", /* vertical light beams — the AnwarPi "A" ray motif */ " for(int i = 0; i < 7; i++){", " float fi = float(i);", " float x = 0.08 + 0.84 * hash(fi + 1.0) + 0.05 * sin(t * 0.7 + fi * 2.4);", " x += (uMouse.x - x) * 0.16;", " float w = 0.016 + 0.05 * hash(fi + 7.0);", " float beam = exp(-pow((uv.x - x) / w, 2.0));", " float flick = 0.55 + 0.45 * sin(t * 1.1 + fi * 1.7);", " flick *= 1.0 + 0.55 * exp(-pow((uv.x - uMouse.x) / 0.24, 2.0));", " float fade = smoothstep(1.0, 0.12, uv.y);", /* brighter toward the bottom, like the mark */ " v += beam * flick * fade * (0.10 + 0.17 * hash(fi + 13.0));", " }", /* cursor halo — the light follows the visitor */ " v += 0.11 * exp(-length((uv - uMouse) * vec2(1.0, 0.9)) * 4.5);", /* broad floor glow + soft vignette */ " v += 0.15 * exp(-uv.y * 2.4);", " v *= smoothstep(1.3, 0.55, uv.y);", " v = clamp(v, 0.0, 1.0);", /* deep blue-black base, aligned with the shared --bg token */ " vec3 base = vec3(0.0005, 0.0618, 0.0896);", " gl_FragColor = vec4(base + vec3(v), 1.0);", "}" ].join("\n"); function compile(type, src) { var s = gl.createShader(type); gl.shaderSource(s, src); gl.compileShader(s); if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) { gl.deleteShader(s); return null; } return s; } var vs = compile(gl.VERTEX_SHADER, vertSrc); var fs = compile(gl.FRAGMENT_SHADER, fragSrc); if (!vs || !fs) { canvas.parentNode.removeChild(canvas); return; } var prog = gl.createProgram(); gl.attachShader(prog, vs); gl.attachShader(prog, fs); gl.linkProgram(prog); if (!gl.getProgramParameter(prog, gl.LINK_STATUS)) { canvas.parentNode.removeChild(canvas); return; } gl.useProgram(prog); var buf = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buf); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), gl.STATIC_DRAW); var loc = gl.getAttribLocation(prog, "p"); gl.enableVertexAttribArray(loc); gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0); var uTime = gl.getUniformLocation(prog, "uTime"); var uRes = gl.getUniformLocation(prog, "uRes"); var uMouse = gl.getUniformLocation(prog, "uMouse"); /* ---- pointer reaction: beams lean toward the cursor, halo follows ---- */ var mouseTX = 0.5, mouseTY = 0.55, mouseX = 0.5, mouseY = 0.55; if (!reduced && !staticMode) { window.addEventListener("pointermove", function (e) { if (e.pointerType === "touch") return; mouseTX = e.clientX / window.innerWidth; mouseTY = 1 - e.clientY / window.innerHeight; }, { passive: true }); document.addEventListener("pointerleave", function () { mouseTX = 0.5; mouseTY = 0.55; }); } gl.uniform2f(uMouse, mouseX, mouseY); var DPR_CAP = 1.5; function resize() { var dpr = Math.min(window.devicePixelRatio || 1, DPR_CAP); var w = Math.max(1, Math.floor(window.innerWidth * dpr)); var h = Math.max(1, Math.floor(window.innerHeight * dpr)); if (canvas.width !== w || canvas.height !== h) { canvas.width = w; canvas.height = h; gl.viewport(0, 0, w, h); } gl.uniform2f(uRes, canvas.width, canvas.height); } var start = (window.performance && performance.now()) || 0; function draw(now) { mouseX += (mouseTX - mouseX) * 0.07; mouseY += (mouseTY - mouseY) * 0.07; gl.uniform1f(uTime, (now - start) / 1000); gl.uniform2f(uMouse, mouseX, mouseY); gl.drawArrays(gl.TRIANGLES, 0, 3); } resize(); draw(start); /* paint one frame synchronously so screenshots capture the field */ /* ---- article reading mode: fade the field down once past the header ---- */ if (document.body.hasAttribute("data-anw-dim")) { var first = document.querySelector("main") && document.querySelector("main").firstElementChild; var dimFrom = first ? first.offsetHeight : 420; var onScroll = function () { canvas.style.opacity = (window.scrollY || 0) > dimFrom ? "0.22" : "1"; }; window.addEventListener("scroll", onScroll, { passive: true }); onScroll(); } if (reduced || staticMode) { window.addEventListener("resize", function () { resize(); draw(start); }); return; } var running = true; function loop(now) { if (running) { draw(now); } window.requestAnimationFrame(loop); } window.requestAnimationFrame(loop); document.addEventListener("visibilitychange", function () { running = !document.hidden; if (running) start = (window.performance && performance.now()) - 0; /* keep phase simple */ }); } /* ================= Scroll reveal ================= */ function initReveal() { if (reduced || staticMode) return; var vh = window.innerHeight || 800; var candidates = document.querySelectorAll( "main section > .container > *, main > .container > *, main .container > .grid > *, main .grid > *" ); var seen = {}; var targets = []; for (var i = 0; i < candidates.length; i++) { var el = candidates[i]; if (seen[el.anwId]) continue; if (el.closest(".menu-panel, .modal, dialog")) continue; var r = el.getBoundingClientRect(); if (r.top < vh * 0.92) continue; /* above the fold: show instantly, never hide */ el.anwId = "anw" + i; seen[el.anwId] = 1; el.setAttribute("data-anw", ""); el.style.transitionDelay = ((i % 3) * 70) + "ms"; targets.push(el); } if (!targets.length) return; document.documentElement.classList.add("anw-anim"); /* Force reveal after a safety window so nothing can stay hidden */ window.setTimeout(function () { targets.forEach(function (el) { el.classList.add("anw-in"); }); }, 3000); if (!("IntersectionObserver" in window)) return; var io = new IntersectionObserver(function (entries) { entries.forEach(function (entry) { if (entry.isIntersecting) { entry.target.classList.add("anw-in"); io.unobserve(entry.target); } }); }, { threshold: 0.1, rootMargin: "0px 0px -8% 0px" }); targets.forEach(function (el) { io.observe(el); }); } /* ================= Current page in mobile navigation ================= */ function initActiveNav() { var topnav = document.querySelector(".topnav"); if (!topnav) return; var page = (location.pathname.split("/").pop() || "index.html").toLowerCase(); var selector = { "index.html": ".logo", "arabic-ai-learning-catalog.html": "nav a[href^='#catalog']", "arabic-ai-learning-catalog-v2.html": "nav a[href^='#catalog']", "article-agent-guide.html": "nav a[href='article-agent-guide.html']", "post-locked.html": "nav a[href='article-agent-guide.html']", "post-unlocked.html": "nav a[href='article-agent-guide.html']", "subscription.html": "nav a[href='#exclusive-guides']", "vip-onboarding.html": "nav a[href='subscription.html']", "account-settings.html": ".nav-account", "login.html": ".logo", "forgot-password.html": ".logo", "privacy.html": "nav a[href='privacy.html']" }[page]; var active = selector && topnav.querySelector(selector); if (active) active.setAttribute("aria-current", "page"); } function boot() { initActiveNav(); initWebGL(); initReveal(); } if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", boot); else boot(); })();