Added Silk component for animated background in Hero section
This commit is contained in:
@@ -2,6 +2,7 @@ import { Link } from "react-router-dom";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { ArrowRight } from "lucide-react";
|
import { ArrowRight } from "lucide-react";
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
|
import Silk from "@/components/Silk";
|
||||||
|
|
||||||
const FOUNDING_DATE = new Date("2026-01-25"); // Samstag, 25. Januar 2026
|
const FOUNDING_DATE = new Date("2026-01-25"); // Samstag, 25. Januar 2026
|
||||||
|
|
||||||
@@ -35,10 +36,18 @@ const Hero = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="relative min-h-screen flex flex-col justify-center bg-background overflow-hidden pt-20">
|
<section className="relative min-h-screen flex flex-col justify-center overflow-hidden pt-20">
|
||||||
{/* Subtle grid lines */}
|
{/* Silk animated background */}
|
||||||
<div className="absolute inset-0 grid-lines opacity-30" />
|
<div className="absolute inset-0 z-0 w-full h-full">
|
||||||
|
<Silk
|
||||||
|
speed={5}
|
||||||
|
scale={1}
|
||||||
|
color="#7B7481"
|
||||||
|
noiseIntensity={1.5}
|
||||||
|
rotation={0}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="container mx-auto px-6 relative z-10">
|
<div className="container mx-auto px-6 relative z-10">
|
||||||
<div className="max-w-6xl">
|
<div className="max-w-6xl">
|
||||||
{/* Label */}
|
{/* Label */}
|
||||||
|
|||||||
158
src/components/Silk.tsx
Normal file
158
src/components/Silk.tsx
Normal file
@@ -0,0 +1,158 @@
|
|||||||
|
/* eslint-disable react/no-unknown-property */
|
||||||
|
import { Canvas, useFrame, useThree } from "@react-three/fiber";
|
||||||
|
import { forwardRef, useRef, useMemo, useLayoutEffect } from "react";
|
||||||
|
import { Color, type Mesh, type ShaderMaterial } from "three";
|
||||||
|
|
||||||
|
const hexToNormalizedRGB = (hex: string): [number, number, number] => {
|
||||||
|
hex = hex.replace("#", "");
|
||||||
|
return [
|
||||||
|
parseInt(hex.slice(0, 2), 16) / 255,
|
||||||
|
parseInt(hex.slice(2, 4), 16) / 255,
|
||||||
|
parseInt(hex.slice(4, 6), 16) / 255,
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
const vertexShader = `
|
||||||
|
varying vec2 vUv;
|
||||||
|
varying vec3 vPosition;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vPosition = position;
|
||||||
|
vUv = uv;
|
||||||
|
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const fragmentShader = `
|
||||||
|
varying vec2 vUv;
|
||||||
|
varying vec3 vPosition;
|
||||||
|
|
||||||
|
uniform float uTime;
|
||||||
|
uniform vec3 uColor;
|
||||||
|
uniform float uSpeed;
|
||||||
|
uniform float uScale;
|
||||||
|
uniform float uRotation;
|
||||||
|
uniform float uNoiseIntensity;
|
||||||
|
|
||||||
|
const float e = 2.71828182845904523536;
|
||||||
|
|
||||||
|
float noise(vec2 texCoord) {
|
||||||
|
float G = e;
|
||||||
|
vec2 r = (G * sin(G * texCoord));
|
||||||
|
return fract(r.x * r.y * (1.0 + texCoord.x));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 rotateUvs(vec2 uv, float angle) {
|
||||||
|
float c = cos(angle);
|
||||||
|
float s = sin(angle);
|
||||||
|
mat2 rot = mat2(c, -s, s, c);
|
||||||
|
return rot * uv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
float rnd = noise(gl_FragCoord.xy);
|
||||||
|
vec2 uv = rotateUvs(vUv * uScale, uRotation);
|
||||||
|
vec2 tex = uv * uScale;
|
||||||
|
float tOffset = uSpeed * uTime;
|
||||||
|
|
||||||
|
tex.y += 0.03 * sin(8.0 * tex.x - tOffset);
|
||||||
|
|
||||||
|
float pattern = 0.6 +
|
||||||
|
0.4 * sin(5.0 * (tex.x + tex.y +
|
||||||
|
cos(3.0 * tex.x + 5.0 * tex.y) +
|
||||||
|
0.02 * tOffset) +
|
||||||
|
sin(20.0 * (tex.x + tex.y - 0.1 * tOffset)));
|
||||||
|
|
||||||
|
vec4 col = vec4(uColor, 1.0) * vec4(pattern) - rnd / 15.0 * uNoiseIntensity;
|
||||||
|
col.a = 1.0;
|
||||||
|
gl_FragColor = col;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
type SilkPlaneProps = {
|
||||||
|
uniforms: {
|
||||||
|
uSpeed: { value: number };
|
||||||
|
uScale: { value: number };
|
||||||
|
uNoiseIntensity: { value: number };
|
||||||
|
uColor: { value: Color };
|
||||||
|
uRotation: { value: number };
|
||||||
|
uTime: { value: number };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const SilkPlane = forwardRef<Mesh, SilkPlaneProps>(function SilkPlane(
|
||||||
|
{ uniforms },
|
||||||
|
ref
|
||||||
|
) {
|
||||||
|
const { viewport } = useThree();
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
if (ref && typeof ref !== "function" && ref.current) {
|
||||||
|
ref.current.scale.set(viewport.width, viewport.height, 1);
|
||||||
|
}
|
||||||
|
}, [ref, viewport]);
|
||||||
|
|
||||||
|
useFrame((_, delta) => {
|
||||||
|
if (ref && typeof ref !== "function" && ref.current) {
|
||||||
|
const mat = ref.current.material as ShaderMaterial & {
|
||||||
|
uniforms: { uTime: { value: number } };
|
||||||
|
};
|
||||||
|
if (mat.uniforms?.uTime) mat.uniforms.uTime.value += 0.1 * delta;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<mesh ref={ref}>
|
||||||
|
<planeGeometry args={[1, 1, 1, 1]} />
|
||||||
|
<shaderMaterial
|
||||||
|
uniforms={uniforms}
|
||||||
|
vertexShader={vertexShader}
|
||||||
|
fragmentShader={fragmentShader}
|
||||||
|
/>
|
||||||
|
</mesh>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
SilkPlane.displayName = "SilkPlane";
|
||||||
|
|
||||||
|
type SilkProps = {
|
||||||
|
speed?: number;
|
||||||
|
scale?: number;
|
||||||
|
color?: string;
|
||||||
|
noiseIntensity?: number;
|
||||||
|
rotation?: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const Silk = ({
|
||||||
|
speed = 5,
|
||||||
|
scale = 1,
|
||||||
|
color = "#7B7481",
|
||||||
|
noiseIntensity = 1.5,
|
||||||
|
rotation = 0,
|
||||||
|
}: SilkProps) => {
|
||||||
|
const meshRef = useRef<Mesh>(null);
|
||||||
|
|
||||||
|
const uniforms = useMemo(
|
||||||
|
() => ({
|
||||||
|
uSpeed: { value: speed },
|
||||||
|
uScale: { value: scale },
|
||||||
|
uNoiseIntensity: { value: noiseIntensity },
|
||||||
|
uColor: { value: new Color(...hexToNormalizedRGB(color)) },
|
||||||
|
uRotation: { value: rotation },
|
||||||
|
uTime: { value: 0 },
|
||||||
|
}),
|
||||||
|
[speed, scale, noiseIntensity, color, rotation]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Canvas
|
||||||
|
dpr={[1, 2]}
|
||||||
|
frameloop="always"
|
||||||
|
style={{ width: "100%", height: "100%" }}
|
||||||
|
camera={{ position: [0, 0, 5], fov: 75 }}
|
||||||
|
>
|
||||||
|
<SilkPlane ref={meshRef} uniforms={uniforms} />
|
||||||
|
</Canvas>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Silk;
|
||||||
Reference in New Issue
Block a user