DEV Community

Cover image for I Coded My Portfolio From Scratch. No Templates.
Syed Ahmer Shah
Syed Ahmer Shah

Posted on

I Coded My Portfolio From Scratch. No Templates.

There is a very specific kind of regret that hits when you deploy someone else's template, change the name and the profile picture, push it to GitHub, and then look at the result and think — yeah. That's me. That's my work.

It's not. It never was.

I made that mistake once. Grabbed something off a free portfolio site, tweaked the colors a bit, added my name in the hero section. It looked clean. It looked professional even. But whenever someone asked me about it I'd skip over the details because deep down I knew I hadn't built any of it. I had dressed up someone else's house and called it home.

So when I finally decided to sit down and build ahmershah.dev properly, the first rule I set for myself was simple — no template. Not even as a reference. Start from index.html and figure the rest out.

What followed was months of fighting with CSS, arguing with Three.js, debugging scroll behavior at 1 AM, and slowly building something that I can actually explain line by line. This is that story.


Why Templates Are a Trap (For Beginners Especially)

Before I get into the build, I want to actually say something here because I see this conversation come up constantly in developer communities. People ask — should I use a template for my portfolio? And the nice answer is: it depends.

The honest answer is: if you're learning, a template will stunt you.

Using a template means you skip the decisions. You skip figuring out why a section is structured the way it is, why a certain animation works the way it does, why the developer chose to reach for a library instead of writing something custom. You inherit a finished product and you don't get any of the understanding that came from building it.

Now if you're a senior developer trying to ship a portfolio in a weekend because you're job hunting — sure. Template makes sense. Time is money.

But if you're a student, if you're early in your career, if you're trying to prove to yourself and to the people hiring you that you can build things — then building your own portfolio is genuinely one of the best projects you can do. Not because the portfolio itself is impressive. Because the process of building it forces you to answer real questions.


The Stack and Why It Looks the Way It Does

My stack for this project is: HTML5, custom CSS (this is the majority of the codebase, not Bootstrap), Bootstrap 5 for the grid layer only, vanilla JavaScript, a little bit of jQuery (honestly way less than I planned), Three.js, TurnJS, TiltJS, Lenis.js, and AJAX for some of the dynamic loading. Contact form runs through Formspree.

If you look at the repo's language breakdown — it's 50.7% JavaScript, 29.3% CSS, 20% HTML. That CSS number felt right when I saw it. A lot of the complexity in this site lives in the stylesheets.

I want to explain why the stack ended up looking like this because I made some deliberate choices and some accidental ones.

Bootstrap vs Custom CSS — this one matters

The instinct a lot of beginners have is to let Bootstrap do everything. You end up with like 50 utility classes on every div and very little actual understanding of what the layout is doing. I made the decision early on to use Bootstrap only for the grid system and for a few responsive breakpoints. Everything else — spacing, typography, animations, color, positioning — is custom CSS using variables.

This was slower. It was also much better for me as a developer. When something broke I had to understand why it broke instead of just switching utility classes until it looked right.

The result is a CSS file that is actually kind of long and in some places probably not perfectly organized. That's real. I'm not going to pretend the codebase is immaculate. There are sections where I know I could refactor things, places where I wrote a specific rule to fix a very specific layout problem and then never cleaned it up properly. The site works and it looks good but the code behind it has the marks of something that was built iteratively over time, not planned from the start.

JavaScript — mostly vanilla, jQuery at the edges

I planned to use jQuery more. Ended up using it way less. Vanilla JS handles most of the interaction logic. jQuery ended up in a few specific places where I was doing quick DOM manipulation and the syntax was just cleaner.

I don't think there's a strong philosophical argument here. It's just that once you start writing vanilla JS properly you realize most of the things you were reaching for jQuery to do are actually not that hard.


Three.js, a Blender File, and the Learning Curve I Underestimated

The Three.js section of this build took way longer than I thought it would.

Three.js is one of those libraries where the documentation is technically good and also kind of confusing if you haven't done any 3D work before. The concepts — scene, camera, renderer, geometry, material, mesh, light — they make complete sense once you get it. Before you get it, it feels like you're assembling furniture from instructions written in a different language.

