Skip to content

Case study

Building Hirak.devv

Designing a static-first publishing platform for technical writing — and treating information architecture, typography, accessibility and performance as one system.

15 min read
  • Platform Engineering
  • Performance
  • GitOps
Building Hirak.devv

I wanted a personal website, but I did not want a conventional portfolio.

Most developer portfolios are designed primarily to present projects, skills, and experience. I wanted something slightly different: a place where the projects, the technical writing, the experiments, and the process behind them could live together.

The website needed to function less like a portfolio and more like a small technical publication.

That created a more interesting problem than simply choosing a framework and building a few pages.

I needed to think about information architecture, content modelling, typography, responsive behaviour, accessibility, performance, authoring, previewing, static generation, and deployment as parts of the same system.

This is the journal of how I designed and built it.

The Hirak home page with its editorial introduction and selected projects.

The finished home route — print-friendly, and still legible with all colour removed.

01. The problem

The original requirement sounded simple:

Build a fast personal website where I can publish projects and technical writing.

But several constraints appeared almost immediately.

I wanted:

  • a CMS-style writing experience
  • Git-based version history
  • draft previews
  • structured technical content
  • static production pages
  • very little client-side JavaScript
  • strong SEO fundamentals
  • excellent mobile behaviour
  • reusable technical components
  • automated deployment
  • no runtime CMS dependency

The last requirement became particularly important.

I wanted a CMS for authoring, but I did not want visitors to depend on that CMS when reading the site.

The production website should behave like a collection of static documents distributed through a CDN.

That became the core architectural principle.

02. Before writing code, I simplified the site

My first sitemap was much larger.

I considered separate sections for:

  • Projects
  • Case Studies
  • Experiments
  • Blog
  • Notes
  • About
  • Contact

Technically, those categories made sense.

From a reader’s perspective, however, the distinction was much less useful.

A benchmark, an engineering note, a tutorial, and an experiment are different editorial formats, but they are all ultimately pieces of writing.

The navigation did not need to expose every internal classification.

So I reduced the public structure to:

text
Home
Projects
Writing
About
Contact

The underlying site became even simpler:

text
/
├── /projects
│   └── /projects/[slug]
│
├── /posts
│   └── /posts/[slug]
│
└── /about
    └── #contact

Information architecture showing the site’s home, projects, writing, about, and contact sections.

The decision was small, but it changed how I approached the entire project.

Instead of modelling the site around content labels, I started modelling it around reader intent.

03. One content model for writing

The next simplification was the content model.

Instead of creating separate schemas for:

text
Experiment
Article
Note
Tutorial
Case Study
Benchmark

I created one core content type:

text
Post

A post contains:

text
title
description
slug
publishedAt
updatedAt
topics
featured
draft
cover
seo
body

The difference between a benchmark and an engineering note can be expressed through the content itself and through lightweight metadata.

The frontend does not need six separate rendering systems.

It needs one robust publishing system.

Content schema diagram comparing editorial formats with a shared Post model.

This reduced both implementation complexity and editorial friction.

It also made future changes easier.

A new kind of article does not require a new route or a new CMS collection.

04. September 7 — Minimalism was becoming emptiness

My initial visual direction was simple:

clean layout, lots of whitespace, restrained colour, very little decoration.

That sounds safe.

It is also easy to get wrong.

My first layouts had too much vertical space. Sections looked attractive when viewed individually, but the page felt disconnected when scrolling.

The problem was not a lack of visual polish.

The problem was that I had treated whitespace as decoration instead of structure.

So I introduced a controlled spacing system.

text
4
8
12
16
24
32
48
64
80
96

The exact numbers mattered less than the relationships between them.

Small gaps indicate association.

Large gaps indicate structural separation.

The interface started feeling much more deliberate once spacing followed a system instead of individual judgement.

Reading rhythm diagram showing spacing used to group and separate content.

The lesson was simple:

minimal does not mean empty.

A minimal interface still needs information density, alignment, rhythm, and hierarchy.

05. The visual system

I wanted the site to feel closer to an engineering publication than a startup landing page.

That meant deliberately rejecting several common visual patterns.

I avoided:

  • gradients
  • glassmorphism
  • large rounded cards
  • decorative dashboards
  • unnecessary shadows
  • full-screen hero sections
  • excessive animation
  • floating navigation
  • ornamental 3D graphics

