diff --git a/public/HATER2.jpg b/public/HATER2.jpg new file mode 100644 index 0000000..035c796 Binary files /dev/null and b/public/HATER2.jpg differ diff --git a/public/no_pigeons_zone.gif b/public/no_pigeons_zone.gif new file mode 100644 index 0000000..c484c57 Binary files /dev/null and b/public/no_pigeons_zone.gif differ diff --git a/public/open 24 hours.gif b/public/open 24 hours.gif new file mode 100644 index 0000000..fbfbf7e Binary files /dev/null and b/public/open 24 hours.gif differ diff --git a/public/welcome.gif b/public/welcome.gif new file mode 100644 index 0000000..ac761ef Binary files /dev/null and b/public/welcome.gif differ diff --git a/src/components/DepthMap.tsx b/src/components/DepthMap.tsx new file mode 100644 index 0000000..6140cf2 --- /dev/null +++ b/src/components/DepthMap.tsx @@ -0,0 +1,142 @@ +"use client"; + +import { useEffect, useRef, useState } from "react"; + +interface DepthMapProps { + originalImg: string; + depthImg: string; + verticalThreshold?: number; + horizontalThreshold?: number; +} + +export function DepthMap({ + originalImg, + depthImg, + verticalThreshold = 15, + horizontalThreshold = 15, +}: DepthMapProps) { + const canvasRef = useRef(null); + const [mousePos, setMousePos] = useState({ x: 0.5, y: 0.5 }); + const [loaded, setLoaded] = useState(false); + const originalImgRef = useRef(null); + const depthImgRef = useRef(null); + + useEffect(() => { + const canvas = canvasRef.current; + if (!canvas) return; + + const ctx = canvas.getContext("2d"); + if (!ctx) return; + + // Load images + const original = new Image(); + const depth = new Image(); + + original.crossOrigin = "anonymous"; + depth.crossOrigin = "anonymous"; + + let loadedCount = 0; + const onLoad = () => { + loadedCount++; + if (loadedCount === 2) { + originalImgRef.current = original; + depthImgRef.current = depth; + setLoaded(true); + } + }; + + original.onload = onLoad; + depth.onload = onLoad; + original.src = originalImg; + depth.src = depthImg; + }, [originalImg, depthImg]); + + useEffect(() => { + if (!loaded || !canvasRef.current) return; + + const canvas = canvasRef.current; + const ctx = canvas.getContext("2d"); + if (!ctx || !originalImgRef.current || !depthImgRef.current) return; + + const original = originalImgRef.current; + const depth = depthImgRef.current; + + // Set canvas size to match image + canvas.width = original.width; + canvas.height = original.height; + + // Calculate displacement based on mouse position + const offsetX = (mousePos.x - 0.5) * horizontalThreshold; + const offsetY = (mousePos.y - 0.5) * verticalThreshold; + + // Clear canvas + ctx.clearRect(0, 0, canvas.width, canvas.height); + + // Draw the original image + ctx.drawImage(original, 0, 0); + + // Get image data for manipulation + const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); + const pixels = imageData.data; + + // Draw depth map to get depth values + ctx.drawImage(depth, 0, 0); + const depthData = ctx.getImageData(0, 0, canvas.width, canvas.height); + const depthPixels = depthData.data; + + // Create displaced image + const displaced = ctx.createImageData(canvas.width, canvas.height); + + for (let y = 0; y < canvas.height; y++) { + for (let x = 0; x < canvas.width; x++) { + const idx = (y * canvas.width + x) * 4; + + // Get depth value (using red channel) - inverted so darker = more movement + const depthValue = 1 - (depthPixels[idx] / 255); + + // Calculate displacement + const displaceX = Math.round(offsetX * depthValue); + const displaceY = Math.round(offsetY * depthValue); + + // Source pixel position + const srcX = Math.max(0, Math.min(canvas.width - 1, x - displaceX)); + const srcY = Math.max(0, Math.min(canvas.height - 1, y - displaceY)); + const srcIdx = (srcY * canvas.width + srcX) * 4; + + // Copy pixel + displaced.data[idx] = pixels[srcIdx]; + displaced.data[idx + 1] = pixels[srcIdx + 1]; + displaced.data[idx + 2] = pixels[srcIdx + 2]; + displaced.data[idx + 3] = pixels[srcIdx + 3]; + } + } + + ctx.putImageData(displaced, 0, 0); + }, [loaded, mousePos, horizontalThreshold, verticalThreshold]); + + const handleMouseMove = (e: React.MouseEvent) => { + const canvas = canvasRef.current; + if (!canvas) return; + + const rect = canvas.getBoundingClientRect(); + const x = (e.clientX - rect.left) / rect.width; + const y = (e.clientY - rect.top) / rect.height; + + setMousePos({ x, y }); + }; + + const handleMouseLeave = () => { + setMousePos({ x: 0.5, y: 0.5 }); + }; + + return ( + + ); +} + diff --git a/src/components/Temp-Placeholder.tsx b/src/components/Temp-Placeholder.tsx index 7fbd634..8a2a066 100644 --- a/src/components/Temp-Placeholder.tsx +++ b/src/components/Temp-Placeholder.tsx @@ -4,8 +4,8 @@ import { CursorDotBackground } from "./CursorDotBackground"; import { HorizontalAccordion } from "./HorizontalAccordion"; import { InstagramFeed } from "./InstagramFeed"; import { useEffect, useRef, useState } from "react"; -import Image from "next/image"; import { motion, AnimatePresence } from "framer-motion"; +import { DepthMap } from "./DepthMap"; export function TempPlaceholder() { const titleRef = useRef(null); @@ -168,12 +168,11 @@ export function TempPlaceholder() { }} className="relative w-full aspect-square" > - Easter egg diff --git a/src/middleware.ts b/src/middleware.ts index dcbc135..61bc9ec 100644 --- a/src/middleware.ts +++ b/src/middleware.ts @@ -5,7 +5,7 @@ export function middleware(request: NextRequest) { const { pathname } = request.nextUrl; // Allow only the home page and Next.js internal routes - if (pathname === '/' || pathname.startsWith('/_next') || pathname.startsWith('/favicon.') || pathname === '/OLIVER.jpeg') { + if (pathname === '/' || pathname.startsWith('/_next') || pathname.startsWith('/favicon.') || pathname === '/OLIVER.jpeg' || pathname === '/OLIVER_depth.jpeg') { return NextResponse.next(); }