Skip to content

Repository files navigation

⚡ EINCODE — Where Code Meets Curiosity

Ein's Digital Laboratory. Not a portfolio. A laboratory. Experiments, prototypes, and open-source artifacts — forged, tested, and refined in public.

EINCODE Banner

LiveNext.jsReactTailwindTS

pnpmNodeLicensePRs


Table of Contents


Philosophy

EINCODE is built as a digital workshop, not a static showcase:

  • Forge in public — every experiment ships with source, live demo, and lab notes.
  • Lab over gallery — WIP is first-class. Progress bars, status indicators, and field notes tell the story of how it was built.
  • Content as code — blog posts are MDX files versioned in content/ (content/building-linux-distro-from-scratch.mdx:1), rendered with next-mdx-remote + shiki + rehype.
  • Modern by default — Next.js 16 App Router, React 19 Server Components, Tailwind v4 CSS-first config, next/font optimized fonts.

If you want a template for a fast, SEO-perfect, MDX-powered personal site that still feels like a hacker lab — this is it.


🔗 Live Demo

EnvironmentURL
Productionhttps://eindev.ir
Alt Domainhttps://eincode.dev (see .env.example:2)

Preview the hero's typewriter, projects grid, lab notes, and workbench directly on the homepage — app/page.tsx:10 composes Header, HeroSection, ProjectsGrid, LabNotes, Workbench, Footer.


✨ Features

AreaWhat you get
Hero LabTypewriter role rotation ("building interfaces", "crafting code"), ASCII terminal, floating version badge — components/hero-section.tsx:6
Artifacts Grid8 open-source projects with shipped / in-progress / archived filters, stars/forks, glassmorphism & hover-lift — components/projects-grid.tsx:7
WorkbenchLive WIP terminal with progress bars (60–90%), ~/ehsanghaffar/active header — components/workbench.tsx:4
Lab Notes4 field notes with category pills & gradient hovers — components/lab-notes.tsx:7
Blog EngineFile-based MDX in content/ (8 posts), gray-matter frontmatter, GFM, autolink headings, pretty-code — lib/mdx-utils.ts:8
ThemingDark/light/system with next-themes, ThemeProvider (app/layout.tsx:100), ThemeToggle + ThemeChanger, OKLCH tokens, globals.css:8
MDX Pipelinenext-mdx-remote + rehype-slug + rehype-autolink-headings + rehype-pretty-code (shiki) + remark-gfmcomponents/mdx-remote.tsx:1
SEO Masterymetadata (app/layout.tsx:25), JSON-LD (lib/structured-data.ts:32), sitemap.ts:4 + robots.ts:3, OG image public/og-image.png
A11y + Perfnext/font (Geist, Geist_Mono, Space_Grotesk), AVIF/WebP images (next.config.mjs:5), reduced-motion, touch targets 44px — app/globals.css:640
UI Kitshadcn/ui on Radix primitives — 20+ components in components/ui/ (accordion, dialog, dropdown-menu, etc.)
AnalyticsVercel Analytics injected in root layout — app/layout.tsx:103

🧱 Tech Stack

Core

