Replaces the prepend/flushSync/scrollBy gymnastics with placeholder divs
sized by each page's width/height. Document height is correct from the
first paint, so resume + backward scroll just work — no scroll
compensation, no gesture fights, no forced aspect ratio distorting images.
- New /api/chapters/[id]/meta returns the dim skeleton for any chapter.
- Chapter page pre-fetches the starting chapter's meta server-side and
parallelizes the two Prisma queries via Promise.all.
- Reader renders placeholders with aspectRatio: w/h, lazy-loads image
URLs in batches via IntersectionObserver, and prefetches the next
chapter's meta ~3 pages from the end.
- Scroll tracker walks only the intersecting-pages set (~3–5 elements)
instead of every loaded page per rAF.
- scroll={false} on all Links into the reader + { scroll: false } on
double-tap router.push, plus a belt-and-suspenders rAF re-scroll, so
resume survives soft navigation and browser scroll-restoration.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Sign all image URLs server-side with 60s expiry presigned URLs
- Add /api/pages endpoint for batched page fetching (7 per batch)
- PageReader prefetches next batch when user scrolls to 3rd page
- Move chapter count badge outside overflow-hidden for 3D effect
- Fix missing URL signing on search and genre pages
- Extract signCoverUrls helper to reduce duplication
- Clamp API limit param to prevent abuse
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>