This repository contains the source code for my portfolio website at mwal.dev.
Personal portfolio site with my blog and a resume page. Built with 200ish lines of Python and no giant bulky frameworks.
Prerequisites:
- Python 3.13.x
Setup:
python -m venv .venv
source .venv/bin/activate # macOS/Linux
pip install -r requirements.txtBuild and serve locally:
make build # Build the site
make serve # Serve at http://localhost:8000
make clean # Remove generated filescontent/
├── articles/ # Blog posts
├── pages/ # Static pages
├── img/ # Images
├── fonts/ # Fonts included
└── extra/ # Static asset
templates/ # HTML templates
output/ # Generated site
build.py # Build script
This project uses Inter by Rasmus Andersson, licensed under the SIL Open Font License 1.1. See content/fonts/LICENSE.txt.
So you want to use this for your own website? Cool! Here's how to get started.
First, install the only dependency:
pip install markdownThat's literally it. One package.
Create this folder structure:
your-site/
├── content/
│ ├── articles/ # Your blog posts (.md files)
│ ├── pages/ # Static pages (about.md, resume.md, etc.)
│ ├── img/ # Images
│ └── extra/ # favicon, robots.txt, whatever
├── templates/
│ └── base.html # Your HTML template
└── build.py # Copy this from the repo
Your template file (templates/base.html) needs two placeholders:
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
<!-- Your CSS goes here -->
</head>
<body>
{{ content }}
</body>
</html>The script replaces {{ title }} with your page title and {{ content }} with your HTML.
Articles go in content/articles/ and look like this:
Title: My First Post
Date: 2024-03-24 20:19
Category: blog
Tags: python, web
Your content starts here...Pages go in content/pages/ and look like this:
title: About Me
date: 2024-01-01
Your content starts here...The metadata format is just key: value. The script parses everything before the first blank line as metadata. Everything else becomes your content.
Use {static} tags when referencing images:
The script converts this to the correct relative path automatically:
- Articles (in subdirectory):
../img/photo.jpg - Pages (in root):
./img/photo.jpg
This way you don't have to remember different paths for different page types.
Run this:
python build.pyYour site gets generated in output/. That's it. You're done.
The script:
- Cleans the output directory
- Copies your images and static files
- Processes all your Markdown files
- Generates a blog index (sorted by date)
- Creates index.html and 404.html
- Articles:
output/articles/{filename}.html - Pages:
output/{filename}.html - Blog listing:
output/blog.html - Home page:
output/index.html - 404 page:
output/404.html
Edit build.py. The functions are commented and the whole file is readable in about 10 minutes.
There's no RSS, no tag pages, no pagination, and no plugins. For a portfolio site I don't need any of that. If you do, you probably want Pelican or Hugo instead.
I wanted the geocities feeling of just making a website without learning a framework first.
Thank you for checking this out!
See LICENSE for details.