Skip to content

Rendering Pipeline ​

The pipeline turns one root document plus project files into a serializable preview update. This page follows data ownership; use Architecture first when deciding which directory should contain a change.

StageOwnerInputOutput
Project readHost IFileProviderRoot URI and relative pathsSource and resource data
Document parseLatexDocumentRoot source, registry, backend modeMetadata, included body, block spans, hashes, maps, diagnostics
Ordered scanLatexCounterScannerBlock text and prior summariesCounters, labels, citations, per-block summaries
Diff and renderSmartRendererDocument state and prior snapshotFull or patch RenderPayload
Host transportVS Code or standalone hostRender payload and lazy-resource requestsTyped preview messages
Browser displayShared preview runtimeFull/patch messagesMounted HTML, virtual shells, PDF canvases, TikZ SVGs

PreviewUpdateService coordinates the document and renderer stages so hosts and end-to-end tests do not have to reproduce their ordering.

Core lifecycle objects ​

ObjectCreated/owned byRetains
RuleRegistrysrc/rules.ts, passed into the serviceActive metadata, rendering, dependency, and splitter declarations
LatexDocumentPreviewUpdateServiceRoot source, included-file map, metadata, block spans/hashes, diagnostics, compact source-map segments, source hints
SmartRendererPreviewUpdateServiceRender snapshots, dependencies, citations, and full/patch state
RenderPayloadSmartRendererSerializable update sent to a preview host
Preview block shellBrowser runtimeStable layout identity and estimated/measured height

The host should not separately drive document parsing and rendering. The preview runtime should not reconstruct document state from HTML.

Initial load ​

  1. A host supplies the root URI, source text, and file provider.
  2. LatexDocument.parse() extracts preamble metadata and expands supported included source.
  3. The selected backend creates coarse block spans and hashes.
  4. The scanner computes numbering, labels, citations, and block summaries.
  5. Dependency rules attach compact dependency fingerprints.
  6. SmartRenderer emits block metadata and initial HTML according to virtual mode.
  7. The preview runtime creates shells and mounts nearby blocks.
  8. A bounded background pass requests remaining HTML serially, refines heights and page boundaries, and releases hidden resource output after measurement.

The initial payload may intentionally omit far-away block HTML. That is a completed virtualized load, not a partial document parse: source spans, hashes, source maps, and shell metadata already exist. Blocks without jump targets omit the optional anchors array instead of serializing an empty array.

The resource marker syntax is shared, but resolution remains host-specific. VS Code maps a project path to a webview URI; standalone maps it to a browser resource or object URL. Both use the same decode-and-escape step before HTML is sent to the preview runtime.

Derived preview state ​

The preview deliberately has three related height representations. They are not interchangeable caches:

RepresentationOwnerLifetime and purpose
Shell HTML by shell instanceBlockVirtualizationControllerSupports remounting one block and is released outside the retain range
Content height by block hashBlockVirtualizationControllerExcludes page spacing, survives mount/unmount, and reuses geometry for unchanged blocks
Current element heightPageLayoutControllerTracks the live DOM element used by the current page layout
Pinned viewport anchorViewportAnchorControllerTemporary visual compensation while a layout mutation is applied

The controller in src/webview/main.ts coordinates these owners. It should not store another authoritative height table or reimplement their invalidation. New derived state should likewise have one owner, one explicit key, a bounded lifetime, and a defined invalidation event. Project text, saved merge baselines, IndexedDB records, and ETags are authoritative state rather than disposable preview caches.

Incremental update ​

text
source edit
    -> update spans and metadata
    -> compare block hashes
    -> collect changed and dependency-dirty blocks
    -> reuse or update block scan summaries
    -> render requested dirty blocks
    -> send patch or full payload
    -> update mounted DOM and virtual shells

Unchanged block text is not duplicated into long-lived renderer snapshots. Hashes determine source equality; dependency fingerprints catch blocks whose own source is unchanged but whose external metadata changed. Empty per-block metadata is omitted, and AST label/citation arrays are reused as immutable artifact data rather than copied into a second snapshot representation.

A dependency-dirty block is therefore an unchanged source block whose rendered inputs changed. For example, editing \title{...} can rerender a separate \maketitle block, and changing cited keys can rerender a bibliography block.

Use these distinctions while debugging:

SymptomInspect first
Wrong block boundary or source lineLatexDocument splitter/source map output
Correct block marked unchanged after external metadata changedDependency descriptors/fingerprint
Correct dirty block produces wrong HTMLSelected backend's render rule/helper
Correct payload does not appear or scrolls incorrectlyPreview message handling/DOM runtime

Rendering rules ​

Legacy preprocessing rules run in ascending priority, protecting generated HTML before Markdown-it. In AST mode, the AST walker tests astRenderRules in array order and gives the first rule returning a result ownership of the current node. Math nodes preserve their original TeX for KaTeX; registered astMathRules trigger a temporary minimal parse only for selected nested commands. Both AST rule arrays use first-match array order, without numeric priorities. Unclaimed AST nodes use the AST fallback renderer; built-in AST rules reuse shared math, citation, table, TikZ, and inline helpers where the output contract is common.

The selected backend runs renderRules or astRenderRules; it is not automatically passed through both. Within an AST math node, the math renderer may additionally invoke astMathRules for registered nested commands.

Full versus patch update ​

Patches preserve unchanged DOM, PDF canvases, and TikZ SVGs. A full update is reserved for initial load, structural resets such as backend switching, and sufficiently broad changes under the renderer's established threshold.

Heavy resources ​

The initial payload does not eagerly compile every TikZ picture or draw every PDF page. Visible output is activated when the owning block mounts. Paged background measurement may compile TikZ to obtain its cropped bounds or read a PDF page viewport without drawing pixels; that hidden output is released immediately. Stale work is rejected by generation-aware scheduling, while the previous successful visible TikZ SVG stays in place until its replacement succeeds.

Continue by subsystem ​

If the change concernsContinue with
AST refinement, artifacts, or AST rule ownershipAST Backend
Cursor, click, scroll, or virtual-target navigationSync Model
Memory, startup, diffing, or virtual layoutPerformance
A new LaTeX command or environmentExtension Model
Verification level and fixturesTesting

A fast structural preview, not a replacement for a full TeX compiler.