A reader people finish, and a library that remembers where they stopped
A reading platform for a comics catalog: a browse surface people can actually navigate, a reader that gets out of the way, and a history that puts everyone back on the page they left.
The brief, in specifics
- Industry
- E-commerce & Retail
- Duration
- 18 weeks
- Cooperation model
- Fixed price, phased
- Services
- Platform engineeringReader experienceEditorial tooling
- Integrations
- Cloudflare ImagesAlgoliaStripe BillingPostmark
- Technologies
- Next.jsTypeScriptPrismaPostgreSQLLaravelTailwind CSSNextAuth
- Team
- 1 Project lead2 Full-stack engineers1 Product designer1 QA engineer
Client name withheld under NDA. Engagement details are shown to the extent our agreement permits.
The hard problem
A catalog is four levels deep (series, volume, chapter, page), and every surface that flattened it lost people. Readers couldn't find where they had stopped, so a series abandoned at chapter nine was rarely resumed.
Readers couldn't find where they had stopped. Position was recorded per series instead of per chapter, so a series abandoned at chapter nine resumed at chapter one or at the latest release, neither of which is where the reader was. In the analytics that showed up as a cliff: series opened twice and never a third time.
A browse surface built on the real hierarchy, with filters that compose; a reader tuned for long sittings; and a reading history that turns a half-finished chapter into an obvious next action instead of something to hunt for.
How the pieces fit
- 01
Modeled the catalog at its real depth: series, volume, chapter, page
The catalog is modeled at its real depth, so nothing about browse has to pretend a volume and a chapter are the same kind of thing.
- 02
Built browse as composable filters over genre, status, author and publisher
The filter set was cut down from what the catalog could support to what readers actually combined: five dimensions out of eleven.
- 03
Tuned the reader for uninterrupted sittings, with keyboard as a first-class input
The reader hides its chrome until intent, preloads ahead of the reading position, and offers the next chapter at the boundary.
- 04
Recorded reading position per chapter so resuming is one action
Position is held per chapter per reader and surfaced wherever the series appears, so resuming is a button, not a search.
- 05
Gave editors the tooling to publish a chapter without an engineer
Editors stage, order and schedule a chapter without an engineer, with pages derived into reading sizes on ingest.
The system we were asked to build
A large comics catalog was losing readers between finding a title and reading it. We built the browse surface, the reader, and the editorial tooling behind both.
A large comics catalog with healthy traffic and poor conversion into actual reading. The structure is four levels deep (series, volume, chapter, page), and every surface that had flattened it for simplicity had lost people at the level it removed. The engagement covered browse, the reader and the editorial tooling, because the three were failing as one system.
Platform & Product Engineering
Composable filters
Genre, status, type, author and publisher narrow together, and every combination is a real linkable state.
Genre, status, type, author and publisher stack on top of each other, and every combination is a real URL with its own server-rendered page. A filtered view can be linked, shared and indexed, where before it existed only in someone's session. Counts update with the selection so a dead-end combination is visible before it's chosen, and the query is one indexed pass over the catalog.
- Filters compose; every combination is a linkable URL
- Server-rendered, so filtered views are shareable and indexable
- Live counts, so a dead-end combination is visible in advance
The filter panel across its five dimensions, each option with a live count. Sports, One-shot and Hollowbrook Books show zero, so the dead end is visible before anyone picks it, and the combination copies as a link to its own server-rendered page.
The reader on page 18 of 29 of Ashfall Harbour's chapter 42. The artwork sits on near-black and the bars fade in only on pointer movement. The position is already saved, the pages ahead are preloaded, and the end of the chapter offers chapter 43.
A reader for long sittings
Pointer or keyboard, no chrome in the way, and a chapter boundary that offers what comes next.
The reader is built for two hours, not two minutes: pointer or keyboard, chrome that gets out of the way and comes back on intent, and pages preloaded ahead of the reading position so a turn never waits. Position is written continuously as pages turn, and the boundary between chapters offers the next one instead of returning the reader to a listing.
- Pointer and keyboard equally, chrome hidden until intent
- Pages preloaded ahead of position, so turns never wait
- Chapter boundary offers what comes next
Resume, not search
Reading position is held per chapter and surfaced wherever the series appears.
Reading position is held per chapter per reader and surfaced everywhere the series appears (the card in a rail, the series page, the home screen), so a half-finished chapter is a button, not something to hunt for. Progress writes optimistically and reconciles, so it survives a closed tab, and a finished series is marked finished instead of looking abandoned.
- Position held per chapter and surfaced wherever the series appears
- Optimistic writes that survive a closed tab
- Finished series marked finished, never left looking abandoned
The library on a phone: six series in progress, each with its exact chapter and page, how far into the chapter that is, and a Resume button.
The home rails: latest, newest, popular and trending, each labeled with the rule that computes it. Popularity is a decayed view count and trending is rate of change, so the series that leads Popular is missing from Trending.
Ranked rails
Latest, newest, popular and trending, each computed from reading data.
Latest, newest, popular and trending are computed from real events, with no hand curation: recency from publication, popularity from a decayed view count, trending from the rate of change instead of the total. That's what stops one perennial hit occupying every rail forever, and it means the front page changes because the readership did.
- Rails computed from events, none hand-curated
- Popularity decayed over time; trending from rate of change
- No perennial hit permanently occupying every rail
Editorial publishing
The release queue an editor publishes from: eight chapters staged with slot times, owners and review state. Moth Hour's chapter is held because three pages are missing, and the page order of the next release, Ashfall Harbour chapter 47, is open mid-drag.
Stage a chapter, order its pages, schedule it. No engineer required.
An editor stages a chapter, orders its pages by drag, sets a publication time and walks away. No engineer, no deploy. Pages upload directly to storage and are derived into reading sizes on ingest. A scheduled chapter is invisible until its moment and then appears in the rails and in every subscriber's continue list without a rebuild.
- Stage, order and schedule a chapter without an engineer
- Direct uploads derived into reading sizes on ingest
- Scheduled chapters appear in rails and resume lists without a rebuild
Phase by phase
Phase 1: Catalogue Modelling
Four Levels, Kept Distinct
Modeled series, volumes, chapters and pages as separate entities instead of collapsing them, so a volume-only release and a chapter-only release are both expressible.
- Catalogue Schema
- Taxonomy Model
- Editorial Field Guide
Phase 2: Browse and Filters
Filters That Compose
Built browse over the taxonomy (genre, status, type, author, publisher), with every combination a real, linkable state instead of a client-side narrowing.
- Browse Surface
- Composable Filter State
- Ranked Rails
Phase 3: The Reader
A Page Turn With Nothing In The Way
Built the reading panel for long sittings: page turn by pointer and by keyboard, chapter boundaries that offer the next chapter, and no chrome competing with the artwork.
- Reader Panel
- Keyboard Navigation
- Chapter Boundary Handling
Phase 4: Memory
Bookmarks and Reading Position
Recorded position per chapter and surfaced it on the series card, so a reader returning after two weeks resumes instead of searching.
- Reading History
- Bookmark Library
- Resume Surface
Phase 5: Editorial Tooling
Publishing Without An Engineer
Built the admin surface so an editor can stage a chapter, order its pages and publish on a schedule without a deployment.
- Editorial Console
- Page Ordering Tool
- Scheduled Publishing
Ashfall Harbour opened at volume three: volumes one and two collapsed and ticked off, chapter 42 carrying the reader's position at page 18 of 29, and chapters 45 and 46 badged as new since the last visit.
What it carries now
+34%
Chapter completion rate
+61%
Series resumed after a week
−72%
Time to publish a chapter
4 levels
Catalogue depth
Chapter completion is the share of opened chapters read to the last page, compared across the quarter before and after. Series resumed after a week is the share of readers returning to a partly-read series between seven and thirty days later. Time to publish a chapter is measured from an editor beginning to the chapter being live.
Client name withheld under NDA. Figures are approximate, drawn from the engagement’s own reporting.
What the architecture settled
- 01
Flattening a four-level catalog loses people at every level you removed.
Every level flattened for simplicity is a level readers then have to reconstruct themselves, and the loss shows up exactly where the flattening happened.
- 02
A filter combination that can't be linked to is a filter combination nobody shares.
An unlinkable filter combination can't be shared, indexed or returned to, which removes most of the value of having built the filters.
- 03
Reading position is the single highest-value thing a reading platform can remember.
Position per chapter is the single most valuable detail this kind of platform can remember. It converts a lapsed reader into a one-tap return.
- 04
Editorial tooling is product work. A publishing step that needs an engineer becomes a bottleneck the week you succeed.
Editorial tooling is product work: the publishing step that needs an engineer is fine at ten chapters a week and fatal at a hundred.
How the work was run
- 01
We rebuilt browse and the reader first and shipped them behind a flag to a tenth of readers, which is where the resume behavior proved itself: it moved completion before any of the editorial tooling existed. The admin surface followed once the reading side was settled.
Phased across eighteen weeks with the editorial tooling in its own phase, not bolted on as a final step, because a publishing flow that needs an engineer becomes the bottleneck the week the platform succeeds. Reader work was validated on long sittings: the failure being fixed only appears after forty minutes of reading.
One reader, a fortnight later
Remember the series and readers start over. Remember the chapter and they resume.
The same reader returns to Lanternwake fourteen days after stopping partway through chapter nine: once under the old per-series position, once under the per-chapter position the rebuild writes. Switch tabs, or use the arrow keys once one is focused.
One position for the whole series, and no page inside chapter 9 to go back to. The series card opens at the start; the new-chapter alert opens at the latest release.
Lanternwake
Tamsin Kilroe
Last read 14 days agoCh. 9, page 14 of 31
- Returning after 14 days
- Reading the stored position
- Landed
What was stored
reader · series(lanternwake)
64 chapters · where the reader was, and where they landed
Why it failed before: position was written per series, not per chapter, so there was no page inside chapter 9 to return to.
From an editor’s upload to a reader’s continue list
Publishing and reading share one catalog. The editor’s side does its work once, on the way in, and the reader’s side reads what's already there, so a chapter going live needs neither an engineer nor a deploy.
- 01 · SourceEditor stages a chapterPages upload directly to storage and the editor orders them by drag. No engineer, no deploy.
- 02 · IngestReading sizes derivedPages are derived into reading sizes on ingest, not when a reader first asks for them.
- 03 · ScheduleScheduled publishA scheduled chapter stays invisible until its moment, however early the editor finished staging it.
- 04 · StatePostgreSQL via PrismaSeries, volume, chapter and page as four separate levels, plus reading position per chapter per reader and the events the rails are computed from.
- 05 · DeliveryServer-rendered surfacesBrowse, rails and continue lists render on the server. Every filter combination is a linkable page, and a published chapter appears without a rebuild.
What goes live, and what is kept
Release timing & reading-position integrity
Invisible until its moment
A scheduled chapter is not shown to readers before its publication time. At that moment it appears in the rails and in every subscriber’s continue list, without a rebuild.
Progress that survives a closed tab
Reading position is written continuously as pages turn, optimistically and then reconciled, so closing the tab mid-chapter doesn't lose the page. It's held per chapter, and a finished series is marked finished.
Publishing without an engineer
Editors stage a chapter, order its pages and schedule it from the console, with no deployment, so a release never waits for an engineer to be free.
Running a catalogue that readers open but don’t finish? Scope your build in 3 minutes.
Scope your buildNearby engagements
Data & AnalyticsA checkout that stopped losing sales to a 6-second load
Profiling found the real bottleneck behind a slow checkout (an N+1 query and an oversized bundle) and tuned both, with before-and-after metrics locked in as a baseline against future regressions.
E-commerce & Retail · 5 weeks
Web PlatformsOne number, a whole handset, and a database that keeps up with 125 brands
A metered IMEI lookup service that turns fifteen digits into a device, its specifications and its status. It's sold three ways to three audiences and backed by a device database that maintains itself.
Consumer Electronics · 22 weeks
Web PlatformsOne platform, two trades, and three quarters of the domain never changed
A multi-tenant Laravel platform sold into two trades. Purchasing, sales, returns, expenses, tenancy and roles are one product; only the nouns on top of them change.
E-commerce & Retail · 30 weeks
Let's talk
Running a large platform, shaping a first MVP, or getting a product ready for a funding round? Tell us where you are. We'll shape the process around it, and stay with you after launch.














