A simple and to-the-point personal portfolio built with modern web technologies.
- Framework: Next.js (App Router)
- Library: React
- Styling: Tailwind CSS & clsx / tailwind-merge
- UI Components: Radix UI & shadcn/ui
- Content: MDX & Remark
- Animations: Motion (Framer Motion) & GSAP
- Icons: Lucide React & React Icons
- Caching/Storage: Cloudflare Workers & R2
- MDX Support: Write content (like the about page and projects) quickly using MDX.
- Interactive Animations: Smooth page transitions and text splitting animations powered by Framer Motion and GSAP.
- Dark/Light Mode: Seamless theme switching with
next-themes. - Responsive Layout: Fully responsive UI relying on Tailwind CSS.
- Dynamic Open Graph Images: Automatically generated OG images for every page, cached on Cloudflare R2 for better performance.
First, install the dependencies (assuming you use npm, yarn, pnpm, or bun):
npm install
# or
yarn install
# or
pnpm install
# or
bun installThen, run the development server:
npm run dev
# or
yarn dev
# or
pnpm dev
# or
bun devOpen http://localhost:3000 with your browser to see the result.
src/app/- Next.js App Router (pages, layout, routing)src/components/- Reusable UI components (buttons, nav, layouts, sections)content/- MDX content files for projects and general pagespublic/- Static assets like images and site manifestscloudflare-r2-worker/- Cloudflare Worker for caching Open Graph images in R2
This project uses a Cloudflare Worker to cache generated Open Graph images. Follow these steps to setup and deploy:
-
Navigate to the worker directory:
cd cloudflare-r2-worker -
Login to Cloudflare:
npx wrangler login
-
Create an R2 bucket:
npx wrangler r2 bucket create portfolio-og
[!IMPORTANT]
portfolio-ogis the recommended bucket name. You can use a different bucket name, but you must updatewrangler.jsonc(line 19),src/index.ts(lines 21 & 26), and regenerate types usingnpx wrangler types. -
Verify the bucket:
npx wrangler r2 bucket list
-
Deploy:
# Optional: Local testing npx wrangler dev # Deploy to production npx wrangler deploy
-
Configure Environment Variable: Get the worker URL from the deployment output (e.g.,
https://cloudflare-r2-worker.yourcloudflare.workers.dev) or usehttp://localhost:8787for local development (output fromnpx wrangler dev), and set it as an environment variable in your project:# Production CLOUDFLARE_R2_WORKER_URL=https://your-worker-url.workers.dev # or # Development CLOUDFLARE_R2_WORKER_URL=http://localhost:8787
Here is an overview of the app's routing structure generated during a production build:
Route (app)
┌ ○ /
├ ○ /_not-found
├ ƒ /og
├ ● /project/[slug]
│ ├ /project/example2
│ └ /project/example
├ ○ /robots.txt
└ ○ /sitemap.xml
○ (Static) prerendered as static content
● (SSG) prerendered as static HTML (uses generateStaticParams)
ƒ (Dynamic) server-rendered on demand


