General structure
- Gave Claude some examples of project websites I like: Personal websites I like.
- Clean grid of project cards, thumbnail + title + year + status. Responsive to hover over and clicking.
- Self-contained static side.
- Should be able to deploy as its own Netlify site.
Buildup
- The data file, the only thing I need to edit to add projects:
projects.js,index.html - Render script that turns the data into cards:
render.js - Stylesheet:
style.css - Netlify config:
netlify.toml= Netlify’s configuration file. It’s optional for a plain static site, but it removes guesswork and saves clicking through settings in their dashboard. - Read me:
README.md - In the folder, there’s also an
images/folder to drop thumbnails in.
To add a project
- Open
project.js. - Copy a block to the top, and fill it in:
title: "My New Thing",
year: "2026",
status: "active", // active | hiatus | archived | offline
blurb: "One short sentence.",
url: "https://the-project.com",
image: "images/my-thing.png", // or "" for a lettered placeholder
tags: ["web", "design"],
}
- Each card shows a thumbnail, title, year, and a colour-coded status pill, an optional blurb, and tags. The whole card links out if you give it an URL.
Deploying to Netlify
See the README.mdfile.
- Drag the project folder onto app.netlify.com/drop.
- Or: Push the folder do its own Github repo, then in Netlify Add new site > Import an existing project. Build command empty, publish dir (already set in
netlify.toml).
Style
All style things lin in style.css, e.g. background colour, font style, card shadows, etc.
If a Google font is used, it needs a link added to index.html.
Good non-Google monospace fonts are e.g. SF Mono, Menlo, Consolas.
Dark mode has its own block with its own colours. If dark mode is not wanted, the entire block can be deleted.
Neo-brutalism: thick borders, hard offset shadows, monospace, flat bright colours. Colours: orange, teal, yellow Square corners, near black frame (#1a1a1a), hard black shadow. Cream background (#f3ece0), so the bright accent colours pop.
Thumbnails
Real project thumbnails will replace the colour blocks per-card; the flat colours only show when a project has no image.
16:10, landscape, is the default setting for thumbnails. Anything else will get cropped to that. Aim for 800 x 500 pixels for good sharpness. Keep under 200 KB.
- Drop the files in the
images/folder. - Reference by filename in
projects.js, e.g.image: "images/climate-notes.jpg". - Filename tips: lowercase, no spaces (use hyphens), and be consistent —
digital-garden.jpg, notDigital Garden.JPG. Netlify’s servers are case-sensitive, soImage.jpgreferenced asimage.jpgwill 404 even though it works on your Mac.
To change to square thumbnails: Change --radius… no — change aspect-ratio: 16 / 10 to 1 / 1 in the .thumb rule (make them 800×800 then).
OR
Have images of wildly different shapes and don’t want cropping? I can switch object-fit: cover to contain (shows the whole image, letterboxed)
Some things I might want to tweak and how
- Title colour — it’s near-black now. Change
--title: var(--ink)to#fc955aif you instead want an orange heading. - All-caps — remove the
text-transform: uppercaselines on.site-header h1/.card-titleif you’d rather keep normal casing. - The three placeholder colours —
--accent-1/2/3. Add more and bump the% 3in render.js if you ever want a longer rotation.
Sections
Photos
Tips
The key idea for a photo gallery: never make the visitor download full-resolution photos up front. A grid of full-size JPEGs is what makes photo pages crawl. Instead — show small thumbnails, and only load the big version when someone actually clicks a photo.
A grid of small thumbnails (300-500 px wide, 30-80 KB)→ click one → it opens the full-size photo in a lightbox (dark overlay, arrow keys to move between photos). This is the standard photo-gallery UX and it’s the fastest: the page only ever loads little thumbnails; full photos load one at a time, on demand.
Lazy loading. loading="lazy" on each image means photos below the fold don’t load until you scroll near them. So a 100-photo gallery loads like a 10-photo one.
Use modern formats WebP, AVIF. 30-50% smaller than JPEG at the same quality. Export your thumbnails as WebP.
Reserve each image’s space (set width/height or aspect-ratio) so the page doesn’t jump around as photos pop in.
How to update
photos.html- the gallery pagephotos.js- your photo list ⇒ the only file to edit to add photosgallery.js- masonry tile-layout and lightbox logicgallery.css- gallery styling with the neo-brutalist styleimages/photos- add the photos there
Photos keep their real proportions (= masonry tile-layout), no cropping. 3 columns. Lightbox = click any photo for a full-size view. Arrow keys or on-screen arrows to move, Esc or click outside to close.
To add own photos:
- Drop files into
images/photos/(lowercase-hyphenated names). - Add a line to
photos.js.:
{ file: "images/photos/my-shot.jpg", caption: "My shot", w: 1600, h: 1000 },
(w/h are optional but recommended, they stop the layout jumping as photos load)
At the top of the gallery.js, there’s
const USE_NETLIFY_IMAGES = false;
Leave it false while previewing locally. Once your site is live on Netlify, set it to true — the gallery will then auto-serve small, compressed WebP thumbnails (and larger versions in the lightbox) via Netlify’s built-in Image CDN, so you can upload full-resolution photos without making thumbnails by hand. It works on same-origin images with no extra netlify.toml config.
Convert to WebP WebP at ~2000px/quality-82 is a good recipe for any new photo. Ask Claude to convert whenever I add one.