add ascii background sections on home page

This commit is contained in:
undersalam 2025-02-06 08:17:52 +07:00
parent a0dab9089d
commit e5010d05b6
5 changed files with 391 additions and 23 deletions

View File

@ -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() {
</motion.h1>
<motion.p
className={cn(
"mx-auto max-w-3xl text-center text-sm leading-7 text-muted-foreground sm:text-lg sm:leading-9 text-balance"
// montserrat.className
"mx-auto max-w-4xl text-center text-sm leading-7 text-muted-foreground sm:text-lg sm:leading-9 text-balance",
"text-[#222222] font-semibold"
)}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
@ -207,11 +208,23 @@ export function Hero() {
const privyAuth = usePrivy();
return (
<section id="hero" className="">
<div className="pt-8 px-3 sm:px-6 layout flex flex-col justify-center items-center border-x">
<HeroPill />
<HeroTitles />
<HeroCTA privyAuth={privyAuth} />
<section id="hero">
<div className="relative">
<div className="relative z-20">
<div className="pt-8 px-3 sm:px-6 layout flex flex-col justify-center items-center border-x">
<HeroPill />
<HeroTitles />
<HeroCTA privyAuth={privyAuth} />
</div>
</div>
<LetterGlitch
glitchSpeed={50}
centerVignette={false}
outerVignette={false}
smooth={true}
glitchColors={["#222222", "#BEBDBD"]}
className="absolute top-0 left-0 right-0 bottom-0 bg-transparent opacity-20"
/>
</div>
<HeroMarquee />
</section>

View File

@ -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 (
<section className="">
<div
className="layout"
style={{
backgroundImage: "url(/background-4.png)",
backgroundColor: "rgba(255, 255, 255, 0.75)",
backgroundBlendMode: "lighten",
}}
>
<div className="layout relative">
<div className="border-x border-b">
<BlurFade className="p-6" inView>
<Badge className="hover:bg-primary rounded-md font-light mb-6">
@ -82,15 +77,23 @@ export function Roadmap() {
>
<li>
<div className="flex items-center gap-3">
<p className="text-5xl">{idx + 1}</p>
<p className="text-lg">Q{idx + 1} 2025</p>
<SevenSegmentDigit digit={`${idx + 1}`} />
<p className="text-lg font-semibold">Q{idx + 1} 2025</p>
</div>
<h2 className="text-2xl font-semibold">Phase 0{idx + 1}</h2>
<p className="text-muted-foreground">{roadmap}</p>
<p className="text-[#222222]">{roadmap}</p>
</li>
</BlurFade>
))}
</ul>
<LetterGlitch
glitchSpeed={50}
centerVignette={false}
outerVignette={false}
smooth={true}
glitchColors={["#222222", "#BEBDBD"]}
className="absolute top-0 left-0 right-0 bottom-0 bg-transparent opacity-10"
/>
</div>
</section>
);

View File

@ -9,7 +9,7 @@ import { Footer } from "@/components/footer";
export default function Home() {
return (
<>
<div className="bg-[url(/background-1.png)]">
<div >
<Hero />
<Features />
<hr className="" />

View File

@ -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<HTMLCanvasElement | null>(null);
const animationRef = useRef<number | null>(null);
const letters = useRef<
{
char: string;
color: string;
targetColor: string;
colorProgress: number;
}[]
>([]);
const grid = useRef({ columns: 0, rows: 0 });
const context = useRef<CanvasRenderingContext2D | null>(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 (
<div
className={cn(
"relative w-full h-full bg-black overflow-hidden",
className
)}
>
<canvas ref={canvasRef} className="block w-full h-full" />
{outerVignette && (
<div className="absolute top-0 left-0 w-full h-full pointer-events-none bg-[radial-gradient(circle,_rgba(0,0,0,0)_60%,_rgba(0,0,0,1)_100%)]"></div>
)}
{centerVignette && (
<div className="absolute top-0 left-0 w-full h-full pointer-events-none bg-[radial-gradient(circle,_rgba(0,0,0,0.8)_0%,_rgba(0,0,0,0)_60%)]"></div>
)}
</div>
);
}

View File

@ -0,0 +1,51 @@
export function SevenSegmentDigit({ digit }: { digit: string }) {
const segmentMap: Record<string, string[]> = {
"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 (
<div className="relative w-12 h-20 flex flex-col items-center justify-center">
{/* 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) => (
<div
key={seg.name}
className={`absolute rounded-full ${seg.className} ${
segmentMap[digit]?.includes(seg.name) ? "bg-black" : "bg-gray-400"
}`}
/>
))}
</div>
);
}