diff --git a/src/app/(main)/_components/hero.tsx b/src/app/(main)/_components/hero.tsx index c479f21..53abdfc 100644 --- a/src/app/(main)/_components/hero.tsx +++ b/src/app/(main)/_components/hero.tsx @@ -15,6 +15,7 @@ import { Button, buttonVariants } from "@/components/ui/button"; import { montserrat, spaceGrotesk } from "@/app/fonts"; import { PrivyInterface, usePrivy } from "@privy-io/react-auth"; import { Skeleton } from "@/components/ui/skeleton"; +import { LetterGlitch } from "@/components/letter-glitch"; function HeroPill() { return ( @@ -74,8 +75,8 @@ function HeroTitles() { -
- - - +
+
+
+
+ + + +
+
+
diff --git a/src/app/(main)/_components/roadmap.tsx b/src/app/(main)/_components/roadmap.tsx index 9e97032..d948ac3 100644 --- a/src/app/(main)/_components/roadmap.tsx +++ b/src/app/(main)/_components/roadmap.tsx @@ -9,25 +9,20 @@ import { spaceGrotesk } from "@/app/fonts"; import Link from "next/link"; import { buttonVariants } from "@/components/ui/button"; import Image from "next/image"; +import { LetterGlitch } from "@/components/letter-glitch"; +import { SevenSegmentDigit } from "@/components/seven-segment-digit"; const ROADMAPS = [ - "Lorem ipsum dolor sit amet consectetur. Et dictum at egestas nisl. Aenean ut a augue viverra adipiscing mi nisl ullamcorper mauris. Ipsum varius ullamcorper mi suscipit. Justo eget faucibus aliquet dui pellentesque sit vitae pellentesque.", - "Lorem ipsum dolor sit amet consectetur. Et dictum at egestas nisl. Aenean ut a augue viverra adipiscing mi nisl ullamcorper mauris. Ipsum varius ullamcorper mi suscipit. Justo eget faucibus aliquet dui pellentesque sit vitae pellentesque.", - "Lorem ipsum dolor sit amet consectetur. Et dictum at egestas nisl. Aenean ut a augue viverra adipiscing mi nisl ullamcorper mauris. Ipsum varius ullamcorper mi suscipit. Justo eget faucibus aliquet dui pellentesque sit vitae pellentesque.", - "Lorem ipsum dolor sit amet consectetur. Et dictum at egestas nisl. Aenean ut a augue viverra adipiscing mi nisl ullamcorper mauris. Ipsum varius ullamcorper mi suscipit. Justo eget faucibus aliquet dui pellentesque sit vitae pellentesque.", + "Optimize inference pipelines to reduce latency and enhance memory efficiency. Introduce dynamic model selection for improved performance. Develop stateful agents capable of maintaining context across interactions.", + "Enable multi-agent collaboration for task delegation and workflow automation. Integrate knowledge graphs to enhance reasoning and decision-making. Develop an interactive agent dashboard for better visualization and control.", + "Strengthen data security with access controls and compliance measures. Expand deployment flexibility with on-premises and cloud options. Enhance API capabilities for seamless third-party integration.", + "Launch a plugin marketplace for custom agent extensions. Develop low-code/no-code tools for easy deployment. Explore AI-driven automation in robotics and IoT applications.", ]; export function Roadmap() { return (
-
+
@@ -82,15 +77,23 @@ export function Roadmap() { >
  • -

    {idx + 1}

    -

    Q{idx + 1} 2025

    + +

    Q{idx + 1} 2025

    Phase 0{idx + 1}

    -

    {roadmap}

    +

    {roadmap}

  • ))} +
    ); diff --git a/src/app/(main)/page.tsx b/src/app/(main)/page.tsx index 274726c..5f8c602 100644 --- a/src/app/(main)/page.tsx +++ b/src/app/(main)/page.tsx @@ -9,7 +9,7 @@ import { Footer } from "@/components/footer"; export default function Home() { return ( <> -
    +

    diff --git a/src/components/letter-glitch.tsx b/src/components/letter-glitch.tsx new file mode 100644 index 0000000..6a08a63 --- /dev/null +++ b/src/components/letter-glitch.tsx @@ -0,0 +1,301 @@ +"use client"; + +import { cn } from "@/lib/utils"; +import { useRef, useEffect } from "react"; + +export function LetterGlitch({ + glitchColors = ["#2b4539", "#61dca3", "#61b3dc"], + glitchSpeed = 50, + centerVignette = false, + outerVignette = true, + smooth = true, + className, +}: { + glitchColors?: string[]; + glitchSpeed: number; + centerVignette: boolean; + outerVignette: boolean; + smooth: boolean; + className: string; +}) { + const canvasRef = useRef(null); + const animationRef = useRef(null); + const letters = useRef< + { + char: string; + color: string; + targetColor: string; + colorProgress: number; + }[] + >([]); + const grid = useRef({ columns: 0, rows: 0 }); + const context = useRef(null); + const lastGlitchTime = useRef(Date.now()); + + const fontSize = 16; + const charWidth = 10; + const charHeight = 20; + + const lettersAndSymbols = [ + "A", + "B", + "C", + "D", + "E", + "F", + "G", + "H", + "I", + "J", + "K", + "L", + "M", + "N", + "O", + "P", + "Q", + "R", + "S", + "T", + "U", + "V", + "W", + "X", + "Y", + "Z", + "!", + "@", + "#", + "$", + "&", + "*", + "(", + ")", + "-", + "_", + "+", + "=", + "/", + "[", + "]", + "{", + "}", + ";", + ":", + "<", + ">", + ",", + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + ]; + + const getRandomChar = () => { + return lettersAndSymbols[ + Math.floor(Math.random() * lettersAndSymbols.length) + ]; + }; + + const getRandomColor = () => { + return glitchColors[Math.floor(Math.random() * glitchColors.length)]; + }; + + const hexToRgb = (hex: string) => { + const shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; + hex = hex.replace(shorthandRegex, (m, r, g, b) => { + return r + r + g + g + b + b; + }); + + const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + return result + ? { + r: parseInt(result[1], 16), + g: parseInt(result[2], 16), + b: parseInt(result[3], 16), + } + : null; + }; + + const interpolateColor = ( + start: { r: number; g: number; b: number }, + end: { r: number; g: number; b: number }, + factor: number + ) => { + const result = { + r: Math.round(start.r + (end.r - start.r) * factor), + g: Math.round(start.g + (end.g - start.g) * factor), + b: Math.round(start.b + (end.b - start.b) * factor), + }; + return `rgb(${result.r}, ${result.g}, ${result.b})`; + }; + + const calculateGrid = (width: number, height: number) => { + const columns = Math.ceil(width / charWidth); + const rows = Math.ceil(height / charHeight); + return { columns, rows }; + }; + + const initializeLetters = (columns: number, rows: number) => { + grid.current = { columns, rows }; + const totalLetters = columns * rows; + letters.current = Array.from({ length: totalLetters }, () => ({ + char: getRandomChar(), + color: getRandomColor(), + targetColor: getRandomColor(), + colorProgress: 1, + })); + }; + + const resizeCanvas = () => { + const canvas = canvasRef.current; + if (!canvas) return; + const parent = canvas.parentElement; + if (!parent) return; + + const dpr = window.devicePixelRatio || 1; + const rect = parent.getBoundingClientRect(); + + canvas.width = rect.width * dpr; + canvas.height = rect.height * dpr; + + canvas.style.width = `${rect.width}px`; + canvas.style.height = `${rect.height}px`; + + if (context.current) { + context.current.setTransform(dpr, 0, 0, dpr, 0, 0); + } + + const { columns, rows } = calculateGrid(rect.width, rect.height); + initializeLetters(columns, rows); + drawLetters(); + }; + + const drawLetters = () => { + if (!context.current || letters.current.length === 0) return; + const ctx = context.current; + const { width, height } = canvasRef.current!.getBoundingClientRect(); + ctx.clearRect(0, 0, width, height); + ctx.font = `${fontSize}px monospace`; + ctx.textBaseline = "top"; + + letters.current.forEach((letter, index) => { + const x = (index % grid.current.columns) * charWidth; + const y = Math.floor(index / grid.current.columns) * charHeight; + ctx.fillStyle = letter.color; + ctx.fillText(letter.char, x, y); + }); + }; + + const updateLetters = () => { + if (!letters.current || letters.current.length === 0) return; // Prevent accessing empty array + + const updateCount = Math.max(1, Math.floor(letters.current.length * 0.05)); + + for (let i = 0; i < updateCount; i++) { + const index = Math.floor(Math.random() * letters.current.length); + if (!letters.current[index]) continue; // Skip if index is invalid + + letters.current[index].char = getRandomChar(); + letters.current[index].targetColor = getRandomColor(); + + if (!smooth) { + letters.current[index].color = letters.current[index].targetColor; + letters.current[index].colorProgress = 1; + } else { + letters.current[index].colorProgress = 0; + } + } + }; + + const handleSmoothTransitions = () => { + let needsRedraw = false; + letters.current.forEach((letter) => { + if (letter.colorProgress < 1) { + letter.colorProgress += 0.05; + if (letter.colorProgress > 1) letter.colorProgress = 1; + + const startRgb = hexToRgb(letter.color); + const endRgb = hexToRgb(letter.targetColor); + if (startRgb && endRgb) { + letter.color = interpolateColor( + startRgb, + endRgb, + letter.colorProgress + ); + needsRedraw = true; + } + } + }); + + if (needsRedraw) { + drawLetters(); + } + }; + + const animate = () => { + const now = Date.now(); + if (now - lastGlitchTime.current >= glitchSpeed) { + updateLetters(); + drawLetters(); + lastGlitchTime.current = now; + } + + if (smooth) { + handleSmoothTransitions(); + } + + animationRef.current = requestAnimationFrame(animate); + }; + + useEffect(() => { + const canvas = canvasRef.current; + if (!canvas) return; + + context.current = canvas.getContext("2d"); + resizeCanvas(); + animate(); + + let resizeTimeout: NodeJS.Timeout; + + const handleResize = () => { + clearTimeout(resizeTimeout); + resizeTimeout = setTimeout(() => { + cancelAnimationFrame(animationRef.current as number); + resizeCanvas(); + animate(); + }, 100); + }; + + window.addEventListener("resize", handleResize); + + return () => { + cancelAnimationFrame(animationRef.current!); + window.removeEventListener("resize", handleResize); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [glitchSpeed, smooth]); + + return ( +
    + + {outerVignette && ( +
    + )} + {centerVignette && ( +
    + )} +
    + ); +} diff --git a/src/components/seven-segment-digit.tsx b/src/components/seven-segment-digit.tsx new file mode 100644 index 0000000..8680089 --- /dev/null +++ b/src/components/seven-segment-digit.tsx @@ -0,0 +1,51 @@ +export function SevenSegmentDigit({ digit }: { digit: string }) { + const segmentMap: Record = { + "0": [ + "top", + "top-left", + "top-right", + "bottom-left", + "bottom-right", + "bottom", + ], + "1": ["top-right", "bottom-right"], + "2": ["top", "top-right", "middle", "bottom-left", "bottom"], + "3": ["top", "top-right", "middle", "bottom-right", "bottom"], + "4": ["top-left", "top-right", "middle", "bottom-right"], + "5": ["top", "top-left", "middle", "bottom-right", "bottom"], + "6": ["top", "top-left", "middle", "bottom-left", "bottom-right", "bottom"], + "7": ["top", "top-right", "bottom-right"], + "8": [ + "top", + "top-left", + "top-right", + "middle", + "bottom-left", + "bottom-right", + "bottom", + ], + "9": ["top", "top-left", "top-right", "middle", "bottom-right", "bottom"], + }; + + return ( +
    + {/* Define segments */} + {[ + { name: "top", className: "w-8 h-1 -top-0 left-2" }, + { name: "top-left", className: "w-1 h-8 top-1 left-1" }, + { name: "top-right", className: "w-1 h-8 top-1 right-1" }, + { name: "middle", className: "w-8 h-1 top-9 left-2" }, + { name: "bottom-left", className: "w-1 h-8 bottom-2 left-1" }, + { name: "bottom-right", className: "w-1 h-8 bottom-2 right-1" }, + { name: "bottom", className: "w-8 h-1 bottom-1 left-2" }, + ].map((seg) => ( +
    + ))} +
    + ); +}