Personal Site Build
The Goal: I previously hosted my portfolio on Canva. While it was easy to set up, I found it incredibly restrictive, I couldn't control the details, the code, or the SEO. I also didn't want to pay monthly subscription fees for a simple portfolio site.
The Solution: I decided to build a static site from scratch using standard HTML and Tailwind CSS. It was a good opportunity to get more comfortable with code and set up a proper development workflow. Now, I have full control over the domain and hosting without the overhead of a website builder.
Escaping the "Builder" Trap
The main driver for this project was cost and flexibility. Website builders are convenient, but they lock you into their ecosystem. By switching to raw HTML, I could create the exact minimalist layout I wanted without fighting against pre-made templates. I used Tailwind CSS to handle the styling because it keeps the CSS file small and easy to manage.
module.exports = {
darkMode: 'class',
theme: {
extend: {
colors: {
// Defining my own simple palette rather than
// relying on a builder's preset themes.
cream: '#F0EFEA',
surface: '#FFFFFF',
'dark-bg': '#18181B',
}
}
}
}
The Deployment Workflow
I wanted the site to be as easy to update as possible. I set up a continuous deployment pipeline using GitHub and Cloudflare Pages. Now, when I want to add a new project or fix a typo, I just edit the code on my laptop and push the changes to the repository. Cloudflare detects the commit and rebuilds the site automatically in seconds.
# The entire update process takes three commands
$ git add .
$ git commit -m "Added new case study"
$ git push origin main
# ... Cloudflare automatically builds and deploys to https://olivertwilliams.com
The "One Template" System
I realized early on that creating a separate HTML file for every new project would be a maintenance nightmare. If I wanted to change the layout, I’d have to edit twenty different files. Instead, I built a single reusable template and a central "database" in JavaScript.
const projects = [
{
title: "Mainframe Studios",
category: "Advertising",
desc: "Unique typeface and poster...",
image: "images/mainframe2.png",
// This link tells the template which data to load
link: "project.html?id=mainframe"
},
// ... other projects follow the same structure
];
How It Works
This array acts as the central nervous system for the portfolio. When you click a project, you aren't going to a unique page, you are going to a master template (project.html) that checks the URL.
It sees ?id=mainframe, looks up the corresponding object in this array, and dynamically injects the title, image, and description into the DOM. This means I can add a new case study just by adding one block of text to this file, instead of having to write a new HTML page.