const { SectionHeading } = window.TheVisualsBrothersDesignSystem_fe64e0; const items = [ { image: "site/work-raastah.jpg", category: "AI Commercial", title: "RAASTAH", url: "https://www.instagram.com/reel/DUQmJkrDYp5/" }, { image: "site/work-odyssey.jpg", category: "Physical Film", title: "The Life After Watching The Odyssey", url: "https://www.instagram.com/reel/DbYcDG4A8UM/" }, { image: "site/work-football.jpg", category: "AI Commercial", title: "Football In Pakistan", url: "https://www.instagram.com/reel/DanhLsOAzZQ/" }, { image: "site/work-oakley.jpg", category: "AI Commercial", title: "Oakley", url: "https://www.instagram.com/reel/DblNmRaNCcu/" }, { image: "site/work-obsession.jpg", category: "Physical + VFX", title: "Obsession", url: "https://www.instagram.com/reel/Dax0Y0xgntP/" }, { image: "site/work-gullylabs.jpg", category: "AI Commercial", title: "Gully Labs", url: "https://www.instagram.com/reel/DZ7lQOZAo1H/" }, { image: "site/work-benzgadi.jpg", category: "AI Commercial", title: "Benz Gadi", url: "https://www.instagram.com/reel/DVeHfDtjfQn/" }, { image: "site/work-strangerthings.jpg", category: "Physical + VFX", title: "Stranger Things", url: "https://www.instagram.com/reel/DTAo5AYDUaX/" }, { image: "site/work-movement.jpg", category: "AI Fashion Commercial", title: "Movement", url: "https://www.instagram.com/reel/DUn6VqxDFdR/" }, ]; const musicItems = [ { image: "site/work-sawal.jpg", category: "Music Video", title: "Sawal", subtitle: "Muddabir Khan", url: "https://www.youtube.com/watch?v=Ne6zdvQVq1g" }, { image: "site/work-tuhinahi.jpg", category: "Music Video", title: "Tu Hi Nahi", subtitle: "Khizer Hameed", url: "https://youtu.be/p1w9OdfueHM?si=1HTbYH0djF7KreAr" }, { image: "site/work-nainadisharab.jpg", category: "Music Video", title: "Naina Di Sharab", subtitle: "Ramzan Jani", url: "https://youtu.be/ElrVekpB2EE?si=CbM-epzkAV-4aBMN" }, ]; let vbActiveVideo = null; function WorkCard({ image, video, category, title, subtitle, url }) { const [hover, setHover] = React.useState(false); const [videoReady, setVideoReady] = React.useState(false); const videoRef = React.useRef(null); const stopTimerRef = React.useRef(null); const canHoverPreview = video && typeof window !== "undefined" && window.matchMedia && window.matchMedia("(hover: hover) and (pointer: fine)").matches; function startPreview() { setHover(true); if (!canHoverPreview) return; const v = videoRef.current; if (!v) return; if (vbActiveVideo && vbActiveVideo !== v) { vbActiveVideo.pause(); } vbActiveVideo = v; v.currentTime = 0; v.muted = true; const playPromise = v.play(); if (playPromise) playPromise.then(() => setVideoReady(true)).catch(() => {}); clearTimeout(stopTimerRef.current); stopTimerRef.current = setTimeout(() => { if (v) v.pause(); }, 2800); } function stopPreview() { setHover(false); setVideoReady(false); clearTimeout(stopTimerRef.current); const v = videoRef.current; if (v) { v.pause(); v.currentTime = 0; } if (vbActiveVideo === v) vbActiveVideo = null; } return ( {canHoverPreview && hover ? ( ) : null} {category} {title}{subtitle ? — {subtitle} : null} ); } function Portfolio() { const canvasRef = React.useRef(null); React.useEffect(() => { const canvas = canvasRef.current, section = canvas.parentElement; const ctx = canvas.getContext("2d"); let w, h, particles, mouse = { x: -9999, y: -9999 }; function resize() { w = canvas.width = section.offsetWidth; h = canvas.height = section.offsetHeight; } function makeParticles() { const count = Math.round((w * h) / 18000); particles = Array.from({ length: count }, () => ({ x: Math.random() * w, y: Math.random() * h, vx: (Math.random() - 0.5) * 0.25, vy: (Math.random() - 0.5) * 0.25, r: Math.random() * 2 + 1, hue: Math.random() < 0.5 ? "217,119,6" : "245,158,11", a: Math.random() * 0.5 + 0.3, })); } const spriteSize = 48, spriteR = spriteSize / 2; const hues = ["217,119,6", "245,158,11"]; const sprites = {}; hues.forEach((hue) => { const s = document.createElement("canvas"); s.width = spriteSize; s.height = spriteSize; const sctx = s.getContext("2d"); const grad = sctx.createRadialGradient(spriteR, spriteR, 0, spriteR, spriteR, spriteR); grad.addColorStop(0, `rgba(${hue},1)`); grad.addColorStop(1, `rgba(${hue},0)`); sctx.fillStyle = grad; sctx.beginPath(); sctx.arc(spriteR, spriteR, spriteR, 0, Math.PI * 2); sctx.fill(); sprites[hue] = s; }); resize(); makeParticles(); window.addEventListener("resize", () => { resize(); makeParticles(); }); section.addEventListener("mousemove", (e) => { const r = section.getBoundingClientRect(); mouse.x = e.clientX - r.left; mouse.y = e.clientY - r.top; }); section.addEventListener("mouseleave", () => { mouse.x = -9999; mouse.y = -9999; }); let raf = null, frameCount = 0, cachedLines = []; function tick() { ctx.clearRect(0, 0, w, h); particles.forEach((p) => { const dx = p.x - mouse.x, dy = p.y - mouse.y, dist = Math.sqrt(dx * dx + dy * dy); if (dist < 120) { const f = (120 - dist) / 120; p.x += (dx / dist) * f * 2.2; p.y += (dy / dist) * f * 2.2; } p.x += p.vx; p.y += p.vy; if (p.x < 0) p.x = w; if (p.x > w) p.x = 0; if (p.y < 0) p.y = h; if (p.y > h) p.y = 0; const d = p.r * 4 * 2; ctx.globalAlpha = p.a; ctx.drawImage(sprites[p.hue], p.x - d / 2, p.y - d / 2, d, d); }); ctx.globalAlpha = 1; if (frameCount % 3 === 0) { cachedLines = []; for (let i = 0; i < particles.length; i++) { for (let j = i + 1; j < particles.length; j++) { const a = particles[i], b = particles[j]; const d = Math.hypot(a.x - b.x, a.y - b.y); if (d < 90) cachedLines.push([a.x, a.y, b.x, b.y, 0.12 * (1 - d / 90)]); } } } frameCount++; cachedLines.forEach(([ax, ay, bx, by, alpha]) => { ctx.strokeStyle = `rgba(217,119,6,${alpha})`; ctx.lineWidth = 1; ctx.beginPath(); ctx.moveTo(ax, ay); ctx.lineTo(bx, by); ctx.stroke(); }); raf = requestAnimationFrame(tick); } const io = new IntersectionObserver((entries) => { const visible = entries[0].isIntersecting; if (visible && raf === null) { raf = requestAnimationFrame(tick); } else if (!visible && raf !== null) { cancelAnimationFrame(raf); raf = null; } }, { threshold: 0 }); io.observe(section); return () => { cancelAnimationFrame(raf); io.disconnect(); }; }, []); return ( {/* SLR camera, top-left */} {/* twin-lens camera, bottom-left */} {/* film reel, bottom-right */} {items.map((it, i) => ( ))} {musicItems.map((it, i) => ( ))} ); } window.Portfolio = Portfolio;