Lightweight 3D engine for WebGL. Used to create the animated 3D particle globe, floating geometry, and real-time background effects on the hero section.
WebGLGPUShaders3D Rendering
Basic 3D Scene Setup
Create a scene, camera, renderer, and add a rotating cube. This is the foundation of any Three.js project — the same pattern used for the portfolio's 3D hero background.
Particle System
Thousands of floating particles with BufferGeometry. Each particle has its own position and velocity. This is exactly how the hero globe particles work — random positions in a sphere, rendered as points.
Render Loop with GSAP
The render loop drives all 3D animations. Combined with GSAP for smooth camera movements and ScrollTrigger for scroll-based transitions.
JavaScript
import * as THREE from'three';
// 1. Create sceneconst scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, w/h, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ antialias: true });
// 2. Add geometry + materialconst geo = new THREE.BoxGeometry(1, 1, 1);
const mat = new THREE.MeshStandardMaterial({
color: 0x6C63FF,
wireframe: true
});
const cube = new THREE.Mesh(geo, mat);
scene.add(cube);
// 3. Position camera
camera.position.z = 3;
// 4. Add lightconst light = new THREE.PointLight(0xffffff, 1);
light.position.set(2, 2, 2);
scene.add(light);
// 5. Render loopfunctionanimate() {
requestAnimationFrame(animate);
cube.rotation.x += 0.01;
cube.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
JavaScript
const COUNT = 5000;
const positions = new Float32Array(COUNT * 3);
for (let i = 0; i < COUNT * 3; i += 3) {
// Random position in a sphereconst r = 5 * Math.cbrt(Math.random());
const theta = Math.random() * Math.PI * 2;
const phi = Math.acos(Math.random() * 2 - 1);
positions[i] = r * Math.sin(phi) * Math.cos(theta);
positions[i + 1] = r * Math.sin(phi) * Math.sin(theta);
positions[i + 2] = r * Math.cos(phi);
}
const geo = new THREE.BufferGeometry();
geo.setAttribute('position',
new THREE.BufferAttribute(positions, 3)
);
const mat = new THREE.PointsMaterial({
size: 0.02,
color: 0x6C63FF,
transparent: true,
blending: THREE.AdditiveBlending
});
const points = new THREE.Points(geo, mat);
scene.add(points);
GreenSock Animation Platform. Powers every scroll-triggered reveal, staggered entrance, morphing transition, and smooth interpolation across all pages. ScrollTrigger handles scroll-linked animations.
ScrollTriggerTimelineEasingStagger
Scroll-Triggered Reveal
Elements fade in and slide up as you scroll to them. The once: true option means they only animate once. Used for every section on the portfolio.
Staggered Card Entrance
Multiple elements animate in sequence with a delay between each. The stagger property controls timing. Used for skill cards, project cards, and repo grids.
Magnetic Button Effect
Buttons follow the mouse cursor within a radius, creating a magnetic pull. On mouse leave, they snap back with elastic easing. The portfolio's CTA buttons use this.
Sequenced Timeline
Chain multiple animations into a precise sequence with labels and offsets. The hero text entrance uses this — words appear one by one with overlapping timing.
butter-smooth scroll library by Darkroom Engineering. Replaces native scroll with inertia-based scrolling that feels like native iOS. Integrates with GSAP ScrollTrigger for synced animations.
Inertia60fpsScroll Sync
Lenis Initialization
Initialize Lenis with duration and easing options. The requestAnimationFrame loop keeps it synced with the browser's repaint cycle.
GSAP ScrollTrigger Integration
Lenis overrides native scroll, so GSAP ScrollTrigger needs to be notified on each frame. The scrolledElement option tells Lenis which element to observe.
The backend is written in pure Go — no framework, no dependencies beyond the database driver. Handles API routes, SQLite CRUD, static file serving, and contact form storage.
net/httpSQLiteREST APIDocker
Go HTTP Server
The entire backend starts in main() — opens the database, creates tables, registers routes, and listens on port 8080. Zero external frameworks, just net/http.
JSON API Handler
Every handler follows the same pattern: parse request, query database, marshal to JSON, write response. CORS headers allow the frontend to call the API from any origin.
SQLite Database Operations
Uses modernc.org/sqlite — a pure Go SQLite implementation with zero CGO. All data (projects, skills, contacts, config) stored in a single data.db file.
funchandleProjects(db *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
// CORS headers
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Content-Type", "application/json")
switch r.Method {
case"GET":
rows, _ := db.Query(`SELECT id, name, description, tags, image
FROM projects ORDER BY id DESC`)
defer rows.Close()
var projects []Project
for rows.Next() {
var p Project
rows.Scan(&p.ID, &p.Name, &p.Description,
&p.Tags, &p.Image)
projects = append(projects, p)
}
json.NewEncoder(w).Encode(projects)
case"POST":
var p Project
json.NewDecoder(r.Body).Decode(&p)
db.Exec(`INSERT INTO projects (name, description, tags, image)
VALUES (?, ?, ?, ?)`,
p.Name, p.Description, p.Tags, p.Image)
json.NewEncoder(w).Encode(map[string]string{"status": "ok"})
}
}
}
Go
funccreateTables(db *sql.DB) {
queries := []string{
`CREATE TABLE IF NOT EXISTS projects (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT, description TEXT,
tags TEXT, image TEXT
)`,
`CREATE TABLE IF NOT EXISTS skills (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT, category TEXT, level INTEGER
)`,
`CREATE TABLE IF NOT EXISTS contacts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT, email TEXT, message TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)`,
`CREATE TABLE IF NOT EXISTS config (
key TEXT PRIMARY KEY,
value TEXT
)`,
}
for _, q := range queries {
db.Exec(q)
}
}
Multi-stage Docker build: compile Go in golang:1.21-alpine, run in alpine:3.19. Final image is ~15MB. Used for Render deployment with persistent SQLite volume.
Multi-stageAlpineRender
Multi-stage Dockerfile
Stage 1 compiles Go binary. Stage 2 copies binary into minimal Alpine image. CGO_ENABLED=0 ensures static binary (pure Go SQLite needs no C compiler).
Render Deployment Config
render.yaml defines the service, Docker build, persistent disk for SQLite data, and auto-deploy from GitHub.
Dockerfile
# Stage 1: BuildFROM golang:1.21-alpine AS builder
WORKDIR /app
COPY backend/ .
RUN CGO_ENABLED=0 go build -o server .
# Stage 2: RunFROM alpine:3.19
RUN apk add --no-cache ca-certificates
WORKDIR /app
COPY --from=builder /app/server .
COPY index.html repos.html story.html ./
COPY css/ css/
COPY js/ js/
COPY admin/ admin/
COPY data/ data/
RUN mkdir -p data
EXPOSE 8080
CMD ["./server"]
YAML
# render.yamlservices:
- type: web
name: mayank-portfolio
runtime: docker
dockerfilePath: ./Dockerfile
envVars:
- key: PORT
value: 8080
disk:
name: data
mountPath: /app/data
sizeGB: 1
Build Output
$ docker build -t portfolio .
JS
Vanilla JavaScript
ES2024Core Language
Zero React, zero frameworks. Pure ES modules, fetch API, Web Animations API, IntersectionObserver, and modern DOM APIs. Every interaction is hand-written.
ES ModulesFetch APIWeb APIsNo Build Step
GitHub API with Fetch
Paginated fetch loop that loads ALL repos across multiple API calls. Handles errors, parses JSON, and concatenates results.
Lazy Loading with IntersectionObserver
Watch elements enter the viewport and trigger animations only when visible. More performant than scroll event listeners.
Debounce Search Input
Prevents API calls on every keystroke. Only fires after the user stops typing for 200ms. Essential for search performance.
JavaScript
// Paginated fetch — gets ALL reposasync functionfetchAllRepos(user) {
let page = 1, all = [];
while (true) {
const res = awaitfetch(
`https://api.github.com/users/${user}/repos` +
`?per_page=100&page=${page}&type=owner`
);
if (!res.ok) throw newError(res.statusText);
const data = await res.json();
if (data.length === 0) break;
all = all.concat(data);
if (data.length < 100) break;
page++;
}
return all;
}
Dynamic theming with CSS variables. The entire color palette, fonts, spacing, and animations are defined as custom properties on :root. Supports dark/light mode toggling.
VariablesThemingGradientsGrid/Flex
Theme System
Every color, font, and spacing value is a CSS variable. Change one value and the entire theme updates. Used for the dark/cyber aesthetic.
Animated Gradients
Background gradients with background-size animation. The marquee, buttons, and section dividers use these for the neon glow effect.
Space Grotesk for headings — geometric, modern. JetBrains Mono for code blocks — designed for readability. Loaded via Google Fonts CDN with display=swap.
Space GroteskJetBrains MonoPreconnect
Font Loading
preconnect establishes early connection to Google's CDN. display=swap shows fallback text immediately, swaps to custom font when loaded.
Font Assignment
Headings get Space Grotesk, code blocks get JetBrains Mono. Font weights are subset to only what's needed for faster loading.
Pure Go SQLite implementation — no CGO, no C compiler needed. Transpiles SQLite C code to Go. Enables Docker builds with CGO_ENABLED=0 and cross-compilation.
Pure GoNo CGOWASM-ready
Database Connection
Register the driver as "sqlite" (not "sqlite3"). Opens a file-based database. The ?_journal_mode=WAL pragma enables concurrent reads.
Prepared Statements
Use db.Query() for SELECT and db.Exec() for INSERT/UPDATE. Parameterized queries prevent SQL injection.
Powers the repos page — fetches all 191 repos with metadata, stars, forks, languages, and topics. No backend caching — direct client-side API calls with CORS.
RESTJSONCORSPagination
List User Repos
Fetch all repos for a user. per_page=100 maximizes each request. Loop through pages until empty response. Each repo includes name, description, language, stars, forks, topics, and fork status.
Rate Limit Handling
Unauthenticated: 60 req/hour. Authenticated: 5,000 req/hour. Always check X-RateLimit-Remaining header. For high-traffic, cache responses in localStorage.
JavaScript
// Fetch all repos with paginationasync functionfetchRepos(user) {
const API = 'https://api.github.com';
let page = 1, repos = [];
while (true) {
const url = `${API}/users/${user}/repos`
+ `?per_page=100&page=${page}&type=owner`;
const res = awaitfetch(url);
const data = await res.json();
if (data.length === 0) break;
repos = repos.concat(data);
if (data.length < 100) break;
page++;
}
return repos; // All repos!
}
// Each repo object includes:// name, full_name, description, fork,// language, stargazers_count, forks_count,// topics, html_url, created_at, updated_at
Cloud hosting with Docker support. Free tier runs one web service. Persistent disk keeps SQLite data alive across deploys. Auto-deploys from GitHub pushes.
DockerPersistent DiskAuto DeployFree Tier
Deploy to Render
Connect your GitHub repo, Render detects the render.yaml or Dockerfile. First build takes ~3min. Subsequent builds ~30s. Free tier spins down after 15min of inactivity.
Shell
# 1. Push to GitHub
git add . && git commit -m "deploy"
git push origin master
# 2. On render.com:# - New > Web Service# - Connect GitHub repo# - Runtime: Docker# - Disk: /app/data (1GB)# - Auto-deploy: On# 3. First build output:# Step 1/8 : FROM golang:1.21-alpine# Step 2/8 : WORKDIR /app# Step 5/8 : RUN go build -o server .# Step 8/8 : CMD ["./server"]# Successfully built abcd1234# Your site is live at:# https://mayank-portfolio.onrender.com
Serverless email sending directly from the browser. No backend needed — the contact form sends emails via EmailJS's SMTP relay using a pre-configured service and template.
SMTPServerlessContact Form
Send Contact Email
Initialize with public key, send with service ID, template ID, and template params. Zero backend — email goes directly from browser to recipient.
JavaScript
import emailjs from'@emailjs/browser';
// Initialize with public key
emailjs.init('Sm0zzKtPUyizJGKVP');
// Send emailconst result = await emailjs.send(
'service_r1wu0ne', // Service ID'template_bkl8nf7', // Template ID
{
from_name: name,
from_email: email,
message: message,
to_name: 'Mayank',
}
);
Fast Markdown parser and compiler. Used in the AI Chat module to render streaming AI responses with full Markdown support — headings, code blocks, lists, links, and tables.
MarkdownStreamingHTML Output
Markdown to HTML
Configure marked with custom renderer for syntax highlighting, then parse streaming chunks into HTML for the chat window.
Fast math typesetting for the web. Renders LaTeX expressions in AI chat responses — formulas, equations, and mathematical notation display beautifully in the browser.
LaTeXMathFast Render
LaTeX to HTML
Auto-render detects $...$ and $$...$$ delimiters in text, then renders them as beautiful math using KaTeX.
Powers the shared background stars animation — 3-layer parallax starfield with shooting stars, mouse tracking, and particle effects. Injected via shared-bg.js on every page.
2D ContextParticlesrequestAnimationFrameStarfield
3-Layer Parallax Stars
Creates a full-screen canvas with 3 depth layers of stars. Each layer moves at different speeds based on mouse position, creating a 3D parallax effect.
Persistent client-side key-value storage. Used for: preloader preference, AI chat history, theme toggle state, cursor mode, and user settings — all survive page reloads.
5MB LimitSync APIPer-originNo Expiry
Store & Retrieve
Used throughout the portfolio — preloader choice, chat messages, theme, and cursor preferences all persist via localStorage.
JavaScript
// Save preloader preference
localStorage.setItem('preloader-type', 'matrix');
// Load AI chat historyconst messages = JSON.parse(
localStorage.getItem('ai-chat-history') || '[]'
);
// Save theme state
localStorage.setItem('theme', 'dark');
// Save cursor mode
localStorage.setItem('cursor-mode', 'default');
Detects when elements enter/exit the viewport. Powers scroll-triggered animations, lazy loading, section navigation highlighting, and the tutorial overlay first-visit detection.
Lazy LoadScroll RevealSection TrackingPerformance
Reveal on Scroll
Watch [data-reveal] elements and add .visible class when they enter viewport. Unobserve after first trigger for performance.
Fully custom cursor with dot, follower, glow, trail, hover labels, and text mode. Centralized in shared-bg.js — injects CSS and DOM on every page. z-index 99999 to stay above all overlays.
10 unique animated preloaders: Matrix Rain, Glitch, Particles, Pulse, Orbit, Wave, Typewriter, Circuit, DNA Helix, and Cyber Grid. Random selection on each visit, user preference saved.
CanvasCSS AnimationslocalStorageRandom Rotation
Preloader Manager
Loads random preloader, tracks completion, fades out. User can choose their favorite via the gear icon selector.
Self-contained floating chat widget — appears on every page as a bottom-right button. Expandable panel with streaming AI, Markdown, LaTeX, and localStorage persistence. Zero configuration.
Self-containedFloating UIAll PagesAuto-init
Auto-Initialize Widget
Include the script, widget auto-creates its own DOM, styles, and event listeners. Works on any page with zero HTML changes.
HTML
<!-- Just include the script --><script src="js/ai-widget.js"></script><!-- Widget auto-creates: --><!-- - Floating button (bottom-right) --><!-- - Expandable chat panel --><!-- - Streaming AI responses --><!-- - Markdown + LaTeX rendering --><!-- - localStorage persistence -->
Google's ad network for monetizing the portfolio. 30 ad spaces across 7 rows — banners and responsive squares. Help Me Grow section encourages visitors to support via ad clicks.
30 Ad SpacesResponsiveAuto AdsRevenue
Ad Unit Setup
Verification script in <head>, ad units with <ins> tags, and push script. 30 spaces in banner/square grid layout.
HTML
<!-- In <head> --><script async
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-2384016999231870"
crossorigin="anonymous"></script><!-- Ad unit --><ins class="adsbygoogle"
style="display:block"
data-ad-client="ca-pub-2384016999231870"
data-ad-slot="SLOT_ID"
data-ad-format="auto"
data-full-width-responsive="true"></ins><script>(adsbygoogle = window.adsbygoogle || []).push({});</script>
Ad Layout
Banner Ad (728x90)
Square (300x250)
Content Area
Banner Ad (728x90)
RD
Responsive Design
CSS3+Layout System
Mobile-first responsive design with CSS Grid, Flexbox, and media queries. Every page adapts from 320px mobile to 4K desktop. Hamburger menu, fluid typography, and adaptive layouts.
Mobile-firstCSS GridFlexboxFluid Typography
Responsive Breakpoints
Standard breakpoints for mobile, tablet, and desktop. Fluid typography with clamp() for smooth scaling.
Pill-shaped toggle with moon/stars (dark) and sun (light) SVG icons. Switches data-theme attribute on <html>. CSS variables update instantly. State saved to localStorage.
data-themeCSS VariablesSVG IconslocalStorage
Theme Switching
Toggle data-theme on <html>. All colors are CSS variables that change with the theme attribute.