I used Blender to create the 3D model that lives in the portfolio. If you've never opened Blender, it is a lot. The interface alone takes a few days to get comfortable with. But for what I needed — modeling a specific object, exporting it in a format Three.js can read — it was the right tool.

The thing nobody tells you about Three.js performance is that 3D on the web is heavy by default and you have to actively fight against that. Geometry complexity, texture resolution, how you're handling the render loop, whether you're correctly disposing of objects when they're not needed — all of this hits your frame rate. I ended up adding a toggle that lets users turn off the 3D effects entirely, specifically for older devices. Some people will land on the site on a five year old phone. The site should still work for them.

Before adding the 3D scene:
The hero section was static. Clean, but kind of flat. No real visual depth.

After:
There's actual spatial weight to the page. The 3D element gives the viewport a sense of depth that you can't really replicate with CSS tricks alone.

The trade-off is performance. I'll be honest — Three.js adds real weight to the bundle and if you don't handle it carefully your Lighthouse score will tell you. I spent time optimizing how and when the scene initializes, deferring it until after critical content loads.


The Certifications Book That Took a Weird Amount of Work

One of the sections I'm most satisfied with is the certifications section. Instead of a standard grid of certificate images, I built a flipbook — an actual book you can page through — using TurnJS combined with TiltJS for the 3D tilt effect when you hover.

TurnJS is a library that simulates page turning. It uses CSS3 transforms and JavaScript to create a page-flip animation that looks like a real book. Wiring it up to work with the actual certificate content, making it responsive, handling the edge cases around what happens when someone is on a touch device — this took more time than I expected.

TiltJS sits on top of that and adds the parallax tilt effect when you move your mouse over the book. The way the two libraries interact required some careful event handling. There were bugs. There were moments where the tilt was triggering when it shouldn't, or where the page flip animation was cutting off because something in the transition timing was conflicting.

But when it works — and it works now — it's genuinely one of the most distinctive things on the site. Every other developer portfolio has a grid of certificates. Mine has a book.


Scroll Behavior: Lenis, IntersectionObserver, and the Scrolljacking Debate

Smooth scroll is one of those things that sounds like a nice small detail and turns into a rabbit hole.

I'm using Lenis.js for smooth scrolling. Lenis intercepts the native scroll and replaces it with a smoother, physics-based animation. The result is this buttery, almost native-app feel when you scroll through the page. It's subtle but it matters. The difference between scrolling a site with and without Lenis is the difference between dragging something across carpet versus dragging it across glass.

The debate around scrolljacking is real and worth acknowledging. Scrolljacking — controlling or manipulating the scroll behavior beyond the user's direct input — has a bad reputation and for good reason. It can feel jarring, it breaks user expectations, and it's particularly bad for accessibility. I made specific choices here: the Lenis implementation I'm using follows the user's actual scroll direction and speed, it doesn't take over or redirect the scroll, it just smooths the physics. That's different from the aggressive scrolljacking you see on some agency sites where sections snap into place whether you wanted them to or not.

IntersectionObserver is what drives the section animations. Elements animate in when they enter the viewport. I'm not using a library for this — it's native browser API, well supported, and honestly not that complicated once you write it a few times. The performance profile is much better than scroll event listeners, which fire constantly and are easy to abuse.


SignalHub: The Section I've Never Seen on Another Portfolio

The section called SignalHub is the one I get the most questions about.

Most portfolios have a contact section with a few social icons at the bottom. Facebook, GitHub, LinkedIn, maybe Twitter. That's fine. Functional. Forgettable.

SignalHub is a full section built around two sides — a personal side and a professional side. It's my complete social presence, organized by context. The professional side has GitHub, LinkedIn, dev.to. The personal side has the stuff that's more me and less resume. Both sides are clean, navigable, and presented as a real part of the site rather than an afterthought footer row.