Instead, the interface relies on:

  • typography
  • alignment
  • thin rules
  • restrained colour
  • consistent spacing
  • content hierarchy

Design system specimen showing typography, color, spacing, and interface elements.

The site should still look intentional if all colour is removed.

That became a useful design test.

06. Typography became the primary interface

On a content-heavy website, typography is not decoration.

It is the interface.

Different areas of the site needed different reading behaviour.

The project index needed relatively high information density.

Long-form writing needed a much narrower reading measure.

Code blocks needed room to breathe.

Metadata needed to remain visible without competing with headings.

So I treated typography as a system.

A typical article page follows roughly this hierarchy:

text
Eyebrow / metadata
        ↓
Large article title
        ↓
Description
        ↓
Publication metadata
        ↓
Body
        ↓
Section heading
        ↓
Body

The main reading column stays intentionally narrow.

Roughly:

text
680–760px

This gives long technical articles a comfortable line length without making the page feel constrained.

Article header showing the title, description, publication metadata, and topics.

An article header: eyebrow, title, description, date and reading time, then the topic list.

Monospace typography is used selectively for:

  • dates
  • metadata
  • commands
  • measurements
  • filenames
  • code

Using monospace everywhere would make the website feel like a terminal-themed portfolio.

Using it selectively gives technical details a distinct voice without overwhelming the reading experience.

07. Responsive design was not an afterthought

I did not want mobile to be a scaled-down desktop.

Technical content creates specific responsive problems:

  • long shell commands
  • wide tables
  • code blocks
  • diagrams
  • screenshots
  • benchmark results
  • deeply nested headings

The article layout therefore needed explicit behaviour for smaller screens.

At desktop widths:

text
Site max width:      ~1200–1280px
Article width:       ~700px
Page padding:        ~32–48px

At mobile widths:

text
Single-column layout
20–24px page padding
Reduced section spacing
Horizontal code overflow
Scrollable wide tables
Responsive diagrams

The same article rendered at 375, 768, and 1440 pixel widths.

The important part was not making everything smaller.

It was deciding what should reflow, what should scroll, and what should retain its natural dimensions.

08. Building a small technical component system

The publishing system needed to support more than paragraphs and headings.

I wanted articles to include:

  • code
  • terminal sessions
  • architecture diagrams
  • benchmark results
  • metric blocks
  • callouts
  • figures
  • tables
  • experiment configurations

So I built a small set of reusable content primitives.

text
ArticleLayout
CodeBlock
Terminal
Callout
MetricGrid
BenchmarkTable
Figure
ArchitectureDiagram
RelatedPosts

Diagram of the reusable content primitives used throughout technical articles.

The goal was not to build an enormous design system.

It was to create enough primitives that technical writing could remain visually consistent without hand-styling every article.

A benchmark should look like a benchmark everywhere.

A warning should look like a warning everywhere.

A terminal session should never need custom styling inside an individual post.

09. September 11 — The CMS should disappear

This became the most important architecture decision.

My original mental model was:

text
Visitor
   ↓
Frontend
   ↓
CMS API
   ↓
Content

There was nothing inherently wrong with this.

But the site did not require dynamic content at request time.

Articles change when I publish them, not every time somebody visits them.

So I inverted the relationship.

The CMS became part of the publishing process instead of part of the delivery process.

The final model became:

text
Keystatic
    ↓
Local content
    ↓
Git
    ↓
Astro build
    ↓
Static HTML
    ↓
CDN
    ↓
Visitor

Comparison of request-time CMS delivery with static-first site delivery.

That meant the public website had no reason to know the CMS existed.

This was exactly what I wanted.

10. Why Keystatic

I wanted an editor, but I also wanted files to remain the canonical content representation.

Keystatic fit that model well.

The editor works on top of content stored in the repository rather than requiring a completely separate content database.

Conceptually:

text
CMS UI
   ↓
MDX
   ↓
Git

That gives me the convenience of structured authoring without losing the properties of Git-based content.

The repository remains readable without the CMS.

The content remains portable.

The entire history remains version controlled.

Keystatic authoring interface connected to local repository content.

11. Git became the source of truth

The publishing workflow is intentionally straightforward.

text
Write
  ↓
Save locally
  ↓
Preview
  ↓
Commit
  ↓
