Browse narratives

EN · · 6 min read

Building Lens of Charlie

Why this site starts with portable content and a deliberately small architecture.

Build LogIntroductoryEvolving

Revised

Lens of Charlie began with a simple requirement: I wanted a place that could hold technical notes, project decisions, and photographs without asking any one platform for permission. The first version did not need accounts, a database, or a publishing dashboard. It needed a point of view, durable source files, and a reading experience quiet enough for the work to remain central.

That distinction matters. It is easy to spend months building the machinery of a personal site while publishing almost nothing. Infrastructure is satisfying because its progress is measurable. Writing is less comfortable: it exposes unfinished thinking. The architecture therefore has to make publication easier, not become another respectable form of postponement.

Start with the purpose

Lens of Charlie is the independent home of a software engineer. Writing and projects are the center. Photography is present because observing carefully is part of how I learn, not because I want the site to present me as a professional photographer.

The name describes a lens rather than a résumé. A project page records what was built; an article records how my understanding changed; a photograph records a moment that resisted being reduced to a technical lesson. Together they form a more honest archive than a conventional portfolio made only of finished work.

A quiet flame

Two paths often appear before a traveler: one familiar and well worn, the other quieter and leading somewhere unknown. I rarely know which one is right. I only know to keep walking, learning, and adapting along the way.

Perhaps the journey is not about finding the perfect path, but becoming someone capable of walking any path.

Curiosity is the quiet flame that keeps learning, building, and exploring alive.

Keep the content portable

The foundation is static HTML generated from Markdown and small data files. The browser receives a document first. JavaScript enhances search, diagrams, lightboxes, and reading progress, but it does not own the article. This keeps the critical path small and makes failure graceful: if an enhancement fails, the reader still has headings, links, code, and prose.

Markdown is valuable here because it is plain enough to survive the current framework. Frontmatter adds the minimum structure needed for dates, language, type, depth, maturity, tags, and series. Astro validates that contract at build time and turns the source into static routes. The generated HTML is disposable; the source and its history are not.

flowchart LR Author["Markdown and metadata"] --> GitHub GitHub --> Build["Astro build"] Build --> Pages["Cloudflare Pages"] Photos["Optimized photos in GitHub"] --> Build Metadata["Photo metadata"] --> Build Pages --> Visitor
ContentSource of truthDelivery
Writing and projectsGitHubStatic HTML on Pages
Article imagesGitHubVersioned static assets
Optimized photographsGitHub, under public/images/photos/Same static site
Photo metadataRepository data; generated manifest when neededIncluded at build time

Decision

Portability is not avoiding every provider. It is keeping provider decisions at clear boundaries so the content can outlive them.

Keep the photo archive small enough to own

I originally planned to put photo derivatives in Cloudflare R2. For the archive I actually want, that adds another service before it solves a problem. I do not expect to publish a huge number of images or offer full-resolution downloads. A modest set of optimized images is enough, and I am comfortable with that limit on quantity and quality.

The decision now is to keep web-ready photographs in this GitHub repository, under public/images/photos/, and deliver them with the static site. Article images already follow the same approach. The repository holds the public versions and their metadata; originals and master edits stay outside it. There is no separate photo bucket, upload credential, or asset domain to maintain.

This has a cost. Image changes grow Git history, and a larger archive would make cloning and deployment heavier. Optimization and a small collection are part of the decision, rather than tasks to leave until the archive gets large. If those limits become uncomfortable, I can revisit external storage then.

The gallery still has its own presentation needs. I want to browse all photos, or gather them around a trip, a region, or a memory. That organization belongs in metadata and does not need to determine where an image file lives. Natural ratios and a square grid are separate viewing choices.

Decision

Updated on 2026-10-09: GitHub now stores the optimized public photos alongside the site. This replaces the earlier R2 plan because the intended archive is small and does not need full-resolution delivery.

Make interaction earn its place

Minimalism is not the absence of interaction. It is a demand that interaction justify the attention it consumes. The project quick preview prevents an unnecessary navigation. The article drawer remains faint until a reader asks for it. Mermaid controls appear because large diagrams genuinely need zoom and pan. The gallery changes layout because photographs benefit from both proportional and comparative views.

Every effect has the same test:

  1. Does it clarify hierarchy, location, or state?
  2. Does it work with a keyboard and reduced motion?
  3. Does the document remain useful when the enhancement is unavailable?
  4. Is the visual cost smaller than the value it provides?

If the answer is no, the effect is decoration pretending to be product work.

Add complexity deliberately

The project currently chooses a static build, a content collection, and a small number of client-side modules. That is enough. Search can operate over rendered metadata. RSS and the sitemap can be produced during the build. Project data can remain in Markdown. There is no need to introduce a database merely because many websites have one.

The threshold for new infrastructure is evidence. A CMS becomes reasonable when editing through Git is a demonstrated constraint. A backend becomes reasonable when a feature owns mutable shared state. Analytics becomes reasonable when a specific decision depends on a metric. Until then, each service adds credentials, failure modes, privacy questions, and maintenance work without improving the reader’s experience.

Trade-off

A static-first architecture moves work to build time. That is an excellent trade while the corpus and build remain small, but it must be measured again when image processing or content volume changes the feedback loop.

Build a publication system, not a finished monument

Lens of Charlie is intentionally evolving. The article schema will become more precise as the library grows. The photo archive will move from mock studies to real, optimized repository assets and privacy-safe metadata. Project pages will gain evidence as the projects mature. None of those changes should require discarding the source.

The useful outcome of this architecture is not that it is clever. It is that a new article can begin as a Markdown file, receive a serious editorial review, and become a fast, accessible document with a stable URL. The system succeeds when it makes that cycle ordinary.

The site will never be complete in the way a product release can be complete. It is a record of learning, and learning keeps moving. The architecture only needs to protect that movement: keep the content portable, keep the boundaries clear, and let complexity arrive with a reason.