Merge version_4_1783202008767 into main #3

Merged
bender merged 2 commits from version_4_1783202008767 into main 2026-07-04 21:57:08 +00:00
4 changed files with 223 additions and 112 deletions

View File

@@ -5,15 +5,15 @@
:root {
/* @colorThemes/lightTheme/grayNavyBlue */
--background: #ffffff;
--card: #f8f9fa;
--foreground: #111827;
--primary-cta: #6366f1;
--background: #050505;
--card: #111111;
--foreground: #ffffff;
--primary-cta: #7c3aed;
--primary-cta-text: #ffffff;
--secondary-cta: #e0e7ff;
--secondary-cta-text: #4f46e5;
--accent: #6b7280;
--background-accent: #f3f4f6;
--secondary-cta: #1a1a1a;
--secondary-cta-text: #7c3aed;
--accent: #a3a3a3;
--background-accent: #0f0f0f;
/* @layout/border-radius/rounded */
--radius: 1.5rem;

View File

@@ -5,7 +5,6 @@
// become component refs.
import React from 'react';
import HeroSection from './HomePage/sections/Hero';
import AboutSection from './HomePage/sections/About';
import ServicesSection from './HomePage/sections/Services';
import TestimonialsSection from './HomePage/sections/Testimonials';
@@ -14,10 +13,11 @@ import FaqSection from './HomePage/sections/Faq';
import ContactSection from './HomePage/sections/Contact';
import MetricsSection from './HomePage/sections/Metrics';export default function HomePage(): React.JSX.Element {
import MetricsSection from './HomePage/sections/Metrics';
import HeroWebglSection from './HomePage/sections/HeroWebgl';export default function HomePage(): React.JSX.Element {
return (
<>
<HeroSection />
<HeroWebglSection />
<AboutSection />

View File

@@ -1,101 +0,0 @@
/* eslint-disable */
// @ts-nocheck — generated by catalog-eject; runtime-correct but TS strict-mode false-positives on inlined catalog body
import Button from "@/components/ui/Button";
import HeroBackgroundSlot from "@/components/ui/HeroBackgroundSlot";
import TextAnimation from "@/components/ui/TextAnimation";
import ImageOrVideo from "@/components/ui/ImageOrVideo";
import AvatarGroup from "@/components/ui/AvatarGroup";
const avatarsSrc = [
"http://img.b2bpic.net/free-photo/smiling-man-wearing-white-shirt_23-2152009541.jpg",
"http://img.b2bpic.net/free-photo/young-businesswoman-portrait-office_1262-1506.jpg",
"http://img.b2bpic.net/free-photo/emotional-young-bearded-man-asking-something-isolated-dark-wall_140725-97014.jpg",
"http://img.b2bpic.net/free-photo/crazy-hero-happy-expression_1194-4140.jpg"
];
const primaryButton = {
text: "Zistiť viac",
href: "#services"
};
const secondaryButton = {
text: "Kontaktovať nás",
href: "#contact"
};
const names = [
"Google",
"Microsoft",
"Amazon",
"Apple",
"Tesla",
"Adobe"
];
type HeroCenteredLogosProps = {
avatarsSrc: string[];
avatarText: string;
title: string;
description: string;
primaryButton: { text: string; href: string };
secondaryButton: { text: string; href: string };
names: string[];
hideMedia?: boolean;
textAnimation: "slide-up" | "fade-blur" | "fade";
} & ({ imageSrc: string; videoSrc?: never } | { videoSrc: string; imageSrc?: never });
const HeroInline = () => {
return (
<section aria-label="Hero section" className="relative h-svh flex flex-col mb-20">
<HeroBackgroundSlot />
{!undefined && (
<div className="absolute inset-0 z-0">
<ImageOrVideo imageSrc={"http://img.b2bpic.net/free-photo/color-year-purple-tones-abstract-landscape-with-fantasy-aesthetic_23-2151394052.jpg"} className="size-full object-cover" />
<div className="absolute inset-0 bg-background/80" />
</div>
)}
<div className="relative z-10 flex-1 flex items-center justify-center">
<div className="flex flex-col items-center gap-3 pt-8 w-content-width mx-auto text-center">
<AvatarGroup avatarsSrc={avatarsSrc} label={"Spolupracujeme s lídrami"} size="lg" />
<TextAnimation
text={"UvaWeb: Budúcnosť vášho marketingu začína dnes"}
variant={"fade-blur"}
gradientText={true}
tag="h1"
className="md:max-w-8/10 text-7xl 2xl:text-8xl leading-[1.15] font-semibold text-center text-balance"
/>
<TextAnimation
text={"Vytvárame pohlcujúce digitálne zážitky, ktoré definujú značky. Špičková kreativita spojená s dátami a špičkovou technológiou."}
variant={"fade-blur"}
gradientText={false}
tag="p"
className="md:max-w-7/10 text-lg md:text-xl leading-snug text-balance"
/>
<div className="flex flex-wrap justify-center gap-3 mt-2 md:mt-3">
<Button text={primaryButton.text} href={primaryButton.href} variant="primary" />
<Button text={secondaryButton.text} href={secondaryButton.href} variant="secondary" animationDelay={0.1} />
</div>
</div>
</div>
<div className="relative z-10 w-content-width mx-auto pb-8 overflow-hidden mask-fade-x">
<div className="flex w-max animate-marquee-horizontal" style={{ animationDuration: "30s" }}>
{[...names, ...names, ...names, ...names].map((name, index) => (
<div key={index} className="shrink-0 mx-3 px-4 py-2 card rounded">
<span className="text-xl font-semibold whitespace-nowrap text-foreground/75">{name}</span>
</div>
))}
</div>
</div>
</section>
);
};
export default function HeroSection() {
return (
<div data-webild-section="hero" data-section="hero" id="hero">
<HeroInline />
</div>
);
}

View File

@@ -0,0 +1,212 @@
import { useEffect, useRef, useState } from "react";
import { motion } from "motion/react";
import Button from "@/components/ui/Button";
export default function HeroWebglSection() {
const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
const canvasRef = useRef<HTMLCanvasElement>(null);
const mouseRef = useRef({ x: typeof window !== 'undefined' ? window.innerWidth / 2 : 0, y: typeof window !== 'undefined' ? window.innerHeight / 2 : 0 });
useEffect(() => {
const updateMousePosition = (e: MouseEvent) => {
setMousePosition({ x: e.clientX, y: e.clientY });
mouseRef.current = { x: e.clientX, y: e.clientY };
};
window.addEventListener("mousemove", updateMousePosition);
return () => window.removeEventListener("mousemove", updateMousePosition);
}, []);
useEffect(() => {
const canvas = canvasRef.current;
if (!canvas) return;
const gl = canvas.getContext("webgl");
if (!gl) return;
const vertexShaderSource = `
attribute vec2 position;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
}
`;
const fragmentShaderSource = `
precision highp float;
uniform vec2 u_resolution;
uniform float u_time;
uniform vec2 u_mouse;
void main() {
vec2 st = gl_FragCoord.xy / u_resolution.xy;
vec2 mouse = u_mouse / u_resolution.xy;
mouse.y = 1.0 - mouse.y;
float dist = distance(st, mouse);
float blob = smoothstep(0.8, 0.0, dist);
vec3 bg = vec3(0.02, 0.02, 0.02);
vec3 accent = vec3(0.48, 0.22, 0.92); // #7c3aed
float noise = fract(sin(dot(st.xy, vec2(12.9898, 78.233))) * 43758.5453) * 0.03;
float wave = sin(st.x * 5.0 + u_time * 0.5) * cos(st.y * 5.0 + u_time * 0.5) * 0.15;
vec3 color = mix(bg, accent, blob * 0.4 + wave);
color += noise;
gl_FragColor = vec4(color, 1.0);
}
`;
const compileShader = (type: number, source: string) => {
const shader = gl.createShader(type);
if (!shader) return null;
gl.shaderSource(shader, source);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error(gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
};
const vertexShader = compileShader(gl.VERTEX_SHADER, vertexShaderSource);
const fragmentShader = compileShader(gl.FRAGMENT_SHADER, fragmentShaderSource);
if (!vertexShader || !fragmentShader) return;
const program = gl.createProgram();
if (!program) return;
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error(gl.getProgramInfoLog(program));
return;
}
gl.useProgram(program);
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
const positions = new Float32Array([
-1.0, -1.0,
1.0, -1.0,
-1.0, 1.0,
-1.0, 1.0,
1.0, -1.0,
1.0, 1.0,
]);
gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);
const positionLocation = gl.getAttribLocation(program, "position");
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
const resolutionLocation = gl.getUniformLocation(program, "u_resolution");
const timeLocation = gl.getUniformLocation(program, "u_time");
const mouseLocation = gl.getUniformLocation(program, "u_mouse");
let animationFrameId: number;
const startTime = performance.now();
const render = () => {
const width = canvas.clientWidth;
const height = canvas.clientHeight;
if (canvas.width !== width || canvas.height !== height) {
canvas.width = width;
canvas.height = height;
gl.viewport(0, 0, width, height);
}
gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
gl.uniform1f(timeLocation, (performance.now() - startTime) / 1000.0);
gl.uniform2f(mouseLocation, mouseRef.current.x, mouseRef.current.y);
gl.drawArrays(gl.TRIANGLES, 0, 6);
animationFrameId = requestAnimationFrame(render);
};
render();
return () => {
cancelAnimationFrame(animationFrameId);
gl.deleteProgram(program);
};
}, []);
const headline = "WE BUILD LOUD IDEAS";
const letters = headline.split("");
return (
<div data-webild-section="hero-webgl" id="hero-webgl" className="relative h-screen w-full flex flex-col items-center justify-center overflow-hidden bg-background cursor-none">
{/* WebGL Background */}
<canvas ref={canvasRef} className="absolute inset-0 w-full h-full z-0" />
{/* Grain Overlay */}
<div className="pointer-events-none absolute inset-0 z-10 opacity-[0.15] mix-blend-overlay" style={{ backgroundImage: 'url("data:image/svg+xml,%3Csvg viewBox=%220 0 200 200%22 xmlns=%22http://www.w3.org/2000/svg%22%3E%3Cfilter id=%22noiseFilter%22%3E%3CfeTurbulence type=%22fractalNoise%22 baseFrequency=%220.8%22 numOctaves=%223%22 stitchTiles=%22stitch%22/%3E%3C/filter%3E%3Crect width=%22100%25%22 height=%22100%25%22 filter=%22url(%23noiseFilter)%22/%3E%3C/svg%3E")' }}></div>
{/* Custom Cursor */}
<motion.div
className="fixed top-0 left-0 w-3 h-3 bg-primary-cta rounded-full pointer-events-none z-50 mix-blend-difference"
animate={{ x: mousePosition.x - 6, y: mousePosition.y - 6 }}
transition={{ type: "spring", stiffness: 1000, damping: 40, mass: 0.1 }}
/>
<motion.div
className="fixed top-0 left-0 w-10 h-10 border border-primary-cta rounded-full pointer-events-none z-50 mix-blend-difference"
animate={{ x: mousePosition.x - 20, y: mousePosition.y - 20 }}
transition={{ type: "spring", stiffness: 250, damping: 20, mass: 0.8 }}
/>
<div className="relative z-20 flex flex-col items-center justify-center w-content-width mx-auto text-center pointer-events-none">
<h1 className="text-[12vw] md:text-[9vw] font-bold text-foreground tracking-tighter leading-[0.85] flex flex-wrap justify-center uppercase">
{letters.map((letter, i) => (
<motion.span
key={i}
initial={{ opacity: 0, y: 100, rotateX: -90 }}
animate={{ opacity: 1, y: 0, rotateX: 0 }}
transition={{ duration: 1, delay: i * 0.05, type: "spring", damping: 15, stiffness: 100 }}
style={{ display: letter === " " ? "inline" : "inline-block", width: letter === " " ? "0.3em" : "auto", transformOrigin: "bottom" }}
>
{letter}
</motion.span>
))}
</h1>
<motion.p
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 1, delay: 1.5 }}
className="mt-8 text-xl md:text-2xl text-accent max-w-2xl"
>
A flagship digital experience. We craft award-winning brands and high-performance platforms.
</motion.p>
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 1, delay: 1.8 }}
className="mt-12 pointer-events-auto"
>
<Button text="Explore Our Work" href="#work" variant="primary" className="rounded-full px-8 py-4 text-lg" />
</motion.div>
</div>
{/* Scroll Down Indicator */}
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 1, delay: 2.5 }}
className="absolute bottom-10 left-1/2 -translate-x-1/2 flex flex-col items-center gap-2 z-20 pointer-events-none"
>
<span className="text-xs uppercase tracking-widest text-accent">Scroll</span>
<motion.div
animate={{ y: [0, 10, 0] }}
transition={{ repeat: Infinity, duration: 1.5, ease: "easeInOut" }}
className="w-[1px] h-12 bg-gradient-to-b from-primary-cta to-transparent"
/>
</motion.div>
</div>
);
}