Two jobs. When you're reading, the app should be invisible and instant: the page is the only thing that exists. When you're choosing what to read, it should feel like walking into a comic shop on a Wednesday: covers face-out, new stuff up front, staff picks, a back-issue bin worth digging through. Existing readers get both wrong. They show a spreadsheet of thumbnails, then a reader that stutters.
We're not short on comic readers. We're short on ones that care about either the reading or the browsing. Each of these does one thing well and loses you somewhere else:
Guided View was the best idea in the category. The Kindle migration buried it: slow store, books-first UI, the series page reads like a product listing.
steal: panel-to-panelavoid: retail chromeThe catalogs are huge, but browsing is algorithm rows with no sense of place. Smart Panels jump-cut between panels, which feels like a slideshow. Reading orders are buried.
steal: event reading listsavoid: Netflix rowsVery good at ingesting and serving files. The UI looks like an admin panel: grids of identical tiles, filter sidebars, title text that competes with the art. Reading feels like a web image viewer.
steal: ComicInfo.xml, OPDSavoid: admin aestheticThe closest to good. Fast, calm, nice defaults. They're still a "file browser plus viewer", though: no discovery, no excitement, no feeling that there's more to find.
steal: calm reading defaultsavoid: library = folderThey nailed vertical scroll, and the end-of-episode "next" hook is excellent. They don't handle print comics, and the browsing is ad-shaped.
steal: the cliffhanger handoffavoid: coins, popupsGreat power-user controls: RTL, spread splitting, cropping borders, per-series settings. Visually it's a settings app with pictures in it.
steal: per-series settingsavoid: 40 toggles up frontThe gap: nobody combines Panels-grade reading calm, ComiXology-grade panel navigation (done as a smooth camera, not jump-cuts) and a browser with the texture of a physical store. That combination is the product.
Covers sell the comic, so they carry the browser. Text labels show up on demand. Color, light and backgrounds come from the art itself.
Once you're reading, every next page is already decoded. A visible load inside an issue counts as a bug, not a performance target.
Spreads stay spreads. Bleeds aren't cropped. Panel order follows the artist. Fit modes serve the page and don't fight it.
Take weight, light, shadow and momentum from the real thing. Leave out fake wood grain, page-curl animations and paper-texture overlays on the art.
Every ending hands off: next issue, next in the event, "you stopped here". Reading flows like a longbox you work through, not files you open one at a time.
Detect RTL, webtoon strips, spreads and margins. Settings exist but you can live a whole life without opening them. Overrides are per series, not global.
| Detect | How | Then |
|---|---|---|
| Spread | Aspect ratio > 1.15 on a single image, or two consecutive pages whose inner edges match pixel-wise | Show it as one wide page. In portrait on a phone, start fit-height and pan, with a "rotate for spread" nudge. |
| Two-up offset | Cover is page 1. Spreads must land on even/odd correctly. | Cover is shown alone. If a known spread lands misaligned, auto-insert a blank and remember that per issue. |
| RTL (manga) | ComicInfo Manga=YesAndRightToLeft, publisher/series lookup, else ask once per series | Flip tap zones, swipe direction and spread order. Remember per series. |
| Webtoon strip | Pages with height/width > 2.5, or consecutive pages with no top/bottom margin | Switch to continuous vertical scroll, fit-width and stitched seams, with momentum scrolling. |
| Scan margins | Uniform border color across page edges | Auto-crop for fit (never destructive), toggled by double-tapping the edge. |
←/→, Space, F fullscreen, Z panel mode, [ ] previous/next issue.Webtoon proved this. After the final page, swipe once more to get an end card: next issue's cover large and already preloaded, "continue" as the primary action, then "next in Event Name reading order" if it applies, then "back to shelf". Swiping again goes straight in. Binge reading has no friction. Also show a quiet "Finished. 22 pages · 9 min."
Guided View is the feature people miss most and the one everyone does crudely. Our version is a camera that glides between panels. It isn't a jump-cut slideshow.
The test is simple: opening the app should make you want to read something you didn't plan to. A shop does that with face-out covers, an arrangement that changes, and areas: new releases, the wall, staff picks, back-issue bins. We copy those areas, not the wood paneling.
New since last visit, or new this Wednesday for pull-list series. Covers are large and face-out. This is the hero of the home screen and it changes every time something lands.
Up to three issues in progress, with a progress sliver along the bottom edge. One tap resumes at the exact page and zoom.
Key issues and #1s of every series you own but haven't started. Big tiles, mosaic layout, sized by "how much there is" (issue count).
A small handwritten-feel card stuck on a cover: "If you liked Saga…". Curated lists plus rules. No black-box algorithm rows.
A flip-through bin of random unread issues. Swipe cards like digging through a box. This is serendipity on purpose.
The full library, but spine-out by default (thin vertical strips colored from the cover) so 3,000 issues fit on one screen. Hover pulls one out face-out. Sort by publisher, era, creator.
The thing a store gives you that apps don't is riffling the pages before you commit. Scrubbing horizontally across a cover (hover-scrub on desktop, press-and-slide on touch) riffles through low-res interior pages at about 8 fps. Let go and you're back on the cover. Nobody does this, and it's the moment that sells the product in a GIF.
Crossover events are the worst part of comics, and we can fix them. An event page shows the reading order as one ribbon across series: tie-ins are interleaved, owned issues are lit, missing ones are ghosted. "Read event" plays it like a playlist, and the end card follows the ribbon instead of the series.
One field that searches titles, characters, creators, story arcs and years (moore 1986). Results come back as covers. A lone # plus a number jumps to an issue in the current series.
CBZ, CBR (unrar via WASM or native), CB7, PDF (render pages to images once), EPUB fixed-layout, loose image folders. Read ComicInfo.xml when it's there and write it back on edits, so the files stay portable.
Parse Series Name (2019) #014 (of 6).cbz-style names, then group by folder. Confidence is shown, and low-confidence matches go to a "sort the pile" screen, the one place where the app looks like a stockroom.
Match against ComicVine (or Metron) for covers, credits, arcs, characters and release dates. Cache aggressively and never block the UI on it. Missing metadata degrades gracefully to "the art and the filename".
On import: extract the cover, generate a 3-size thumbnail set (AVIF), take a thumbhash placeholder, pull the palette (for matte and series page), detect panels, sample riffle frames. All of it runs in a worker queue at low priority.
Local folder first. Then OPDS (Komga/Kavita servers), so we can be the beautiful front-end for libraries people already have. That's a wedge with a ready-made audience.
Progress (issue, page, panel, zoom) is a tiny record. Sync it through a headless JSON store, keyed per user. Files never leave the device.
A warm near-black stage (#14120f, like a store at closing time with spotlights on the racks) so covers glow. An optional light "newsprint" theme (#f6f1e7). A single accent, signal red (#e23b2e), is reserved for "new" and "pull" states. Everything else takes its color from the art.
A neutral grotesk (Inter) for UI. A condensed display face for section headers only. Pick one with real lettering character, licensed, and use it sparingly, like store signage. Never put display type over cover art.
| Token | Value | Used for |
|---|---|---|
| spring.page | stiffness 380 · damping 38 | Page settle after drag or flick |
| spring.camera | critically damped · ~350 ms | Panel camera moves |
| dur.chrome | 160 ms ease-out | Toolbars in/out |
| dur.matte | 400 ms linear crossfade | Ambient background change |
| lift.cover | translateY −8px · rotate −1.2° · 250 ms | Hover/press on covers |
| open.issue | shared-element zoom, cover → page 1 | Shelf → reader. The cover becomes the first page and nothing cuts. |
Respect prefers-reduced-motion: springs become 120 ms fades, there's no riffle autoplay, and the camera cuts with a crossfade.
| Moment | Budget | Technique |
|---|---|---|
| Finger down → page moves | < 1 frame | Transform-only layers, no layout during the gesture |
| Next/prev page shown | 0 ms (already decoded) | Keep ±3 pages decoded via createImageBitmap in a worker. Preload the next issue's first 3 pages at 80% of the current one. |
| Open issue from shelf | < 150 ms to first page | Cover thumb is the placeholder, page 1 is pre-extracted at import |
| Scroll a 10k-issue library | 60 fps, no blank tiles | Virtualized grid, thumbhash placeholders, AVIF thumbs in 3 sizes |
| Cold app start | < 800 ms to interactive shelf | Index in IndexedDB/SQLite, so the shelf renders from cache before the scan |
| Memory, 4K spreads | < 400 MB on iPad | Downscale decode to screen size × DPR, keep originals for zoom only |
Reading feel first, because it's the part people judge in 10 seconds. The store second. Clever stuff last.
Open a CBZ, decode pipeline, drag/flick/tap turns with springs, spreads, ambient matte, keyboard.
Exit: a 4K CBZ on a mid phone never shows a blank page, and a blind A/B against Panels feels at least equal.
Folder import, filename parsing, ComicInfo, thumbnail and palette pipeline, IndexedDB/SQLite index.
Exit: 2,000 messy files grouped into series with fewer than 5% needing manual sorting.
Front rack, counter, longboxes (spine-out), series poster page, end card, shared-element open.
Exit: someone opens it and starts an issue they hadn't planned to read.
Import-time detection, spring camera, pair framing, manual fix-up.
Exit: correct order on 90% or more of standard-grid pages in the test shelf, and graceful full-page fallback on the rest.
Flip-through riffle, back-issue bin, staff picks, event reading orders, metadata enrichment, OPDS.
Exit: the riffle GIF is good enough to be the launch post.
A fixed set of about 10 legally owned or public-domain issues (Digital Comic Museum golden-age books are perfect and free) that every build is checked against:
An issue with 3+ double-page spreads, including one stored as two separate files.
A chapter with spreads and no ComicInfo, to test detection and per-series memory.
A tall-strip chapter split into irregular image slices.
A golden-age scan with yellowed margins, skew and uneven gutters.
Painted, bleed-heavy pages where panel detection should give up.
A 4K-per-page CBZ and a 300 MB PDF, for the memory and decode budget.
| Question | Recommendation |
|---|---|
| Platform | Web/PWA first (works on iPad, desktop and phone, and is deployable to lima-city), with CBR via WASM unrar. Wrap it in Tauri later if file-system access gets painful. |
| Bring-your-own-files vs. catalog | BYO files + OPDS. There's no licensing, and Komga/Kavita users are an existing audience starving for a nice front-end. |
| Panel detection | Classic CV first (no model, runs anywhere). Consider a small on-device model only if M4 misses 90%. |
| Name | Undecided. It should sound like a shop, not a utility ("Longbox", "Wednesday", "Back Issue"). |