A production-ready developer portfolio built with Next.js 15, featuring a tiled window manager aesthetic inspired by Hyprland/Arch Linux. Showcases MDX-powered blog and projects, Cloudflare CDN integration, Resend contact form and parallax scrolling mobile layout. Deployed on Railway with zero-config Railpack builds.
Modern tech stack meets terminal aesthetics—designed for developers who appreciate both craft and performance.
- It is not a generic portfolio shell. The site ships a Hyprland-inspired desktop UI, a distinct mobile layout, MDX-backed writing, and a resume system with automated PDF generation and layout validation in one repo.
- The repo shows product thinking, not just frontend polish: contact delivery, spam protection, CDN-aware media handling, typed content pipelines, and recruiter-ready resume workflows are all versioned together.
- The build pipeline proves more than “it compiles.”
npm run buildregenerates resume PDFs, and the resume verification scripts enforce page count, whitespace, and font consistency so role-specific resume links do not quietly drift.
- Next.js 15 + React 19: one deployable surface for the app shell, API routes, blog, project pages, and resume route without splitting the portfolio into multiple services.
- TypeScript strict mode: keeps config, MDX-derived content, and resume data changes from silently drifting.
- Content Collections + MDX: stores blog and project content in tracked files with build-time validation instead of a separate CMS.
- Tailwind CSS v4 + modular CSS + Framer Motion: mixes fast utility styling with deliberately scoped stylesheet modules and animation control for the window-manager aesthetic.
- Resend + Zod: gives the contact flow production email delivery plus schema-validated input handling.
- Local resume PDF tooling: the repo generates and validates 13 resume variants with local Computer Modern fonts, layout baselines, and deterministic PDF checks.
- Optional Cloudflare R2: keeps the project deployable without CDN setup while still supporting a faster production media path.
- Desktop Layout: 6-tile Hyprland-inspired layout (Neofetch, Navigation, Content, Theme Preset, Accent Color, Background)
- Keyboard Navigation: Vim-style hjkl movement + Tab cycling + workspace indicators via Polybar
- Mobile Experience: Parallax scrolling with depth effects and scroll progress indicators
- Theme System: 3 curated presets (Tokyo Night, Nord, Solarized Light) + 15 accent color swatches
- Content Management: MDX-powered blog and projects with syntax highlighting and reading time
- Audio Narration: Blog post audio with auto-detection, playback controls, and analytics tracking
- Contact Form: Production-ready Resend integration with 5-layer spam protection (honeypot, rate limiting, validation)
- CDN Integration: Optional Cloudflare R2 for optimized image delivery with automatic fallback
- Modern Architecture: Next.js 15.5 + TypeScript strict mode + modular CSS (12 focused modules under 200 LOC each)
- Zero-Config Deployment: Railway + Railpack auto-detection with intelligent caching
node >= 18.0.0
npm >= 9.0.0# Clone and install
git clone https://github.com/kmokdefi/kmok-portfolio.git
cd kmok-portfolio
npm install
# Configure environment
cp .env.example .env.local
# Edit .env.local with your RESEND_API_KEY and NEXT_PUBLIC_CONTACT_EMAIL
# Run development server
npm run devVisit http://localhost:3000
npm run build # Production build
npm run start # Start production server
npm run typecheck # TypeScript validation
npm run lint # Code lintingThese top-level npm entrypoints are normally run exactly as shown here; the repo does not rely on extra README-level flags for day-to-day use.
npm run build also regenerates resume PDFs in public/resume/.
Resume PDF rendering uses local Computer Modern assets in public/fonts/cmu/ for deterministic layout metrics.
npm run measure:resume-layout # Measure bottom whitespace for all generated resume PDFs
npm run calibrate:resume-layout # Auto-tune per-variant print settings toward legacy baseline
npm run verify:resume-layout # Enforce legacy baseline bottom whitespace lock
npm run validate-resume-pdfs # Full gate: page count, page size, fonts, bold, layout baselineLayout rules and baseline source are documented in docs/resume/resume-generation-spec.md.
Create .env.local from template and configure:
| Variable | Required | Description |
|---|---|---|
RESEND_API_KEY |
✅ Yes | Resend API key (resend.com - free: 100 emails/day, 3K/month) |
RESEND_FROM_EMAIL |
✅ Yes | Verified domain email for Resend (e.g., contact@kmok.ai) |
NEXT_PUBLIC_CONTACT_EMAIL |
✅ Yes | Email address to receive form submissions |
NEXT_PUBLIC_CDN_URL |
Optional | Cloudflare R2 CDN URL (e.g., https://cdn.kmok.ai) |
NEXT_PUBLIC_NAME |
Recommended | Your full name |
NEXT_PUBLIC_TITLE |
Recommended | Your professional title |
NEXT_PUBLIC_SEO_TITLE |
Recommended | Site or homepage SEO title |
NEXT_PUBLIC_SEO_DESCRIPTION |
Recommended | Site or homepage SEO description |
NEXT_PUBLIC_GITHUB_URL |
Recommended | GitHub profile URL |
NEXT_PUBLIC_LINKEDIN_URL |
Optional | LinkedIn profile URL |
NEXT_PUBLIC_TWITTER_URL |
Optional | Twitter/X profile URL |
NEXT_PUBLIC_UPWORK_URL |
Optional | Upwork profile URL used by homepage CTAs and neofetch |
NEXT_PUBLIC_UPWORK_HANDLE |
Optional | Upwork handle shown in neofetch |
See .env.example for the complete environment variable list.
Homepage lead copy is versioned in config/portfolio.config.ts, so production deploys can pick it up from git without needing an untracked env override.
This project supports Cloudflare R2 for image hosting:
Without CDN (default):
- Images served from
/public/images/ - Works out-of-the-box, no setup required
With CDN (recommended for production):
- Images served from Cloudflare R2
- Faster load times, reduced server bandwidth
- See CLAUDE.md - Image Storage for setup guide
Quick Setup:
- Create Cloudflare R2 bucket
- Upload images maintaining
/images/folder structure - Connect custom domain (e.g.,
cdn.kmok.ai) - Set
NEXT_PUBLIC_CDN_URLin environment variables - Deploy - images automatically load from CDN!
Edit config/portfolio.config.ts to customize:
- Personal information and bio
- Project portfolio with metrics
- Skills and technologies
- Blog posts
- ASCII art and system info
See CLAUDE.md for detailed architecture documentation.
Auto-deployment with Railpack builder:
- Visit railway.app → New Project → Deploy from GitHub
- Select
kmok-portfoliorepository - Add environment variables in Variables tab:
RESEND_API_KEY(required)RESEND_FROM_EMAIL(required)NEXT_PUBLIC_CONTACT_EMAIL(required)NEXT_PUBLIC_CDN_URL(optional - for Cloudflare R2)- See
.env.examplefor complete list
- Railway auto-detects Next.js and deploys with Railpack
Features:
- Zero-config deployment (no Dockerfile needed)
- Automatic NEXT_PUBLIC_* variable injection
- Fast builds with intelligent caching
npm i -g vercel
vercelAdd environment variables via Vercel dashboard → Settings → Environment Variables.
Framework: Next.js 15.5.4 with App Router and Turbopack Language: TypeScript 5.0 (strict mode) Styling: Tailwind CSS v4 + Modular CSS architecture (12 modules) Content: Content Collections + MDX (blog & projects) Animation: Framer Motion 12.23 Email: Resend API 6.1.2 + React Email Audio: HTML5 Audio API + Custom analytics (7 event types) CDN: Cloudflare R2 (image storage & delivery) Validation: Zod 4.1 (schema validation) State: React Context API (Theme, Focus) Icons: React Icons 5.5 + Custom ASCII art Fonts: JetBrains Mono, Geist, Geist Mono
- Modular CSS: 12 focused stylesheets organized by concern
- MDX Content: Blog and projects powered by Content Collections with syntax highlighting
- CDN Integration: Cloudflare R2 for optimized image delivery with fallback to local
- Responsive: Desktop (≥1024px) tiled layout, Mobile (<1024px) dual-mode
- Contact Security: 5-layer spam protection (honeypot, rate limiting, validation)
- Theme System: CSS variables with localStorage persistence
kmok-portfolio/
├── app/ # Next.js App Router
│ ├── api/contact/ # Contact form API endpoint
│ ├── styles/ # 12 modular CSS files
│ └── globals.css # CSS module imports
├── components/
│ ├── layout/ # Desktop & mobile layouts
│ ├── tiles/ # Desktop tile components
│ └── ui/ # Reusable UI components
├── config/
│ ├── portfolio.config.ts # Main configuration
│ ├── projects.config.ts # Project definitions
│ └── types.ts # TypeScript types
├── content/ # MDX content
│ ├── blog/ # Blog posts (*.mdx)
│ └── projects/ # Project pages (*.mdx)
├── contexts/ # React Context providers
├── hooks/ # Custom React hooks
├── lib/ # Utility libraries
├── public/ # Static assets
│ ├── audio/blog/ # Blog post audio files (MP3)
│ ├── fonts/ # Custom fonts
│ └── images/ # Local images (CDN fallback)
├── scripts/ # Build and utility scripts
├── docs/ # Documentation
├── content-collections.ts # Content Collections config
├── next.config.ts # Next.js configuration
├── tailwind.config.ts # Tailwind CSS config
├── tsconfig.json # TypeScript config
└── railway.toml # Railway deployment config
- CLAUDE.md - Architecture, commands, and development guide
- docs/README.md - Documentation hub and folder map
- docs/resume/resume-generation-spec.md - Resume PDF baseline/spacing/bold rules and verification workflow
- docs/specs/CONTACT_FORM_SPEC.md - Contact form implementation details
- docs/specs/CDN_DEPLOYMENT_SPEC.md - Cloudflare R2 CDN setup guide
MIT License © 2025 David Leer
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- Hyprland - Dynamic tiling Wayland compositor
- r/unixporn - Linux customization community
- Neofetch - System information tool
- Kyrre Gjerstad's Portfolio (GitHub) - Mobile layout design
- Tokyo Night by enkia
- Nord by Arctic Ice Studio
- Solarized by Ethan Schoonover
- Built with Next.js by Vercel
- Content managed with Content Collections
- Styled with Tailwind CSS
- Animated with Framer Motion
- Emails powered by Resend
- CDN hosted on Cloudflare R2
- Built a hybrid recruiter-facing resume that combines Next.js web delivery with an agentic engineering story, making
/resumelead with the strongest current full-stack narrative by default. - Added a visible summary block for the default resume variant, so recruiters immediately see the stack and the 4 concurrent AI workflow angle before scanning project bullets.
- Separated AI/devtools work into a dedicated
Agentic Engineeringsection, keeping web projects and agentic systems distinct without losing one-page fit. - Kept homepage and PDF entry points in sync by deriving the CTA PDF link from the default variant instead of hard-coding an older web-only file.
- Auto-generated and validated 13 resume variants and kept role-specific links consistent, so resume content stayed accurate whenever project details changed.
- Designed a portfolio experience with a 6-panel desktop layout and smooth mobile flow, so hiring managers could scan skills, projects, and resume links quickly without getting lost in navigation.
- Added 3 themes and 15 accent colors to keep content readable across preferences, improving first impressions for recruiters and reducing friction for returning visitors.
- Set up 5 spam checks on the contact form and cut low-quality submissions, so real recruiter outreach was easier to identify and respond to quickly.
- Split styles into 12 small CSS modules (under 200 lines each), making edits safer and reducing accidental UI regressions during rapid updates.
- Auto-generated and validated 13 resume variants and kept role-specific links consistent, so resume content stayed accurate whenever project details changed.
- Designed a portfolio experience with a 6-panel desktop layout and smooth mobile flow, so hiring managers could scan skills, projects, and resume links quickly without getting lost in navigation.
- Added 3 themes and 15 accent colors to keep content readable across preferences, improving first impressions for recruiters and reducing friction for returning visitors.
- Set up 5 spam checks on the contact form and cut low-quality submissions, so real recruiter outreach was easier to identify and respond to quickly.
- Split styles into 12 small CSS modules (under 200 lines each), making edits safer and reducing accidental UI regressions during rapid updates.
- Auto-generated and validated 13 resume variants and kept role-specific links consistent, so resume content stayed accurate whenever project details changed.
- Designed a portfolio experience with a 6-panel desktop layout and smooth mobile flow, so hiring managers could scan skills, projects, and resume links quickly without getting lost in navigation.
- Added 3 themes and 15 accent colors to keep content readable across preferences, improving first impressions for recruiters and reducing friction for returning visitors.
- Set up 5 spam checks on the contact form and cut low-quality submissions, so real recruiter outreach was easier to identify and respond to quickly.
- Split styles into 12 small CSS modules (under 200 lines each), making edits safer and reducing accidental UI regressions during rapid updates.
- Auto-generated and validated 13 resume variants and kept role-specific links consistent, so resume content stayed accurate whenever project details changed.
- Designed a portfolio experience with a 6-panel desktop layout and smooth mobile flow, so hiring managers could scan skills, projects, and resume links quickly without getting lost in navigation.
- Added 3 themes and 15 accent colors to keep content readable across preferences, improving first impressions for recruiters and reducing friction for returning visitors.
- Set up 5 spam checks on the contact form and cut low-quality submissions, so real recruiter outreach was easier to identify and respond to quickly.
- Split styles into 12 small CSS modules (under 200 lines each), making edits safer and reducing accidental UI regressions during rapid updates.
- Auto-generated and validated 13 resume variants and kept role-specific links consistent, so resume content stayed accurate whenever project details changed.
- Designed a portfolio experience with a 6-panel desktop layout and smooth mobile flow, so hiring managers could scan skills, projects, and resume links quickly without getting lost in navigation.
- Added 3 themes and 15 accent colors to keep content readable across preferences, improving first impressions for recruiters and reducing friction for returning visitors.
- Set up 5 spam checks on the contact form and cut low-quality submissions, so real recruiter outreach was easier to identify and respond to quickly.
- Split styles into 12 small CSS modules (under 200 lines each), making edits safer and reducing accidental UI regressions during rapid updates.
- Auto-generated and validated 13 resume variants and kept role-specific links consistent, so resume content stayed accurate whenever project details changed.
- Designed a portfolio experience with a 6-panel desktop layout and smooth mobile flow, so hiring managers could scan skills, projects, and resume links quickly without getting lost in navigation.
- Added 3 themes and 15 accent colors to keep content readable across preferences, improving first impressions for recruiters and reducing friction for returning visitors.
- Set up 5 spam checks on the contact form and cut low-quality submissions, so real recruiter outreach was easier to identify and respond to quickly.
- Split styles into 12 small CSS modules (under 200 lines each), making edits safer and reducing accidental UI regressions during rapid updates.
- Auto-generated and validated 13 resume variants and kept role-specific links consistent, so resume content stayed accurate whenever project details changed.
- Built a portfolio that is easy to scan with a 6-panel desktop layout, so recruiters can find key information quickly on both desktop and mobile.
- Added 3 themes and 15 color options to improve readability for different viewers and make longer browsing sessions more comfortable.
- Used 5 spam checks in the contact form and reduced junk messages, so real hiring conversations received faster attention.
- Kept 13 resume variants aligned automatically and avoided manual cleanup, so each role-focused resume stayed accurate after content updates.
- Organized styles into 12 small modules (under 200 lines each) and made updates predictable, reducing avoidable rework during iterative changes.
- Built a portfolio that is easy to scan with a 6-panel desktop layout, so recruiters can find key information quickly on both desktop and mobile.
- Added 3 themes and 15 color options to improve readability for different viewers and make longer browsing sessions more comfortable.
- Used 5 spam checks in the contact form and reduced junk messages, so real hiring conversations received faster attention.
- Kept 13 resume variants aligned automatically and avoided manual cleanup, so each role-focused resume stayed accurate after content updates.
- Organized styles into 12 small modules (under 200 lines each) and made updates predictable, reducing avoidable rework during iterative changes.
- Built a portfolio that is easy to scan with a 6-panel desktop layout, so recruiters can find key information quickly on both desktop and mobile.
- Added 3 themes and 15 color options to improve readability for different viewers and make longer browsing sessions more comfortable.
- Used 5 spam checks in the contact form and reduced junk messages, so real hiring conversations received faster attention.
- Kept 13 resume variants aligned automatically and avoided manual cleanup, so each role-focused resume stayed accurate after content updates.
- Organized styles into 12 small modules (under 200 lines each) and made updates predictable, reducing avoidable rework during iterative changes.
- Built a portfolio that is easy to scan with a 6-panel desktop layout, so recruiters can find key information quickly on both desktop and mobile.
- Added 3 themes and 15 color options to improve readability for different viewers and make longer browsing sessions more comfortable.
- Used 5 spam checks in the contact form and reduced junk messages, so real hiring conversations received faster attention.
- Kept 13 resume variants aligned automatically and avoided manual cleanup, so each role-focused resume stayed accurate after content updates.
- Organized styles into 12 small modules (under 200 lines each) and made updates predictable, reducing avoidable rework during iterative changes.
David Leer
- GitHub: @kmokdefi
- Twitter: @kmok_defi
Built with <3 by @kmokdefi