The reason I built it this way is that I think there's actually a signal in how a developer organizes their online presence. Showing that I've thought about context — personal vs professional, what belongs where — says something. It's also just more useful for whoever is looking at the site. If a recruiter lands on it they go to the professional side. If another developer is curious about what I'm actually like as a person they go to the other side.

Is it unconventional? Yes. Did some people think it was weird when I described it? Also yes. It's still on the site.


Nine Sections, One Page, Zero Frameworks

The portfolio is a single page application in the most literal sense — it's one HTML file with nine distinct sections: Home, About, Education, Skills, Certification, Blog, Contact, Projects, and SignalHub.

No React. No Vue. No Next.js. Just HTML, CSS, JavaScript, and a set of libraries that handle specific things.

I want to defend this choice because the developer community has a habit of treating framework usage as a marker of seriousness. If you're not using React you're not building real things, that sort of attitude. I think that's backwards.

For a static portfolio site, a framework adds complexity without adding value. React's component model solves problems that a single-page portfolio doesn't have. The virtual DOM solves a reconciliation problem that doesn't exist when your content doesn't change at runtime. You're adding a build step, a node_modules folder, a mental model, and a bundle size — and none of those things make the portfolio better for the people visiting it.

The cursor tracking, the trailing cursor effect, the animations — all of that is JavaScript. Not framework JavaScript. Just JavaScript.


SEO on a Static Site: The Part Most Portfolio Guides Skip

This part took longer than any feature.

I want to go through what's actually implemented because "I set up SEO" is a phrase people say without explaining what that means.

Meta Tags and Open Graph

Every important meta tag is in the head. Open Graph tags so the site previews correctly when shared on social media. Twitter card meta. Canonical URL. Description. Keywords. These are the basics and they take maybe 30 minutes but a lot of portfolio sites don't have them.

JSON-LD Structured Data

This is the thing most developers skip. JSON-LD is a way to embed structured data in your page that search engines can parse to understand what your page is about. For a personal portfolio, the relevant schema types are Person, WebSite, and potentially BreadcrumbList. Having this in place means Google can potentially show rich results — things like your name and links directly in the search results, not just the page title.

llms.txt

If you haven't heard of llms.txt, it's a relatively new convention — a plain text file at the root of your site that describes your site to large language models. The idea is similar to robots.txt but for AI crawlers. I added one because I think it's going to matter more over time as AI-driven search and AI assistants become the primary way people discover content.

robots.txt and sitemap.xml

Both are present. The sitemap is submitted to both Google Search Console and Bing Webmaster Tools. The robots.txt is correctly configured — there's nothing sophisticated to block, so it's mostly permissive, but having it there properly formatted matters.

Cloudinary for Image Delivery

Images are served from Cloudinary in WebP format with PNG fallbacks. WebP images are on average 25-35% smaller than equivalent JPEG or PNG files. When you're serving a portfolio that has project screenshots, certificate images, profile photos — that size difference accumulates. Cloudinary also gives you automatic format selection and responsive image delivery, so mobile users aren't downloading desktop-sized images.

Google and Bing Indexing

The site is verified with both Google Search Console and Bing Webmaster Tools. Manual indexing requests were submitted. I know this because I did it. Not passively waiting for crawlers to find it.

Structured Heading Hierarchy

One H1 per page. H2s for major sections. H3s inside sections where appropriate. This isn't just SEO — it's accessibility. Screen readers navigate by heading structure. If your headings are a mess the page is a mess.


The "Over-Clean" Problem

There is a thing that happens when you have full control over a codebase and you spend too much time on it. Everything starts looking a little too perfect. Every spacing value is consistent, every transition matches, every color is deliberate. And then you look at it from a distance and something feels slightly off. Too polished. Like a room that nobody actually lives in.

I've had a few people describe my portfolio as "over-clean." I understand what they mean. There's something about a site that looks like it was designed in Figma and exported perfectly that can feel slightly removed. Like you're looking at a product shot rather than a person's work.

I don't have a full solution for this. I've thought about adding more intentional asymmetry, rougher textures, sections that break the grid on purpose. Some of the upcoming features I'm working on — a built-in blog, a personal AI integration, a game — those might add the kind of lived-in quality that the site currently lacks.

