A high-performance, 3D-integrated portfolio and blog built for speed, SEO, and top-tier developer experience.
This repository is more than just a personal website—it is a playground for bleeding-edge web technologies, meticulous software architecture, and immersive 3D web experiences.
- ⚡ Extreme Performance: Optimized for small bundles, rapid compile times, and scored with Vercel Speed Insights & Web Analytics.
- 🎨 Immersive 3D & Animation: Powered by
@react-three/fiber,@react-three/postprocessing,gsap, andmotionfor fluid, interactive visuals. - 📝 Modern Content Pipeline: Full MDX and Markdown support for blogging, with beautiful syntax highlighting powered by
sugar-high. - 🔍 Technical SEO: Fully automated sitemaps,
robots.txt, JSON-LD schema generation, and dynamic OpenGraph (OG) images. - 💅 Styling & Typography: Styled with Tailwind CSS, utilizing the sleek, highly-legible Geist font.
- 🧪 Enterprise Testing: Comprehensive testing suite featuring Vitest for unit tests and Playwright for E2E.
Want to run the codebase locally? Follow these steps:
- Node.js
>=24.0.0 - npm, yarn, or pnpm
# Clone the repository
git clone https://github.com/anthonycoffey/coffey.codes.git
# Navigate into the project
cd coffey.codes
# Install dependencies
npm install| Command | Action |
|---|---|
npm run dev |
Starts the local development server at http://localhost:3000 |
npm run build |
Builds the application for production |
npm run lint |
Runs ESLint across the codebase |
npm run test |
Executes unit tests via Vitest |
npm run test:e2e |
Runs End-to-End tests via Playwright |
npm run typecheck |
Runs TypeScript compiler checks |
The project uses the Next.js App Router architecture:
- Server-Centric Routing: File-system based routing within the
app/directory - React Server Components (RSCs): Components render on the server by default, reducing client-side JavaScript
- Client Components: Interactive UI elements opt-in via
'use client';directive - API Routes: Backend functionality via
app/api/directory
coffey.codes/
├── app/ # Next.js App Router
│ ├── api/ # API routes (search, contact)
│ ├── articles/ # Blog — listing, slugs, categories, tags, search
│ │ ├── posts/ # MDX blog post files
│ │ ├── [slug]/page.tsx # Individual article rendering
│ │ ├── category/[category]/page.tsx
│ │ └── tag/[tag]/page.tsx
│ ├── case-studies/ # Case studies listing
│ ├── contact/ # Contact page
│ ├── lp/ # ICP-targeted landing pages
│ ├── og/ # OG image generation (route handler)
│ ├── portfolio/ # Portfolio showcase
│ ├── rss/ # RSS feed (route handler)
│ ├── layout.tsx # Root layout
│ ├── page.tsx # Homepage
│ ├── robots.ts # robots.txt
│ └── sitemap.ts # Sitemap
├── components/ # Reusable React components
├── docs/ # Project documentation (DDD)
├── hooks/ # Custom React hooks
├── public/ # Static assets
├── styles/ # Global styles (SASS)
├── utils/ # Utility functions
├── CLAUDE.md # AI agent development guidelines
└── README.md # Project overview
| Layer | Technology | Notes |
|---|---|---|
| Framework | Next.js App Router (canary) | Hybrid SSR/SSG |
| Language | TypeScript | Strict mode |
| UI | React | Server + Client Components |
| Styling | Tailwind CSS v4 | darkMode: 'class' |
| Global styles | SASS | styles/global.sass |
| Theming | next-themes | System preference only |
| Content | next-mdx-remote + sugar-high | MDX blog posts |
| 3D | @react-three/fiber + drei | Homepage scenes |
| Animation | motion | UI animations |
| Icons | @heroicons/react | |
| Package Manager | npm | package.json |
| Hosting | Vercel | Auto-deploy from main |
| Analytics | Google Tag Manager | GTM-KJC6Q389 |
Chosen for hybrid SSR/SSG, React Server Components, and integrated features (image optimization, API routes, OG image generation).
Strict typing for code quality and maintainability across the codebase.
Utility-first CSS for rapid development. Complemented by SASS for global styles.
Allows JSX components within markdown, enabling rich interactive blog posts. Processed by next-mdx-remote.
npm is preferred for stability/practicality. Lock file is package.json.
- Server Components (default): static content, data fetching, SEO metadata
- Client Components (
'use client';): state, effects, browser APIs, user interaction
Key client components:
components/SearchBox.tsx— article search UIcomponents/ContactForm.tsx— contact formcomponents/ThreeScene.tsx,FishbowlScene.tsx— 3D scenes
Client Components cannot export metadata. Pattern: wrap in a Server Component layout.tsx that exports the metadata.
Example: app/portfolio/layout.tsx (Server, exports metadata) wraps app/portfolio/page.tsx (Client).
Custom components available in blog posts are registered in components/mdx.tsx. To add a new component usable in MDX:
- Create the component in
components/ - Register it in the
componentsmap incomponents/mdx.tsx
- Request hits
app/articles/[slug]/page.tsx - Page component reads MDX file from
app/articles/posts/{slug}.mdx next-mdx-remoteprocesses MDX content with custom components fromcomponents/mdx.tsxgenerateMetadataconstructs title from frontmattertitlefield, description fromsummary
- User types in
components/SearchBox.tsx(Client Component) - Debounced
useEffectcallsGET /api/search?q=... app/api/search/route.tsfilters post metadata and returns JSON- Results display inline or navigate to
app/articles/search/page.tsx
app/og/route.tsxgenerates dynamic OG images- Used in article
generateMetadatawith optionalimagefrontmatter field
npm install # Install dependencies (requires Node >= 22)
npm dev # Dev server at http://localhost:3000
npm build # Production build
npm start # Run production build locally
npm lint # ESLint
npm lint:fix # ESLint auto-fixAll SEO data work runs through @anthonycoffey/periscope, a TypeScript CLI that unifies Google Search Console, GA4, Bing Webmaster Tools, and Google Ads Keyword Planner under a single command surface.
| Command | What it does |
|---|---|
npm run seo:snapshot |
Pull all four engines into a dated JSON + Markdown pair in docs/strategy/data/ |
npm run seo:diff -- <ref> |
Diff snapshots with natural refs (yesterday, 7d, "last month", YYYY-MM-DD) or .json paths. newer defaults to latest. |
npm run seo:audit-articles |
Flag articles ranking on long-tails where Ads suggests a higher-volume term |
npm run seo:discover-topics |
Ranked editorial backlog of fresh keyword ideas (drops topics already covered) |
npm run seo:validate-lps |
Verdict per app/lp/* page: WELL_TARGETED / UNDER_INVESTED / OVER_AMBITIOUS |
npm run seo:probe -- <url> |
One-shot competitor URL probe — top 30 keyword ideas to stdout |
npm run seo:doctor |
Diagnose engine credentials and access (currently Google Ads) |
Common flags pass through after --, e.g. npm run seo:snapshot -- --engines=gsc --window=180 --asof=2026-05-09.
A few diff examples:
npm run seo:diff -- yesterday # latest vs yesterday
npm run seo:diff -- 7d # latest vs 7 days ago
npm run seo:diff -- "last month" # latest vs ~30 days ago
npm run seo:diff -- 2026-05-10 # latest vs explicit date
npm run seo:diff -- 2026-05-10 2026-05-17 # both explicitProject-specific values live in periscope.config.mjs at the repo root (siteUrl, GA4 property, article and LP dirs, categories, bot regions). Engine credentials come from .env / .env.local.
- Generate a GitHub PAT with only
read:packagesscope at https://github.com/settings/tokens. - Set the env var:
setx GITHUB_PACKAGES_TOKEN "ghp_yourTokenHere"(open a new terminal after). .npmrcis already committed (with env-var interpolation, no secrets).npm installwill resolve@anthonycoffey/periscopefrom GitHub Packages.- Verify:
npx periscope --versionandnpx periscope --help.
Engine setup (Google service account, Bing API key, Google Ads dev token) is documented in docs/documentation/guides/seo-snapshot-setup.md. When something auth-related goes sideways, npm run seo:doctor pinpoints the exact misconfiguration.
npm update @anthonycoffey/periscopeAnthony Coffey
- 🌐 coffey.codes
- 🐙 GitHub
This project is licensed under the MIT License - see the LICENSE file for details.