TechVersionPurposeConfig
Next.js16.1.0App Router, Turbopack, SSR/SSG, Metadata APInext.config.mjs:1
React19.2.3Server Components, use client islandspackage.json:64
TypeScript5.9.3Strict types, path alias @/*tsconfig.json:25
Tailwind CSS4.1.9CSS-first @import "tailwindcss", OKLCH, @plugin typographyapp/globals.css:1

UI & Styling

TechDetails
Radix UI16 primitives — accordion, dialog, popover, tabs, toast, etc. — package.json:24
shadcn/uicomponents.json + components/ui/ + lib/utils.ts:1 (cn = clsx + tailwind-merge)
Lucide React0.454.0 icons throughout
next-themes0.4.6 class-based dark mode
tw-animate-css1.3.3 animation utilities

Content & Markdown

TechUsage
next-mdx-remote6.0.0Serialize & hydrate MDX
gray-matter4.0.3Frontmatter parsing — lib/mdx-utils.ts:3
remark-gfm4.0.1GitHub Flavored Markdown
rehype-slug / autolink-headings / pretty-codeAnchors + Shiki highlighting
shiki3.22.0Syntax highlighting
@tailwindcss/typography0.5.19Prose styling .proseapp/globals.css:163

Tooling

TechVersion
pnpm>=9 recommended (lockfile pnpm-lock.yaml)
ESLinteslint .package.json:18
Vercel Analyticslatest
zod3.25, react-hook-form7.60, recharts2.15, date-fns4.1, embla-carousel...Extra UI deps pre-wired

📁 Project Structure

eincode/
├── app/ # Next.js 16 App Router — app/layout.tsx:92
│ ├── (public)/ # Route group (shared layout)
│ │ ├── blog/
│ │ │ ├── [postSlug]/page.tsx # Dynamic MDX post — lib/mdx-utils.ts:34
│ │ │ └── page.tsx # Blog index
│ │ ├── projects/page.tsx
│ │ ├── workbench/page.tsx
│ │ ├── notes/page.tsx
│ │ ├── introduction/page.tsx
│ │ └── layout.tsx
│ ├── page.tsx # Homepage — composes 6 sections
│ ├── layout.tsx # Root layout, fonts, metadata, ThemeProvider
│ ├── globals.css # Tailwind v4 + OKLCH tokens + animations
│ ├── sitemap.ts # Dynamic sitemap from MDX — app/sitemap.ts:4
│ ├── robots.ts # Robots.txt — app/robots.ts:3
│ ├── error.tsx / not-found.tsx
│ └── favicon.ico
├── components/
│ ├── hero-section.tsx # Typewriter + ASCII terminal
│ ├── projects-grid.tsx # Filterable artifacts grid
│ ├── workbench.tsx # Terminal-style WIP list
│ ├── lab-notes.tsx # Field notes grid
│ ├── header.tsx / footer.tsx
│ ├── cursor-glow.tsx
│ ├── mdx-remote.tsx / mdx-components.tsx
│ ├── theme-provider.tsx / theme-toggle.tsx / theme-changer.tsx
│ └── ui/ # 20+ shadcn/ui components
├── content/ # MDX blog source (8 posts)
│ ├── building-linux-distro-from-scratch.mdx
│ ├── mcp-protocol-llm-applications.mdx
│ ├── nextjs-16-tailwind-v4-migration.mdx
│ └── ... (5 more)
├── lib/
│ ├── mdx-utils.ts # getAllMDXPosts(), getMDXPostBySlug()
│ ├── blog-data.tsx # Legacy in-memory posts + helpers
│ ├── structured-data.ts # JSON-LD: BlogPosting, WebSite, Person
│ ├── themes.ts / utils.ts
├── types/mdx.ts # BlogPostFrontmatter, BlogPost
├── public/
│ ├── og-image.png / og-images/
│ ├── icon.svg / apple-icon.png
│ └── site.webmanifest
├── docs/ # architecture.md, performance.md, etc.
├── next.config.mjs # AVIF/WebP, deviceSizes
├── components.json # shadcn config
├── tsconfig.json # @/* alias
└── package.json

🚀 Getting Started

Prerequisites

  • Node.js>=18 (20+ recommended)
  • pnpmnpm i -g pnpm or see pnpm.io
  • Git

1. Clone & Install

git clone https://github.com/ehsanghaffar/eincode.git
cd eincode
pnpm install

2. Environment

cp .env.example .env
# edit .env
VariableRequiredDefaultDescription
NEXT_PUBLIC_SITE_URLNohttps://eindev.irCanonical URL for metadata/sitemap — app/layout.tsx:26
NEXT_PUBLIC_GITHUB_URLNohttps://github.com/ehsanghaffarSocial link
NEXT_PUBLIC_TWITTER_URLNoSocial link
NEXT_PUBLIC_LINKEDIN_URLNoSocial link

No database, no API keys. The site is fully static + MDX. Analytics is zero-config on Vercel.

3. Run Dev Server (Turbopack)

pnpm dev
# → http://localhost:3000

Hot reload is near-instant with Next.js 16 Turbopack.

4. Production Build

pnpm build
pnpm start
# → http://localhost:3000 (optimized)

✍️ Content Authoring — MDX

All posts live in content/*.mdx and are read at build time via lib/mdx-utils.ts:8.

Frontmatter Schema — types/mdx.ts:1

---
title: "Building a Linux Distro from Scratch"excerpt: "A comprehensive guide to compiling the kernel..."date: "2025-11-15"# display datedateISO: "2025-11-15"# used for sorting — lib/mdx-utils.ts:29category: "systems"# systems | ai | frontendreadTime: "12 min read"tags: ["linux", "kernel", "devops"]author: "Ehsan Ghaffar"published: true # false = draft, filtered outimage: "/og-images/my-post.png"# optional
---

Create a New Post

# 1. Add file
touch content/my-new-post.mdx
# 2. Write MDX — supports GFM, code blocks with Shiki, headings with anchors
---title: "My New Post"excerpt: "One-line hook for the blog index."date: "2026-08-23"dateISO: "2026-08-23"category: "frontend"readTime: "5 min read"tags: ["nextjs", "tailwind"]published: true---## Introduction
Hello MDX!
```tsexportconst hello ="world"```> Tip: headings auto-get `id` + anchor links via `rehype-slug` + `rehype-autolink-headings`.

No restart needed in dev — just refresh. For production, the post is auto-added to sitemap.ts:48.

Helpers

import{getAllMDXPosts,getMDXPostBySlug,getAllMDXCategories}from"@/lib/mdx-utils"import{getPostBySlug,getRelatedPosts}from"@/lib/blog-data"// legacy helper

🗺 Routes & App Router

RouteFileDescription
/app/page.tsx:10Hero + Projects + Lab Notes + Workbench + Footer
/blogapp/(public)/blog/page.tsxPaginated MDX listing
/blog/[postSlug]app/(public)/blog/[postSlug]/page.tsxMDX render + JSON-LD + related posts
/projectsapp/(public)/projects/page.tsxFull artifacts archive
/workbenchapp/(public)/workbench/page.tsxDedicated WIP view
/notesapp/(public)/notes/page.tsxLab notes archive
/introductionapp/(public)/introduction/page.tsxAbout / intro
/sitemap.xmlapp/sitemap.ts:4Auto-generated from static + MDX routes
/robots.txtapp/robots.ts:3allow: /, disallow: /api/, /_next/

Static routes use weekly/daily changeFrequency; blog posts use monthly with priority: 0.7.


🎨 Design System

Tokens — app/globals.css:8

  • OKLCH paletteoklch(0.5 0.22 170) primary (teal) for both light & dark, with tailored lightness.
  • CSS-first Tailwind v4 — no tailwind.config.js; all tokens in @theme inlineapp/globals.css:86.
  • FontsGeist (sans), Geist_Mono (mono), Space_Grotesk via next/font/google with display: swap + CSS variables — app/layout.tsx:9.

Utilities

  • .glass / .glass-strong — backdrop-blur + saturate
  • .hover-lifttranslateY(-4px) + shadow
  • .cursor-glow — 400px radial gradient following cursor (hidden on mobile) — app/globals.css:188
  • .scanlines — subtle repeating linear gradient overlay — app/globals.css:206
  • Animations: fade-in-up, scale-in, slide-in-*, float, pulse-glow, shimmer + stagger-1..8

Theming

// app/layout.tsx:100<ThemeProviderattribute="class"defaultTheme="dark"enableSystemstorageKey="theme-mode">

Toggle via components/theme-toggle.tsx and multi-theme switcher components/theme-changer.tsx + lib/themes.ts.


🔍 SEO & Performance

  • Metadata APItitle.template, openGraph, twitter, robots, icons, manifestapp/layout.tsx:25
  • JSON-LDWebSite + Person on homepage (app/page.tsx:12), BlogPosting + BreadcrumbList on posts — lib/structured-data.ts:3
  • Sitemap & Robots — dynamic, MDX-aware
  • Imagesformats: ['image/avif','image/webp'], 8 deviceSizes — next.config.mjs:5
  • Fontsnext/font self-hosted, no CLS
  • A11yprefers-reduced-motion, 44px touch targets, focus-visible rings, semantic headings
  • Perf — Turbopack dev, transform: translateZ(0) hardware accel, blur reduction on touch devices — app/globals.css:140

Check deeper dives in docs/performance.md, docs/accessibility.md, docs/architecture.md.


📜 Scripts

CommandDescriptionSource
pnpm devStart dev server (Turbopack)next dev
pnpm buildProduction buildnext build
pnpm startServe production buildnext start
pnpm lintESLinteslint .
pnpm analyzeBundle analyzernext experimental-analyze

☁️ Deployment

Optimized for Vercel — zero config.

# via CLI
pnpm i -g vercel
vercel --prod
# or connect GitHub repo → Vercel auto-deploys on push

Other platforms (Netlify, Docker, Node server): pnpm build && pnpm start serves on PORT (default 3000). For Docker, see the sibling template next16-docker-tw4-starter.

Environment on Vercel: set NEXT_PUBLIC_SITE_URL to your production domain.


🤝 Contributing

Contributions are welcome — especially fixes to MDX rendering, a11y, or new lab notes!

  1. Open an issue for larger changes
  2. Branch: git checkout -b feat/my-change
  3. Commit with clear messages
  4. PR with screenshots for UI changes, and ensure pnpm build passes

Code style: TypeScript strict, eslint ., Tailwind v4 utilities, Radix + shadcn patterns.


📄 License & Author

MIT © 2024–2025 Ehsan Ghaffargithub.com/ehsanghaffar · eindev.ir · twitter.com/ehsanghaffar

Built with ❤️, oklch, and a healthy obsession with next/font.


Forge. Break. Rebuild. Repeat. — EINCODE

About

A modern personal portfolio and digital laboratory built with Next.js 16, React 19 and cutting-edge web technologies.

Topics

Resources

Stars

10 stars

Watchers

0 watching

Forks

Contributors

Languages