Push
  ↓
Validate
  ↓
Build
  ↓
Deploy

The CMS does not publish directly to production.

Git does not merely contain the application code.

It contains the content as well.

This gives every article:

  • history
  • diffs
  • rollback
  • reviewability
  • branch-based previews

It also makes the workflow extremely compatible with coding agents.

12. The coding agent is part of the editorial workflow

One interesting consequence of the architecture is that a coding agent can operate on both the application and the content.

I can use the CMS when I want a visual editing experience.

I can use the agent when I want assistance with:

  • restructuring an article
  • adding frontmatter
  • creating a diagram
  • validating internal links
  • generating reusable components
  • formatting benchmark data
  • checking image metadata
  • fixing build failures

The workflow becomes:

text
                Me
                 │
        ┌────────┴────────┐
        │                 │
        ▼                 ▼
    Keystatic         Coding Agent
        │                 │
        └────────┬────────┘
                 ▼
            Git Repository
                 │
                 ▼
                CI/CD

Publishing workflow from writing and previewing through validation, build, and deployment.

The agent is not required for the site to function.

That is important.

Routine publishing remains deterministic.

The agent is used when intelligence is useful, not as an essential infrastructure dependency.

13. Previewing through the real renderer

I did not want the CMS to maintain a second interpretation of the page.

The most reliable preview is the actual website.

So locally, the workflow is:

text
Keystatic
    ↓
Save content
    ↓
Astro detects change
    ↓
Real article route

I can keep the editor in one tab and the rendered article in another.

Preview workflow showing the editor alongside the rendered post route.

For larger changes, Git branches create another level of preview:

text
Branch
   ↓
Push
   ↓
Preview deployment
   ↓
Review
   ↓
Merge

This means I can inspect the actual production build before changing the live website.

14. Static by default

The site’s core reading experience does not require client-side JavaScript.

A normal article can be represented as:

text
HTML
+
CSS
+
Images

JavaScript is only introduced where it adds something meaningful.

Examples include:

  • copying code
  • search
  • interactive charts
  • optional diagrams

This follows a simple rule:

JavaScript should enhance the document, not be required to read it.

Static delivery layers showing HTML, CSS, JavaScript, and their availability.

This also keeps the mental model of the site simple.

The website is fundamentally a document system.

15. Performance as an architectural property

Performance was not something I wanted to add at the end.

Most of the largest performance decisions happened before implementation.

Choosing static generation already removed several potential runtime costs.

The remaining work focused on keeping individual pages disciplined.

That included:

  • minimal JavaScript
  • responsive images
  • modern image formats
  • restrained font loading
  • static generation
  • limited third-party scripts
  • avoiding unnecessary component hydration
  • keeping article layouts simple

Performance measurements and page-weight breakdown.

The measurements I care about include:

text
LCP
CLS
INP
Transferred JavaScript
HTML size
CSS size
Image weight
Font requests

Every number below was measured against the production build, not a development server.

16. Accessibility

Minimal interfaces are not automatically accessible.

In some cases, reducing visual elements can make state and interaction harder to perceive.

So accessibility needed explicit attention.

The implementation includes or should include:

  • semantic page landmarks
  • logical heading order
  • skip navigation
  • visible keyboard focus
  • sufficient contrast
  • reduced motion support
  • meaningful image alt text
  • properly labelled controls
  • accessible tables
  • native elements where possible

Accessibility annotations highlighting page landmarks, focus, headings, and controls.

I try to use ARIA only when native HTML cannot express the interaction correctly.

That keeps both the markup and the accessibility model easier to reason about.

17. Technical content exposed edge cases

Designing normal marketing pages does not expose the same problems as designing technical documentation.

A technical article might suddenly contain:

bash
kubectl get pods --all-namespaces --field-selector=status.phase=Running -o custom-columns=...

or a table with eight columns.

Or a network diagram that is wider than the reading column.

Or a block of logs containing extremely long identifiers.

The design system therefore needed explicit behaviour for edge cases.

For example:

text
Code
→ horizontal scrolling


Tables
→ contained horizontal scrolling on small screens


Figures
→ may break out beyond article measure


Text
→ remains constrained to readable width


Diagrams
→ responsive but never compressed into illegibility

A long kubectl command in a horizontally scrollable code block.

