A minimal, fast, accessible and SEO-first developer portfolio template with projects, case studies and a blog. Built with Next.js (App Router), Tailwind CSS v4 and Framer Motion. Fully static, no backend.
Live demo: https://salahu01.github.io/quietfolio-template/ (sample content)
Click Use this template on GitHub, or:
git clone https://github.com/salahu01/quietfolio-template my-site && cd my-site
nvm use # Node 22 (.nvmrc)
npm install
npm run dev # http://localhost:3000- You — edit
lib/data.ts: name, role, bio, links, projects, experience, tech stack. Setprofile.githubUserfor the activity graph. - Writing — edit
content/work.json(case studies) andcontent/blog.json(posts). Runnpm run validateto catch broken links, missing images and duplicate slugs. - Images — replace
public/img/avatar.jpegandpublic/img/projects/*.jpg.python3 scripts/make_sample_assets.pyregenerates neutral placeholders. - Brand assets —
python3 scripts/make_brand_assets.py "Your Name" "Your Role" "yourdomain.com"regenerates the favicon, Apple icon and social image from your avatar. - SEO — set
NEXT_PUBLIC_SITE_URL(see.env.example) and reviewlib/site.ts(description, keywords, Twitter handle). - Resume —
/resumeis a printable page generated from your data. Regenerate the PDF withnpm run build && npm start, thennpm run resume. - Banner — the animated pixel-art banner comes from
python3 scripts/make_banner.py(needs Pillow). Edit the script to change the scene.
- Single-page home (about, projects with filters, experience, tech stack, GitHub activity) plus
/work/[slug]case studies,/blogand/resume. - Animated pixel-art banner, pixel cursor trail + focus reticle, dark/light theme (no flash), ⌘K command palette.
- SEO / AEO / GEO: per-page metadata and canonical URLs, Open Graph + Twitter cards (per-post generated images), JSON-LD (
Person,WebSite,ProfilePage,TechArticle,BlogPosting,Blog,BreadcrumbList),sitemap.xml,robots.txt, RSS (/feed.xml),llms.txtandllms-full.txt,security.txt, web manifest. - Accessibility: skip link, landmarks, AA contrast, visible focus,
prefers-reduced-motion(static banner, no cursor effects), keyboard-operable palette and filters. - Hardening: security headers and a strict CSP in production, no third-party scripts,
X-Powered-Byremoved, JSON-LD escaped.
| Script | Purpose |
|---|---|
npm run dev |
Dev server |
npm run build / npm start |
Production build / serve |
npm run lint · npm run typecheck |
ESLint · TypeScript |
npm run validate |
Validates content/*.json, links and assets |
npm run check |
Everything above, in order (what CI runs) |
npm run deploy:pages |
Static export → gh-pages branch (GitHub Pages) |
npm run resume |
Regenerate public/resume.pdf |
Blocks: h2, h3, p, ul, ol, quote, code, img, table. Inline: **bold**, *italic*, `code`, [text](url). See the sample posts in content/blog.json.
Copy .env.example:
| Variable | Default | Purpose |
|---|---|---|
NEXT_PUBLIC_SITE_URL |
https://example.com |
Canonical URL (origin + optional sub-path) for metadata, sitemap, feeds, JSON-LD. A warning is printed at build time if unset. |
NEXT_PUBLIC_BASE_PATH |
(empty) | Sub-path when served from a folder, e.g. /my-repo. Set automatically by deploy:pages. |
NEXT_PUBLIC_NOINDEX |
(unset) | 1 makes the build non-indexable (for demos/mirrors). |
STATIC_EXPORT |
(unset) | 1 builds a static out/ folder instead of a Node server build. |
Netlify / Vercel / any Node host — connect the repo and set NEXT_PUBLIC_SITE_URL to your domain. Security headers, the CSP and the /work redirect apply in this mode (netlify.toml is included).
GitHub Pages (static export) — no server, no Actions required:
npm run deploy:pagesThis builds with STATIC_EXPORT=1, NEXT_PUBLIC_BASE_PATH=/<repo> and publishes out/ to the gh-pages branch. Then in the repo go to Settings → Pages → Deploy from a branch → gh-pages / root. It is served at https://<user>.github.io/<repo>/ and does not affect your other Pages sites. Notes:
- Custom headers/CSP and redirects don't exist on a static host, and images aren't optimized at request time (keep images web-sized;
scripts/optimize_images.pyshrinks project covers). - Demo builds set
NEXT_PUBLIC_NOINDEX=1so a mirror never competes with your canonical site in search. Remove that variable inscripts/deploy_pages.shif the Pages site is your real one.
After deploying, verify /sitemap.xml, /robots.txt, /llms.txt, /feed.xml, and test a page in the Rich Results Test. Submit the sitemap in Google Search Console and Bing Webmaster Tools.
If you change third-party origins (for example the GitHub activity API), update the CSP in next.config.ts.
app/ routes, metadata files (sitemap, robots, manifest, OG images, feeds)
components/ UI (Hero, Projects, Navbar, CursorFx, JSON-LD, article renderer…)
content/ case studies + blog posts (JSON)
lib/ data, site config, SEO helpers, content loader
public/img/ images
scripts/ asset generators, content validator, deploy script
See CONTRIBUTING.md, SECURITY.md and CODE_OF_CONDUCT.md.
MIT.
