← Back

Architectural Decision Records

Chronological log of decisions and their tradeoffs.


2024-09-30 · Next.js App Router as the foundation

Rebuilt the site on Next.js 14 App Router.

For: Server components, static export, and built-in image optimisation are well suited to a portfolio. File-based routing keeps things simple.

Against: App Router conventions add mental overhead compared to a basic static site generator. Some third-party packages still have incomplete App Router support — ran into this later.


2024-11-02 · Snowfall as a standalone page

The snowfall animation lives at its own route rather than embedded in the portfolio.

For: Full-screen immersive experience. Can be shared or linked to as a standalone piece.

Against: Requires a back-link so users aren't stranded. The dark background couldn't be set globally — it bled into other pages on navigation because the framework doesn't unload page-level styles on client-side transitions. Required a more deliberate scoping approach.


2024-11-04 · Third-party analytics

Added page view tracking via a deferred script so it loads after the page is interactive.

For: Understand which content gets traffic without slowing down the page.

Against: Blocked by most ad-blockers, so data is always incomplete. Adds a third-party dependency to every page load.


2024-11-29 · Auth added, then removed

Built a login-protected section using Google SSO. Removed in a later pass.

For: Lets you protect private content without building custom auth.

Against: Hit a production build error that required a patch. Auth infrastructure is significant overhead for a mostly-public portfolio. The protected content was eventually removed, making auth pointless.

Conclusion: Auth is not worth the complexity here. If private sections are needed in future, a simple password-protected page or a separate deployment is a better fit.


2025-09-20 · Writings as a plain list, not a blog system

Writings are a typed list of titles, dates, and links — not a full CMS or markdown pipeline.

For: Zero infrastructure. External articles and internal posts coexist in the same list. Trivial to add a new entry.

Against: Each internal post still needs a hand-written page file. No support for drafts or scheduled publishing. Doesn't scale gracefully past roughly ten posts.


2026-04-08 · Blog posts as plain code files

Individual blog posts are written directly as page files. No markdown, no headless CMS.

For: Full control over layout and styling per post. No build pipeline complexity.

Against: Each new post requires creating a file and writing code rather than prose. Not a good authoring experience as volume grows.

Why not a CMS: A CMS was evaluated and fully reverted due to unstable APIs at the time. For infrequent, high-effort posts, a code file is acceptable for now.


2026-05-02 · Single file as the content layer

All manually managed content — writings, paintings, software, recent items — lives in one typed file.

For: One place to update anything. The type system enforces that every piece of content has the required fields.

Against: The file grows with content volume. Adding or removing a section requires code changes — this isn't something a non-technical collaborator could do.


2026-05-02 · Filesystem-based image loading for comics

Comic images are read from disk at build time, sorted by file modification time.

For: Adding new comics requires no code changes at all — just drop a file into a folder. Order is controlled by when you drop the file, regardless of filename.

Against: Only works at build time on the server — can't be done in the browser. Modification time resets when files are copied or a repo is re-cloned, which can scramble ordering unexpectedly.


2026-05-02 · Page rendered as a server component with isolated client islands

The portfolio page is server-rendered. Only the lightbox, waitlist form, and contact form are client-side.

For: No JavaScript sent to the browser for the page itself — fast load, good for search engines. Server rendering can read from the filesystem at build time.

Against: Any interactivity has to be pushed into a separate isolated component. Easy to accidentally break by adding browser-only code to the wrong file.


2026-05-02 · Single image grid component with multiple navigation modes

One reusable grid handles three different interaction patterns: standalone images, a shared navigable gallery, and multi-panel comics where clicking a panel opens that sequence.

For: Lightbox behaviour, keyboard navigation, watermarking, and grid layout are written once and shared across all image sections.

Against: The multi-panel mode relies on each grid item carrying extra metadata — the contract isn't obvious from looking at the component. Multiple modes mean multiple code paths to maintain.


2026-05-02 · Recently section is manually curated

The recently feed is populated explicitly rather than auto-aggregated from all content.

For: Full editorial control. An ongoing practice series with many images can appear as a single entry rather than flooding the feed.

Against: Easy to forget to add an entry when publishing. Some content is registered in two places — once in its own section, once in the recent feed.

Why not auto-aggregation: Ongoing series don't belong in a feed as individual items. The noise outweighed the convenience.


2026-05-02 · Single typeface

One font loaded, with a system fallback. A second decorative font was removed.

For: One fewer network request. Consistent visual rhythm across the page.

Against: Less typographic contrast between headings and body text.


2026-05-02 · Visible watermark using colour inversion

A text watermark is rendered on all image thumbnails and the lightbox using a blend mode that inverts against the background.

For: Automatically visible on both white and dark backgrounds without choosing a specific colour.

Against: Can look unusual on mid-tone or colourful backgrounds. Can be removed with basic image editing — not a true technical barrier.

Why not adversarial image poisoning: Tools like Glaze apply imperceptible perturbations that confuse AI style models at the pixel level. This must be done offline before images are uploaded. The web watermark is a supplementary layer, not a replacement. Glaze is recommended for high-value originals.


2026-05-02 · AI crawler blocking in robots declaration

Known AI training crawlers are explicitly blocked from image directories. Images are also flagged to prevent indexing by search engines.

For: Major AI labs publicly commit to honouring these declarations. It is the most practical protection available without a server or CDN.

Against: Declarations are not enforceable. Rogue scrapers ignore them. The list of known crawlers requires ongoing maintenance as new ones appear.