added depthmap to oliver
This commit is contained in:
parent
7af9d05f48
commit
94b9eeea15
BIN
public/HATER2.jpg
Normal file
BIN
public/HATER2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.8 KiB |
BIN
public/no_pigeons_zone.gif
Normal file
BIN
public/no_pigeons_zone.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 34 KiB |
BIN
public/open 24 hours.gif
Normal file
BIN
public/open 24 hours.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.8 KiB |
BIN
public/welcome.gif
Normal file
BIN
public/welcome.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
142
src/components/DepthMap.tsx
Normal file
142
src/components/DepthMap.tsx
Normal file
@ -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<HTMLCanvasElement>(null);
|
||||||
|
const [mousePos, setMousePos] = useState({ x: 0.5, y: 0.5 });
|
||||||
|
const [loaded, setLoaded] = useState(false);
|
||||||
|
const originalImgRef = useRef<HTMLImageElement | null>(null);
|
||||||
|
const depthImgRef = useRef<HTMLImageElement | null>(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<HTMLCanvasElement>) => {
|
||||||
|
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 (
|
||||||
|
<canvas
|
||||||
|
ref={canvasRef}
|
||||||
|
onMouseMove={handleMouseMove}
|
||||||
|
onMouseLeave={handleMouseLeave}
|
||||||
|
className="w-full h-full object-cover"
|
||||||
|
style={{ display: loaded ? 'block' : 'none' }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@ -4,8 +4,8 @@ import { CursorDotBackground } from "./CursorDotBackground";
|
|||||||
import { HorizontalAccordion } from "./HorizontalAccordion";
|
import { HorizontalAccordion } from "./HorizontalAccordion";
|
||||||
import { InstagramFeed } from "./InstagramFeed";
|
import { InstagramFeed } from "./InstagramFeed";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import Image from "next/image";
|
|
||||||
import { motion, AnimatePresence } from "framer-motion";
|
import { motion, AnimatePresence } from "framer-motion";
|
||||||
|
import { DepthMap } from "./DepthMap";
|
||||||
|
|
||||||
export function TempPlaceholder() {
|
export function TempPlaceholder() {
|
||||||
const titleRef = useRef<HTMLHeadingElement | null>(null);
|
const titleRef = useRef<HTMLHeadingElement | null>(null);
|
||||||
@ -168,12 +168,11 @@ export function TempPlaceholder() {
|
|||||||
}}
|
}}
|
||||||
className="relative w-full aspect-square"
|
className="relative w-full aspect-square"
|
||||||
>
|
>
|
||||||
<Image
|
<DepthMap
|
||||||
src="/OLIVER.jpeg"
|
originalImg="/OLIVER.jpeg"
|
||||||
alt="Easter egg"
|
depthImg="/OLIVER_depth.jpeg"
|
||||||
fill
|
verticalThreshold={40}
|
||||||
unoptimized
|
horizontalThreshold={70}
|
||||||
className="object-cover"
|
|
||||||
/>
|
/>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -5,7 +5,7 @@ export function middleware(request: NextRequest) {
|
|||||||
const { pathname } = request.nextUrl;
|
const { pathname } = request.nextUrl;
|
||||||
|
|
||||||
// Allow only the home page and Next.js internal routes
|
// 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();
|
return NextResponse.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user