Code scrolls horizontally. Wrapping a shell command changes what it means.

A wide benchmark table contained in a horizontally scrollable region.

Tables keep their natural width inside a scrollable region, with numeric columns right-aligned.

These details are easy to overlook until the website starts containing real engineering content.

18. Search engine architecture

SEO was mostly an exercise in keeping the site understandable.

The core routes remain stable:

text
/posts/[slug]
/projects/[slug]

Each page can expose:

  • canonical URL
  • descriptive title
  • meta description
  • Open Graph metadata
  • structured data
  • semantic headings

The site can also generate:

text
sitemap.xml
robots.txt
RSS

Internal linking becomes particularly important as the writing archive grows.

A Kubernetes article should naturally connect to related experiments, projects, and follow-up posts.

The goal is not to manufacture SEO pages.

It is to make the information architecture legible to both humans and crawlers.

19. September 18 — Cards were making the site feel like a dashboard

An earlier version used cards for almost everything.

Project cards.

Article cards.

Topic cards.

Featured cards.

They were visually consistent, but they also made every piece of information feel equally important.

The website started looking more like a SaaS dashboard than a publication.

So I removed many of them.

Writing entries became simple editorial rows.

Project listings became structured blocks separated by rules.

Typography and alignment took over the work that containers had been doing.

Comparison of a card-heavy dashboard layout with a simpler editorial archive.

The result felt both simpler and more intentional.

20. CI/CD turned publishing into software delivery

A content push goes through the same discipline as a code change.

The pipeline can validate:

text
Content schema
Required metadata
Unique slugs
Internal links
Image references
TypeScript
Linting
Static build

Conceptually:

text
git push
   ↓
validate
   ↓
test
   ↓
build
   ↓
deploy

Content validation and deployment pipeline from a Git push to static output.

If validation fails, the current production site remains untouched.

That makes publishing predictable.

21. Final architecture

The finished system is deliberately small.

text
                 AUTHORING


            Keystatic      Agent
                 \          /
                  \        /
                   Git Repo
                      │
                      ▼
                    GitHub
                      │
                      ▼
                     CI
                      │
                      ▼
                    Astro
                      │
                      ▼
                 Static Files
                      │
                      ▼
                     CDN
                      │
                      ▼
                   Visitor

Publishing architecture from authoring through GitHub, CI, Astro, static files, and a CDN.

There is:

text
No production CMS dependency
No runtime database
No required client-side application
No duplicate content store

The application is mostly a publishing pipeline that produces documents.

That is intentionally boring infrastructure.

And for this kind of website, boring is useful.

22. What I would measure

The project is not complete when the website looks finished.

So I measured whether the architectural decisions actually produced the intended result.

The numbers below are from the production build:

text
Lighthouse performance
LCP
CLS
INP


Total JavaScript
Total CSS
Typical article weight


Accessibility audit
Broken link count


Build time
Deployment time


Mobile performance
Desktop performance

Lighthouse performance, accessibility, best-practices, and SEO metrics.

Measurements, not assumptions.

23. What I learned

The most useful lesson from this project was that frontend work is often less about individual components than about the systems surrounding them.

The final interface is influenced by:

text
Content model
Information architecture
Typography
CSS
Responsive behaviour
Accessibility
Build architecture
CMS design
Version control
Deployment

Each decision changes the others.

A CMS choice affects previewing.

A content model affects URLs.

Typography affects layout.

Layout affects responsive behaviour.

Rendering strategy affects performance.

Deployment affects editorial workflow.

Treating those as one system produced a much better result than treating the website as a collection of pages.

24. The outcome

What started as a personal portfolio became a small publishing platform.

The final system gives me:

  • a structured CMS
  • Git-backed content
  • local previews
  • branch previews
  • static production pages
  • reusable technical components
  • responsive long-form layouts
  • automated deployment
  • measurable performance
  • complete control over the frontend

More importantly, the platform is designed around the work I actually want to publish.

Projects can explain what I built.

Writing can explain what I learned.

Experiments can show evidence.

The website itself becomes another engineering project documenting the decisions behind it.

25. Closing note

I wanted the website to communicate one idea clearly:

Build systems. Test assumptions. Write down what happens.

The site is now part portfolio, part engineering notebook, and part publishing system.

And because the architecture is intentionally simple, the focus remains where it should be:

on the work.

Related