diff --git a/client/app/not-found.tsx b/client/app/not-found.tsx new file mode 100644 index 0000000..88a0a16 --- /dev/null +++ b/client/app/not-found.tsx @@ -0,0 +1,460 @@ +"use client"; + +import React, { useEffect, useRef, useCallback, useState } from "react"; +import { motion, useMotionValue, useSpring, useTransform } from "framer-motion"; +import gsap from "gsap"; +import { + Home, + ArrowLeft, + Cpu, + Terminal, + WifiOff, + Activity, + Zap, + Scan, + AlertTriangle, + Radio, +} from "lucide-react"; +import { + RiFingerprintLine, + RiRadarLine, + RiCpuLine, + RiSignalTowerLine, +} from "react-icons/ri"; +import Link from "next/link"; + +export default function NotFound() { + const containerRef = useRef(null); + const canvasRef = useRef(null); + const titleRef = useRef(null); + const diagRef = useRef(null); + + const [glitchText, setGlitchText] = useState("404"); + const [coords, setCoords] = useState({ x: 0, y: 0 }); + + const mouseX = useMotionValue(0); + const mouseY = useMotionValue(0); + const springCfg = { damping: 30, stiffness: 100 }; + const rotX = useSpring(useTransform(mouseY, [-0.5, 0.5], [8, -8]), springCfg); + const rotY = useSpring(useTransform(mouseX, [-0.5, 0.5], [-8, 8]), springCfg); + const transX = useSpring(useTransform(mouseX, [-0.5, 0.5], [-20, 20]), springCfg); + const transY = useSpring(useTransform(mouseY, [-0.5, 0.5], [-20, 20]), springCfg); + + const handleMouseMove = useCallback( + (e: React.MouseEvent) => { + const rect = containerRef.current?.getBoundingClientRect(); + if (!rect) return; + const x = (e.clientX - rect.left) / rect.width - 0.5; + const y = (e.clientY - rect.top) / rect.height - 0.5; + mouseX.set(x); + mouseY.set(y); + setCoords({ x: e.clientX - rect.left, y: e.clientY - rect.top }); + }, + [mouseX, mouseY] + ); + + useEffect(() => { + const chars = "01アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワヲン"; + const original = "404"; + let interval: NodeJS.Timeout; + + const triggerGlitch = () => { + let iter = 0; + const inner = setInterval(() => { + setGlitchText( + original + .split("") + .map((c, i) => (i < iter ? original[i] : chars[Math.floor(Math.random() * chars.length)])) + .join("") + ); + iter += 0.4; + if (iter >= original.length) clearInterval(inner); + }, 35); + }; + + triggerGlitch(); + interval = setInterval(triggerGlitch, 3500); + return () => clearInterval(interval); + }, []); + + useEffect(() => { + const tl = gsap.timeline({ defaults: { ease: "expo.out" } }); + + tl.fromTo(".iris-canvas", { opacity: 0 }, { opacity: 1, duration: 1.5 }) + .fromTo( + ".grid-h", + { scaleX: 0, opacity: 0 }, + { scaleX: 1, opacity: 0.15, duration: 1.2, stagger: 0.12, transformOrigin: "center" }, + "-=1" + ) + .fromTo( + ".grid-v", + { scaleY: 0, opacity: 0 }, + { scaleY: 1, opacity: 0.15, duration: 1.2, stagger: 0.12, transformOrigin: "center" }, + "-=1.2" + ) + .fromTo( + ".iris-badge", + { y: -30, opacity: 0, scale: 0.9 }, + { y: 0, opacity: 1, scale: 1, duration: 0.8 }, + "-=0.6" + ) + .fromTo( + titleRef.current, + { y: 60, opacity: 0, skewX: 8 }, + { y: 0, opacity: 1, skewX: 0, duration: 1 }, + "-=0.4" + ) + .fromTo( + ".sub-status", + { opacity: 0, letterSpacing: "0px" }, + { opacity: 1, letterSpacing: "0.25em", duration: 0.8 }, + "-=0.6" + ) + .fromTo( + diagRef.current, + { opacity: 0, y: 30, scale: 0.95 }, + { opacity: 1, y: 0, scale: 1, duration: 0.8 }, + "-=0.4" + ) + .fromTo( + ".iris-btn", + { opacity: 0, y: 20 }, + { opacity: 1, y: 0, duration: 0.6, stagger: 0.1 }, + "-=0.4" + ) + .fromTo( + ".corner-deco", + { opacity: 0 }, + { opacity: 1, duration: 0.6, stagger: 0.1 }, + "-=0.6" + ); + }, []); + + useEffect(() => { + const canvas = canvasRef.current; + if (!canvas) return; + const ctx = canvas.getContext("2d"); + if (!ctx) return; + + let W = window.innerWidth; + let H = window.innerHeight; + canvas.width = W; + canvas.height = H; + + const particles: Array<{ + x: number; + y: number; + vx: number; + vy: number; + size: number; + pulse: number; + }> = []; + + for (let i = 0; i < 80; i++) { + particles.push({ + x: Math.random() * W, + y: Math.random() * H, + vx: (Math.random() - 0.5) * 0.6, + vy: (Math.random() - 0.5) * 0.6, + size: Math.random() * 1.8 + 0.5, + pulse: Math.random() * Math.PI, + }); + } + + let raf: number; + const draw = () => { + ctx.fillStyle = "rgba(0,0,0,0.08)"; + ctx.fillRect(0, 0, W, H); + + particles.forEach((p) => { + p.x += p.vx; + p.y += p.vy; + p.pulse += 0.05; + + 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 alpha = 0.4 + Math.sin(p.pulse) * 0.3; + ctx.beginPath(); + ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2); + ctx.fillStyle = `rgba(0,255,65,${alpha})`; + ctx.fill(); + }); + + for (let i = 0; i < particles.length; i++) { + for (let j = i + 1; j < particles.length; j++) { + const dx = particles[i].x - particles[j].x; + const dy = particles[i].y - particles[j].y; + const dist = Math.sqrt(dx * dx + dy * dy); + if (dist < 140) { + ctx.beginPath(); + ctx.moveTo(particles[i].x, particles[i].y); + ctx.lineTo(particles[j].x, particles[j].y); + ctx.strokeStyle = `rgba(0,255,65,${0.15 * (1 - dist / 140)})`; + ctx.lineWidth = 0.6; + ctx.stroke(); + } + } + } + + raf = requestAnimationFrame(draw); + }; + + draw(); + + const onResize = () => { + W = window.innerWidth; + H = window.innerHeight; + canvas.width = W; + canvas.height = H; + }; + window.addEventListener("resize", onResize); + return () => { + cancelAnimationFrame(raf); + window.removeEventListener("resize", onResize); + }; + }, []); + + return ( +
+ + +
+
+ +
+ {[...Array(6)].map((_, i) => ( +
+ ))} + {[...Array(6)].map((_, i) => ( +
+ ))} +
+ +
+ {[...Array(5)].map((_, i) => ( + + {i % 2 === 0 ? : } + + ))} +
+ + +
+
+
+ +
+ + +
+ + + + IRIS Neural Core + + + + + + + + +

+ {glitchText} +

+ + + 404 + + + 404 + + +
+ {"<<"} +
+
+ {"/>"} +
+
+ +
+

+ PAGE_NOT_FOUND +

+
+ +
+ + Pathway Not Found +
+ + +
+
+ + DIAGNOSTIC_STREAM +
+
+
+
+
+
+
+ +
+ {[ + { label: "ERROR_CODE", value: "0x404_PAGE_NULL", icon: AlertTriangle }, + { label: "AI_CORE", value: "IRIS_OFFLINE", icon: Activity }, + { label: "REALITY_ANCHOR", value: "UNSTABLE", icon: Zap }, + { label: "TIMESTAMP", value: new Date().toISOString(), icon: RiSignalTowerLine }, + ].map((row, idx) => ( +
+ + + {row.label} + + {row.value} +
+ ))} +
+ +
+ +
+ + +
+ + + + + Return to Base + +
+ + + + window.history.back()} + className="cursor-pointer iris-btn group relative w-full sm:w-auto px-10 py-4 bg-[#00ff41]/5 border border-[#00ff41]/40 text-[#00ff41] font-bold tracking-[0.2em] uppercase overflow-hidden rounded-sm hover:border-[#00ff41] hover:bg-[#00ff41]/10 transition-all duration-300" + > + + + Previous PAGE + + +
+
+ +
+
+
+
+ + + + IRIS_v1.2.4 // VOID_PAGE_SEVERED + + + + + IRIS_LINK: SEVERED + + +
+ {[...Array(10)].map((_, i) => ( + + {[...Array(20)].map(() => Math.round(Math.random())).join(" ")} + + ))} +
+
+ ); +} \ No newline at end of file