For now I'm sitting with it. Sometimes clean is clean and that's fine.


What's Coming Next (The Honest Version)

Here are the features I'm actively working on or thinking seriously about:

Personal AI integration — an AI assistant that knows my work, my writing, my projects, and can answer questions about me. This is actually more interesting technically than it sounds because it requires some form of retrieval-augmented generation rather than just wrapping a model API call.

Built-in blog — not links to external posts. Articles that live inside the portfolio itself, properly rendered, indexed, and consistent with the site's design language.

Case studies for projects — right now the project section shows what I built. The plan is to add case studies that show why I built it, what decisions I made, what I'd change. The how matters less than the thinking behind it.

Performance and accessibility audit — Lighthouse scores are okay but there's work left. WCAG 2.1 AA compliance is the target for accessibility. fetchpriority hints for above-the-fold images. Better font loading strategy.

Replacing the current modal with a custom one — the modal system I'm using right now is borrowed. Writing my own gives me full control over the interaction model and removes an external dependency.


The Thing That Actually Mattered

145 commits to the main branch. 23 stars. 7 forks. JavaScript at 50.7% of the codebase.

None of those numbers are the point.

The point is that when someone asks me how the certification flipbook works, I can explain it. When someone asks why I chose Lenis over native smooth scroll, I have an actual answer. When someone asks about the SEO implementation, I don't have to guess — I built it, I know what's in there.

A template can look better than what I built. Probably several of them do. But a template doesn't teach you anything except how to edit someone else's decisions. And if you're at the beginning of your career, decisions — making them, understanding them, owning them — are what you're supposed to be practicing.

Build your own portfolio. Make it messy if you have to. Make decisions you'll regret later and then learn why you regret them. Put your name on something you actually built.

That's the whole thing.


Stack summary: HTML5, custom CSS3, Bootstrap 5 (grid only), Vanilla JS, jQuery (minimal), Three.js, Blender (3D modeling), TurnJS, TiltJS, Lenis.js, AJAX, Formspree, Cloudinary, GitHub Pages / custom domain

Live: ahmershah.dev

GitHub Repo: ahmershahdev/Portfolio


Find Me Across the Web

Top comments (46)

Collapse
 
sourabh_mourya_3f8d350fc0 profile image
Sourabh Mourya

This is nice, but the speed is too slow. Design is great and looking awesome🙂.

Collapse
 
syedahmershah profile image
Syed Ahmer Shah

Thankyou , I will try to improve the speed

Collapse
 
musabsheikh profile image
Faraz

Your argument about skipping frameworks like React for a single-page portfolio is spot on. The industry has conditioned people to bundle an entire runtime and node_modules just to render a static profile. Sticking to vanilla JavaScript, custom CSS, and selective libraries keeps the footprint clean and matches the exact scope of the project. It is refreshing to see someone defend proper fundamental architecture instead of over-engineering with a virtual DOM where it is not required.

Collapse
 
syedahmershah profile image
Syed Ahmer Shah

Agreed. Frameworks are powerful tools, but for a static portfolio, they often introduce unnecessary bloat. Stripping it back to basics forces a deeper understanding of the browser's native capabilities.

Collapse
 
shubhradev profile image
Shubhra Pokhariya

The “over-clean” point you mentioned is honestly the most interesting part of the whole post.

Most people would just take that feedback as a compliment and move on, but you are already thinking about intentional imperfection and making it feel more lived-in, which is a much harder design problem than just polishing things.

I like the idea of the built-in blog for that. Actual writing usually does more to add that “someone lives here” feeling than any visual tweak ever can.

Curious if you already have ideas on how you want to introduce that texture without breaking the clean structure too much.

Collapse
 
syedahmershah profile image
Syed Ahmer Shah

I'm leaning heavily into the blog for that exact reason. To keep the clean structure intact while adding character, I’m planning to use subtle typography shifts—like a more organic serif font for long-form text—and raw, unpolished dev logs alongside polished articles. I might also introduce slight asymmetrical layouts or custom, hand-drawn utility icons that break the rigid grid just enough to feel human.

