0f66dae4eb
Two changes: Eliminate cloning in the publish path. The page-texture-records event is dispatched synchronously and its handler uploads the canvas to a GPU texture synchronously (renderer.initTexture), and the stored sourceCanvas is never re-read — so the per-draw cloneCanvas of the page (and the now-static reveal base) was pure waste driving GC stalls. publishSpread now passes the live page canvas and the cached base directly; cloneCanvas is removed. Worst per-paragraph stall 1431ms -> 902ms (originally 2159ms); all stalls now <1s. Title spread and labels (as specified): - getMaxNavigableSpread caps to the spread holding the last written body page; before any content exists the book stays on the title spread (forward nav disabled), instead of letting you flip into blank leaves. - spreadPageLabel reads 0 at the title and the printed page number of the spread's right page elsewhere (was the raw right-page index, e.g. "3" before a game). Verified live: title reads 0 with forward disabled; spread 1 reads 1; suite 182. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>