# SVGRenderer

Import it from `@grafloria/renderer`.

```ts
class SVGRenderer implements IRenderer
```

**Properties**

| Name | Type | Default | Description |
| --- | --- | --- | --- |
| `mode` |  |  | Renderer mode |
| `capabilities` | `RendererCapabilities` |  | What this renderer can actually do — so callers can ask instead of assuming. `supportsExport` is now TRUE (see `export()` below); hit-testing and text measurement still are not implemented here, and saying so is the point. |

**Methods**

- `getRegistry(): DiagramRegistry` — Register shapes / styles / markers / link-pipeline stages for THIS renderer alone. The module-level `registerShape()` & friends remain the process-wide registry, and this one shadows it — see `ext/diagram-registry.ts`.
- `constructor( private engine: DiagramEngine, config: SVGRendererConfig = {}, theme?: Theme )`
- `render(viewport: Rectangle, zoom: number): VNode` — Render diagram to VNode tree.
- `getQualityState(): { tier: LODLevel; governor?: GovernorState }` — The tier actually rendered last frame, and the governor's reasoning for it.
- `invalidateFrame(): void` — Drop the cached frame. Call from anything whose effect on the picture the mutation epoch cannot see — a topology event, a style/theme invalidation, a registry swap. Cheap and idempotent: the cost of calling it when you did not need to is one rebuilt frame; the cost of NOT calling it when you did is a stale picture, so when in doubt, call it.
- `getInvalidationEpoch(): number` — How many times this renderer has been told "the picture you have is no longer the picture you would draw".
- `getFrameCoverage(): FrameCoverage | null` — The {@link FrameCoverage} of the most recent `render()` pass.
- `getFrameStats(): { built: number; skipped: number }` — The incrementality is only real if these move. `framesSkipped` counts frames served from the previous root (zero DOM work); `framesBuilt` counts frames actually walked. An idle canvas should build ONE.
- `getTheme(): Theme` — Get current theme
- `setHighlightConnected(value: boolean | HighlightConnectedOptions | undefined): void` — Switch `highlightConnected` live: `false` turns it off, `true` takes the defaults, an object tunes it. The next frame redraws every line.
- `getHighlightConnected(): boolean | HighlightConnectedOptions`
- `getLineOverlay(): VNode | null` — The lifted lines, as an `<svg>` in WORLD coordinates for the overlay the instance keeps at the end of the HTML layer — above SVG nodes and HTML custom nodes alike, moved by the same camera transform. `null` when `highlightConnected` is off; an empty `<svg>` when nothing is lifted.
- `setTheme(theme: Theme): void`
- `applyThemeVariables(theme: Theme): void` — THE HOT-SWAP. Re-theme by rewriting this instance's `--grafloria-*` variables.
- `getColorMode(): ColorMode | undefined` — The colorMode in force, or undefined when the host never asked for one.
- `setColorMode(mode: ColorMode, themes?: ThemeSet): void` — Switch colour mode at runtime. `'system'` starts following the OS; the other two pin it. Creates the media-query subscription on first use, so a host can opt in after construction.
- `setTokenBridge(bridge: TokenBridge | null | undefined): void` — Point this diagram's variables at the host design system's tokens (`shadcnBridge()`, `muiBridge()`, `tailwindBridge()`, or a hand-written map). `null` removes the bridge.
- `getTokenBridge(): TokenBridge | undefined` — The bridge currently applied, if any.
- `getInstanceId(): string` — This renderer's instance id (`grafloria-3`). It is the value of the `data-grafloria-instance` attribute on the root `<svg>`, the scope of this diagram's CSS variables, and the suffix of its `<style>` element id.
- `getStyleElementId(): string` — Id of the `<style>` element holding THIS renderer's theme variables.
- `getOverrideElementId(): string` — Id of the `<style>` element holding THIS renderer's bridge + a11y overrides.
- `getStyleSheet(): string` — The complete stylesheet this renderer would inject into `<head>`: the shared theme-independent rules, the animation rules, and THIS instance's `--grafloria-*` variable block.
- `applyInstanceScope(element: Element | null | undefined): void` — Put this diagram's scope on a host element.
- `setViewLifecycle(lifecycle: ViewLifecycle | null): void` — Install the freeze / lazy-mount gate.
- `getViewLifecycle(): ViewLifecycle | null`
- `getDeferredEntities(): ReadonlyArray<readonly [LazyEntityKind, string]>` — What culling admitted on the last frame and the gate held back.
- `getThemeBoundEntityCount(): number` — How many entities the NEXT theme swap would have to restyle. Zero means the swap is a pure variable rebind. Exposed because "no restyle of every VNode" is a claim that should be measurable, not taken on trust — the tests assert on it, and so can a host.
- `getPerformanceMetrics(): PerformanceMetrics` — Get performance metrics
- `async export(format: ExportFormat = 'svg', options: ExportOptions = {}): Promise<string>` — Export the diagram.
- `exportSvgString(options: ExportOptions = {}): SvgExportResult` — The synchronous, fully headless SVG path — what `export('svg')` returns, plus the fidelity `warnings` (foreignObject, unresolved theme vars) that the string-only `IRenderer.export` signature has nowhere to put.
- `exportPdf(options: ExportOptions = {}): PdfExportResult` — A TRUE VECTOR PDF: paths stay paths and text stays text, so it is selectable, searchable and scales without pixelation.
- `exportPages(pagination: PaginationOptions, options: ExportOptions = {}): PagedSvgResult` — Slice the diagram into pages.
- `exportPaginatedPdf(pagination: PaginationOptions, options: ExportOptions = {}): PdfExportResult` — A multi-page PDF of a diagram too big for one sheet.
- `collectExportImageUrls(options: ExportOptions = {}): string[]` — Every EXTERNAL image URL the exported tree will reference — a panel node's avatar/logo/icon (`<image href="https://…">` painted by the renderer itself), or any registered shape that emits one. Widget (HTML-layer) captures are NOT in this tree; their URLs are collected from the captures by the instance layer.
- `getRoutingStats(): { routed: number; reused: number; cached: number }` — How many links this frame actually had to route, and how many were served from the previous frame.
- `dispose(): void` — Dispose renderer and clean up resources
- `getRouteSolverStats(): RouteSolverStats | null` — What the off-thread solver has been doing.
- `setAccessibleFocus(target: { type: 'node' | 'link' | 'comment'; id: string } | null): void` — Tell the renderer which entity the keyboard controller has focused, so the next frame emits `tabindex=0` on it (and `-1` on everything else).
- `getAccessibleFocus(): { type: 'node' | 'link' | 'comment'; id: string } | null`
- `setCommentSource(source: CommentSource | null): void` — Attach (or detach) the source of comment pins.
- `getCommentSource(): CommentSource | null`
- `getContainerId(nodeId: string): string | undefined` — Get container ID for a node (if it uses foreignObject)
- `isUsingForeignObject(nodeId: string): boolean` — Check if a node uses foreignObject rendering
- `getAnimationService(): AnimationService` — The animation service — global animation enable/speed, reduced-motion and battery-saver policy. Public because these are HOST decisions: the service existed with a full config surface and no accessor, so nothing outside this class could e.g. opt out of the battery auto-toggle (`respectBatteryStatus: false`) — a laptop under 20% silently killed every edge animation with no way back.
