73

developer.ericgitangu.com

Personal portfolio and technical showcase — Next.js 13 App Router, Contentlayer MDX project pages, Upstash Redis view counting and Snake leaderboard, 79-certification carousel across 9 authorities, virtual vCard/ICS business card with QR code, PWA, Framer Motion, and a canvas Snake game with mobile swipe + haptic support.

What it is

Personal portfolio built to be a technical artifact, not just a landing page. Every feature uses the full stack: Redis for real-time counters and leaderboards, Contentlayer for type-safe MDX content, qrcode.react for a downloadable contact card, canvas + react-swipeable for a mobile-playable Snake game, and a 79-entry certification dataset across 9 authorities rendered in a navigable carousel.

Live: developer.ericgitangu.com
Source: github.com/ericgitangu/deveric

Projects — Contentlayer + Redis view counting

Projects are MDX files processed by Contentlayer at build time into typed Project objects — no CMS, no database reads for content. Each project page increments a view counter in Upstash Redis using an atomic INCR on page load (server action), giving real-time counts without polling. The projects grid is statically generated; only the counter fetch is dynamic.

Certifications — 79 certs, 9 authorities, 10 domains

app/certifications/data.ts (803 lines) is the source of truth: 79 certifications with id, name, url, authority, domain, date, licenseNumber, and featured flag. Authorities: Meta (20), LinkedIn Learning (39), Coursera (12), Duke University (Rust specialization), DeepLearning.AI, HackerRank, Udemy, SoloLearn, HackerX. Domains span Backend, Frontend, Mobile, Data Science, Blockchain, Security, DevOps, Languages, AI/ML, and Fundamentals.

CertificationCarousel renders them in a swipeable carousel grouped by domain. CertificationCard links directly to the issuing authority. CarouselDots tracks position. All filtered client-side — no server round-trip for domain switching.

Virtual business card — vCard/ICS download + QR code

BusinessCardPanel.tsx (373 lines) is a full contact-card implementation:

  • VCF file served at /eric-gitangu.vcf — standard vCard 3.0 format, importable by iOS Contacts, Android, Outlook, macOS Contacts
  • QR code generated client-side via qrcode.react pointing to the VCF URL — scan-to-import from any phone
  • WhatsApp deep-link QR for direct chat
  • Dual phone numbers: US (+1-978-710-9475) and Kenya (+254-708-078-997)
  • LinkedIn, GitHub, and portfolio links in a single panel
  • UI: fixed left-edge tab on desktop (vertical text), floating bottom-left pill on mobile — no layout shift
  • Panel reveals with Framer Motion spring animation

Snake game — canvas, swipe, haptic feedback, Redis leaderboard

SnakeGame.tsx (383 lines):

  • Canvas rendering with a 20px grid. Responsive canvas: 300px mobile / 350px tablet / 400px desktop, recalculated on resize via ResizeObserver
  • Keyboard (arrow keys) + react-swipeable for mobile swipe detection — same game, both input surfaces
  • Speed curve: starts at 200ms tick interval, decreases by 5ms per food eaten, floor at 50ms
  • Collision detection: wall bounds + self-intersection check on every move
  • useHaptics custom hook fires the Vibration API on food eat and game over — progressive enhancement, no-op on desktop
  • GameOverModal prompts for a display name, then writes { name, score, timestamp } to Upstash Redis sorted set snake:leaderboard with ZADD (score as sort key)
  • Leaderboard fetched from Redis on game start — top 10 by score, displayed alongside the game
  • HapticSnackbar shows score milestones mid-game without interrupting play

Fun zone

app/fun/page.tsx composes: SnakeGame + TipFetcher + Particles background (canvas-based particle system, no library dependency).

TipFetcher calls app/api/tips/route.ts — a Next.js route handler that returns a random development tip from a static array. Auto-refreshes every 30s client-side. The API route is edge-compatible.

PWA

PWAInstallPrompt.tsx hooks the beforeinstallprompt browser event and surfaces a custom install prompt rather than relying on the browser default. manifest.json is generated at build time with the correct theme color and icon set. The site is fully installable on iOS (Add to Home Screen) and Android (PWA install).

SEO and structured data

app/lib/structured-data.ts (166 lines) generates Schema.org JSON-LD for every page type: Person, WebSite, ProfilePage, BreadcrumbList, ItemList (projects), and AboutPage. Injected via next/head script tags — no third-party SEO library. <meta> og/twitter tags are per-page via Next.js 13 generateMetadata.

Stack

Next.js 13 App Router · TypeScript · Tailwind CSS · Contentlayer · Upstash Redis · Framer Motion · qrcode.react · react-swipeable · @vercel/analytics · Vercel · Rome formatter · Rehype + Remark plugins · Inter + CalSans fonts