Collapse
 
shubhradev profile image
Shubhra Pokhariya

That makes a lot of sense. Curious to see how you balance that over time, feels like one of those things that evolves with real usage more than planning.

Collapse
 
syedfarzeenshahofficial profile image
Vinod Oad

Building a custom 3D mesh in Blender and optimizing the Three.js render loop is no joke for a web project. You made an excellent call by implementing a dedicated toggle to disable the 3D scene entirely for older mobile devices. Many developers throw heavy WebGL elements onto their landing pages without considering low-end hardware or initial layout shift, so deferring initialization shows real consideration for user experience.

Collapse
 
syedahmershah profile image
Syed Ahmer Shah

Thanks for highlighting that. Performance isn't a "nice-to-have"—it's a requirement. Managing the render loop for mobile users ensures the site remains accessible regardless of hardware.

Collapse
 
sahilkumar profile image
Sahil Kumar • Edited

This is awesome. A custom-built portfolio says a lot more about your skills to potential employers than a pre-made theme ever could. Looking forward to seeing how you continue to iterate and grow it over time.

Collapse
 
syedahmershah profile image
Syed Ahmer Shah

Really impressed by the commitment to building this from the ground up, Syed. There's a massive difference between knowing how to use a framework and understanding the architecture that makes it work. That 'hands-on' approach you've taken—especially with the custom Three.js implementation and optimization for mobile—is exactly what sets a developer apart. Great work!

Collapse
 
syedasharshah profile image
Vicky Jaish

There is a unique kind of satisfaction that comes from writing every line of code yourself. It is the best way to truly learn and understand how everything connects. Thanks for sharing your journey and inspiring others to ditch the templates.

Collapse
 
syedahmershah profile image
Syed Ahmer Shah

Thankyou

Collapse
 
farzeenshahofficial profile image
Zohaib

Building a portfolio from scratch is no small feat, but the payoff is completely worth it. It gives you absolute control over your code and design, which templates just can't match. Great work on taking the harder, more rewarding route.

Collapse
 
syedahmershah profile image
Syed Ahmer Shah

The attention to detail here is top-tier. Most people overlook the 'invisible' parts of a portfolio, but things like the llms.txt file and the deliberate choice to optimize the 3D render loop for mobile show that you’re thinking about the next generation of web accessibility. It’s refreshing to see someone focus on building a lean, performant experience rather than just adding layers of abstraction.

Collapse
 
faique_26 profile image
Faique

Using Bootstrap exclusively for the layout grid layer while writing pure custom CSS for the typography, variables, and animations is a fantastic middle ground. It prevents the typical utility-class bloat where HTML becomes unreadable, and as you mentioned, it forces you to actually debug the layout model yourself when things break rather than just guessing with random framework helper classes.

Collapse
 
syedahmershah profile image
Syed Ahmer Shah

Exactly. Using Bootstrap only for the grid keeps the CSS modular without sacrificing control over the design system.

Collapse
 
farzeendev profile image
Sagar Kumar

The inclusion of an llms.txt file is an incredibly forward-thinking addition for a personal site. Most portfolio tutorials stop at basic open graph tags, completely ignoring semantic search and structured JSON-LD data. Making your source code and documentation readily scannable for AI crawlers is going to become highly relevant as the landscape transitions away from traditional search engines.

Collapse
 
syedahmershah profile image
Syed Ahmer Shah

Glad you noticed the llms.txt. With how quickly AI search is evolving, ensuring our personal sites are machine-readable is just as important as being human-readable.

Collapse
 
farzeen profile image
Tahir

This post highlights exactly why building from scratch matters. When you inherit a pre-built template, you lose the technical depth of knowing why specific performance trade-offs or design adjustments were made. Being able to explain every single animation, asset optimization strategy, and script choice line by line is precisely what differentiates a true engineer from someone who just modifies configuration files.

Collapse
 
syedahmershah profile image
Syed Ahmer Shah

Understanding the "why" behind every line of code is what separates someone who just uses tools from an engineer who can truly master them.