From a958d5353414f287613c2d1b87c1d0a51e7ca2a6 Mon Sep 17 00:00:00 2001 From: kudinDmitriyUp Date: Sat, 4 Jul 2026 21:54:02 +0000 Subject: [PATCH 1/2] Bob AI: Update global theme to dark mode with ultraviolet accent --- src/index.css | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/index.css b/src/index.css index d72a363..3b5461d 100644 --- a/src/index.css +++ b/src/index.css @@ -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; -- 2.49.1 From 1564199c5151a1054d02e80454ef83d24476b4ef Mon Sep 17 00:00:00 2001 From: kudinDmitriyUp Date: Sat, 4 Jul 2026 21:56:19 +0000 Subject: [PATCH 2/2] Bob AI: Replace hero section with custom WebGL interactive backgroun --- src/pages/HomePage.tsx | 6 +- src/pages/HomePage/sections/Hero.tsx | 101 ----------- src/pages/HomePage/sections/HeroWebgl.tsx | 212 ++++++++++++++++++++++ 3 files changed, 215 insertions(+), 104 deletions(-) delete mode 100644 src/pages/HomePage/sections/Hero.tsx create mode 100644 src/pages/HomePage/sections/HeroWebgl.tsx diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx index 9bfe142..eea2292 100644 --- a/src/pages/HomePage.tsx +++ b/src/pages/HomePage.tsx @@ -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 ( <> - + diff --git a/src/pages/HomePage/sections/Hero.tsx b/src/pages/HomePage/sections/Hero.tsx deleted file mode 100644 index 2891a83..0000000 --- a/src/pages/HomePage/sections/Hero.tsx +++ /dev/null @@ -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 ( -
- - {!undefined && ( -
- -
-
- )} - -
-
- - - - - - -
-
-
-
- -
-
- {[...names, ...names, ...names, ...names].map((name, index) => ( -
- {name} -
- ))} -
-
-
- ); -}; - -export default function HeroSection() { - return ( -
- -
- ); -} diff --git a/src/pages/HomePage/sections/HeroWebgl.tsx b/src/pages/HomePage/sections/HeroWebgl.tsx new file mode 100644 index 0000000..5bf4d12 --- /dev/null +++ b/src/pages/HomePage/sections/HeroWebgl.tsx @@ -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(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 ( +
+ {/* WebGL Background */} + + + {/* Grain Overlay */} +
+ + {/* Custom Cursor */} + + + +
+

+ {letters.map((letter, i) => ( + + {letter} + + ))} +

+ + + A flagship digital experience. We craft award-winning brands and high-performance platforms. + + + +
+ + {/* Scroll Down Indicator */} + + Scroll + + +
+ ); +} \ No newline at end of file -- 2.49.1