In Part 1, I described how the web page, once a document containing data and interface together, has been hollowed out. In Part 2, I looked at what that costs us: layers of infrastructure, cognitive overhead, and an economic floor that prices out small projects entirely.
Now I want to talk about how we started to see a way through.
The frustration
Pagelove didn’t start as a product It started as frustration.
I wanted to build a small web application for myself: a character sheet for a tabletop role-playing game - just a game of Dungeons & Dragons amongst friends. Nothing ambitious. No scale. No users - other than some friends and I. Just a page or two that could store some data and let me edit them over time.
Something the web should be good at.
Instead, I immediately ran into the modern web stack. To do even this modest thing "properly," I was expected to set up a database, design an API, run an application server, choose a frontend framework, build React components and wire it all together. The amount of machinery required felt wildly out of proportion to the task.
This wasn't just annoying. It felt wrong.
A different web
As discussed in part 2, the web I grew up with didn't work like this.
It was inspectable. You could look at a page and understand it. Data and structure lived together. A page was a document, not a runtime.
Somewhere along the way, that simplicity had been lost, replaced by layers of infrastructure and indirection. I had accepted this as "just how the web is now," but this experience made it impossible to ignore.
So I started asking a different question.
Not "which framework should I use?" but what should building this actually require?
A small loophole
That question led me back to HTML & HTTP. I spent weeks reading through IETF RFCs and W3C specifications, searching for something that might have been overlooked.
Deep in the HTTP spec is the Range header. It's nothing new. It’s been in place since 1997, and its
purpose was to be able to request chunks of a document, specified by byte ranges, enabling capabilities like getting streaming
video from three quarters of the way through it, being able to resume a download of a large file.
But in my repeated readings, I realized that the specification doesn’t insist that ranges must be bytes, in fact, it directly states that units other than bytes are acceptable:
Range = byte-ranges-specifier / other-ranges-specifier
other-ranges-specifier = other-range-unit "=" other-range-set
other-range-set = 1*VCHAR
That was the first moment where something new clicked.
What if a range wasn't a byte offset? What if a range could describe elements inside a document? What if I could say: this request applies to that part of the page? What could be used to address a part of a page with accuracy?
At first, this felt like a neat trick. A clever hack. A way to avoid some boilerplate. I started experimenting, still thinking in terms of client-side JavaScript and request handlers bolted onto pages.
I hadn't yet grasped what this actually implied.
Clarity
The deeper understanding came later, and it took time.
I kept iterating, layering workarounds on top of this idea, still assuming that HTML was just a delivery format. Still treating JavaScript as the real engine. Still assuming that the "proper" data lived somewhere else.
Then it landed.
HTML is structured data.
Not metaphorically. Literally.
HTML is a tree. A hierarchy. A structured, addressable graph. CSS selectors are a query language over that structure. The DOM is, in effect, a serialised B-tree with a native query mechanism built in.
And a B-tree is the fundamental structure of a database.
At that moment, the framing inverted.
We tell ourselves that HTML is not a first-class citizen. That it's just markup. That data must live behind APIs and schemas and ORMs. But the web already shipped with a structured data model. We just stopped treating it seriously.
When the server understands the document
The final piece was realising where the intelligence to maintain state needed to live.
Not in JavaScript glued onto pages. On the server.
If the server understands the DOM (not just as text, but as structure and meaning) then the document itself becomes the unit of storage, manipulation, and authority.
Requests no longer target endpoints. They target elements. State no longer lives "behind" the page. It is the page.
At that point, this stopped being a trick and started to become something more.
A familiar idea, rediscovered
Looking back, this aligns closely with ideas that were always present in the web's architecture.
Roy Fielding's description of hypermedia as the engine of application state was never wrong. We just stopped building systems that took it seriously. By splitting data out of documents, we broke that model.
By letting servers reason about documents again, it becomes possible to restore it. Without inventing a new web. Without abandoning HTTP.
What followed
Pagelove emerged from this realisation, not as a business plan, but as an inevitable consequence of a simple insight.
If documents are structured data. If selectors are queries. If HTTP can target parts of documents. Then a lot of the web's complexity simply can disappear.
But that is the next part of the story. In Part 4, I'll show you what we've built, and how it builds upon not only these ideas, but other elements of the HTTP & HTML specification.