Project: GeekBrain.io single-page website Status: Ready for Implementation Date: 2026-03-21 Based on: 2026-03-21-geekbrain-vc-webpage-design.md
A single-page website for GeekBrain.io, a VC fund. The site establishes brand presence with a futuristic/tech aesthetic, showcasing the fund's identity with particle effects, glitch text animations, and glowing UI elements. This is a minimal launch site (no portfolio yet) designed for easy expansion later.
Goals:
Type: Static website (no backend required)
| Technology | Version | Purpose |
|---|---|---|
| Next.js | 14.x (App Router) | Framework |
| React | 18.x | UI library |
| TypeScript | 5.x | Type safety |
| Tailwind CSS | 3.x | Styling with custom utilities |
| @tsparticles/react | 3.x | Particle background system |
| @tsparticles/slim | 3.x | Lightweight particle preset |
| next/font | built-in | Font optimization |
| Google Fonts | - | Space Grotesk, Inter |
Why this stack:
geekbrain-site/ ├── app/ │ ├── layout.tsx # Root layout with fonts, dark theme, metadata │ ├── page.tsx # Main page composing all sections │ └── globals.css # Tailwind imports + custom animations ├── components/ │ ├── Hero.tsx # Full-screen hero with GlitchText │ ├── About.tsx # Glassmorphism card with fund info │ ├── Contact.tsx # LinkedIn social link (uses GlowButton) │ ├── ParticleBackground.tsx # Full-screen particle canvas │ ├── GlitchText.tsx # Reusable glitch text component │ └── GlowButton.tsx # Reusable glowing button/link component ├── public/ │ ├── assets/ │ │ └── images/ │ │ └── Geekbrain-io.png # Logo/brand image │ └── favicon.ico # Favicon (optional, to be added) ├── lib/ │ └── particles-config.ts # tsparticles configuration ├── tailwind.config.ts # Custom glow utilities, colors ├── next.config.js # Next.js configuration ├── tsconfig.json # TypeScript configuration ├── package.json # Dependencies & scripts ├── .env.example # Environment variable template ├── .gitignore # Git ignore rules └── README.md # Project documentation
Theme: Dark mode, blue-dominant, cyber aesthetic
| Name | Hex | Tailwind Name | Usage |
|---|---|---|---|
| Background | #050510 |
bg-primary-dark |
Page background |
| Primary Accent | #0088ff |
text-primary / border-primary |
Main glows, highlights, borders |
| Secondary Accent | #00ddff |
text-secondary |
Bright accents, hover states |
| Tertiary Accent | #6600ff |
accent-purple |
Subtle contrast, depth |
| Heading Text | #ffffff |
text-white |
Headings |
| Body Text | #8899bb |
text-muted |
Body text |
| Card Background | rgba(0, 40, 80, 0.3) |
bg-card |
Glassmorphism cards |
| Glow Layer | rgba(0, 136, 255, 0.3) |
glow-blue |
Box shadow glow |
Tailwind Color Extension (tailwind.config.ts):
theme: {
extend: {
colors: {
primary: {
DEFAULT: '#0088ff',
dark: '#0066cc',
light: '#00aaff',
},
secondary: {
DEFAULT: '#00ddff',
dark: '#00aacc',
},
accent: {
purple: '#6600ff',
},
}
}
}
| Element | Font | Weight | Size (mobile → desktop) |
|---|---|---|---|
| H1 (Hero) | Space Grotesk | 700 | 3xl → 6xl |
| H2 (Section) | Space Grotesk | 600 | 2xl → 3xl |
| Body | Inter | 400 | base → lg |
| Code/Mono | JetBrains Mono | 400 | (optional) |
Font loading (layout.tsx):
import { Space_Grotesk, Inter } from 'next/font/google'
const spaceGrotesk = Space_Grotesk({
weight: ['600', '700'],
subsets: ['latin'],
variable: '--font-space-grotesk',
})
const inter = Inter({
weight: ['400', '500'],
subsets: ['latin'],
variable: '--font-inter',
})
Implementation: @tsparticles/react with tsparticles-slim preset + custom blue/cyan config.
Configuration:
// lib/particles-config.ts
export const particlesConfig = {
fullScreen: { enable: true, zIndex: -1 },
particles: {
number: { value: 100, density: { enable: true, value_area: 800 } },
color: { value: ['#0088ff', '#00ddff', '#6600ff'] },
shape: { type: 'circle' },
opacity: { value: 0.5, random: true },
size: { value: { min: 1, max: 3 } },
move: {
enable: true,
speed: 0.5,
direction: 'none',
random: true,
straight: false,
outModes: { default: 'out' },
},
links: {
enable: true,
distance: 150,
color: '#0088ff',
opacity: 0.3,
width: 1,
},
},
interactivity: {
events: {
onHover: { enable: true, mode: 'repulse' },
onClick: { enable: true, mode: 'push' },
},
modes: {
repulse: { distance: 100, duration: 0.4 },
push: { quantity: 4 },
},
},
detectRetina: true,
}
Performance optimizations:
visibilitychange event)requestAnimationFrame (built into tsparticles)Implementation: CSS keyframes with pseudo-elements for chromatic aberration
Component: GlitchText.tsx
interface GlitchTextProps {
text: string;
as?: 'h1' | 'h2' | 'h3' | 'span';
className?: string;
intensity?: 'subtle' | 'normal' | 'aggressive'; // controls animation speed
}
CSS Animation (globals.css):
@keyframes glitch-anim-1 {
0%, 100% { clip-path: inset(40% 0 61% 0); transform: translate(-2px, 2px); }
20% { clip-path: inset(92% 0 1% 0); transform: translate(2px, -2px); }
40% { clip-path: inset(43% 0 1% 0); transform: translate(-1px, 1px); }
60% { clip-path: inset(25% 0 58% 0); transform: translate(1px, -1px); }
80% { clip-path: inset(54% 0 7% 0); transform: translate(0px, 0px); }
}
@keyframes glitch-anim-2 {
0%, 100% { clip-path: inset(65% 0 36% 0); transform: translate(2px, -2px); }
20% { clip-path: inset(79% 0 14% 0); transform: translate(-2px, 2px); }
40% { clip-path: inset(51% 0 68% 0); transform: translate(1px, -1px); }
60% { clip-path: inset(87% 0 13% 0); transform: translate(-1px, 1px); }
80% { clip-path: inset(32% 0 67% 0); transform: translate(0px, 0px); }
}
.glitch {
position: relative;
color: white;
}
.glitch::before,
.glitch::after {
content: attr(data-text);
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.glitch::before {
color: #00ddff;
animation: glitch-anim-1 2.5s infinite linear alternate-reverse;
z-index: -1;
}
.glitch::after {
color: #0066cc;
animation: glitch-anim-2 2.5s infinite linear alternate-reverse;
z-index: -2;
}
@media (prefers-reduced-motion: reduce) {
.glitch::before,
.glitch::after {
animation: none;
}
}
Usage:
<GlitchText text="GEEKBRAIN.IO" as="h1" intensity="normal" />
Timing: 2.5s loop, ~70% stable, 30% glitching
Custom Tailwind utilities (tailwind.config.ts):
plugin: function({ addUtilities }) {
addUtilities({
'.glow-blue': {
boxShadow: `
0 0 5px rgba(0, 136, 255, 0.5),
0 0 10px rgba(0, 136, 255, 0.3),
0 0 15px rgba(0, 136, 255, 0.2)
`,
},
'.glow-cyan': {
boxShadow: `
0 0 5px rgba(0, 221, 255, 0.5),
0 0 10px rgba(0, 221, 255, 0.3)
`,
},
'.text-glow-blue': {
textShadow: `
0 0 5px rgba(0, 136, 255, 0.7),
0 0 10px rgba(0, 136, 255, 0.5)
`,
},
'.animate-pulse-glow': {
animation: 'pulse-glow 2s ease-in-out infinite',
},
})
}
Additional keyframe:
@keyframes pulse-glow {
0%, 100% { box-shadow: 0 0 5px rgba(0, 136, 255, 0.5); }
50% { box-shadow: 0 0 15px rgba(0, 136, 255, 0.8); }
}
GlowButton component:
interface GlowButtonProps {
children: React.ReactNode;
onClick?: () => void;
href?: string;
variant?: 'primary' | 'secondary' | 'outline';
className?: string;
}
Implementation: IntersectionObserver API (native, no library needed)
Utility hook (optional): useIntersectionObserver to trigger fade-in when elements enter viewport
Animation classes:
.scroll-reveal {
opacity: 0;
transform: translateY(30px);
transition: opacity 0.6s ease-out, transform 0.6s ease-out;
}
.scroll-reveal.visible {
opacity: 1;
transform: translateY(0);
}
/* Staggered for list items */
.stagger-1 { transition-delay: 0.1s; }
.stagger-2 { transition-delay: 0.2s; }
.stagger-3 { transition-delay: 0.3s; }
Content:
GEEKBRAIN.IO (GlitchText component, default glitch effect)Layout:
min-h-screen)Implementation:
export default function Hero() {
return (
<section className="flex flex-col items-center justify-center min-h-screen relative z-10">
<GlitchText text="GEEKBRAIN.IO" as="h1" intensity="normal" />
<p className="mt-4 text-xl md:text-2xl text-muted font-light">
Backing the builders of tomorrow
</p>
<ScrollIndicator /> {/* Optional */}
</section>
)
}
Content:
GeekBrain.io is a venture capital fund focused on backing technical founders building transformative technologies. We believe the best companies start with builders who understand the problem they're solving. Our mission is to provide the capital, network, and strategic support these founders need to turn bold ideas into reality.
Layout:
rgba(0, 40, 80, 0.3) background with borderborder-primary glow-bluep-6 md:p-8max-w-3xl centeredImplementation:
export default function About() {
return (
<section className="py-20 px-4 relative z-10">
<div className="max-w-3xl mx-auto">
<h2 className="text-3xl font-bold text-white mb-6 text-center">About</h2>
<div className="bg-card border border-primary rounded-lg p-6 md:p-8 glow-blue scroll-reveal">
<p className="text-muted leading-relaxed">
GeekBrain.io is a venture capital fund focused on backing technical founders...
</p>
</div>
</div>
</section>
)
}
Content:
Layout:
Implementation:
export default function Contact() {
return (
<section className="py-20 px-4 relative z-10">
<div className="max-w-2xl mx-auto text-center">
<h2 className="text-3xl font-bold text-white mb-6">Connect</h2>
<GlowButton
href="https://linkedin.com/company/geekbrainio"
target="_blank"
rel="noopener noreferrer"
aria-label="Connect with GeekBrain.io on LinkedIn"
className="inline-flex items-center gap-2"
>
<LinkedInIcon className="w-6 h-6" />
<span>LinkedIn</span>
</GlowButton>
</div>
</section>
)
}
Purpose: Animated glitch text effect for headings
Interface:
interface GlitchTextProps {
text: string; // Required: text to display
as?: 'h1' | 'h2' | 'h3' | 'span'; // HTML element, default 'h1'
className?: string; // Additional CSS classes
intensity?: 'subtle' | 'normal' | 'aggressive'; // Animation intensity
}
Implementation details:
subtle: 3s interval (63% stable, 37% glitch)normal: 2.5s interval (70% stable, 30% glitch) ← defaultaggressive: 1.5s interval (50% stable, 50% glitch)prefers-reduced-motion by disabling animationdata-text for CSS pseudo-element contentPurpose: Interactive button/link with glowing hover effect
Interface:
interface GlowButtonProps {
children: React.ReactNode;
onClick?: () => void;
href?: string; // If provided, renders as <a>
variant?: 'primary' | 'secondary' | 'outline';
className?: string;
[rest: React.HTMLAttributes<HTMLButtonElement | HTMLAnchorElement>]: any;
}
Variants:
primary: Filled background (bg-primary), white text, blue glow on hoversecondary: Transparent background, cyan border/text, cyan glow on hoveroutline: Transparent, primary border, blue glow on hover ← defaultStyling:
px-6 py-3 (adjustable via className)rounded-lgtransition-all duration-300 ease-outhover:glow-blue (or hover:glow-cyan for secondary)focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2Purpose: Full-screen particle canvas behind all content
Interface:
interface ParticleBackgroundProps {
config?: ParticlesConfig; // Optional override of default config
className?: string;
}
Behavior:
z-index: -1Particles component from @tsparticles/reactlib/particles-config.ts by defaultImplementation:
'use client'
import { Particles } from '@tsparticles/react'
import { particlesConfig } from '@/lib/particles-config'
export default function ParticleBackground({ className }: { className?: string }) {
return (
<Particles
id="tsparticles"
className={className}
options={particlesConfig}
/>
)
}
Structure:
┌─────────────────────────────────────────────┐ │ [ParticleBackground - fixed, z-index: -1] │ │ ┌─────────────────────────────────────┐ │ │ │ HERO (100vh, flex center) │ │ │ │ ┌─────────────────────────────┐ │ │ │ │ │ GEEKBRAIN.IO (glitch) │ │ │ │ │ │ "Backing the builders... │ │ │ │ │ └─────────────────────────────┘ │ │ │ │ ↓ (optional) │ │ │ └─────────────────────────────────────┘ │ │ ┌─────────────────────────────────────┐ │ │ │ ABOUT (py-20 px-4) │ │ │ │ ┌─────────────────────────────┐ │ │ │ │ │ [Glass card, blue glow] │ │ │ │ │ │ About text... │ │ │ │ │ └─────────────────────────────┘ │ │ │ └─────────────────────────────────────┘ │ │ ┌─────────────────────────────────────┐ │ │ │ CONTACT (py-20 px-4, center) │ │ │ │ ┌─────────────────────────────┐ │ │ │ │ │ [GlowButton - LinkedIn] │ │ │ │ │ └─────────────────────────────┘ │ │ │ └─────────────────────────────────────┘ │ │ [Footer - optional (copyright)] │ └─────────────────────────────────────────────┘
Sizing:
px-4 on mobile, larger sections use container max-w-6xl mx-autosm:, md:, lg:)GlitchText respects prefers-reduced-motion (disables animation)@media (prefers-reduced-motion: reduce)aria-label (e.g., "GeekBrain.io on LinkedIn")alt text (if decorative, use alt="")focus-visible classes)next/font (no layout shift)layout.tsx head elements:
export const metadata: Metadata = {
title: 'GeekBrain.io - Venture Capital for Technical Founders',
description: 'GeekBrain.io is a venture capital fund backing technical founders building transformative technologies.',
keywords: ['venture capital', 'VC fund', 'technical founders', 'startup funding', 'GeekBrain'],
openGraph: {
title: 'GeekBrain.io',
description: 'Backing the builders of tomorrow',
type: 'website',
locale: 'en_US',
siteName: 'GeekBrain.io',
},
twitter: {
card: 'summary_large_image',
title: 'GeekBrain.io',
description: 'Backing the builders of tomorrow',
},
}
Favicon/OG Image:
favicon.ico in /publicog-image.jpg (1200×630px) with logo and tagline/public/assets/images/Based on Tailwind defaults:
| Breakpoint | Width | Usage |
|---|---|---|
| mobile (default) | < 640px | Stack layout, smaller text (text-base, h1: text-3xl) |
| sm | 640px+ | Tablet portrait |
| md | 768px+ | Tablet landscape, smaller laptop |
| lg | 1024px+ | Standard laptop/desktop |
| xl | 1280px+ | Large desktop screens |
Typography scaling:
text-3xl sm:text-4xl md:text-5xl lg:text-6xltext-base md:text-lgp-6 md:p-8 lg:p-12Container strategy:
<div className="max-w-6xl mx-auto w-full px-4 sm:px-6 lg:px-8">
{/* Content */}
</div>
next.config.js:
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
// Optional: output 'standalone' for Docker deployment
// output: 'standalone',
}
module.exports = nextConfig
No special configuration needed for this static site. Default settings suffice.
tsconfig.json (use Next.js default):
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
package.json:
{
"name": "geekbrain-site",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"next": "^14.2.5",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"@tsparticles/react": "^3.0.0",
"@tsparticles/slim": "^3.0.0"
},
"devDependencies": {
"typescript": "^5.5.3",
"@types/node": "^20.14.10",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"tailwindcss": "^3.4.7",
"postcss": "^8.4.40",
"autoprefixer": "^10.4.19",
"eslint": "^8.57.0",
"eslint-config-next": "^14.2.5"
}
}
Not required for this static site. If any APIs are added later, use .env.local:
# Example (not used currently) # NEXT_PUBLIC_ANALYTICS_ID=...
Initialize Next.js project:
npx create-next-app@latest geekbrain-site --typescript --tailwind --eslint --app --src-dir=false --import-alias="@/*" cd geekbrain-site
Install additional dependencies:
npm install @tsparticles/react @tsparticles/slim npm install -D tailwindcss postcss autoprefixer npx tailwindcss init -p
Configure Tailwind (use config from this spec)
Create file structure as shown above
Add fonts via next/font in layout.tsx
Add logo to public/assets/images/Geekbrain-io.png
Run dev server:
npm run dev
Recommended: Vercel (zero-config for Next.js)
Alternative: Netlify
Steps:
npm run build.next (automatically detected)Domain: Configure DNS for geekbrain.io to point to Vercel
The architecture supports easy additions:
app/portfolio/page.tsx) - showcase investmentsapp/team/page.tsx) - team biosapp/api/contact/route.ts) + email serviceapp/blog/[...slug]/page.tsx with MDX or CMStailwind.config.ts configured with custom colors, glow utilitiesnext.config.js createdlib/particles-config.ts writtenapp/globals.css includes Tailwind directives + custom glitch keyframescomponents/GlitchText.tsx implemented + testscomponents/GlowButton.tsx implemented + testscomponents/ParticleBackground.tsx implementedcomponents/Hero.tsx implementedcomponents/About.tsx implementedcomponents/Contact.tsx implementedapp/layout.tsx - font setup, metadata, dark backgroundapp/page.tsx - compose all componentspublic/assets/images/All components are client components only when necessary (ParticleBackground, GlitchText with animations). Use 'use client' directive only in those files. Layout and page can remain server components.
Animation performance: Use transform and opacity for 60fps. Avoid animating top, left, width, height.
Scroll reveal: Can be implemented in page root with IntersectionObserver hook that adds .visible class to elements with .scroll-reveal.
Glassmorphism: Uses backdrop-filter: blur() if desired. Test browser support. Fallback to semi-transparent background only.
Logo usage: Use Next.js Image component for optimization:
import Image from 'next/image'
<Image src="/assets/images/Geekbrain-io.png" alt="GeekBrain.io" width={200} height={60} />Code quality: Follow TypeScript best practices, proper error boundaries if needed (no error boundaries needed for this static site).
Git: Commit frequently with clear messages. Create feature branches if needed.
| Date | Version | Changes |
|---|---|---|
| 2026-03-21 | 1.0 | Consolidated spec created, ready for implementation |
Ready to build! 🚀