Most portfolio templates come with React, Next.js, or at least a build step. I wanted something different: a template that designers can actually understand and modify without touching a terminal (beyond the initial setup).
So I built one from scratch. 300KB. Zero dependencies. Vanilla everything.
Why vanilla?
I'm a product designer who codes. My own portfolio (diyor.design) runs on plain HTML, CSS, and JavaScript. When I decided to turn it into a template, I had a choice: rewrite it in a framework, or keep it simple.
I kept it simple. Here's why:
- Designers can read it. No JSX, no components, no state management. Just HTML files you can open in a browser.
- No build step. Edit a file, refresh the browser. Done.
-
It'll work in 10 years. No deprecated packages, no breaking updates, no
npm auditwarnings. - 300KB total. The entire template. Not the JavaScript bundle — the whole thing.
What's inside
- Bilingual support — Russian and English with a language switcher. Easy to adapt for any two languages.
- Dark mode — toggle button + automatic system preference, saved in localStorage.
- Case study template — numbered sections, stats grid, image lightbox with zoom, previous/next navigation.
-
Terminal easter egg — press
~for a secret terminal with design quotes. -
Design system overlay — press
Shift+Gto see the 12-column grid. -
One-command setup —
./setup.shasks your name, generates a favicon, replaces all placeholders. - SEO ready — Open Graph, JSON-LD, sitemap, canonical tags, hreflang.
- Accessible — ARIA, keyboard nav, focus-visible, reduced motion.
The setup experience
git clone https://github.com/diyoriko/portfolio-template.git my-portfolio
cd my-portfolio
./setup.sh
The script asks for your name, domain, email, socials. Then it:
- Replaces "Jane Smith" everywhere
- Generates an SVG favicon with your initial
- Updates CNAME, sitemap, config.json
- Done. Push to GitHub Pages.
What I'd do differently
The dark mode architecture. I started with just prefers-color-scheme but quickly realized users want a manual toggle. I ended up with a dual system: @media (prefers-color-scheme: dark) { :root:not(.light) { ... } } for auto mode, plus html.dark { ... } for manual. It works, but the CSS is duplicated. Next time I'd use CSS layers or a single class-based approach from the start.
Hardcoded colors. My first pass had rgba(0, 0, 0, 0.08) scattered everywhere for borders and shadows. In dark mode, they were invisible. I had to go back and replace them all with CSS custom properties. Lesson: use variables from day one, even for "obvious" values.
Try it
- Live demo — my actual portfolio, built with the same code
- GitHub repo — fork it, clone it, use the template button
- One-click deploy — GitHub template, ready to go
MIT licensed. If you build something with it, I'd love to see it.
I'm Diyor, a product and brand designer. I write about design systems, automation, and building things from scratch. diyor.design
Top comments (0)