Add webtoon (vertical-scroll) renderer for comics

New <foliate-webtoon> custom element: every page stacked in one
scrolling column (max-width 900px centered on wide screens), the
standard long-strip manga reading mode.

- Pages lazy-load through an IntersectionObserver with a 150% root
  margin so they're ready before scrolling into view; placeholders
  carry an estimated min-height until the image loads, then the real
  aspect-ratio — set on the placeholder element — so geometry stays
  stable across unloads and the scrollbar never jumps.
- Pages more than 12 positions from the reading point are unloaded
  (image removed, section blob URL revoked) to bound memory on long
  webtoons; they simply reload if the user scrolls back.
- Relocate events ({reason:'scroll', index, fraction, size:1}) fire on
  rAF-throttled scroll with the viewport-center page as index and the
  visible position within it as fraction — compatible with view.js's
  SectionProgress enrichment, so progress saving/restoring, the
  slider, and the back-stack all work unchanged.
- Renderer contract mirrors fixed-layout: goTo(await {index}) scrolls
  the page into view; next/prev page by ~one screen (view.init()'s
  fresh-start probe is a no-op that reports location); goLeft/goRight
  map to prev/next (vertical flow is direction-independent).
  No zoom/magnifier APIs — the host already gates those on the flow.
- Page images honor --fx-filter from the host for the new
  brightness/contrast/invert controls.

view.js picks the renderer when book.format === 'comic' (now tagged
by makeComicBook) and options.comic.flow === 'webtoon'.
This commit is contained in:
2026-08-18 08:15:59 -04:00
parent 1c812e8813
commit ea268dffbe
3 changed files with 230 additions and 1 deletions
+5 -1
View File
@@ -251,7 +251,11 @@ export class View extends HTMLElement {
}
this.isFixedLayout = this.book.rendition?.layout === 'pre-paginated'
if (this.isFixedLayout) {
if (this.book.format === 'comic' && options?.comic?.flow === 'webtoon') {
await import('./webtoon.js')
this.renderer = document.createElement('foliate-webtoon')
}
else if (this.isFixedLayout) {
await import('./fixed-layout.js')
this.renderer = document.createElement('foliate-fxl')
} else {