diff --git a/src/index.html b/src/index.html index f88535a..a4bf9de 100644 --- a/src/index.html +++ b/src/index.html @@ -17846,6 +17846,15 @@ const h = (state.customArt?.height || 1080) / 96; return Math.max(w, h); } + if (mode === 'deck') { + // The preview renders the deck's first slide. Deck slides + // default to 1920x1080 = 20x11.25in like customart / slide. + const slides = state.deck?.slides || []; + const sl = slides[0]?.slide || {}; + const w = (Number(sl.width) || 1920) / 96; + const h = (Number(sl.height) || 1080) / 96; + return Math.max(w, h); + } // disc-sheet, jewel: letter-sized return 11; } @@ -17857,9 +17866,50 @@ if (mode === 'jewel') return renderJewelSheetToExportCanvas(dpi); if (mode === 'customart' || mode === 'slide') return renderCustomArtToExportCanvas(dpi); if (mode === 'pixelart') return renderPixelArtToExportCanvas(); + if (mode === 'deck') return renderDeckToExportCanvas(dpi); throw new Error(`Premium preview not supported for mode "${mode}".`); } + // Render the deck's first slide (themed via composeSlideForDeck) + // as the premium preview source. This is the slide buyers see + // before unlocking — using slide 1 matches the deck-thumbnail + // convention. Decks with zero slides produce an empty canvas + // rather than throwing so the publish modal can still proceed. + async function renderDeckToExportCanvas(dpi) { + const deck = state.deck || {}; + const slides = Array.isArray(deck.slides) ? deck.slides : []; + // Prefer the currently-edited slide if the user is mid-edit; + // otherwise slide 1. + let entry = null; + if (deck.editingIndex != null && slides[deck.editingIndex]) { + entry = slides[deck.editingIndex]; + } else if (slides[0]) { + entry = slides[0]; + } + if (!entry) { + const canvas = document.createElement('canvas'); + setupExportCanvas(canvas, 20, 11.25, dpi); + return canvas; + } + const composed = composeSlideForDeck(entry, deck.theme || {}); + const sl = composed.slide || {}; + const wIn = (Number(sl.width) || 1920) / 96; + const hIn = (Number(sl.height) || 1080) / 96; + const canvas = document.createElement('canvas'); + const ctx = setupExportCanvas(canvas, wIn, hIn, dpi); + const bg = sl.background || '#ffffff'; + if (bg && bg.toLowerCase() !== '#ffffff' && bg.toLowerCase() !== '#fff') { + ctx.fillStyle = bg; + ctx.fillRect(0, 0, canvas.width, canvas.height); + } + const layers = (composed.layers || []) + .filter(l => (l.target === 'canvas' || !l.target) && !l.hidden && !l._generatedDiscLayer) + .slice() + .sort((a, b) => (a.z || 0) - (b.z || 0)); + for (const layer of layers) await drawLayerToCanvas(ctx, layer, dpi); + return canvas; + } + // Render the standalone pixel-art design (state.pixelArt frame 0) into // a canvas suitable for the premium watermarked preview. Native pixel // dimensions are tiny (32-128 px), so scale up by the largest integer