Live Preview¶
For editor-style previews, paint pages directly into a <canvas> instead of
round-tripping through PNG/SVG. paint is WASM-only, both the Typst and
acroform backends support it, and it shares the cached compile with the
byte-output render path. The code below continues from the quill, doc and
engine of the JavaScript Quickstart.
const session = await engine.open(quill, doc); // compile once (async)
// Surface session-level diagnostics from compile time.
for (const w of session.warnings) console.warn(w.message);
function renderPage(canvas, page, userZoom = 1) {
canvas.style.width = "100%"; // the box sets display size
if (canvas.clientWidth === 0) return; // no layout box yet
const cssPxPerPt = canvas.clientWidth / session.pageSize(page).widthPt;
const scale = cssPxPerPt * (window.devicePixelRatio || 1) * userZoom;
session.paint(canvas.getContext("2d"), page, scale);
}
for (let p = 0; p < session.pageCount; p++) renderPage(canvases[p], p);
session.free(); // when the editor closes
Key contract points:
scaleis backing-store pixels per point: the CSS px per point the page is shown at, timesdevicePixelRatioand any in-app zoom.- A canvas with no layout box (
display: none, detached) hasclientWidth0, andpaintthrowsbackend::invalid_raster_scaleon a 0 scale: skip it, and paint once aResizeObserverreports a width. - The painter owns
canvas.width/canvas.heightand rewrites them on every call (so eachpaintis a full repaint: noclearRectneeded), reducingscalewhere it must so neither exceeds 16384 px. The consumer ownscanvas.style.*. pageCountandpageSize(page)reflect the session's current compile: stable between edits, but re-read them after a committedupdate(doc), which recompiles in place and can change the page count (ChangeSet.pageCount).- In an edit loop, repaint
dirtyPages ∩ visiblerather than every page:
function onEdit(editedDoc) {
const { pageCount, dirtyPages } = session.update(editedDoc);
for (const p of dirtyPages) if (isVisible(p)) renderPage(canvases[p], p);
}
update is transactional: if it throws, the canvas still shows the
last-good compile, so keep it up and surface the diagnostics.
Full design rationale: PREVIEW.md.