My personal portfolio and blog — built with Next.js 16 (App Router), MDX, and interactive animated components.
Live → mmishchenko.dev
- Interactive MDX blog with custom animated React components (Tokenizer, FlowDiagram, EmbeddingSpace, Aside)
- Automated devlog pipeline — LinkedIn posts auto-expand into long-form blog articles via GPT-4o
- Dark theme with spotlight hover effects and smooth Framer Motion animations
- RSS feed at
/blog/feed.xml - SEO optimized — dynamic sitemap, static OpenGraph fallback, canonical URLs, security headers
- Contact form powered by Resend API
- Responsive — mobile-first design
| Layer | Technology |
|---|---|
| Framework | Next.js 16 (App Router, Turbopack) |
| Language | TypeScript 5 (strict) |
| Styling | Tailwind CSS v4 |
| Animations | Framer Motion |
| Blog | MDX via next-mdx-remote/rsc |
| Syntax Highlighting | sugar-high |
| Resend API | |
| Deployment | Vercel; Cloudflare Workers via OpenNext with a size dry-run guard |
| Domain | Cloudflare DNS |
# Install dependencies
npm install
# Run development server
npm run dev
# Build for production
npm run build
# Lint
npm run lintThis app is full-stack Next.js (App Router plus API routes), so Cloudflare readiness uses Cloudflare Workers with the OpenNext adapter instead of static Pages.
# Build and preview in the Workers runtime
npm run preview
# Build and check the Worker upload size before deploying
npm run cf-dry-run
# Build and deploy to Cloudflare Workers
npm run deploy
# Regenerate Worker environment types after wrangler.jsonc changes
npm run cf-typegenRequired Cloudflare setup:
- Create or use a Cloudflare account with Workers enabled.
- Enable Cloudflare Images transformations for the zone because the app uses
next/image. - Set
CLOUDFLARE_ACCOUNT_IDandCLOUDFLARE_API_TOKENas GitHub repository secrets for.github/workflows/cloudflare-deploy.yml. - Add runtime secrets in Cloudflare, not in source:
RESEND_API_KEY,CONTACT_EMAIL,GITHUB_TOKEN,BLOG_PUBLISH_SECRET, andSTAGING_SECRET. - Route
mmishchenko.devto themmishchenko-portfolioWorker after the first successful deploy.
Free-plan deployment notes:
- Cloudflare rejects Worker uploads above the 3 MiB gzip size limit with error code
10027. - The deploy workflow builds the OpenNext bundle, runs
wrangler deploy --dry-runas a size guard, and only deploys after that guard passes. - Dynamic
next/ogimage routes were removed because@vercel/ogbundles WASM into the Worker. Metadata now uses the existing static avatar image instead of generated per-route OpenGraph images. - Mermaid MDX diagrams render as source blocks to avoid bundling the Mermaid browser runtime into the Worker. Current posts do not use Mermaid diagrams.
src/
├── app/ # Next.js App Router pages
├── components/ # React components
│ └── mdx/
│ └── interactive/ # Animated blog components
├── lib/ # Constants, utilities
content/
└── blog/ # MDX blog posts
The blog supports interactive MDX components:
<Tokenizer>— Animated text → subword → token ID visualization with play/pause controls<FlowDiagram>— Step-by-step animated flow diagrams<EmbeddingSpace>— SVG-based word vector visualization<Aside>— Collapsible supplementary info panels