diff --git a/src/index.html b/src/index.html index a9083c0..55b7116 100644 --- a/src/index.html +++ b/src/index.html @@ -10620,48 +10620,34 @@ thumb.className = 'bookPageTileThumb'; tile.appendChild(thumb); if (p.type === 'design') { - // Designed page thumb: master layers underneath, then the - // page's own. Both remapped to 'canvas' so the preview - // helper's flat-canvas filter accepts them. Master text - // layers run through token substitution so `{page-number}` - // et al resolve against this page's place in the manifest. - // J6 accuracy: subtract bleed from each layer's x/y so the - // tile (trim-only canvas) matches what would print. Also - // strip text-frame dashed outlines — they're an authoring - // affordance, not a print element. Threaded chapter text - // still paints over the bare frame area via - // _paintThreadedFramesOnThumb below. - const pageTarget = `book-page:${p.id}`; - const masterId = effectiveMasterIdForPage(p); - const masterTarget = masterId ? `book-master:${masterId}` : null; - const isPrintLayer = (l) => !(l.type === 'shape' && l.shape?.kind === 'text-frame'); - const masterLayersRaw = masterTarget - ? (state.layers || []).filter(l => l.target === masterTarget && !l.hidden && isPrintLayer(l)) - : []; - const ctx = bookTokenContext(book, p.id, 0); - const masterLayers = applyBookTokensToLayers(masterLayersRaw, ctx); - const pageLayers = (state.layers || []).filter(l => l.target === pageTarget && !l.hidden); - const pageLayersForThumb = pageLayers.filter(isPrintLayer); - const composed = [ - ...masterLayers.map((l, i) => ({ ...offsetForThumb(l), target: 'canvas', z: -1e6 + i })), - ...pageLayersForThumb.map(l => ({ ...offsetForThumb(l), target: 'canvas' })), - ]; - try { - renderCustomArtPreviewDOM(thumb, { - customArt: { - width: trimW * 96, - height: trimH * 96, - background: p.background || book.spec?.background || '#ffffff', - }, - layers: composed, - }, { compact: true }); - // J4.c.1: paint threaded chapter text into any text-frame - // layers on this page that hold a placed chapter. Each - // frame gets its slice from the chain pagination. - _paintThreadedFramesOnThumb(thumb, pageLayers, book, trimW, trimH); - } catch (err) { - console.warn('book page thumb render failed', err); - } + // J6 accuracy: render the tile through the same canvas + // pipeline that produces the PDF — renderBookDesignedPageToCanvas. + // The DOM-based preview helper drifted from the editor in + // a handful of subtle ways (linked-design async resolve, + // z-order with threaded text, clip-path serialisation, + // group transforms) and was never going to match exactly. + // Routing through the PDF rasteriser guarantees the tile + // shows whatever the print + Reader Mode would. + // + // Stage 1 is a cheap placeholder (background colour so the + // grid doesn't shift). Stage 2 awaits the canvas + swaps + // in an . The thumb's `.isConnected` check guards + // against late completions for tiles that have since been + // re-rendered (the grid clears + rebuilds on every render + // call, so the old element is detached when fresh tiles + // exist). + thumb.style.background = p.background || book.spec?.background || '#ffffff'; + const ctxToken = bookTokenContext(book, p.id, 0); + renderBookDesignedPageToCanvas(p, 72, ctxToken).then(canvas => { + if (!thumb.isConnected) return; + const img = document.createElement('img'); + img.src = canvas.toDataURL('image/png'); + img.style.cssText = 'position:absolute;inset:0;width:100%;height:100%;object-fit:contain;display:block'; + thumb.innerHTML = ''; + thumb.appendChild(img); + }).catch(err => { + console.warn('book page thumb canvas paint failed', err); + }); } else if (p.type === 'reflow') { // Reflow tile: same master underlay as designed pages, // then the first paginated page of the chapter rendered