GameGains API & Components
Comprehensive documentation for all public APIs, functions, and components used in the GameGains landing page.
Overview
GameGains is a Next.js 14 application built with React 18, TypeScript, and Tailwind CSS. It features a modern, responsive landing page with animated components, Supabase integration for email collection, and a distinctive visual design with pixel grid backgrounds and ASCII art decorations.
Next.js 14
App Router with server components
Tailwind CSS
Utility-first styling
Supabase
Email collection backend
Getting Started
Installation
Clone the repository and install dependencies:
git clone https://github.com/yourusername/gamegains-landing.git
cd gamegains-landing
npm installEnvironment Variables
Create a .env.local file with the following variables:
NEXT_PUBLIC_SUPABASE_URL=your_supabase_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_keyDevelopment
Start the development server:
npm run devThe app will be available at http://localhost:3000
Production Build
npm run build
npm startComponents
The application is built with modular React components. Below is documentation for each public component.
Component Architecture
src/
├── app/
│ ├── page.tsx # Main landing page with all sections
│ ├── layout.tsx # Root layout with metadata
│ └── globals.css # Global styles and CSS variables
├── components/
│ └── Video2Ascii.tsx # Video to ASCII art converter
└── lib/
└── supabase.ts # Supabase client configurationVideo2Ascii Component
A React component that converts video frames to ASCII art in real-time using canvas rendering.
Import
import Video2Ascii from '@/components/Video2Ascii';Props
| Prop | Type | Default | Description |
|---|---|---|---|
| videoSrc | string | - | Path to the video file to convert |
| className | string | "" | Additional CSS classes to apply |
| fontSize | number | 8 | Font size for ASCII characters in pixels |
| characters | string | " .:-=+*#%@" | Character set for brightness mapping (dark to light) |
Usage Example
<Video2Ascii
videoSrc="/background-video.mp4"
className="opacity-50"
fontSize={10}
characters=" .:░▒▓█"
/>How It Works
- Loads the video element (hidden) and a canvas element
- On each animation frame, draws the video to the canvas
- Reads pixel data and calculates brightness for each grid cell
- Maps brightness to ASCII characters and renders to canvas
- Automatically handles resize and video looping
EmailSignup Component
A form component for collecting email addresses and storing them in Supabase.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| size | "default" | "large" | "default" | Controls the size of the input and button |
Usage Example
// Default size
<EmailSignup />
// Large size for hero sections
<EmailSignup size="large" />States
idle- Initial state, form is ready for inputloading- Submitting email to Supabasesuccess- Email successfully saved, shows confirmation
PixelGridBackground Component
An animated 8-bit style pixel grid background with randomly glowing squares.
Configuration
const gridSize = 40; // 40x40 grid
const numGlowingSquares = 20; // Number of active glowing squares
const interval = 15000; // Milliseconds between glow changesAnimation
Squares transition between states using CSS transitions and the pulseGlow keyframe animation.
@keyframes pulseGlow {
0%, 100% {
background: rgba(250, 204, 21, 0.1);
box-shadow: 0 0 15px rgba(250, 204, 21, 0.2);
}
50% {
background: rgba(250, 204, 21, 0.2);
box-shadow: 0 0 25px rgba(250, 204, 21, 0.4);
}
}Supabase Integration
The application uses Supabase for storing email signups.
Client Configuration
// lib/supabase.ts
import { createClient } from '@supabase/supabase-js'
const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL || ''
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || ''
export const supabase = supabaseUrl && supabaseAnonKey
? createClient(supabaseUrl, supabaseAnonKey)
: nullDatabase Schema
CREATE TABLE emails (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
-- Enable Row Level Security
ALTER TABLE emails ENABLE ROW LEVEL SECURITY;
-- Allow public inserts
CREATE POLICY "Allow public insert" ON emails
FOR INSERT WITH CHECK (true);Usage
// Insert a new email
const { error } = await supabase
.from('emails')
.insert([{
email: userEmail,
created_at: new Date().toISOString()
}]);Styling & Theming
The application uses CSS custom properties for consistent theming.
CSS Variables
:root {
/* Typography */
--font-heading: system-ui, -apple-system, sans-serif;
--font-mono: 'SF Mono', 'Monaco', monospace;
/* Colors */
--color-bg: #0d0d0d;
--color-text: #ffffff;
--color-accent: #FACC15;
--color-accent-dark: #EAB308;
--color-green: #4ade80;
--color-red: #f87171;
--color-border: rgba(255, 255, 255, 0.08);
--color-card-bg: rgba(20, 20, 20, 0.8);
/* Layout */
--section-padding: clamp(80px, 10vw, 160px);
}Utility Classes
.card-borderCard with background and border styling
.glassGlassmorphism effect with backdrop blur
.gradient-textYellow gradient text effect
.link-hoverAnimated underline on hover
Animations
The application includes various animation utilities for scroll-triggered and interactive effects.
Scroll-Triggered Animations
// IntersectionObserver for fade-in animations
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add('visible');
entry.target.classList.add('animate-in');
}
});
}, { threshold: 0.1, rootMargin: '50px' });Animation Classes
.fade-in-upFade in with upward movement
.staggerStaggered animation delays for children (0.1s increments)
.waterfallCascading reveal animation (0.15s increments)
.animate-floatGentle floating animation
Hover Effects
/* Card lift effect */
.card:hover {
transform: translateY(-8px);
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.3);
}
/* Button color change */
.button:hover {
background: var(--color-accent);
color: #000000;
transform: scale(1.02);
}
/* Image desaturate effect */
.image-hover img {
filter: grayscale(30%);
}
.image-hover:hover img {
transform: scale(1.03);
filter: grayscale(0%);
}