update home page

This commit is contained in:
2026-06-18 16:32:31 +05:30
parent d9cc83aa82
commit 8e0d704438
57 changed files with 2813 additions and 301 deletions

View File

@@ -0,0 +1,214 @@
"use client";
import { useEffect, useRef } from "react";
import { Mesh, Plane, Program, Renderer, Texture } from "ogl";
const vertex = `
attribute vec2 uv;
attribute vec2 position;
varying vec2 vUv;
void main() {
vUv = uv;
gl_Position = vec4(position, 0.0, 1.0);
}
`;
const fragment = `
precision highp float;
uniform sampler2D tMap;
uniform vec2 uResolution;
uniform vec2 uImageResolution;
uniform vec2 uPointer;
uniform vec2 uVelocity;
uniform float uStrength;
varying vec2 vUv;
vec2 coverUv(vec2 uv, vec2 screen, vec2 image) {
float screenRatio = screen.x / screen.y;
float imageRatio = image.x / image.y;
vec2 scale = vec2(1.0);
if (screenRatio > imageRatio) {
scale.y = imageRatio / screenRatio;
} else {
scale.x = screenRatio / imageRatio;
}
return (uv - 0.5) * scale + 0.5;
}
void main() {
vec2 uv = coverUv(vUv, uResolution, uImageResolution);
vec2 pointerDelta = uv - uPointer;
float distanceFromPointer = length(pointerDelta);
float cursorMask = smoothstep(0.36, 0.0, distanceFromPointer);
float innerMask = smoothstep(0.16, 0.0, distanceFromPointer);
vec2 pull = normalize(pointerDelta + 0.0001) * innerMask * 0.0035;
vec2 distortion = ((uVelocity * 0.075) - pull) * cursorMask * uStrength;
uv += distortion;
float red = texture2D(tMap, uv + distortion * 0.12).r;
float green = texture2D(tMap, uv).g;
float blue = texture2D(tMap, uv - distortion * 0.1).b;
gl_FragColor = vec4(red, green, blue, 1.0);
}
`;
interface HeroImageSceneProps {
imageSrc: string;
}
export function HeroImageScene({ imageSrc }: HeroImageSceneProps) {
const rootRef = useRef<HTMLDivElement>(null);
const pointerRef = useRef({ x: 0.5, y: 0.5 });
const velocityRef = useRef({ x: 0, y: 0 });
const strengthRef = useRef(0);
const lastMoveTimeRef = useRef(0);
useEffect(() => {
const root = rootRef.current;
if (!root) return;
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)");
if (reduceMotion.matches) return;
const renderer = new Renderer({
alpha: true,
antialias: true,
dpr: Math.min(window.devicePixelRatio, 2),
});
const gl = renderer.gl;
root.appendChild(gl.canvas);
gl.canvas.className = "absolute inset-0 h-full w-full";
gl.clearColor(0, 0, 0, 0);
const texture = new Texture(gl, {
generateMipmaps: false,
minFilter: gl.LINEAR,
magFilter: gl.LINEAR,
});
const image = new Image();
image.src = imageSrc;
image.onload = () => {
texture.image = image;
texture.needsUpdate = true;
};
const program = new Program(gl, {
vertex,
fragment,
uniforms: {
tMap: { value: texture },
uResolution: { value: [1, 1] },
uImageResolution: { value: [1883, 855] },
uPointer: { value: [0.5, 0.5] },
uVelocity: { value: [0, 0] },
uStrength: { value: 0 },
},
transparent: true,
});
const mesh = new Mesh(gl, {
geometry: new Plane(gl, { width: 2, height: 2 }),
program,
});
let animationFrame = 0;
let width = 1;
let height = 1;
const resize = () => {
const rect = root.getBoundingClientRect();
width = Math.max(1, rect.width);
height = Math.max(1, rect.height);
renderer.setSize(width, height);
program.uniforms.uResolution.value = [width, height];
};
const onPointerMove = (event: PointerEvent) => {
const rect = root.getBoundingClientRect();
const isInside =
event.clientX >= rect.left &&
event.clientX <= rect.right &&
event.clientY >= rect.top &&
event.clientY <= rect.bottom;
if (!isInside) {
velocityRef.current = { x: 0, y: 0 };
return;
}
const nextPointer = {
x: (event.clientX - rect.left) / rect.width,
y: 1 - (event.clientY - rect.top) / rect.height,
};
const now = performance.now();
const elapsed = Math.max(16, now - lastMoveTimeRef.current);
lastMoveTimeRef.current = now;
velocityRef.current = {
x: ((nextPointer.x - pointerRef.current.x) / elapsed) * 16.67,
y: ((nextPointer.y - pointerRef.current.y) / elapsed) * 16.67,
};
pointerRef.current = nextPointer;
strengthRef.current = Math.min(1, strengthRef.current + 0.72);
};
const onPointerLeave = () => {
velocityRef.current = { x: 0, y: 0 };
};
const render = () => {
strengthRef.current *= 0.86;
velocityRef.current = {
x: velocityRef.current.x * 0.74,
y: velocityRef.current.y * 0.74,
};
program.uniforms.uPointer.value = [
pointerRef.current.x,
pointerRef.current.y,
];
program.uniforms.uVelocity.value = [
velocityRef.current.x,
velocityRef.current.y,
];
program.uniforms.uStrength.value = strengthRef.current;
renderer.render({ scene: mesh });
animationFrame = requestAnimationFrame(render);
};
const observer = new ResizeObserver(resize);
observer.observe(root);
window.addEventListener("pointermove", onPointerMove);
root.addEventListener("pointerleave", onPointerLeave);
resize();
animationFrame = requestAnimationFrame(render);
return () => {
cancelAnimationFrame(animationFrame);
observer.disconnect();
window.removeEventListener("pointermove", onPointerMove);
root.removeEventListener("pointerleave", onPointerLeave);
gl.canvas.remove();
};
}, [imageSrc]);
return (
<div
ref={rootRef}
aria-hidden="true"
className="hero-ogl-scene absolute inset-[-18px]"
>
<div
className="absolute inset-0 bg-cover bg-center"
style={{ backgroundImage: `url(${imageSrc})` }}
/>
</div>
);
}