# LinearMafDisplay

Auto-generated @jbrowse/mobx-state-tree API for the current JBrowse release —
see [pluggable elements](https://jbrowse.org/jb2-staging/docs/developer_guide/) for concepts. Provided by the
`maf` plugin.
[View source](https://github.com/GMOD/jbrowse-components/blob/main/plugins/maf/src/LinearMafDisplay/stateModel.ts).

## Example usage

A complete `MafTrack` config to paste into `tracks`. `samples` lists the aligned
species in track order; `rowHeight` sets the per-sample band height in px (or
`0` to stretch rows to fill the track height):

```js
{
  type: 'MafTrack',
  trackId: 'multiz',
  name: 'Multiz alignment',
  assemblyNames: ['hg38'],
  adapter: {
    type: 'BigMafAdapter',
    bigBedLocation: { uri: 'https://example.com/multiz.bb' },
    samples: ['hg38', 'panTro4', 'mm10'],
  },
  displays: [
    {
      type: 'LinearMafDisplay',
      displayId: 'multiz-LinearMafDisplay',
      rowHeight: 16,
      showCoverage: true,
    },
  ],
}
```

The configuration slots for this model are documented on its
[config schema page](../../config/linearmafdisplay).

Members a composed model contributes are listed here too, so these tables are
the whole surface.

## Properties

<!-- prettier-ignore -->
| Member | Description | Defined by |
| --- | --- | --- |
| <span id="property-type">**type**</span><br><code>type: types.literal('LinearMafDisplay')</code> |  | LinearMafDisplay |
| <span id="property-configuration">**configuration**</span><br><code>configuration: ConfigurationReference(configSchema)</code> |  | LinearMafDisplay |
| <span id="property-id">**id**</span><br><code>id: ElementId</code> |  | [BaseDisplay](../basedisplay#property-id) |
| <span id="property-layout">**layout**</span><br><code>layout: types.stripDefault(types.frozen&lt;S[]&gt;(), [])</code> |  | [TreeSidebarMixin](../treesidebarmixin#property-layout) |
| <span id="property-clustertree">**clusterTree**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>clusterTree: types.stripDefault(types.maybe(types.string), unde…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>clusterTree: types.stripDefault(types.maybe(types.string), undefined)</code></pre></dialog></span> |  | [TreeSidebarMixin](../treesidebarmixin#property-clustertree) |
| <span id="property-clusterprovenance">**clusterProvenance**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>clusterProvenance: types.stripDefault( types.maybe(types.frozen…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>clusterProvenance: types.stripDefault(&#10;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;types.maybe(types.frozen&lt;ClusterProvenance&gt;()),&#10;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;undefined,&#10;&#160;&#160;&#160;&#160;&#160;&#160;)</code></pre></dialog></span> | <span data-pagefind-ignore>What `clusterTree` was computed from — the locus and the settings. Set only for a tree this app computed; a supplied phylogeny (maf's `.nh`) leaves it undefined. Persisted with the tree so it survives a session snapshot, which is the case that most needs it: a shared link otherwise hands over a dendrogram with no way to learn its locus.</span> | [TreeSidebarMixin](../treesidebarmixin#property-clusterprovenance) |
| <span id="property-treeareawidth">**treeAreaWidth**</span><br><code>treeAreaWidth: types.stripDefault(types.number, 80)</code> |  | [TreeSidebarMixin](../treesidebarmixin#property-treeareawidth) |
| <span id="property-subtreefilter">**subtreeFilter**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>subtreeFilter: types.stripDefault( types.maybe(types.array(type…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>subtreeFilter: types.stripDefault(&#10;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;types.maybe(types.array(types.string)),&#10;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;undefined,&#10;&#160;&#160;&#160;&#160;&#160;&#160;)</code></pre></dialog></span> |  | [TreeSidebarMixin](../treesidebarmixin#property-subtreefilter) |
| <span id="property-runclustering">**runClustering**</span><br><code>runClustering: types.maybe(types.boolean)</code> | <span data-pagefind-ignore>Transient declarative launch spec, the same idea as `LinearGenomeView`'s `init`: a session or config sets this true and the real clustering RPC runs once automatically, with no dialog, as soon as the display reports itself ready. `setupRunClusteringAutorun` clears it afterwards, so a saved session never re-triggers.<br><br>Lives here rather than on each display because it is the trigger for a run whose *output* — `clusterTree`, `clusterProvenance`, `layout` — is this mixin's state. Three displays declared it identically, each with its own wrapper module that existed to code-split the clustering code and, along the way, hand-wrote the same six-member duck type of the display. Splitting inside the `run` callback does the same job and loads on a run rather than on every attach. What each run actually *is* stays per display, in that callback.</span> | [TreeSidebarMixin](../treesidebarmixin#property-runclustering) |
| <span id="property-clusterregion">**clusterRegion**</span><br><code>clusterRegion: types.maybe(types.string)</code> | <span data-pagefind-ignore>Where that run reads from, as a locstring (whitespace-separated for several). Clustering is region-scoped, so running it over the visible window feeds the estimator whatever happens to be on screen; naming the locus instead lets a session cluster on the signal and then show it against its context — otherwise a zoom the user has to perform in the right order. Cleared with `runClustering`, since it is that flag's argument and a locus left standing describes a run that is not coming.</span> | [TreeSidebarMixin](../treesidebarmixin#property-clusterregion) |
| <span id="property-sortrowsby">**sortRowsBy**</span><br><code>sortRowsBy: types.maybe(types.frozen&lt;RowSortSpec&gt;())</code> | <span data-pagefind-ignore>Transient declarative launch spec, the same idea as `runClustering`: set `{refName, pos}` to order the rows once by the value each carries at that genomic column — the session-expressible form of the right-click "Sort rows by ... here". `setupRowSortAutorun` applies it once the region containing it has loaded and then clears it, so the resulting `layout` persists but a saved session never re-sorts.<br><br>Where clustering orders rows by the whole region in view and `layout` states an order outright, only this one says "rank them here", which is what lets a figure open a cohort ranked at a candidate locus with the surrounding context still on screen. What the value at the column *is* stays per display, in its `sortRows` callback.</span> | [TreeSidebarMixin](../treesidebarmixin#property-sortrowsby) |

## Volatiles

<!-- prettier-ignore -->
| Member | Description | Defined by |
| --- | --- | --- |
| <span id="volatile-wiredatamap">**wireDataMap**</span><br><code>wireDataMap: regionDataMap&lt;MafWireRegionData&gt;('wireDataMap')</code> | Rows as the worker sent them: named by species, with no screen position. `rpcDataMap` is this placed against the current row order, and this is what a reorder re-places from instead of refetching. | LinearMafDisplay |
| <span id="volatile-rpcdatamap">**rpcDataMap**</span><br><code>rpcDataMap: regionDataMap&lt;MafRegionData&gt;('rpcDataMap')</code> | `wireDataMap` with every row assigned its on-screen `rowIndex` (see `placeMafRegionData`). Everything that draws, hit-tests or measures rows reads this one. | LinearMafDisplay |
| <span id="volatile-summarydatamap">**summaryDataMap**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>summaryDataMap: regionDataMap&lt;MafSummaryRecord[]&gt;('summaryDataM…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>summaryDataMap: regionDataMap&lt;MafSummaryRecord[]&gt;('summaryDataMap')</code></pre></dialog></span> | Per-region `bigMafSummary` rows for the zoom-out path, populated by `fetchMafSummaryData` only while `showSummary` is active. Kept separate from `rpcDataMap` so the GPU sequence canvas and the summary overlay never read each other's data. | LinearMafDisplay |
| <span id="volatile-framesdatamap">**framesDataMap**</span><br><code>framesDataMap: regionDataMap&lt;MafFrameRecord[]&gt;('framesDataMap')</code> | Per-region CDS frame rows (UCSC `mafFrames`) for the annotation overlay, populated by the frames RPC in parallel with the main fetch. Kept separate from the alignment/summary maps so the overlay survives the summary↔detail data swap. | LinearMafDisplay |
| <span id="volatile-framesgateblocked">**framesGateBlocked**</span><br><code>framesGateBlocked: false</code> | The last frames fetch declined to read the `annotationAdapter` because its own byte estimate was over budget (`framesReadOverBudget`). The overlay is auxiliary and fails soft, so the only thing that happens is that the strip stops drawing — this is what lets the menu say so rather than leaving the tick on over nothing.<br><br>Volatile and not a config slot: it describes a measurement of the current viewport, not a setting. **Never in `rpcProps()`** — it is written by the fetch, which is the loop trap ARCHITECTURE.md names. | LinearMafDisplay |
| <span id="volatile-prefersoffset">**prefersOffset**</span><br><code>prefersOffset: true</code> |  | LinearMafDisplay |
| <span id="volatile-sourcesvolatile">**sourcesVolatile**</span><br><code>sourcesVolatile: [] as MafSource[]</code> | The worker's authoritative row set, in tree (leaf) order. `layout` overlays any user reorder/relabel on top; `editableSources` merges the two and `sources` narrows that by the subtree filter. | LinearMafDisplay |
| <span id="volatile-treenewickvolatile">**treeNewickVolatile**</span><br><code>treeNewickVolatile: undefined as string &#124; undefined</code> | The worker's guide-tree Newick (the default, before any reorder). The active displayed tree lives in the mixin's `clusterTree`, which a reorder clears (rows no longer match the dendrogram) and "Clear arrangement" restores from here — so we keep the worker tree separately rather than re-fetching it. | LinearMafDisplay |
| <span id="volatile-error">**error**</span><br><code>error: undefined as unknown</code> |  | [BaseDisplay](../basedisplay#volatile-error) |
| <span id="volatile-statusmessage">**statusMessage**</span><br><code>statusMessage: undefined as string &#124; undefined</code> |  | [BaseDisplay](../basedisplay#volatile-statusmessage) |
| <span id="volatile-statusprogress">**statusProgress**</span><br><code>statusProgress: undefined as number &#124; undefined</code> | <span data-pagefind-ignore>determinate progress fraction [0,1] for the current status, or undefined when the in-flight phase is indeterminate. Set alongside `statusMessage` by `setStatusMessage`; a display that never shows a bar simply leaves it undefined.</span> | [BaseDisplay](../basedisplay#volatile-statusprogress) |
| <span id="volatile-scrolltop">**scrollTop**</span><br><code>scrollTop: 0</code> |  | [TrackHeightMixin](../trackheightmixin#volatile-scrolltop) |
| <span id="volatile-loadedregions">**loadedRegions**</span><br><code>loadedRegions: regionDataMap&lt;LoadedRegion&gt;('loadedRegions')</code> | <span data-pagefind-ignore>regions whose data has been fetched and committed, keyed by displayedRegionIndex; populated only after the fetch work callback returns</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#volatile-loadedregions) |
| <span id="volatile-forceloadtrack">**forceLoadTrack**</span><br><code>forceLoadTrack: false</code> | <span data-pagefind-ignore>The force-load button's track-wide approval. Volatile so it never reaches a saved session; the `forceLoad` config slot is the durable form.</span> | [RegionTooLargeMixin](../regiontoolargemixin#volatile-forceloadtrack) |
| <span id="volatile-byteestimate">**byteEstimate**</span><br><code>byteEstimate: undefined as ByteEstimate &#124; undefined</code> | <span data-pagefind-ignore>The last byte measurement: bytes, the span they were taken at, and whether zooming has been shown not to shrink them. Survives `clearAllRpcData`; dropped on chromosome navigation and on a tier swap.</span> | [RegionTooLargeMixin](../regiontoolargemixin#volatile-byteestimate) |
| <span id="volatile-gatemeasuredviewportkey">**gateMeasuredViewportKey**</span><br><code>gateMeasuredViewportKey: undefined as string &#124; undefined</code> | <span data-pagefind-ignore>The viewport key the gate last asked the adapter about, on either axis. Separate from `byteEstimate` because a density refusal measures no bytes.</span> | [RegionTooLargeMixin](../regiontoolargemixin#volatile-gatemeasuredviewportkey) |
| <span id="volatile-canvasdrawn">**canvasDrawn**</span><br><code>canvasDrawn: false</code> | <span data-pagefind-ignore>flips true on first paint; read by test selectors to detect render</span> | [RenderLifecycleMixin](../renderlifecyclemixin#volatile-canvasdrawn) |
| <span id="volatile-currentrenderingbackend">**currentRenderingBackend**</span><br><code>currentRenderingBackend: undefined</code> | <span data-pagefind-ignore>current backend reference, updated on context-loss recovery. Typed `unknown` (not generic `B`) on purpose: this mixin is composed by every display via a non-generic factory, so the per-display backend type `B` isn't known here — it's supplied at `attachRenderingBackend<B>` and narrowed with `as B` inside the autoruns. Don't "fix" the cast.</span> | [RenderLifecycleMixin](../renderlifecyclemixin#volatile-currentrenderingbackend) |
| <span id="volatile-rendertick">**renderTick**</span><br><code>renderTick: 0</code> | <span data-pagefind-ignore>counter the render autorun observes; bumped to force a re-render</span> | [RenderLifecycleMixin](../renderlifecyclemixin#volatile-rendertick) |
| <span id="volatile-autorunsinstalled">**autorunsInstalled**</span><br><code>autorunsInstalled: false</code> | <span data-pagefind-ignore>guards attachRenderingBackend so the autorun pair spawns once per instance</span> | [RenderLifecycleMixin](../renderlifecyclemixin#volatile-autorunsinstalled) |
| <span id="volatile-rendererror">**renderError**</span><br><code>renderError: undefined</code> | <span data-pagefind-ignore>the render-backend (GPU/Canvas2D init or context-loss) error, or undefined. Single source of truth for the render-error terminal state: `useRenderingBackend` writes it from the canvas-init mechanism so the model — not React-local hook state — owns every terminal state. Read by `displayPhase` (whose `renderError` term outranks `loading`, suppressing the scrim) and by `DisplayChrome` (shows the retry overlay).</span> | [RenderLifecycleMixin](../renderlifecyclemixin#volatile-rendererror) |
| <span id="volatile-activestoptoken">**activeStopToken**</span><br><code>activeStopToken: undefined as StopToken &#124; undefined</code> | <span data-pagefind-ignore>stop token of the in-flight fetch, or undefined when idle</span> | [FetchMixin](../fetchmixin#volatile-activestoptoken) |
| <span id="volatile-fetchgeneration">**fetchGeneration**</span><br><code>fetchGeneration: 0</code> | <span data-pagefind-ignore>bumps at every fetch end; autoruns read it to re-evaluate, and it doubles as the staleness epoch inside runFetch</span> | [FetchMixin](../fetchmixin#volatile-fetchgeneration) |
| <span id="volatile-reloadcounter">**reloadCounter**</span><br><code>reloadCounter: 0</code> | <span data-pagefind-ignore>Bumped by `reload()` and read unconditionally by the fetch autoruns, so a user retry re-runs the body even where nothing else moved — after an error every other fetch input is unchanged. It is also the half that survives a `reload()` override that forgets to invalidate, which is the dead Retry button `makeRetryContractCheck` reports. Declared here because this is the one mixin both LGV fetch foundations compose, the same argument that put `fetchInert` below; the comparative family carries its own on `SyntenyFetchStateMixin` (ADR-054).</span> | [FetchMixin](../fetchmixin#volatile-reloadcounter) |
| <span id="volatile-statuswindow">**statusWindow**</span><br><code>statusWindow: createStatusWindow(writeStatus(self))</code> | <span data-pagefind-ignore>This display's status field, and the only thing that writes it: one throttle window, one slot per concurrent operation, so N parallel per-region fetches thin to one stream between them rather than N and a second operation cannot end the first one's label (ADR-081). Lent whole to `createStopTokenRotation` by a display that also runs a bare-autorun fetch — see `StatusReporter`.</span> | [FetchMixin](../fetchmixin#volatile-statuswindow) |
| <span id="volatile-fetchcanceled">**fetchCanceled**</span><br><code>fetchCanceled: false</code> | <span data-pagefind-ignore>true after the user explicitly cancels a load (the loading overlay's cancel button → `cancelFetchByUser`). A durable, blocking state — unlike `cancelFetch`, it does not retrigger the fetch autoruns — so the load stays stopped until the user retries (`reload`) or the viewport changes. Any new fetch clears it (`runFetch` resets it at the start).</span> | [FetchMixin](../fetchmixin#volatile-fetchcanceled) |
| <span id="volatile-fetchrotation">**fetchRotation**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>fetchRotation: createStopTokenRotation(self, { statusWindow: se…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>fetchRotation: createStopTokenRotation(self, {&#10;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;statusWindow: self.statusWindow,&#10;&#160;&#160;&#160;&#160;&#160;&#160;})</code></pre></dialog></span> | <span data-pagefind-ignore>**The latest-wins machine this mixin is a wrapper around**, and not a second one: `createStopTokenRotation` owns token rotation, the `isCurrent` guard, the status slot and the supersede-versus-end rule (ADR-080, ADR-081), for every fetch in the codebase that has one. `runFetch` adds the observable bookkeeping a display needs on top — `isLoading`, `error`, `fetchGeneration`, `fetchCanceled` — and nothing else.<br><br>It was two implementations of that machine until 2026-08-20, which is how they came to disagree about whether a completed fetch releases its token. A display's *primary* fetch is this wrapper; a second concurrent fetch on the same node holds a rotation of its own, which is why the primitive is the thing that exists and this is the thing built on it (ADR-054 §1).<br><br>It is lent this display's `statusWindow`, so the fetch takes a slot on the one field rather than opening a second window over it — the whole point of `StatusReporter`.</span> | [FetchMixin](../fetchmixin#volatile-fetchrotation) |
| <span id="volatile-hoveredtreenode">**hoveredTreeNode**</span><br><code>hoveredTreeNode: undefined as HoveredTreeNode &#124; undefined</code> |  | [TreeSidebarMixin](../treesidebarmixin#volatile-hoveredtreenode) |
| <span id="volatile-treecanvas">**treeCanvas**</span><br><code>treeCanvas: null as HTMLCanvasElement &#124; null</code> |  | [TreeSidebarMixin](../treesidebarmixin#volatile-treecanvas) |
| <span id="volatile-mouseovercanvas">**mouseoverCanvas**</span><br><code>mouseoverCanvas: null as HTMLCanvasElement &#124; null</code> |  | [TreeSidebarMixin](../treesidebarmixin#volatile-mouseovercanvas) |
| <span id="volatile-contextmenuinfo">**contextMenuInfo**</span><br><code>contextMenuInfo: undefined as Info &#124; undefined</code> |  | [ContextMenuMixin](../contextmenumixin#volatile-contextmenuinfo) |

## Getters

<!-- prettier-ignore -->
| Member | Description | Defined by |
| --- | --- | --- |
| <span id="getter-view">**view**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>ModelInstanceTypeProps&lt;_OverrideProps&lt;_OverrideProps&lt;…&gt;, { ...;…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>ModelInstanceTypeProps&lt;_OverrideProps&lt;_OverrideProps&lt;…&gt;, { ...; }&gt;&gt; &amp; ... 25 more ... &amp; IStateTreeNode&lt;...&gt;</code></pre></dialog></span> |  | LinearMafDisplay |
| <span id="getter-rowproportion">**rowProportion**</span><br><code>number</code> |  | LinearMafDisplay |
| <span id="getter-showallletters">**showAllLetters**</span><br><code>boolean</code> |  | LinearMafDisplay |
| <span id="getter-mismatchrendering">**mismatchRendering**</span><br><code>boolean</code> |  | LinearMafDisplay |
| <span id="getter-showasuppercase">**showAsUpperCase**</span><br><code>boolean</code> |  | LinearMafDisplay |
| <span id="getter-showcoverage">**showCoverage**</span><br><code>boolean</code> |  | LinearMafDisplay |
| <span id="getter-showalignments">**showAlignments**</span><br><code>boolean</code> |  | LinearMafDisplay |
| <span id="getter-coverageheight">**coverageHeight**</span><br><code>number</code> |  | LinearMafDisplay |
| <span id="getter-showconservation">**showConservation**</span><br><code>boolean</code> |  | LinearMafDisplay |
| <span id="getter-conservationheight">**conservationHeight**</span><br><code>number</code> |  | LinearMafDisplay |
| <span id="getter-conservationmode">**conservationMode**</span><br><code>"base" &#124; "codon"</code> |  | LinearMafDisplay |
| <span id="getter-rowidentitymode">**rowIdentityMode**</span><br><code>"heatmap" &#124; "none" &#124; "xyplot"</code> |  | LinearMafDisplay |
| <span id="getter-rowidentityautozoom">**rowIdentityAutoZoom**</span><br><code>boolean</code> |  | LinearMafDisplay |
| <span id="getter-showannotations">**showAnnotations**</span><br><code>boolean</code> |  | LinearMafDisplay |
| <span id="getter-showtranslation">**showTranslation**</span><br><code>boolean</code> |  | LinearMafDisplay |
| <span id="getter-colorbychromosome">**colorByChromosome**</span><br><code>boolean</code> |  | LinearMafDisplay |
| <span id="getter-showinversions">**showInversions**</span><br><code>boolean</code> |  | LinearMafDisplay |
| <span id="getter-conf">**conf**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>ModelInstanceTypeProps&lt;Record&lt;…&gt;&gt; &amp; { setSubschema(slotName: st…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>ModelInstanceTypeProps&lt;Record&lt;…&gt;&gt; &amp; { setSubschema(slotName: string, data: Record&lt;string, unknown&gt;): any; setSlot(slotName: string, value: unknown): void; } &amp; IStateTreeNode&lt;...&gt;</code></pre></dialog></span> | the config typed off the concrete schema; `ConfigurationReference` erases `self.configuration` to `any`, so direct reads route through this to stay typed (same move as `BaseAdapter<CONF>`) | LinearMafDisplay |
| <span id="getter-referencesampleid">**referenceSampleId**</span><br><code>string &#124; undefined</code> | Which sample row IS the reference — the worker's own answer (`referenceSampleId`, resolved from the block whose sequence the row carries), with the view's assembly name as the fallback before any region has landed.<br><br>The view's assembly name is only coincidentally the MAF's name for the reference: a MAF-tabix track sets `refAssemblyName` on the adapter precisely when the two differ, and a bigMaf/TAF file names its reference by whatever db name it was built with. Reading it here rather than in each consumer is what keeps the codon conservation band's excluded row and the per-base band's (computed in the worker) the same row.<br><br>Any loaded region answers — a track has one reference species — so this takes the first that names one. | LinearMafDisplay |
| <span id="getter-annotationadapterconfig">**annotationAdapterConfig**</span><br><code>Record&lt;string, unknown&gt; &#124; undefined</code> | The configured CDS-frame annotation adapter snapshot (UCSC `mafFrames`), or undefined when unset. Read from the MAF *adapter* config as a swappable sub-adapter (alongside `summaryAdapter`), not the display — a frozen slot, so this is a plain snapshot the frames RPC hands straight to `getAdapter`.<br><br>Read with an array slot path off the **live** parent track, not as `readConfObject(self.adapterConfig, …)`. `adapterConfig` is itself a snapshot, and a slot read against a snapshot is the case `core/configuration/CLAUDE.md` warns about: `types.stripDefault` omits a slot sitting at its default, so the read reports a defaulted slot as absent. Harmless for these two — they default to null and are only tested for presence — but the array path costs nothing and doesn't depend on that staying true. | LinearMafDisplay |
| <span id="getter-summaryadapterconfig">**summaryAdapterConfig**</span><br><code>Record&lt;string, unknown&gt; &#124; undefined</code> | The configured `bigMafSummary` sub-adapter snapshot, or undefined when unset. Same journey as `annotationAdapterConfig`.<br><br>Declared here, beside its sibling, so `showSummary` has one place to ask whether the tier exists. The gate reaches the same slot through `byteGateAdapterPath` rather than through this getter, since it needs the path anyway to read the tier's own budget. | LinearMafDisplay |
| <span id="getter-annotationsactive">**annotationsActive**</span><br><code>boolean</code> | Whether the per-species CDS frame *strip* should draw: an annotation adapter is configured and the "Show CDS frames" toggle is on. The codon view consumes the same frames data but is gated separately (see `annotationDataActive`), so the strip can be off while codon view is on. | LinearMafDisplay |
| <span id="getter-annotationdataactive">**annotationDataActive**</span><br><code>boolean</code> | Whether the frames data needs to be fetched: an annotation adapter is configured and either the strip or the codon view wants it. Gates the frames RPC and keys the fetch cache so toggling *either* consumer on triggers the fetch. | LinearMafDisplay |
| <span id="getter-editablesources">**editableSources**</span><br><code>MafSource[]</code> | The full row set with the user's arrangement applied: `layout` supplies order + label/color overrides, merged over the worker's `sourcesVolatile` by name. Empty `layout` (no customization) passes the worker set through. Not subtree-filtered — this is what the arrangement dialog edits. Empty until the first fetch populates the worker set; `sourcesKnown` is the readiness question.<br><br>The shared `reconcileLayout`, same as multi-row features and multi-wiggle. Its append half matters here: a sample-discovery track learns of a genome only from the region whose blocks contain it (see `setSamples` / `unionSources`), and the hand-rolled merge this replaced iterated `layout` alone — so with any custom arrangement saved, a species revealed by a later region never got a row at all. | LinearMafDisplay |
| <span id="getter-sources">**sources**</span><br><code>MafSource[]</code> | The display rows: `editableSources` narrowed to the selected subtree.<br><br>**Resolved — an array, never `undefined`**, the shared spelling across the row displays. The two consumers that used to read the absent case were both asking "has the species list arrived", which is `sourcesKnown`; everything else already collapsed it with `?.length` or `?? 0`. An empty array reaches here two ways that must stay indistinguishable to a *renderer* — no fetch yet, and a subtree filter that matched nothing — which is exactly why the readiness question needs its own name rather than a truthiness test on this. | LinearMafDisplay |
| <span id="getter-sourcesknown">**sourcesKnown**</span><br><code>boolean</code> | The species list has arrived from the adapter. The readiness half of what `sources` used to answer by being `undefined`: `rowsVisible` and the render callback's first-paint gate both need "a fetch has landed", and neither can get it from an empty `sources`, which a subtree filter narrowing to nothing also produces. | LinearMafDisplay |
| <span id="getter-subtreefilterset">**subtreeFilterSet**</span><br><code>string[] &#124; undefined</code> | `subtreeFilter` as the worker sees it: a **set**, sorted, and a plain array. The one expression both the RPC payload (`fetchMafData`) and the cache key (`rpcProps`) read, so the bytes sent and the key they are cached under cannot drift apart.<br><br>Sorted because the key is a JSON string while the worker consumes the value as `new Set(...)` and places rows by species name — so order is unobservable to the fetch but would still move the key. Re-picking the same clade after a re-cluster hands `setSubtreeFilter` the same names in the tree's new leaf order, which refetched every loaded region for identical data. ARCHITECTURE.md §"Row order is not a fetch input".<br><br>Copied out of the MST node for the same reason: the key is a JSON string and an MST node's serialization is not this module's to depend on. | LinearMafDisplay |
| <span id="getter-showsummary">**showSummary**</span><br><code>boolean</code> | Use the cheap summary path when a `bigMafSummary` sub-adapter is configured and the view is zoomed out past the force-load threshold, which is where the detail fetch stops being affordable at all. Tracks without a summary never enter this path.<br><br>`aboveForceLoadFloor` is the gate's own comparison against that threshold (`RegionTooLargeMixin`), read rather than restated so the swap and the gate can't end up disagreeing about where the floor is. It deliberately excludes the opt-in terms, which is what keeps this from being a cycle — everything below that reads this getter (`byteGateAdapterPath`) sits downstream of the floor, never upstream.<br><br>The swap point is 20kb and stays there even though the byte gate has no floor at all any more: where the summary tier starts being the better *picture* is a rendering question, and where the detail fetch gets too expensive is a bytes question. They coincided before only because the gate had nothing to say below 20kb. `aboveForceLoadFloor` survives for this and for the density axis; nothing else compares against 20kb.<br><br>Declared this early in the chain — well before the fetch and rendering getters that are its obvious neighbours — because the band layout below needs it: `coverageBandActive` is what zeroes the band's height, and `rowsTopOffset` (and the whole height cascade under it) is resolved long before here. Both its inputs come off the compose, so there is nothing to order it after. | LinearMafDisplay |
| <span id="getter-coveragebandactive">**coverageBandActive**</span><br><code>boolean</code> | The coverage band is on *and* has data to put in it.<br><br>`showCoverage` is the user's setting — the menu ticks it, a config sets it — but the band's depths come from `coverage.coverageDepths` on the alignment blocks, and the summary path clears `rpcDataMap` on purpose. Reading the setting as if it answered both questions left the band reserving `coverageHeight` px above the rows and painting nothing whatsoever into them: no bars, no axis, no label — ~45px of dead chrome on every track with a `summaryAdapter` zoomed out past the floor.<br><br>Everything that lays the band out, paints it, hit-tests it or exports it reads this; only the track menu reads `showCoverage`, so the tick keeps reporting what the user chose rather than where they happen to be zoomed — and zooming back in restores the band without touching the config. Same split as `basesRenderingActive` vs `activeRowRendering`, for the same reason. | LinearMafDisplay |
| <span id="getter-conservationbandactive">**conservationBandActive**</span><br><code>boolean</code> | The conservation band is on *and* has data to put in it — the exact twin of `coverageBandActive`, and it exists because the band had the bug that getter was written to fix.<br><br>Percent identity is computed from the alignment: the per-base mode reads `coverage.identityScores` off the blocks and the codon mode translates them, so both come out of `rpcDataMap`, which the summary path clears. `showConservation` alone therefore left 40px of band, a fixed 0–100% axis and a resize handle drawn over nothing at every zoom past the floor. Unlike coverage it is off by default, which is the only reason it went unnoticed for longer.<br><br>Same split as its twin: everything that lays the band out, paints it or exports it reads this, so the menu tick keeps reporting what the user chose and zooming back in restores the band without touching the config.<br><br>The one other reader of the raw setting is `annotationDataActive`, and it has to stay raw: it is an `rpcProps()` cache key, so resolving it through this getter would make the key zoom-dependent and drop every loaded region on each crossing of the summary floor. Fetching frames the codon band can't draw yet costs one small read; refetching the alignment costs the tier swap twice over. | LinearMafDisplay |
| <span id="getter-samples">**samples**</span><br><code>Sample[]</code> | Sample list keyed by sample id (alias of `sources` mapped to the project's canonical `{ id, label, color }` shape). Consumed by MafSequenceWidget, color legend, etc. | LinearMafDisplay |
| <span id="getter-rowindexbysrc">**rowIndexBySrc**</span><br><code>Map&lt;string, number&gt;</code> | Maps a `src` (species) to its display row index. The single source for the `src`→row projection used by the summary-bar and CDS-frame overlays and the frame hover lookup, so they can't disagree on row placement. | LinearMafDisplay |
| <span id="getter-defaultcodonspecies">**defaultCodonSpecies**</span><br><code>string &#124; undefined</code> | The anchor species whose `mafFrames` reading frame is used to translate every row (UCSC `codonDefault`). Tied to the *reference assembly*, not the top display row: every species' codon is compared against the reference sequence (`block.refSeqBytes`), so the frame must be enumerated from the reference's own frames. A row reorder (layout) can move a non-reference species to row 0 — reading `sources[0]` there would enumerate codons in the wrong frame. Falls back to the worker's canonical first row (pre-reorder) when the reference isn't itself a listed sample.<br><br>The reference is `referenceSampleId` — the row the worker saw carrying the reference sequence — not the view's assembly name, which is a different string whenever the MAF names its reference differently. | LinearMafDisplay |
| <span id="getter-coveragedisplayheight">**coverageDisplayHeight**</span><br><code>number</code> | Height of the coverage band above the rows (0 when hidden, and on the summary path, where it has nothing to draw). | LinearMafDisplay |
| <span id="getter-conservationdisplayheight">**conservationDisplayHeight**</span><br><code>number</code> | Height of the conservation (percent identity) band (0 when hidden, and on the summary path, where it has nothing to draw). | LinearMafDisplay |
| <span id="getter-rowstopoffset">**rowsTopOffset**</span><br><code>number</code> | Top offset of the per-sample rows area = the stacked band heights above it (coverage + conservation). The single source of truth for "where the rows start" — every rows hit-test / draw / export offset routes through this so adding a band can't desync them. | LinearMafDisplay |
| <span id="getter-nrow">**nrow**</span><br><code>number</code> | Number of displayed rows (at least 1, so the fit-mode division is safe). | LinearMafDisplay |
| <span id="getter-rowsvisible">**rowsVisible**</span><br><code>boolean</code> | The per-sample rows area has something to draw: the view can place it, the rows are shown at all, and the row set is known.<br><br>Every rows layer is a full per-cell scan of the visible blocks, and with `showAlignments` off the area is 0px tall — so the gate lives here rather than being re-spelled by each `visible*` getter, which is how the summary bars came to be the only rows layer that could run before the view was initialized. | LinearMafDisplay |
| <span id="getter-maxrowsheight">**maxRowsHeight**</span><br><code>number</code> | Max CSS-px height the rows canvas may take before its backing store (`× dpr`) hits the browser/GPU canvas limit. The single ceiling both the fit-target sizing and the `rowHeight` cap respect. | LinearMafDisplay |
| <span id="getter-fittargetheight">**fitTargetHeight**</span><br><code>number</code> | The track height that fit-to-height mode divides among rows. Once the user drags, the explicit `height` config slot wins; before any drag we size to show every row at the default px height, so a typical alignment looks exactly like fixed mode.<br><br>Bounded by `DEFAULTS.maxAutoFitHeight`, past which the rows shrink instead of the track growing. Sizing purely to content made the default height scale with the species count — 4141px for a 447-way, across a stack of full-height overlay canvases — and left `maxRowsHeight` (a crash guard, at the backing-store limit) as the only thing bounding it. This is the *policy* bound; that one stays as the hard floor under a deliberate drag. | LinearMafDisplay |
| <span id="getter-rowsheight">**rowsHeight**</span><br><code>number</code> | Height of the per-sample rows *viewport* — the track height minus the stacked bands, which is exactly the rows canvas. Zero when alignments are hidden, collapsing the display to the coverage band.<br><br>This is the viewport, not the content: with a fixed `rowHeight` the rows can add up to far more than this and the extra is reached by scrolling (`rowsContentHeight` / `scrollableHeight`), never by growing the canvas. Capped at `maxRowsHeight` so even a deliberate drag can't push the backing store past the browser/GPU canvas limit. | LinearMafDisplay |
| <span id="getter-resizablebandbounds">**resizableBandBounds**</span><br><code>{ max: number; }</code> | The legal range for the two drag-resizable bands stacked over the rows (coverage, conservation).<br><br>The ceiling is what makes the drag recoverable: `rowsHeight` above floors at 0, so without one a band dragged past the track height squashes the rows to nothing *and* carries its own resize handle — drawn at the band's bottom edge — off the display, leaving no way back. Bounded against `fitTargetHeight`, the same pot `rowsHeight` divides, and per band rather than across both: two bands dragged large can still crowd the rows, but each stays reachable. | LinearMafDisplay |
| <span id="getter-autorowheight">**autoRowHeight**</span><br><code>number</code> | Per-row height in fit-to-height mode: the rows viewport split evenly across rows, so the content always fits exactly and the display never scrolls in this mode.<br><br>Deliberately NOT floored at 1px. A sub-pixel row is the legitimate answer for more species than the track has pixels, and flooring it made the rows area taller than the height it was asked to fit inside — which defeated `fitTargetHeight`'s own ceiling past ~555 species (2000 species floored to 1px re-grew the track to 2045px) and would now make fit mode report a phantom scroll. The non-positive guard belongs in `effectiveRowHeight`, which is the resolved value consumers divide by. Same rule, and same regression, as the multi-sample variant display's `autoRowHeight`.<br><br>A **fixed** height goes the other way and is used as-is however many species there are: the rows canvas is the viewport (`rowsHeight`), so hundreds of tall rows cost scroll extent, not backing store. The canvas-size ceiling that `effectiveRowHeight` used to apply — shrinking every row so the whole stack could be one canvas — now lives on `rowsHeight` itself, where the canvas actually is. | LinearMafDisplay |
| <span id="getter-rowscontentheight">**rowsContentHeight**</span><br><code>number</code> | Height the per-sample rows add up to — the scrolled content behind the `rowsHeight` viewport. Equal to it in fit-to-height mode (which is what makes that mode never scroll); larger whenever a fixed `rowHeight` asks for more rows than the track shows. | LinearMafDisplay |
| <span id="getter-totalheight">**totalHeight**</span><br><code>number</code> | Full display height = rows viewport + stacked bands. | LinearMafDisplay |
| <span id="getter-scrollableheight">**scrollableHeight**</span><br><code>number</code> | Max valid `scrollTop`: how far the rows scroll before the last one reaches the viewport floor. Zero when they fit, so this doubles as the "does this display scroll" answer (the scrollbar and the wheel handler both read it). Fit-to-height always fits. | LinearMafDisplay |
| <span id="getter-height">**height**</span><br><code>number</code> | Override BaseLinearDisplay.height so the track container matches the rendering canvases exactly (stacked bands + rows viewport). | LinearMafDisplay |
| <span id="getter-hierarchy">**hierarchy**</span><br><code>ClusterHierarchyNode &#124; undefined</code> | Positioned tree hierarchy. Coordinates are computed against `(rowsContentHeight, treeAreaWidth)` so leaf rows align with row tops even where the rows scroll past the viewport — the tree canvas and the SVG labels shift the whole thing by `scrollTop`, exactly as the rows do. The coverage band is offset separately by the React layer. | LinearMafDisplay |
| <span id="getter-spatialindex">**spatialIndex**</span><br><code>TreeSpatialIndex &#124; undefined</code> |  | LinearMafDisplay |
| <span id="getter-colorpalette">**colorPalette**</span><br><code>MafColorPalette</code> | Theme-derived color palette (per-base colors + match/gap/mismatch/ unknown/insertion), read by `gpuProps()` and `renderState`. Derived from the session theme so it's always available — including headless SVG export and RPC, where no component mounts to seed it. Theme changes trigger a main-thread re-encode but never an RPC refetch. | LinearMafDisplay |
| <span id="getter-encodebinbp">**encodeBinBp**</span><br><code>number</code> | Genomic bp the GPU encoder collapses into one cell — `subPixelBinBp` off the *debounced* `coarseBpPerPx` (the same input `zoomedToBaseLevel` uses), which the encode autorun tracks. Zoomed in this is `1` (encode every base). Once a base falls below half a CSS pixel the per-base quads are individually invisible — a 500kb region across 10 species emits 1.7M of them into a 28MB buffer, all but ~15k of which lose the sub-pixel race for their pixel — so the encoder decimates to one sample per bin instead. | LinearMafDisplay |
| <span id="getter-coveragedomain">**coverageDomain**</span><br><code>[number, number] &#124; undefined</code> | [min, max] coverage domain over the currently visible content blocks, derived from the worker-shipped `coverage.coverageDepths` arrays (which already reflect the active subtree — see `rpcProps`). Linear and unbounded: sample counts are already bounded and well-distributed, so this display composes no score axis to configure. Feeds `coverageTicks`. | LinearMafDisplay |
| <span id="getter-coverageticks">**coverageTicks**</span><br><code>YScaleTicks &#124; undefined</code> | Y-axis tick marks for the coverage band. | LinearMafDisplay |
| <span id="getter-coveragebandcolors">**coverageBandColors**</span><br><code>{ colors: MafCoverageColors; gpuColors: CoverageBandColors; }</code> | The coverage band's colours, in both representations the two backends need: CSS strings for the Canvas2D painters, packed ABGR for the GPU passes. Its own getter so the pack — which parses nine CSS colours — is memoized against the palette rather than re-run inside `renderState`, which every scroll frame invalidates. | LinearMafDisplay |
| <span id="getter-coveragebandstate">**coverageBandState**</span><br><code>MafCoverageBandState &#124; undefined</code> | The coverage band as the renderers take it, or undefined for "draw no band": the setting is off, the summary tier owns the view, or the autoscaled domain has not resolved yet. Every mark in the band is a fraction of the domain max, so the third case is not a shorter band — it is bars of arbitrary height, which is why one nullable object carries the height and the domain together. | LinearMafDisplay |
| <span id="getter-renderstate">**renderState**</span><br><code>MafGPURenderState</code> | Render state passed to GPU/Canvas2D backend each frame.<br><br>`canvasHeight` is the WHOLE canvas — the stacked bands plus the rows viewport — because the coverage band draws on the same canvas as the rows, scissored out of it, the way the alignments display draws its coverage band above its pileup. A display gets one rendering backend, so a second GPU band cannot mean a second canvas. `rowsTop` / `rowsHeight` are the rows band inside it. | LinearMafDisplay |
| <span id="getter-inversionconsensus">**inversionConsensus**</span><br><code>StrandConsensus</code> | The orientation each (row, source chromosome) is measured against for the inversion indicator (`consensusStrandByRowChr`). A memoized computed for the same reason as `sourceChromRanks`: it walks every block × row of every *loaded* region — deliberately, so the consensus stays put as the user scrolls within loaded data — while its only consumer runs on every pan and zoom. Empty when the indicator is off, so a track that never shows inversions pays nothing. | LinearMafDisplay |
| <span id="getter-visibleemptylines">**visibleEmptyLines**</span><br><code>EmptyLineSegment[]</code> | Positioned bridge-line segments for `e`-line (empty/bridged) rows. | LinearMafDisplay |
| <span id="getter-visibledeletions">**visibleDeletions**</span><br><code>DeletionMarker[]</code> | Positioned deletion runs for the visible aligned rows; the overlay draws the deleted-base count inside each run when it fits. | LinearMafDisplay |
| <span id="getter-visibleinversions">**visibleInversions**</span><br><code>InversionMarker[]</code> | Positioned strand-flip (inversion) markers for the visible aligned rows. Empty unless the indicator is toggled on. | LinearMafDisplay |
| <span id="getter-zoomedtobaselevel">**zoomedToBaseLevel**</span><br><code>boolean</code> | At base level each reference base spans at least a pixel, so individual bases / SNP marks are legible (UCSC's `zoomedToBaseLevel`). Read off the debounced `coarseBpPerPx` so the rendering swap it gates doesn't thrash mid-zoom. False until the view is initialized. | LinearMafDisplay |
| <span id="getter-selectedrowrendering">**selectedRowRendering**</span><br><code>RowRendering</code> | The row coloring the *user picked*, as one value across the three slots that store it. `activeRowRendering` below is what is actually painting; this is the setting behind it, and the two differ wherever zoom or the summary path overrides the choice.<br><br>Zoom-independent on purpose. The radio it drives would otherwise move its own tick as the user zoomed — the identity plot yields to the bases at base level, codon view only exists there — which reads as the menu changing the setting behind their back.<br><br>This is where precedence between the three slots is decided, once: `activeRowRendering` starts from the answer rather than re-deriving it, so the two cannot disagree about which setting won. | LinearMafDisplay |
| <span id="getter-activerowrendering">**activeRowRendering**</span><br><code>"bases" &#124; "codon" &#124; "sourceChrom" &#124; RowIdentityMode</code> | Single source of truth for what the per-sample rows area draws right now: `bases` (the GPU SNP/base coloring), `codon` (per-codon change coloring from `mafFrames`), `sourceChrom` (color-by-source-chromosome SV mode), or a per-row identity style (`heatmap` / `xyplot`). The GPU canvas, the identity/chromosome canvases, the codon overlay, and SVG export all branch on this one getter so they can't disagree about what's on screen.<br><br>`selectedRowRendering` is the setting; this applies the two things that can override it, and falls back to the bases — the rendering that needs nothing beyond the alignment — whenever it does:<br><br>- the cheap summary path carries neither per-row bases nor per-row source chromosomes, so no alternative can draw from it; - zoom, in the two directions UCSC `wigMaf` uses. Codons only exist at base level, and with `rowIdentityAutoZoom` (the default) the identity plot yields to the bases there, where the letters say more than a per-pixel mean of them. Auto off pins the plot on at every zoom.<br><br>Deriving from the selection rather than restating its precedence is also what keeps a config that sets two of the three slots — the state the old menu of independent checkboxes could reach, and a hand-written config still can — painting the one the menu ticks. Re-deriving let a lower-precedence slot take over at the zooms where the winner couldn't draw, so the menu said "Codon changes" while the rows were colored by source chromosome. | LinearMafDisplay |
| <span id="getter-basesrenderingactive">**basesRenderingActive**</span><br><code>boolean</code> | The GPU base canvas owns the rows: per-base SNP cells are what's painted, so the per-base letters draw, insertion markers are live (drawn, hoverable, clickable), and the encode autorun has a buffer worth building.<br><br>Named once here because it is the question six consumers ask — the encode and render callbacks, the insertion overlay and its cursor, the insertion click, and SVG export — and a mode added to `activeRowRendering` has to reach all six or the markers keep drawing over a rendering that isn't theirs.<br><br>**Not simply `activeRowRendering === 'bases'`.** That getter answers which of the *selectable* renderings wins, and summary mode resolves to `bases` there because none of the alternatives can draw from summary rows. But the base canvas can't draw from them either: `fetchMafSummaryData` clears `rpcDataMap` on purpose, and the rows the user sees are the summary overlay's. So the two questions genuinely differ here, and answering this one with that one pinned the display in `loading` forever — the render callback took the paint-from- `rpcDataMap` branch, `renderBlocks` returned `painted: false` over an empty map every frame, and `canvasDrawn` never flipped, so `computeLoadingTerm`'s `rendersCanvas && !canvasDrawn` stayed true under a track that was fully loaded and visibly drawn. | LinearMafDisplay |
| <span id="getter-rowscanvas2dmode">**rowsCanvas2dMode**</span><br><code>"sourceChrom" &#124; RowIdentityMode &#124; undefined</code> | Which rendering the sibling Canvas2D rows layer paints, or undefined when it paints nothing (`bases` is the GPU canvas, `codon` is its own overlay). The on-screen canvas and SVG export both branch on this rather than re-deriving the same cascade, which is what let the export grow a four-branch chain against the canvas's two. | LinearMafDisplay |
| <span id="getter-visiblelabels">**visibleLabels**</span><br><code>VisibleLabel[]</code> | Positioned per-base SNP/sequence letters. Suppressed in any non-base rendering (the identity plot and codon view both replace the letters). | LinearMafDisplay |
| <span id="getter-visibleinsertions">**visibleInsertions**</span><br><code>InsertionMarker[]</code> | Positioned insertion markers (interbase) for the visible aligned rows.<br><br>Lives here, past `basesRenderingActive`, rather than beside the other block overlays: the markers are drawn only in `bases` mode (the overlay and the SVG export both gate on it), so the identity plot, codon view and color-by-chromosome were each paying a full per-column insertion walk of every visible block × row, every frame, for markers nothing rendered. The identity plot is the expensive case — it is the zoom-out default once `rowIdentityMode` is set, which is exactly where the walk covers the most blocks. Same mistake, and same fix, as the deletion overlay building 679k markers to draw none; see agent-docs/reference/MAF_LARGE_BLOCKS.md.<br><br>The hover hit-test does NOT read this — it resolves insertions from the blocks directly (`findRowHoverAtBp`) — so gating costs no interactivity. | LinearMafDisplay |
| <span id="getter-visiblesummarybars">**visibleSummaryBars**</span><br><code>SummaryBar[]</code> | Positioned per-species presence bars for the zoom-out summary overlay. Unmatched `src` rows drop via the `sources` index, keeping the render robust to summary files that list extra species.<br><br>Drawn on the summary tier, **and as the coarse stand-in for a region the detail tier hasn't landed yet** — which is the swap back in, and used to be a blank track. Zooming in past the floor stays spatially inside the region the summary fetch loaded, so `viewportWithinLoadedData` is true and `canvasDrawn` is already set: the display reads as `ready` with nothing in it, for the 600ms fetch debounce plus the alignment RPC, which on a deep alignment is the slow one. Nothing was wrong except that the rows we could still draw had been switched off.<br><br>Suppressed per region rather than in one decision, because the tiers arrive per region: the one under the cursor can be showing bases while its neighbour is still bars. `showSummary` short-circuits it because the two maps *can* both hold a region — zooming back out reuses the summary cache and never calls `clearAlignmentData`, and the bars are what is on screen there. | LinearMafDisplay |
| <span id="getter-visibleframes">**visibleFrames**</span><br><code>FrameMarker[]</code> | Positioned per-species CDS frame boxes for the annotation overlay. Empty unless an annotation adapter is configured and the overlay is on. Reuses the `src`→row mapping the summary bars established, so frame rows for species the track doesn't list drop out. | LinearMafDisplay |
| <span id="getter-codoncellsactive">**codonCellsActive**</span><br><code>boolean</code> | The codon overlay is what the rows area is painting. | LinearMafDisplay |
| <span id="getter-codonconservationactive">**codonConservationActive**</span><br><code>boolean</code> | The conservation band is in per-codon (amino-acid identity) mode, with frames to define codons and per-base blocks to translate — the cheap summary path ships neither. | LinearMafDisplay |
| <span id="getter-locatedcodons">**locatedCodons**</span><br><code>LocatedCodon[]</code> | Every reference codon the fetched blocks resolve, in the anchor species' reading frame — the shared spine of the codon cells and the codon conservation band. A memoized computed rather than a call inside each consumer: the resolution (enumerate the anchor's codons, index every block's reference columns, locate each codon) is the expensive half, and with both modes on it used to run twice per frame. Empty when neither consumer is active, so a track with codon view off pays nothing. | LinearMafDisplay |
| <span id="getter-sourcechromranks">**sourceChromRanks**</span><br><code>{ ranks: Map&lt;number, Map&lt;string, number&gt;&gt;; maxRank: number; }</code> | Each row's source chromosomes ranked by aligned bp (`perRowChromRanks`). A memoized computed for the same reason as `locatedCodons` above: the rank walk covers every block × row of every loaded region, and it had two independent callers — the legend (already a cached computed) and `drawSourceChrom`, which recomputed it inside a draw that re-fires on every pan and zoom.<br><br>Ranked over the loaded regions, exactly as `inversionConsensus` is, and for both of its reasons. The colors stay put as the user scrolls within loaded data — a rank is a claim about the row, and a block ought not change color because a pan brought a different scaffold into view — and the walk re-runs on new data rather than on movement.<br><br>It used to be keyed on `renderBlocks`, which is rebuilt on every pan tick (its `screenStartPx` moves), so the memo missed on every frame of a pan and re-ranked every (block, row) pair to produce the identical map: those blocks only selected *which region* to walk, and the region they selected carries the whole buffered span either way. Pinned by `sourceChromRanks.test.ts`.<br><br>Empty when the mode is off, so a track that never colors by chromosome pays nothing. | LinearMafDisplay |
| <span id="getter-visiblecodons">**visibleCodons**</span><br><code>CodonMarker[]</code> | Per-species codon cells for the codon view (the per-codon change coloring that replaces the SNP cells). Empty unless codon view is the active rendering and an anchor species is known. | LinearMafDisplay |
| <span id="getter-visiblecodonconservation">**visibleCodonConservation**</span><br><code>CodonConservationBar[]</code> | Per-codon amino-acid conservation bars for the conservation band's codon mode. Draws only inside the CDS (where frames define codons); everywhere else the band is blank. | LinearMafDisplay |
| <span id="getter-bandlabels">**bandLabels**</span><br><code>{ text: string; top: number; }[]</code> | Titles for the stacked bands, with the y they sit at — empty unless both bands draw, which is the only case they are needed for: two stacked filled-histogram bands are otherwise told apart only by their Y-axis units (depth vs %).<br><br>A getter for the same reason as `legendItems` below: the on-screen labels and the SVG export both read it. The export had no titles at all, so the one figure that needs them most — both bands drawn, and an exported PNG where nothing can be hovered to disambiguate — was the one shipping without them.<br><br>The conservation title names what the band is *drawing* (`codonConservationActive`), not the mode that was asked for: codon mode falls back to per-base wherever frames or per-base blocks are missing, and a band captioned "aa identity" while drawing nucleotide identity is worse than no caption. | LinearMafDisplay |
| <span id="getter-legenditems">**legendItems**</span><br><code>LegendItem[]</code> | The color key for whatever `activeRowRendering` is painting, or empty where the rendering needs no key (plain bases). One getter rather than a component per mode, because both the on-screen legend and the SVG export read it — an exported codon or source-chromosome figure whose swatches are its only decoder used to ship with no key at all.<br><br>A dispatch, not a description: each key is built by the module that paints the rendering, out of the colors it paints with. Written out here instead, all three had drifted from the screen — the codon swatches skipped the alpha the cells are composited with, the X-Y plot got the heatmap's ramp when it paints one color and varies height, and the source-chromosome key kept adding rows past the point where its palette stops changing. | LinearMafDisplay |
| <span id="getter-msahighlights">**msaHighlights**</span><br><code>MsaHighlight[]</code> | Get highlight regions from connected MSA views | LinearMafDisplay |
| <span id="getter-gateenabled">**gateEnabled**</span><br><code>boolean</code> | Enable byte-estimate gating: a MAF-aware byte estimate (per-species sequence × span) is checked against `fetchSizeLimit` inside the tier's own RPC, blocking the fetch with a force-load prompt rather than downloading hundreds of species' bases at genome scale.<br><br>On for **both** tiers, and `byteGateAdapterPath` below is what makes that safe: each RPC measures the file it actually reads — the alignment index on the detail path, the `summaryAdapter` sub-adapter on the summary one. This used to be `!showSummary`, exempting the summary tier on the grounds that it is the cheap one. It is cheap *per base* — no sequence — but it is still a whole-feature download (`BigBedAdapter.getFeatures`), and `showSummary` covers every zoom from 20kb to the whole genome. So the one path that existed to escape the gate was also the one that could pull an unbounded number of per-species records with nothing quoting the size. A genuinely small summary read is nowhere near `fetchSizeLimit` and never sees a banner; that is the estimate's job to decide, not this getter's. | LinearMafDisplay |
| <span id="getter-bytegateadapterpath">**byteGateAdapterPath**</span><br><code>string[]</code> | Measure whichever tier is about to be fetched: the `summaryAdapter` sub-adapter while `showSummary`, otherwise the MAF adapter itself. Without this the summary tier would be gated against the *alignment's* estimate — a number describing a download that isn't happening, which at genome scale would block the cheap tier on the expensive one's cost.<br><br>The only hook the swap needs: `byteGateAdapterConfig` is the config at this path and `adapterFetchSizeLimit` is that config's own `fetchSizeLimit` slot, so the measurement and the budget describe one file by construction rather than by two overrides agreeing.<br><br>Reading `showSummary` here is not a cycle: it resolves through `aboveForceLoadFloor`, which deliberately excludes every opt-in term (`RegionTooLargeMixin`), so nothing in the gate is upstream of it. | LinearMafDisplay |
| <span id="getter-parenttrack">**parentTrack**</span><br><code>AbstractTrackModel</code> |  | [BaseDisplay](../basedisplay#getter-parenttrack) |
| <span id="getter-renderingcomponent">**RenderingComponent**</span><br><code>FC&lt;…&gt;</code> |  | [BaseDisplay](../basedisplay#getter-renderingcomponent) |
| <span id="getter-displayblurb">**DisplayBlurb**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>FC&lt;{ model: ModelInstanceTypeProps&lt;{ id: IOptionalIType&lt;ISimple…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>FC&lt;{ model: ModelInstanceTypeProps&lt;{ id: IOptionalIType&lt;ISimpleType&lt;string&gt;, [undefined]&gt;; type: ISimpleType&lt;string&gt;; }&gt; &amp; { ...; } &amp; { ...; } &amp; IStateTreeNode&lt;...&gt;; }&gt; &#124; null</code></pre></dialog></span> |  | [BaseDisplay](../basedisplay#getter-displayblurb) |
| <span id="getter-adapterconfig">**adapterConfig**</span><br><code>Record&lt;string, unknown&gt;</code> |  | [BaseDisplay](../basedisplay#getter-adapterconfig) |
| <span id="getter-isminimized">**isMinimized**</span><br><code>boolean</code> | <span data-pagefind-ignore>Returns true if the parent track is minimized. Used to skip expensive operations like autoruns when track is not visible.</span> | [BaseDisplay](../basedisplay#getter-isminimized) |
| <span id="getter-hoveredfeature">**hoveredFeature**</span><br><code>unknown</code> | <span data-pagefind-ignore>Overridable hook (default `undefined`): what the pointer is currently over, for readers **outside** the display. `LinearGenomeViewContainer` publishes it to `session.hovered`, the view-wide "what is the user pointing at" channel a plugin can subscribe to.<br><br>Declared here because a cross-display consumer can only read a name the base declares — the same reason `SyntenyFetchStateMixin.fetchInert` is a hook rather than a getter each display invents. The container used to read `featureUnderMouse`, which only the wiggle, alignments and Manhattan families spelled that way — canvas said `hoveredFeature`, variants `hoveredGenotype` — so the channel carried a hover from a third of the display types and nothing said which. It also asked only `displays[0]` of each track.<br><br>`unknown` because the payload genuinely differs — a read, a wiggle bin, a SNP, a genotype cell — and `session.hovered` is typed to match ("can be anything; code that wants to deal with this should examine it"). Narrow it in the override.</span> | [BaseDisplay](../basedisplay#getter-hoveredfeature) |
| <span id="getter-featurenoun">**featureNoun**</span><br><code>string</code> | <span data-pagefind-ignore>Overridable hook (default `'feature'`): the SINGULAR word for one of the things this display draws, as a menu row or a chip says it — "Hide this read", "Showing 3 variants".<br><br>Declared here for the same reason as `hoveredFeature` above: it is read across the display boundary, by chrome that has no idea which display it is drawing for (`SoloSelectionChip`, alignments' group-label overlay), and a name only the base declares is a name every such consumer can rely on. Two displays declared it independently and one of those declarations WAS this default.<br><br>**A control keeps the generic word; content takes this one.** "Variant height" reads as a different setting from "Feature height" when it is the same one, so the shared menus stay on "feature" however the display answers here, and the noun varies where it names what the user is looking at — "Showing 3 variants", "Hide this read". A display drawing something the generic word already fits is right to leave this alone.<br><br>Distinct from the per-hit noun a context menu takes off the clicked item's own `type` ("mRNA", "gene"); that names one annotation, this names what the track holds. The hit noun falls back to this.</span> | [BaseDisplay](../basedisplay#getter-featurenoun) |
| <span id="getter-featurewidgettype">**featureWidgetType**</span><br><code>{ type: string; id: string; }</code> | <span data-pagefind-ignore>Overridable hook: which widget `openFeatureWidget` opens for one of this display's features. The default is the generic one, which is what a display drawing plain features wants and what the canvas base spelled out by hand.<br><br>An override is a display whose features have a vocabulary of their own — a read, a variant, a synteny block — and the `id` is deliberately part of it: two displays naming one id share the drawer panel, which is the behaviour when the two are showing the same kind of thing.</span> | [BaseDisplay](../basedisplay#getter-featurewidgettype) |
| <span id="getter-resizing">**resizing**</span><br><code>boolean</code> | <span data-pagefind-ignore>True for the duration of a height drag on this track, whichever handle is running it. A display whose row geometry is a function of the track height restretches every row per animation frame, and can use this to sit an expensive per-frame layer out of the drag (MAF's dense per-base letter overlay is a Canvas2D pass that scales with rows x columns).<br><br>The flag itself is the track's (`BaseTrackModel`), so the view brackets a drag without needing the active display to have opted into this mixin. Reading it here is what makes `self.resizing` available to a display that did.</span> | [TrackHeightMixin](../trackheightmixin#getter-resizing) |
| <span id="getter-host">**host**</span><br><code>RegionHost</code> | <span data-pagefind-ignore>The containing LinearGenomeView, typed once for every display in this family — see `containingHost` for the cast it owns and why both foundations still declare the name.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-host) |
| <span id="getter-canvaswidthpx">**canvasWidthPx**</span><br><code>number</code> | <span data-pagefind-ignore>The CSS width of this display's on-screen canvas, in px — and the `canvasWidth` its `renderState` must carry, since the two have to agree or the bp→px mapping is scaled against a box it doesn't fill.<br><br>`trackWidthPx`, **not** `view.width`: `TrackRenderingContainer` insets the rendering component by the 2px track outline under `contain: strict`, so a `view.width`-wide canvas overhangs its own container and the browser clips the overhang away. It renders almost identically, which is why MAF drifted onto `view.width` uncaught.<br><br>A getter rather than a note on each display, because the choice was being made by copying a neighbour out of four plausible view getters — `width` (the viewport), this one, and `totalWidthPx` / `totalWidthPxWithoutBorders` (the *content* width, which the global family's heatmaps legitimately want: a different question, not a different answer). `no-restricted-syntax` bans the underlying read everywhere but this line, since a second spelling agrees until it doesn't.<br><br>SVG export is the one exception: the export shell has no outline, so `renderSvg` overrides `canvasWidth` with the shell's own width (see `LgvSvgBodyProps`).</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-canvaswidthpx) |
| <span id="getter-canrender">**canRender**</span><br><code>boolean</code> | <span data-pagefind-ignore>Overrides `RenderLifecycleMixin`'s default-true hook with the LGV precondition both foundations share — see `foundationCanRender`.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-canrender) |
| <span id="getter-viewportwithinloadeddata">**viewportWithinLoadedData**</span><br><code>boolean</code> | <span data-pagefind-ignore>true when every visible block lies within an already-fetched region — i.e. the viewport shows data we actually loaded, not the stale fringe left after a zoom-out/pan. Drives the loading overlay through the pre-refetch debounce.<br><br>**Spatial only, and it stays that way.** Whether the data held for a block is still what a fetch would bring back is `isCacheValid`, which `dataCurrent` conjoins for the export gate. The scrim reads this getter alone: a phase that went `loading` on a moved `regionFetchKey` would raise the overlay into every zoom.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-viewportwithinloadeddata) |
| <span id="getter-viewportempty">**viewportEmpty**</span><br><code>boolean</code> | <span data-pagefind-ignore>No content block is on screen, so this display has nothing to fetch and nothing to paint — see `viewportEmpty.ts` for the one viewport that reaches it, how narrow that is, and why the state still has to be terminal rather than a permanent scrim. Both foundations declare it over that one expression, the same way they each declare `host` and `paintInert`.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-viewportempty) |
| <span id="getter-layoutready">**layoutReady**</span><br><code>boolean</code> | <span data-pagefind-ignore>Overridable hook (default false): whether a searchable feature layout currently exists. Any display defining a feature-lookup method (`searchFeatureByID`, `getFeatureById`) must override it, so callers can tell "laid out, but off-display" from "no layout exists yet" — a distinction only the display can make. See packages/display-kit/CLAUDE.md §"Four readiness axes".</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-layoutready) |
| <span id="getter-regionfetchkey">**regionFetchKey**</span><br><code>string</code> | <span data-pagefind-ignore>Overridable hook (default `''`): what a fetch issued right now would produce for a region, as a string — the display's per-region content axis. `fetchRegions` captures it before it issues the RPC and stamps it beside the loaded region; `isCacheValid` refetches a region whose stamp no longer matches. Wiggle returns `String(view.bpPerPx)` (adr-008), canvas the peptide-overlay threshold, the variant matrix its zoom in matrix mode only.<br><br>NOT an `rpcProps()` field: this invalidates one region's held data where `rpcProps` invalidates all of it, and a zoom-swinging value in the RPC payload blanks the display at the force-load floor — see REGION_TOO_LARGE.md §"How the verdict is built".<br><br>A getter, so the observables it reads register as dependencies of `FetchVisibleRegions`; MobX runs an action untracked and the autorun would keep a stale answer.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-regionfetchkey) |
| <span id="getter-datasuperseded">**dataSuperseded**</span><br><code>boolean</code> | <span data-pagefind-ignore>Overridable hook (default false): the held data is loaded and covers the viewport, but a fetch input has moved past it, so the data is about to be cleared and refetched. A display says so here rather than overriding `dataCurrent`, for the reason `FetchMixin.fetchInert` is a hook: an override has to restate the freshness terms and then misses the next one added.<br><br>On screen this window is invisible (the clear lands a tick later and the loading scrim covers it), which is exactly why it needs saying: `awaitSvgReady` samples freshness once, and an export that samples it inside this window renders the data that is about to be discarded — or, once the clear lands mid-render, nothing at all. GWAS's LD auto-index is the case: adopting the top hit as the index SNP is an `rpcProps` change, so the very load that produced the top hit is what it invalidates.<br><br>**The input need not have settled yet.** Alignments counts the debounce window ahead of its per-base bin, where the bin the data was fetched under has not moved and the clear is inevitable rather than committed. That is the half of the window an export lands in, since a reader zooms and then reaches for the menu. What may NOT go in is a change that could still be taken back: this fails hung, not stale.<br><br>So state the live-vs-settled half as a **value** compare and leave key strings alone. The settled half — the stamp a fetch committed under against the key a fetch now would use — is the foundation's already, through the `isCacheValid` term in `dataCurrent`, and an override restating it buys nothing: a second derivation of the key's vocabulary reads `"16\|fine"` against a live `"16"` the day the key grows an axis, latches this true, and every export of the display then waits out `awaitSvgReady`'s backstop instead of failing.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-datasuperseded) |
| <span id="getter-renderblocks">**renderBlocks**</span><br><code>RenderBlock[]</code> | <span data-pagefind-ignore>Shared cached view for every LGV-based GPU display. A single displayedRegion may produce multiple render blocks (shared GPU buffer, different scissor clips on screen). Plugins that want to suppress rendering in certain states (e.g. no domain yet) can override this getter to return [] — the autorun lifecycle will then issue an empty-blocks render that clears the canvas.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-renderblocks) |
| <span id="getter-datacurrent">**dataCurrent**</span><br><code>boolean</code> | <span data-pagefind-ignore>This family's answer to the shared freshness question every display foundation must answer (`dataCurrent`): the held data corresponds to what is on screen right now. Four terms — spatial coverage of every visible block, `loadedRegions.size` to rule out the vacuously-true empty viewport, `isCacheValid` per block, and the display's own `dataSuperseded`. Regions stream in one at a time, so this (not "the first datum arrived") is what keeps a multi-region/whole-genome export complete.<br><br>**`isCacheValid` belongs here and not in the scrim.** Coverage answers "is the data here", never "is it what a fetch now would bring back", so a zoom that moves `regionFetchKey` leaves every held region covered and stale at once — and an export sampling `svgReady` across that window painted bins the worker computed for the previous zoom. `displayPhase` still reads `viewportWithinLoadedData` alone: folding staleness into the phase raises the loading scrim into every zoom, which is the trade REJECTED_IDEAS.md "Folding content staleness into `displayPhase`" turned down and this does not take.<br><br>The term cannot latch, and the reason is structural rather than a case list: a block reaches `fetchNeeded` unless `planRegionFetch` finds it ungated, covered AND cache-valid, and it reads that last term tracked. The `&&` short-circuits ahead of it drop its observables only where the block is fetched anyway, so the key move that closes this gate is the same read, in the same dependency set, that wakes the refetch reopening it.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-datacurrent) |
| <span id="getter-loadedassembly">**loadedAssembly**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(ModelInstanceTypeProps&lt;…&gt; &amp; { error: unknown; loadingP: Promis…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(ModelInstanceTypeProps&lt;…&gt; &amp; { error: unknown; loadingP: Promise&lt;…&gt; &#124; undefined; ... 10 more ...; refNameMismatches: Map&lt;…&gt;; } &amp; ... 13 more ... &amp; IStateTreeNode&lt;...&gt;) &#124; undefined</code></pre></dialog></span> | <span data-pagefind-ignore>The assembly the data in hand came from, once it can answer about refNames — `undefined` before that.<br><br>Off the first LOADED region rather than the view's displayed ones, which is the distinction that makes it belong here: a display holding fetched data is asking about the assembly THAT data is on, and the view's regions can already have moved on.<br><br>The `initialized` gate is why this returns the assembly rather than its name. `getCanonicalRefName2` and `refNameToIndex` answer WRONGLY rather than throwing before the aliases land — identity, and a miss — so a caller that skips the gate gets a plausible answer and no signal. Handing back `undefined` until it can answer is what makes the caller write its fallback.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-loadedassembly) |
| <span id="getter-svgready">**svgReady**</span><br><code>boolean</code> | <span data-pagefind-ignore>true once an off-screen (SVG) export can safely read this display's data. Policy single-sourced in `computeSvgReady`; this family supplies only the freshness half, which `foundationSvgReady` reads as `dataCurrent` or the vacuous currency of `viewportEmpty`. Off-screen renderers gate on it via `awaitSvgReady(model)` instead of inlining the condition.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-svgready) |
| <span id="getter-paintinert">**paintInert**</span><br><code>boolean</code> | <span data-pagefind-ignore>Fills `RenderLifecycleMixin`'s `paintInert` hook — see there for why a failed fetch has to read as finished to the consumers outside the display, and `foundationPaintInert` for the second such state and why both fetch families answer it through one function. Overridable, as the hook is: a display with a third inert state of its own says so here.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-paintinert) |
| <span id="getter-displayphase">**displayPhase**</span><br><code>DisplayPhase</code> | <span data-pagefind-ignore>The display's mutually-exclusive visual state, mapped in `foundationDisplayPhase` — every foundation calls it and supplies only its staleness argument, so a term added to `computeLoadingTerm` reaches all three without being wired three times.<br><br>This family's argument is spatial: `loading` also covers stale data (viewport past loaded) still on screen through the pre-refetch debounce. A thunk, so a suppressed or already-loading display doesn't subscribe to viewport churn.<br><br>A subclass customizes this through `fetchInert` (FetchMixin), never by overriding the getter — see that hook.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-displayphase) |
| <span id="getter-densitygateenabled">**densityGateEnabled**</span><br><code>boolean</code> | <span data-pagefind-ignore>Whether the density axis applies. `CanvasFeatureGateMixin` contributes `true` beside its measurement; byte-only displays leave it.</span> | [RegionTooLargeMixin](../regiontoolargemixin#getter-densitygateenabled) |
| <span id="getter-bytegateadapterconfig">**byteGateAdapterConfig**</span><br><code>Record&lt;string, unknown&gt;</code> | <span data-pagefind-ignore>The adapter config the gate measures — the one at `byteGateAdapterPath`. Overridable for a display whose adapter config is synthesized rather than read off the track.</span> | [RegionTooLargeMixin](../regiontoolargemixin#getter-bytegateadapterconfig) |
| <span id="getter-configuredfetchsizelimit">**configuredFetchSizeLimit**</span><br><code>number</code> | <span data-pagefind-ignore>The display's `fetchSizeLimit` slot, from `regionTooLargeConfigSchemaFields`.</span> | [RegionTooLargeMixin](../regiontoolargemixin#getter-configuredfetchsizelimit) |
| <span id="getter-densitytoolarge">**densityTooLarge**</span><br><code>boolean</code> | <span data-pagefind-ignore>The density axis's verdict; canvas overrides it.</span> | [RegionTooLargeMixin](../regiontoolargemixin#getter-densitytoolarge) |
| <span id="getter-adapterfetchsizelimit">**adapterFetchSizeLimit**</span><br><code>number &#124; undefined</code> | <span data-pagefind-ignore>The measured adapter's own `fetchSizeLimit` slot, read off the live track config rather than the `adapterConfig` snapshot, which omits slots at their default.</span> | [RegionTooLargeMixin](../regiontoolargemixin#getter-adapterfetchsizelimit) |
| <span id="getter-configforceload">**configForceLoad**</span><br><code>boolean</code> | <span data-pagefind-ignore>The declarative `forceLoad` slot.</span> | [RegionTooLargeMixin](../regiontoolargemixin#getter-configforceload) |
| <span id="getter-gateviewport">**gateViewport**</span><br><code>GateViewport &#124; undefined</code> | <span data-pagefind-ignore>What a measurement taken now would be about: the span on screen and a key for the stretch of genome it covers. Undefined until the view is measured, and the mixin's only read of the view. Captured before the fetch's round trip, never at commit.</span> | [RegionTooLargeMixin](../regiontoolargemixin#getter-gateviewport) |
| <span id="getter-bytegateadapterkey">**byteGateAdapterKey**</span><br><code>string</code> | <span data-pagefind-ignore>Which tier the estimate is about, as a comparable string.</span> | [RegionTooLargeMixin](../regiontoolargemixin#getter-bytegateadapterkey) |
| <span id="getter-aboveforceloadfloor">**aboveForceLoadFloor**</span><br><code>boolean</code> | <span data-pagefind-ignore>Whether the span on screen is at or above `AUTO_FORCE_LOAD_BP`, the one comparison against that constant. False on an unmeasured view.</span> | [RegionTooLargeMixin](../regiontoolargemixin#getter-aboveforceloadfloor) |
| <span id="getter-gateexempt">**gateExempt**</span><br><code>boolean</code> | <span data-pagefind-ignore>Nothing may gate on either axis: the `forceLoad` slot or the button.</span> | [RegionTooLargeMixin](../regiontoolargemixin#getter-gateexempt) |
| <span id="getter-estimatedfetchbytes">**estimatedFetchBytes**</span><br><code>number &#124; undefined</code> | <span data-pagefind-ignore>The stored estimate's bytes; undefined when nothing has been measured.</span> | [RegionTooLargeMixin](../regiontoolargemixin#getter-estimatedfetchbytes) |
| <span id="getter-gatemeasurementstale">**gateMeasurementStale**</span><br><code>boolean</code> | <span data-pagefind-ignore>Whether the last measurement is about a viewport the user has since left. True before any measurement.</span> | [RegionTooLargeMixin](../regiontoolargemixin#getter-gatemeasurementstale) |
| <span id="getter-gatebytelimit">**gateByteLimit**</span><br><code>number</code> | <span data-pagefind-ignore>The byte budget: the adapter's limit, else the display's, doubled below `AUTO_FORCE_LOAD_BP`. Read only through `resolvedByteLimit()`.</span> | [RegionTooLargeMixin](../regiontoolargemixin#getter-gatebytelimit) |
| <span id="getter-gateactive">**gateActive**</span><br><code>boolean</code> | <span data-pagefind-ignore>Whether the gate may act right now, on any axis: opted in, not exempt, view measured. The view is read last, so an ungated display never touches it.</span> | [RegionTooLargeMixin](../regiontoolargemixin#getter-gateactive) |
| <span id="getter-densitygateactive">**densityGateActive**</span><br><code>boolean</code> | <span data-pagefind-ignore>`gateActive` plus the density axis's own terms: the axis is on, and the span is above the floor.</span> | [RegionTooLargeMixin](../regiontoolargemixin#getter-densitygateactive) |
| <span id="getter-toolargestatus">**tooLargeStatus**</span><br><code>RegionTooLargeStatus</code> | <span data-pagefind-ignore>The verdict and its banner text, from the stored estimate against `resolvedByteLimit()` and the density axis when it may act.</span> | [RegionTooLargeMixin](../regiontoolargemixin#getter-toolargestatus) |
| <span id="getter-regiontoolarge">**regionTooLarge**</span><br><code>boolean</code> |  | [RegionTooLargeMixin](../regiontoolargemixin#getter-regiontoolarge) |
| <span id="getter-regiontoolargereason">**regionTooLargeReason**</span><br><code>string</code> | <span data-pagefind-ignore>Banner text for the axis that tripped; empty when not too large.</span> | [RegionTooLargeMixin](../regiontoolargemixin#getter-regiontoolargereason) |
| <span id="getter-zoomcanreleasegate">**zoomCanReleaseGate**</span><br><code>boolean</code> | <span data-pagefind-ignore>Whether "zoom in to see features" is honest advice. Density always releases on zoom; bytes only if the last zoom-in moved the estimate.</span> | [RegionTooLargeMixin](../regiontoolargemixin#getter-zoomcanreleasegate) |
| <span id="getter-gateskipsmeasuredviewport">**gateSkipsMeasuredViewport**</span><br><code>boolean</code> | <span data-pagefind-ignore>The skip both fetch skeletons apply: the banner is up and its measurement already describes the viewport on screen.</span> | [RegionTooLargeMixin](../regiontoolargemixin#getter-gateskipsmeasuredviewport) |
| <span id="getter-renderscanvas">**rendersCanvas**</span><br><code>boolean</code> | <span data-pagefind-ignore>Overridable hook (default true): whether this display paints a canvas in its **current** configuration, as opposed to a deliberate static placeholder (LD with the triangle off, sequence past base resolution — both render a message where the `<canvas>` would go, so `canvasRef` is never called and `canvasDrawn` can never flip).<br><br>Lives here, beside `canvasDrawn`, because every consumer of "has this display painted" needs the pair — and until 2026-08 each family declared its own copy (per-region hard-coded `true`, global carried the hook for LD), so a display could express the state only to whichever family it happened to compose. See `painted` below for the reader that was missed.</span> | [RenderLifecycleMixin](../renderlifecyclemixin#getter-renderscanvas) |
| <span id="getter-painted">**painted**</span><br><code>boolean</code> | <span data-pagefind-ignore>**The first-paint answer every consumer outside the display should read**, `canvasDrawn` being only the raw flag: a display that is deliberately not painting a canvas has finished, and saying otherwise is a lie that never resolves.<br><br>The two `rendersCanvas: false` states each had three of their four consumers wired by hand — the loading scrim (`rendersCanvas` / `fetchInert`) and the SVG export (`fetchInert`) — while the fourth, `data-display-drawn`, went on publishing `"false"` forever off the raw flag. That attribute is what `PENDING_DISPLAYS` (`@jbrowse/browser-test-utils`) selects on, so a zoomed-out reference sequence track made every `waitForDisplaysDone` on the page burn its full timeout — silently, since that wait swallows its own. Same shape as `fetchInert` on the comparative side: the reader you forget is the one outside the display, so the display has to publish one name for it.<br><br>`paintInert` is the third term and the same argument once more, for the state where a display *would* paint a canvas and never gets to — a fetch that failed before first paint. See that hook.</span> | [RenderLifecycleMixin](../renderlifecyclemixin#getter-painted) |
| <span id="getter-isloading">**isLoading**</span><br><code>boolean</code> | <span data-pagefind-ignore>true while a fetch is active</span> | [FetchMixin](../fetchmixin#getter-isloading) |
| <span id="getter-isloadingorcanceled">**isLoadingOrCanceled**</span><br><code>boolean</code> | <span data-pagefind-ignore>`isLoading` widened to cover a user-canceled load. **This, not `isLoading`, is what a `displayPhase` loading term wants.** `cancelFetchByUser` clears the stop token synchronously, so `isLoading` goes false the instant the user clicks Cancel — and the loading overlay that unmounts on it is carrying the Retry button, which is the only way back: the state is deliberately durable, so no autorun restarts the fetch on its own. A bare `isLoading` therefore reads as `ready` over a display that is stopped, empty and offering nothing.<br><br>Arc read `isLoading` directly and had exactly that hole. It is a getter here so no family has to remember the second term.</span> | [FetchMixin](../fetchmixin#getter-isloadingorcanceled) |
| <span id="getter-fetchinert">**fetchInert**</span><br><code>boolean</code> | <span data-pagefind-ignore>Overridable hook (default false): the states where this display deliberately never fetches, so it holds no data and none is coming. Sequence sets it past base resolution ("Zoom in to see sequence"); LD sets it with the triangle toggled off.<br><br>**One hook, three readers**, and that is the whole point — a display that grows such a state has one thing to say rather than three, and the reader it would have forgotten is always the one outside itself:<br><br>- the loading scrim (`computeLoadingTerm`), which otherwise parks over the placeholder, permanently once a cancel has been clicked; - the SVG export (`computeSvgReady`'s `extraTerminal`), whose `awaitSvgReady` is an unbounded `when`, so one such display hangs the whole view's export; - the dev-only retry check (`makeRetryContractCheck`), which would otherwise report a dead Retry on a display correctly declining to load anything.<br><br>It was three hooks — `loadingSuppressed`, `svgReadyExtraTerminal` on each of the two foundations, and `fetchInert` on the comparative family, which had already collapsed them. Both LGV displays that override it returned one expression for all three, and one of the three was hard-coded `false` on the global family for a while, which is how LD came to be able to express only half its own state. Same name and same meaning as `SyntenyFetchStateMixin.fetchInert` now, so the retry check reads one field across all three fetch families. ADR-082.<br><br>A hook rather than a `displayPhase` override, because overriding the getter means restating the whole loading condition — which is how sequence came to hold a verbatim copy of the other terms, one `git blame` away from silently missing the next one added.<br><br>It lives **here** because this is the one mixin all three display foundations compose. Same argument, one level down, that put `rendersCanvas` on `RenderLifecycleMixin` beside `canvasDrawn`.</span> | [FetchMixin](../fetchmixin#getter-fetchinert) |
| <span id="getter-awaitingprerequisite">**awaitingPrerequisite**</span><br><code>boolean</code> | <span data-pagefind-ignore>Overridable hook (default false), read only by the dev-only retry check (`makeRetryContractCheck`): "this run declined because a prerequisite fetch in another autorun has not landed, and its arrival wakes this one again". It **defers** the retry verdict to that later run rather than waiving it, so a display cannot spend its retry on a decline it called preliminary.<br><br>Two displays say it, one per fetch foundation, which is why it lives beside `fetchInert` rather than on either: HiC's contacts fetch declines until `CoreGetInfo` lands, and `MultiSampleVariantBaseModel`'s `fetchNeeded` declines until `sourcesBase` does. Both have a `reload()` that wakes the prerequisite's autorun as well as their own.<br><br>**It has to be strictly narrower than the gate it explains.** One that restates the gate's negation makes every decline a deferred one, so no run is ever judged and the display has silently opted out — an exemption by another name. HiC is in that shape deliberately, because its gate and its prerequisite are one condition; what covers its retry instead is `LinearHicDisplay/infoFetchFailure.test.ts`.<br><br>Not for a display deliberately not fetching at all — that is `fetchInert` above, which the loading scrim and the export read too.</span> | [FetchMixin](../fetchmixin#getter-awaitingprerequisite) |
| <span id="getter-rpcpropscachekey">**rpcPropsCacheKey**</span><br><code>string</code> | <span data-pagefind-ignore>The RPC cache key both fetch foundations invalidate on: this display's `rpcProps()` payload serialized to a string. `serializeRpcProps` owns the why, including the silently-dead-axis corollary.<br><br>Here, beside the two hooks above, for the same reason they are: it describes the display, and every foundation composes this mixin. The per-region family watches it from `SettingsInvalidate` and the global one from its fetch autorun's trigger list — one getter and one name, so the two cannot come to invalidate on different axes. The global side built its own local `computed` over the same function until 2026-08, which was the same value under a second spelling.</span> | [FetchMixin](../fetchmixin#getter-rpcpropscachekey) |
| <span id="getter-rowheight">**rowHeight**</span><br><code>number</code> | <span data-pagefind-ignore>Raw per-row height setting: `0` is fit-to-display-height, any positive value is a fixed px height. The resolved value is `effectiveRowHeight` — consumers read that, never this. On the config rather than the display snapshot for the same reason `height` is: the config node outlives the display instance, so a fixed height survives unticking and reticking the track.</span> | [RowHeightMixin](../rowheightmixin#getter-rowheight) |
| <span id="getter-effectiverowheight">**effectiveRowHeight**</span><br><code>number</code> | <span data-pagefind-ignore>Resolved per-row height. `rowHeight === 0` divides the display's own `autoRowHeight` across the rows; any positive value is the fixed px height, used as-is however many rows there are.<br><br>Sub-pixel is legitimate and deliberately not floored here — a cohort with more rows than the track has pixels has a genuinely fractional row height, and flooring it makes the content taller than the height it was asked to fit inside. `resolveRowHeight` floors only a **non-positive** result, which consumers divide by.</span> | [RowHeightMixin](../rowheightmixin#getter-effectiverowheight) |
| <span id="getter-showtree">**showTree**</span><br><code>boolean</code> | <span data-pagefind-ignore>Whether the dendrogram sidebar is drawn.</span> | [TreeSidebarMixin](../treesidebarmixin#getter-showtree) |
| <span id="getter-showbranchlength">**showBranchLength**</span><br><code>boolean</code> | <span data-pagefind-ignore>Whether tree nodes are positioned by branch length (dendrogram) or evenly by topology (cladogram).</span> | [TreeSidebarMixin](../treesidebarmixin#getter-showbranchlength) |
| <span id="getter-showrowlabels">**showRowLabels**</span><br><code>boolean</code> | <span data-pagefind-ignore>Whether each row's name is drawn over the left of the plot.</span> | [TreeSidebarMixin](../treesidebarmixin#getter-showrowlabels) |
| <span id="getter-parsedtree">**parsedTree**</span><br><code>HierarchyNode&lt;NewickNode&gt; &#124; undefined</code> |  | [TreeSidebarMixin](../treesidebarmixin#getter-parsedtree) |
| <span id="getter-root">**root**</span><br><code>HierarchyNode&lt;NewickNode&gt; &#124; undefined</code> |  | [TreeSidebarMixin](../treesidebarmixin#getter-root) |
| <span id="getter-treehasbranchlengths">**treeHasBranchLengths**</span><br><code>boolean</code> |  | [TreeSidebarMixin](../treesidebarmixin#getter-treehasbranchlengths) |
| <span id="getter-roworderiscustom">**rowOrderIsCustom**</span><br><code>boolean</code> | <span data-pagefind-ignore>Whether the rows have been arranged away from the order they arrived in — what "Reset row order" is offered on. A written `layout` here; a display whose config seeds `layout` on load (the multi-sample variant displays' `colorBy` / `groupBy`) overrides it to compare against that seed, so the reset does not appear on a track nobody has touched.</span> | [TreeSidebarMixin](../treesidebarmixin#getter-roworderiscustom) |

## Methods

<!-- prettier-ignore -->
| Member | Description | Defined by |
| --- | --- | --- |
| <span id="method-contextmenuitems">**contextMenuItems**</span><br><code>() =&gt; MenuItem[]</code> | Items for the right-click menu, built from the column the click landed on. The position is captured when the menu opens rather than read inside the onClick, because `closeContextMenu` runs first when an item is clicked. | LinearMafDisplay |
| <span id="method-rowgeometry">**rowGeometry**</span><br><code>() =&gt; MafRowGeometryParams</code> | Where the rows sit on screen: the resolved row height, plus the scroll offset and viewport that every rows layer places and culls against. One source for all of them — a layer spelling out its own geometry could quietly read the raw `rowHeight` sentinel, or forget the scroll and hang its markers a scroll-distance below the cells they annotate. | LinearMafDisplay |
| <span id="method-gpuprops">**gpuProps**</span><br><code>() =&gt; MafGpuProps</code> | Inputs to the main-thread GPU instance encoder. Changes here re-encode in the per-region encode autorun — no RPC roundtrip. Intentionally excludes `showAsUpperCase` (label-only) and view-shape props (rowHeight, rowProportion — driven by shader uniforms). | LinearMafDisplay |
| <span id="method-rpcprops">**rpcProps**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>() =&gt; { subtreeFilter: string[] &#124; undefined; annotationDataActi…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>() =&gt; { subtreeFilter: string[] &#124; undefined; annotationDataActive: boolean; }</code></pre></dialog></span> | Worker-fetch inputs that invalidate cached data when changed (tier-1, via MultiRegionDisplayMixin's `SettingsInvalidate` autorun → refetch).<br><br>Row *order* is deliberately absent: no fetch argument depends on it any more, since the worker names rows by species and the main thread places them (`placeMafRegionData`). A reorder therefore re-places the cached payload — the heaviest in the plugin — instead of refetching it.<br><br>`subtreeFilter` stays because it is a fetch argument, and the *set* is the only thing about the rows that is: the worker ships only the rows in it and scopes coverage/identity to them. It is sent as a set, never an order, so reordering inside a filter is still free.<br><br>The discovered row set growing is deliberately NOT a key — see `setSamples` for why re-placement covers it.<br><br>Nothing here may be fetch-derived. Keying on a value that is undefined until the first fetch lands and defined after flips the key on every track load, and `SettingsInvalidate` then throws away the region that just arrived — a measured 2 × `LinearMafGetAlignmentData` per region. Loop-safe but not free, which is exactly the case ARCHITECTURE.md's "`rpcProps()` loop trap and how to break it" is about. Pinned by `singleFetchPerRegion.test.ts`. | LinearMafDisplay |
| <span id="method-rowhoverinfo">**rowHoverInfo**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(displayedRegionIndex: number, bp: HoverBp, rowIndex: number, b…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(displayedRegionIndex: number, bp: HoverBp, rowIndex: number, bpPerPx: number) =&gt; {…} &#124; { ...; } &#124; { ...; } &#124; { ...; } &#124; undefined</code></pre></dialog></span> | Resolve a hover hit on `rowIndex` at the cursor's genomic position (absolute uint32, per worker-output convention): an aligned base (`cell`) or a bridged/empty region (`empty`), each tagged with the sample label. Returns undefined when no fetched block covers the bp, the row is out of range, or the cell is a gap.<br><br>`bp` carries both readings of the cursor (see `HoverBp`) because the cell and the interbase insertion marker are selected by different ones, and they differ on a reversed region. | LinearMafDisplay |
| <span id="method-rownavigationtarget">**rowNavigationTarget**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(displayedRegionIndex: number, startBp: number, endBp: number,…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(displayedRegionIndex: number, startBp: number, endBp: number, rowIndex: number) =&gt; {…} &#124; undefined</code></pre></dialog></span> | Where `rowIndex` sits in its own genome across the reference bp range `[startBp, endBp)` — the locus a "open this species here" navigation targets. Undefined when the row has no aligned base in the range, when no fetched block covers it, or when the row's genome isn't loaded as an assembly (`Sample.assemblyName` unset), since there is then nowhere to navigate to. | LinearMafDisplay |
| <span id="method-framehoverinfo">**frameHoverInfo**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(displayedRegionIndex: number, bp: number, rowIndex: number) =&gt;…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(displayedRegionIndex: number, bp: number, rowIndex: number) =&gt; { name: string; } &#124; undefined</code></pre></dialog></span> | The CDS frame record covering absolute genomic `bp` (uint32) on display `rowIndex`, or undefined when no frame overlaps there (or no frames data is loaded). Gated on `annotationDataActive` not the strip toggle, so the gene name still reads on hover in codon view with the strip off. The species is matched by the same `src`→row projection the overlay draws with, so the tooltip and the strip can't disagree about which row a gene is on.<br><br>`bp` is a base index — the caller passes `MafPointer.baseBp`, not a floored `gposFrac`, so this names the same base the row hover and the coverage tooltip do on a reversed region. | LinearMafDisplay |
| <span id="method-coveragetooltipbin">**coverageTooltipBin**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(displayedRegionIndex: number, position: number, bpPerPx: numbe…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(displayedRegionIndex: number, position: number, bpPerPx: number, reversed?: boolean) =&gt; {…} &#124; undefined</code></pre></dialog></span> | Build a per-position coverage tooltip bin (depth + SNP base counts) for the given absolute genomic bp + region index. Delegates the math to alignments-core's `buildCoverageTooltipBin` — same code path the alignments display uses. Insertions are reported separately via `coverageInsertionHit`, so they never mix into the depth/SNP table. Returns undefined when the region has no fetched data or depth is zero.<br><br>`reversed` is the region's orientation, and the SNP snap below needs it for the reason alignments' `hitTestCoverage` does: the snap widens `position` into the bp the CURSOR'S PIXEL covers, and which side of `position` those bp lie on is what the orientation decides. `position` itself already comes through `basePaintedAt`, so it is the right base either way — widening rightward regardless searched the neighbouring pixel's bp on a flipped region, and reported a SNP the cursor was not over. | LinearMafDisplay |
| <span id="method-coverageinsertionhit">**coverageInsertionHit**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(displayedRegionIndex: number, gposFrac: number, bpPerPx: numbe…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(displayedRegionIndex: number, gposFrac: number, bpPerPx: number) =&gt; CoverageInsertionHit &#124; undefined</code></pre></dialog></span> | Hit-test an insertion bar in the coverage band at fractional genomic `gposFrac`. Returns the interbase summary (count + length range + interbaseDepth) when the cursor is on the bar, else undefined — drives the dedicated interbase tooltip, kept separate from the depth/SNP one. | LinearMafDisplay |
| <span id="method-codonhoverinfo">**codonHoverInfo**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(displayedRegionIndex: number, bp: number, rowIndex: number) =&gt;…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(displayedRegionIndex: number, bp: number, rowIndex: number) =&gt; CodonHit &#124; undefined</code></pre></dialog></span> | The codon under the cursor on display `rowIndex` at absolute genomic `bp`, when the codon view is the active rendering: the species' codon + amino acid, the reference codon + amino acid, and the syn/nonsyn/stop classification. Reads the memoized `locatedCodons` the colored cells are drawn from, so the tooltip and the cell can't disagree and a mousemove costs a scan rather than a fresh codon resolution pass. Undefined off codon view or where no codon covers the row there. | LinearMafDisplay |
| <span id="method-trackmenuitems">**trackMenuItems**</span><br><code>() =&gt; MenuItem[]</code> |  | LinearMafDisplay |
| <span id="method-regionhasdata">**regionHasData**</span><br><code>(displayedRegionIndex: number) =&gt; boolean</code> | Whether the tier the current zoom needs holds this region: crossing the summary↔detail threshold inside an already-loaded region wouldn't trip the bounds-based coverage check, so the answer is which map has it.<br><br>The presence hook rather than `regionFetchKey`, which stays empty, because the two tiers cache side by side: the detail fetch keeps the summary records (`clearAlignmentData` runs one way only), and a summary/detail key would refetch the summary on every zoom back out. | LinearMafDisplay |
| <span id="method-renderingprops">**renderingProps**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>() =&gt; { displayModel: ModelInstanceTypeProps&lt;{ id: IOptionalITy…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>() =&gt; { displayModel: ModelInstanceTypeProps&lt;{ id: IOptionalIType&lt;…&gt;; type: ISimpleType&lt;string&gt;; }&gt; &amp; { ...; } &amp; { ...; } &amp; { ...; } &amp; IStateTreeNode&lt;...&gt;; }</code></pre></dialog></span> | <span data-pagefind-ignore>props passed to the renderer's React "Rendering" component. these are client-side only and never sent to the worker. includes displayModel and callbacks</span> | [BaseDisplay](../basedisplay#method-renderingprops) |
| <span id="method-iscachevalid">**isCacheValid**</span><br><code>(displayedRegionIndex: number) =&gt; boolean</code> | <span data-pagefind-ignore>Whether the data held for a region still answers the current view. Not a hook a display fills: a display states its rule as `regionFetchKey` (what a fetch now would produce) and `regionHasData` (did the last one store anything), and this compares the key against the one the region was fetched under. A subclass that changes what it fetches spells the change in the key, and one that forgets gets a redundant fetch rather than a cached answer for a zoom the data was never fetched at.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#method-iscachevalid) |
| <span id="method-resolvedbytelimit">**resolvedByteLimit**</span><br><code>() =&gt; number &#124; undefined</code> | <span data-pagefind-ignore>The budget the worker enforces and the banner compares against — the one spelling of that pair. Undefined when the gate may not act.</span> | [RegionTooLargeMixin](../regiontoolargemixin#method-resolvedbytelimit) |
| <span id="method-gatefetchstate">**gateFetchState**</span><br><code>() =&gt; GateFetchState</code> | <span data-pagefind-ignore>The gate as it stands for a fetch about to be issued. Calling it is the capture, which is why it is a method.</span> | [RegionTooLargeMixin](../regiontoolargemixin#method-gatefetchstate) |
| <span id="method-willcleartree">**willClearTree**</span><br><code>(next: S[]) =&gt; boolean</code> |  | [TreeSidebarMixin](../treesidebarmixin#method-willcleartree) |

## Actions

<!-- prettier-ignore -->
| Member | Description | Defined by |
| --- | --- | --- |
| <span id="action-setrowproportion">**setRowProportion**</span><br><code>(n: number) =&gt; void</code> |  | LinearMafDisplay |
| <span id="action-setshowallletters">**setShowAllLetters**</span><br><code>(f: boolean) =&gt; void</code> |  | LinearMafDisplay |
| <span id="action-setmismatchrendering">**setMismatchRendering**</span><br><code>(f: boolean) =&gt; void</code> |  | LinearMafDisplay |
| <span id="action-setsamples">**setSamples**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>({ samples, treeNewick, samplesCanonical, }: { samples: Sample[…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>({ samples, treeNewick, samplesCanonical, }: { samples: Sample[]; treeNewick: string &#124; undefined; samplesCanonical: boolean; }) =&gt; void</code></pre></dialog></span> | Receive the worker's `samples` + serialized Newick tree.<br><br>`samplesCanonical` says whether that set is authoritative. Config- and tree-derived sets are: they're complete and identical on every region fetch, so they replace, and a species dropped from the config stops being a row. A sample-discovery set is not: it names only the genomes the fetched region's blocks contained, so it is unioned into the rows already known (`unionSources`). Replacing there dropped rows: a genome only one region aligns would stop having a row the moment another region reported its own set, and a region with no blocks at all (or the summary path, which never discovers) names none and so blanked every row.<br><br>With either resolution the deepEqual guard makes this fire once and skips the redundant frozen-array reassignment (and downstream `sources`/instance-buffer recompute) on later scroll/zoom. The active `clusterTree` is set from the worker tree only when there's no custom arrangement — a reorder has cleared it and must keep it cleared until the user clears the layout.<br><br>The guard covers the sample set only: a tree can change while the set doesn't (an edited `.nh`), and folding it in left `treeNewickVolatile` — and so what "Clear arrangement" restores — pinned to the first tree the session ever saw.<br><br>A set that *changes* after one was already established invalidates nothing: the fetched rows name their species rather than a row index, so the placement autorun re-places them against the widened order and they are correct again without a refetch. This used to bump a `sampleSetGeneration` counter into `rpcProps()`, from a design where the worker narrowed each region's blocks to the client's sample list and so genuinely lost rows it had not been told about. It no longer takes one — the row set is config-derived or discovered per region in the worker, and the only thing the client sends is `subtreeFilter` — so the counter had become a pure refetch of every loaded region, once per newly seen genome, on exactly the discovery tracks that can least afford it. | LinearMafDisplay |
| <span id="action-setshowasuppercase">**setShowAsUpperCase**</span><br><code>(arg: boolean) =&gt; void</code> |  | LinearMafDisplay |
| <span id="action-setshowcoverage">**setShowCoverage**</span><br><code>(arg: boolean) =&gt; void</code> |  | LinearMafDisplay |
| <span id="action-setshowalignments">**setShowAlignments**</span><br><code>(arg: boolean) =&gt; void</code> |  | LinearMafDisplay |
| <span id="action-setcoverageheight">**setCoverageHeight**</span><br><code>(arg: number) =&gt; void</code> |  | LinearMafDisplay |
| <span id="action-setshowconservation">**setShowConservation**</span><br><code>(arg: boolean) =&gt; void</code> |  | LinearMafDisplay |
| <span id="action-setconservationmode">**setConservationMode**</span><br><code>(arg: "base" &#124; "codon") =&gt; void</code> |  | LinearMafDisplay |
| <span id="action-setrowidentitymode">**setRowIdentityMode**</span><br><code>(arg: "heatmap" &#124; "none" &#124; "xyplot") =&gt; void</code> |  | LinearMafDisplay |
| <span id="action-setrowidentityautozoom">**setRowIdentityAutoZoom**</span><br><code>(arg: boolean) =&gt; void</code> |  | LinearMafDisplay |
| <span id="action-setshowannotations">**setShowAnnotations**</span><br><code>(arg: boolean) =&gt; void</code> |  | LinearMafDisplay |
| <span id="action-setshowtranslation">**setShowTranslation**</span><br><code>(arg: boolean) =&gt; void</code> |  | LinearMafDisplay |
| <span id="action-setcolorbychromosome">**setColorByChromosome**</span><br><code>(arg: boolean) =&gt; void</code> |  | LinearMafDisplay |
| <span id="action-setshowinversions">**setShowInversions**</span><br><code>(arg: boolean) =&gt; void</code> |  | LinearMafDisplay |
| <span id="action-setconservationheight">**setConservationHeight**</span><br><code>(arg: number) =&gt; void</code> |  | LinearMafDisplay |
| <span id="action-clearlayout">**clearLayout**</span><br><code>() =&gt; void</code> | Drop the custom arrangement and restore the worker's guide tree (the base `clearLayout` only clears it — the worker tree lives in `treeNewickVolatile`). | LinearMafDisplay |
| <span id="action-setfittoheight">**setFitToHeight**</span><br><code>() =&gt; void</code> | Switch to fit-to-height mode: rows stretch to fill the track height. Seeds the `height` config slot from the current content height so toggling on doesn't jump, then `rowHeight = 0` makes `effectiveRowHeight` derive from it. | LinearMafDisplay |
| <span id="action-resizeheight">**resizeHeight**</span><br><code>(distance: number) =&gt; number</code> | Drag-resize the track. In fit-to-height mode the new height flows straight into `autoRowHeight`, so the rows stretch with the drag. With a fixed `rowHeight` the rows keep the size the user chose and the drag reveals more of them — the fixed height used to be scaled by the same ratio, which kept content and viewport locked together and made dragging a track taller unable to show a single extra species.<br><br>The `resizing` flag that sits the letter overlay out of the drag is set on the track by the handle itself (TrackContainer / `MafBandResizeHandle`), not here — this action sees only individual deltas and can't tell the last one from the next, which is why it used to need a settle timer. | LinearMafDisplay |
| <span id="action-resizecoverageheight">**resizeCoverageHeight**</span><br><code>(distance: number) =&gt; void</code> | Apply one drag delta to the coverage band. Reads the current height inside the action rather than taking an absolute target: `ResizeHandle` emits one delta per animation frame, so a component computing `renderHeight + delta` drops every tick that lands before React re-renders. Mirrors `resizeHeight`.<br><br>Sits here rather than with its `setCoverageHeight` twin because the ceiling comes off `fitTargetHeight`, which is declared above this block. | LinearMafDisplay |
| <span id="action-resizeconservationheight">**resizeConservationHeight**</span><br><code>(distance: number) =&gt; void</code> | Per-frame drag delta for the conservation band — see `resizeCoverageHeight` for why this reads the height itself. | LinearMafDisplay |
| <span id="action-sortrowsbybaseat">**sortRowsByBaseAt**</span><br><code>(refName: string, pos: number) =&gt; void</code> | Reorder the rows by the base each species carries in the reference column at (refName, pos) — the MAF analogue of the multi-row painting's "sort rows by color here". Reads the placed region data already in hand, no refetch, and writes the order through `layout`, the channel clustering and the arrangement dialog write, so "Reset row order" undoes all three.<br><br>Declines with fewer than two rows, and at a column no loaded region covers, for the reasons the other two displays' twins state: the empty write is not a no-op (`setLayout` drops the tree — here the guide phylogeny — whenever the row set changes), and every row reading "no base" writes back the order it already had. | LinearMafDisplay |
| <span id="action-setrowrendering">**setRowRendering**</span><br><code>(rendering: RowRendering) =&gt; void</code> | Pick the row coloring, writing all three slots so exactly one is on.<br><br>The exclusivity has to be written, not just displayed: the slots are independent booleans, `activeRowRendering` resolves a clash by precedence, and the menu used to offer them as separate checkboxes — so turning on color-by-chromosome while an identity plot was selected left a setting that was on, persisted into the session, and painting nothing. Selecting through here is what makes the tick the truth.<br><br>A session saved before this (or hand-written config) can still carry two of them; nothing migrates, `selectedRowRendering` just reports the one that wins, and the next pick clears the rest. | LinearMafDisplay |
| <span id="action-setrpcdata">**setRpcData**</span><br><code>(regionIndex: number, data: MafWireRegionData) =&gt; void</code> |  | LinearMafDisplay |
| <span id="action-placefetchedrows">**placeFetchedRows**</span><br><code>(rowIndexBySrc: Map&lt;string, number&gt;) =&gt; void</code> | Re-place every cached region against the row order now on screen. Driven by the autorun below, so a reorder repaints from data already in hand — the fetched rows name their species, so nothing about them is order-specific. Replacing the region objects is what re-runs the per-region encode. | LinearMafDisplay |
| <span id="action-setsummarydata">**setSummaryData**</span><br><code>(regionIndex: number, records: MafSummaryRecord[]) =&gt; void</code> |  | LinearMafDisplay |
| <span id="action-setframesdata">**setFramesData**</span><br><code>(regionIndex: number, records: MafFrameRecord[]) =&gt; void</code> |  | LinearMafDisplay |
| <span id="action-setframesgateblocked">**setFramesGateBlocked**</span><br><code>(blocked: boolean) =&gt; void</code> | Record whether the last frames read was declined as over budget. Set both ways by every fetch pass that reaches the annotation adapter, so zooming back in clears it without anything else having to. | LinearMafDisplay |
| <span id="action-clearalignmentdata">**clearAlignmentData**</span><br><code>() =&gt; void</code> |  | LinearMafDisplay |
| <span id="action-cleardisplayspecificdata">**clearDisplaySpecificData**</span><br><code>() =&gt; void</code> |  | LinearMafDisplay |
| <span id="action-startrenderingbackend">**startRenderingBackend**</span><br><code>(backend: MafRenderingBackend) =&gt; void</code> |  | LinearMafDisplay |
| <span id="action-fetchneeded">**fetchNeeded**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(needed: { region: Region; displayedRegionIndex: number; }[]) =…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(needed: { region: Region; displayedRegionIndex: number; }[]) =&gt; Promise&lt;void&gt;</code></pre></dialog></span> |  | LinearMafDisplay |
| <span id="action-rendersvg">**renderSvg**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(opts: ExportSvgDisplayOptions) =&gt; Promise&lt;ReactElement&lt;unknown…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(opts: ExportSvgDisplayOptions) =&gt; Promise&lt;ReactElement&lt;unknown, string &#124; JSXElementConstructor&lt;any&gt;&gt; &#124; Iterable&lt;ReactNode&gt; &#124; AwaitedReactNode&gt;</code></pre></dialog></span> | Dynamic import so the export path — and everything it pulls in — stays out of the bundle until someone actually exports. | LinearMafDisplay |
| <span id="action-setstatusmessage">**setStatusMessage**</span><br><code>(status?: RpcStatus &#124; undefined) =&gt; void</code> |  | [BaseDisplay](../basedisplay#action-setstatusmessage) |
| <span id="action-seterror">**setError**</span><br><code>(error?: unknown) =&gt; void</code> |  | [BaseDisplay](../basedisplay#action-seterror) |
| <span id="action-clearhoveredfeature">**clearHoveredFeature**</span><br><code>() =&gt; void</code> | <span data-pagefind-ignore>Overridable hook (default no-op): drop whatever `hoveredFeature` reports. The writing twin of that getter, and what `installClearHoverOnViewportChange` calls.<br><br>A display that STORES its hover owes an override; one that derives it from the live pointer (MAF, Hi-C, LD) owes nothing, and the default costs it nothing. Declared here so the clear can be installed for every display rather than remembered per display — forgetting it is the failure ARCHITECTURE.md's stored-hover section is about, and it used to be six closures at six call sites, which is six chances to omit one.</span> | [BaseDisplay](../basedisplay#action-clearhoveredfeature) |
| <span id="action-reload">**reload**</span><br><code>() =&gt; void</code> | <span data-pagefind-ignore>base display reload does nothing, see specialized displays for details</span> | [BaseDisplay](../basedisplay#action-reload) |
| <span id="action-setscrolltop">**setScrollTop**</span><br><code>(scrollTop: number) =&gt; void</code> | <span data-pagefind-ignore>Clamped into `[0, scrollableHeight]`, so no caller has to remember the bound. Unbounded for a display that leaves `scrollableHeight` at its `Infinity` default.</span> | [TrackHeightMixin](../trackheightmixin#action-setscrolltop) |
| <span id="action-setheight">**setHeight**</span><br><code>(displayHeight: number) =&gt; number</code> |  | [TrackHeightMixin](../trackheightmixin#action-setheight) |
| <span id="action-expandtocontentheight">**expandToContentHeight**</span><br><code>() =&gt; number</code> | <span data-pagefind-ignore>Grow the track by exactly the content it is currently hiding, so a display scrolled over a taller stack ends up showing all of it. The track's resize handle runs this on a double click.<br><br>`scrollableHeight` is the whole measurement — it is already every scrolling display's answer to "how much is off the bottom", so no display has to supply a second one. A display that doesn't scroll internally leaves it at `Infinity` and gets a no-op, as does one already showing everything (0).<br><br>Routed through `resizeHeight` rather than `setHeight` so grow mode's override still gets to leave grow first; going straight to the slot would let the reactive height re-derive `grownHeight` and the double click would appear to do nothing.</span> | [TrackHeightMixin](../trackheightmixin#action-expandtocontentheight) |
| <span id="action-setloadedregion">**setLoadedRegion**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(displayedRegionIndex: number, region: Region, fetchKey?: strin…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(displayedRegionIndex: number, region: Region, fetchKey?: string) =&gt; void</code></pre></dialog></span> | <span data-pagefind-ignore>The raw write behind `ctx.commitRegion`, and **not what a fetch should call**: a display naming its own span is the bug this family spent a release on, and going through the context is what makes that inexpressible — see RegionFetchContext. Direct callers are tests staging an already-loaded display.<br><br>An action so callers after an async boundary stay in MST strict mode. Stamps the region with the fetch key its data came back under. `fetchRegions` passes the key it captured before issuing the RPC; the default reads it *now*, which is right for a caller holding the region already and wrong for anything resuming after an await, where the viewport may have moved under the fetch.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#action-setloadedregion) |
| <span id="action-droploadedregion">**dropLoadedRegion**</span><br><code>(displayedRegionIndex: number) =&gt; void</code> | <span data-pagefind-ignore>Forget one region — for a display pruning what has scrolled off screen.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#action-droploadedregion) |
| <span id="action-clearallrpcdata">**clearAllRpcData**</span><br><code>() =&gt; void</code> | <span data-pagefind-ignore>full reset: cancels fetch, clears error, loadedRegions, display-specific data, and the canvas-drawn flag. The too-large gate is derived (a pure function of the cached estimate × viewport), so it needs no explicit clear here — the fetch autorun re-measures at the new viewport and the verdict follows.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#action-clearallrpcdata) |
| <span id="action-fetchregions">**fetchRegions**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(needed: IndexedRegion[], work: (ctx: RegionFetchContext) =&gt; Pr…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(needed: IndexedRegion[], work: (ctx: RegionFetchContext) =&gt; Promise&lt;void&gt;) =&gt; Promise&lt;void&gt;</code></pre></dialog></span> | <span data-pagefind-ignore>Run a per-region fetch. The work callback calls `ctx.commitRegion` as it stores each region's payload, which is what marks it loaded — see RegionFetchContext for why this function no longer does that itself. Its only callers are the three helpers in `fetchEachRegion.ts`, which make that call for every display in the family; a display reaching past them owns both `ctx.isStale()` guards and the commit by hand, and none does.<br><br>The fetch key is captured here, at issue, and carried into every commit — never re-read after the await. `ctx.isStale()` trips on a newer fetch or a cancel, not on a viewport that moved under a fetch that is still current, so a key read at commit time would stamp this data with a zoom it was not fetched at.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#action-fetchregions) |
| <span id="action-afterattach">**afterAttach**</span><br><code>() =&gt; void</code> | <span data-pagefind-ignore>installs the fetch-lifecycle autoruns (DisplayedRegionsChange, FetchVisibleRegions, SettingsInvalidate, ClearBlockingStateOnViewportChange)</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#action-afterattach) |
| <span id="action-setbyteestimate">**setByteEstimate**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(measurement: { bytes: number; viewport: GateViewport; }) =&gt; vo…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(measurement: { bytes: number; viewport: GateViewport; }) =&gt; void</code></pre></dialog></span> | <span data-pagefind-ignore>The bytes half of a measurement alone, for a test staging a display. Production commits through `commitFetchBytes`.</span> | [RegionTooLargeMixin](../regiontoolargemixin#action-setbyteestimate) |
| <span id="action-clearbyteestimate">**clearByteEstimate**</span><br><code>() =&gt; void</code> | <span data-pagefind-ignore>Drops the estimate and the viewport stamp. `forceLoadTrack` survives: it is a track-wide approval.</span> | [RegionTooLargeMixin](../regiontoolargemixin#action-clearbyteestimate) |
| <span id="action-setforceloadtrack">**setForceLoadTrack**</span><br><code>(flag: boolean) =&gt; void</code> |  | [RegionTooLargeMixin](../regiontoolargemixin#action-setforceloadtrack) |
| <span id="action-commitfetchbytes">**commitFetchBytes**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(perRegionBytes: (number &#124; undefined)[], issued: GateFetchState…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(perRegionBytes: (number &#124; undefined)[], issued: GateFetchState) =&gt; void</code></pre></dialog></span> | <span data-pagefind-ignore>The byte axis of a finished fetch, called by the fetch runners with the `gateFetchState()` they captured at issue. Commits the per-region max; an empty batch, or an ungated display, commits nothing.</span> | [RegionTooLargeMixin](../regiontoolargemixin#action-commitfetchbytes) |
| <span id="action-forceload">**forceLoad**</span><br><code>() =&gt; void</code> | <span data-pagefind-ignore>The banner's button: exempt the track on both axes and refetch.</span> | [RegionTooLargeMixin](../regiontoolargemixin#action-forceload) |
| <span id="action-markcanvasdrawn">**markCanvasDrawn**</span><br><code>() =&gt; void</code> |  | [RenderLifecycleMixin](../renderlifecyclemixin#action-markcanvasdrawn) |
| <span id="action-resetcanvasdrawn">**resetCanvasDrawn**</span><br><code>() =&gt; void</code> |  | [RenderLifecycleMixin](../renderlifecyclemixin#action-resetcanvasdrawn) |
| <span id="action-stoprenderingbackend">**stopRenderingBackend**</span><br><code>() =&gt; void</code> |  | [RenderLifecycleMixin](../renderlifecyclemixin#action-stoprenderingbackend) |
| <span id="action-rendernow">**renderNow**</span><br><code>() =&gt; void</code> |  | [RenderLifecycleMixin](../renderlifecyclemixin#action-rendernow) |
| <span id="action-setrendererror">**setRenderError**</span><br><code>(error: unknown) =&gt; void</code> | <span data-pagefind-ignore>set/clear the render-backend error. Called by `useRenderingBackend`: with the error when the canvas factory rejects (or context-loss re-init fails), and with `undefined` on successful (re)init and on retry.</span> | [RenderLifecycleMixin](../renderlifecyclemixin#action-setrendererror) |
| <span id="action-attachrenderingbackend">**attachRenderingBackend**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>&lt;B&gt;(backend: B, setup: () =&gt; RenderingBackendCallbacks&lt;B&gt;) =&gt; v…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>&lt;B&gt;(backend: B, setup: () =&gt; RenderingBackendCallbacks&lt;B&gt;) =&gt; void</code></pre></dialog></span> | <span data-pagefind-ignore>attach a GPU/Canvas2D backend and install the upload + render autorun pair. Idempotent: re-calling swaps the backend and does not run `setup` again, so the callbacks and everything they close over are the first call's.</span> | [RenderLifecycleMixin](../renderlifecyclemixin#action-attachrenderingbackend) |
| <span id="action-stopactivefetch">**stopActiveFetch**</span><br><code>() =&gt; void</code> | <span data-pagefind-ignore>Abort the in-flight fetch (if any) and retire its slot. The shared preamble of both cancel paths; the difference between them is only what they do to `fetchCanceled` / `fetchGeneration` afterward.</span> | [FetchMixin](../fetchmixin#action-stopactivefetch) |
| <span id="action-openstatusstream">**openStatusStream**</span><br><code>(isCurrent: () =&gt; boolean) =&gt; StatusStream</code> | <span data-pagefind-ignore>Open one operation's slot on the display's status field: an RPC `statusCallback` throttled through the display-wide window and guarded so a callback that fires after the node is torn down (RPCs resolve their status stream asynchronously) is a safe no-op, plus the `clear` that retires the slot when the operation ends.<br><br>**Every operation on the display opens one**, and the two come back together because an operation that never retires goes on voting for a phase that is over. The viewport fetch (`runFetch`), the clustering run and a lent `createStopTokenRotation` are three of them on one field; before ADR-081 each blanked the field outright and the last one to finish decided what the other two were still saying.<br><br>`isCurrent` is required and has no "node is alive" default, because alive is not the interesting question: a *superseded* fetch is on a live node, and its late status repainting the overlay of the fetch that replaced it is the failure this guards. `runFetch` passes `!isStale()`, which is what every display gets for free through `ctx.statusCallback`; a caller outside a fetch (the clustering autorun) passes its own run's flag. Defaulting to `isAlive` made the loose answer the easy one and five displays took it.<br><br>Declared this early only so `runFetch` can put one on every `FetchContext`.</span> | [FetchMixin](../fetchmixin#action-openstatusstream) |
| <span id="action-cancelfetch">**cancelFetch**</span><br><code>() =&gt; void</code> | <span data-pagefind-ignore>cancel any in-flight fetch and bump fetchGeneration (always bumps, so callers can retrigger fetch autoruns even when nothing was in flight). This is the *internal* reset `clearAllRpcData` runs — it clears any user-cancel flag so the retrigger actually re-fetches.</span> | [FetchMixin](../fetchmixin#action-cancelfetch) |
| <span id="action-cancelfetchbyuser">**cancelFetchByUser**</span><br><code>() =&gt; void</code> | <span data-pagefind-ignore>User-initiated cancel from the loading overlay. Stops the in-flight fetch and lands in a durable `fetchCanceled` state. Unlike `cancelFetch`, it does NOT bump fetchGeneration — so the fetch autoruns don't immediately restart the load. The user retries via `reload` (the overlay's retry button), or it clears on the next viewport change.</span> | [FetchMixin](../fetchmixin#action-cancelfetchbyuser) |
| <span id="action-beforedestroy">**beforeDestroy**</span><br><code>() =&gt; void</code> | <span data-pagefind-ignore>Release an in-flight fetch's stop token on teardown. Without this, a display destroyed mid-fetch (track/view closed while loading) never signals the worker to abort the now-useless work, and its in-flight HTTP reads keep downloading. MST auto-chains lifecycle hooks, so a composing display can still define its own beforeDestroy.</span> | [FetchMixin](../fetchmixin#action-beforedestroy) |
| <span id="action-endfetch">**endFetch**</span><br><code>(current: boolean, stopToken: StopToken) =&gt; void</code> | <span data-pagefind-ignore>The `finally` half of `runFetch`'s bookkeeping, an action of its own because `runFetchOnce`'s `finally` resumes on a microtask the flow does not own — a direct volatile write there is outside the action context, which is the one thing hoisting the sequence into a shared function costs. The stale branch is a superseded fetch: whoever superseded it — a newer `begin`, or `cancel` — already released this token.</span> | [FetchMixin](../fetchmixin#action-endfetch) |
| <span id="action-runfetch">**runFetch**</span><br><code>(work: (ctx: FetchContext) =&gt; Promise&lt;void&gt;) =&gt; Promise&lt;void&gt;</code> | <span data-pagefind-ignore>Run a cancel-safe fetch (cancels any prior). The work callback gets a FetchContext with a stopToken to forward to the RPC and an isStale() check to short-circuit commits once the user has moved on.<br><br>**The MST-flow wrapper over the shared `runFetchOnce` sequence**, and only the wrapper: the begin/clear/run/commit/error/end order, and the rules that keep a superseded run from writing back, are the same function every other fetch in the tree runs. What this adds is the observable bookkeeping a display needs — `isLoading` through `activeStopToken`, `fetchGeneration`, the user-cancel clear — and the flow itself, which is an action, so `work`'s synchronous prefix runs untracked wherever a fetch autorun calls this.</span> | [FetchMixin](../fetchmixin#action-runfetch) |
| <span id="action-setrowheight">**setRowHeight**</span><br><code>(n: number) =&gt; void</code> | <span data-pagefind-ignore>Pin a px row height. `0` is the fit sentinel, but enter fit mode through `setFitToHeight` instead — displays whose `height` getter is content-derived have to re-seed the slot on the way in, and that is what the action is for.</span> | [RowHeightMixin](../rowheightmixin#action-setrowheight) |
| <span id="action-setshowtree">**setShowTree**</span><br><code>(arg: boolean) =&gt; void</code> |  | [TreeSidebarMixin](../treesidebarmixin#action-setshowtree) |
| <span id="action-setshowbranchlength">**setShowBranchLength**</span><br><code>(arg: boolean) =&gt; void</code> |  | [TreeSidebarMixin](../treesidebarmixin#action-setshowbranchlength) |
| <span id="action-setshowrowlabels">**setShowRowLabels**</span><br><code>(arg: boolean) =&gt; void</code> |  | [TreeSidebarMixin](../treesidebarmixin#action-setshowrowlabels) |
| <span id="action-setlayout">**setLayout**</span><br><code>(layout: S[]) =&gt; void</code> |  | [TreeSidebarMixin](../treesidebarmixin#action-setlayout) |
| <span id="action-setclustertree">**setClusterTree**</span><br><code>(tree?: string &#124; undefined) =&gt; void</code> |  | [TreeSidebarMixin](../treesidebarmixin#action-setclustertree) |
| <span id="action-setlayoutandclustertree">**setLayoutAndClusterTree**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(layout: S[], tree?: string &#124; undefined, provenance?: ClusterPr…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(layout: S[], tree?: string &#124; undefined, provenance?: ClusterProvenance &#124; undefined) =&gt; void</code></pre></dialog></span> |  | [TreeSidebarMixin](../treesidebarmixin#action-setlayoutandclustertree) |
| <span id="action-settreeareawidth">**setTreeAreaWidth**</span><br><code>(width: number) =&gt; void</code> |  | [TreeSidebarMixin](../treesidebarmixin#action-settreeareawidth) |
| <span id="action-setsubtreefilter">**setSubtreeFilter**</span><br><code>(names?: string[] &#124; undefined) =&gt; void</code> |  | [TreeSidebarMixin](../treesidebarmixin#action-setsubtreefilter) |
| <span id="action-setrunclustering">**setRunClustering**</span><br><code>(arg?: boolean &#124; undefined) =&gt; void</code> |  | [TreeSidebarMixin](../treesidebarmixin#action-setrunclustering) |
| <span id="action-setclusterregion">**setClusterRegion**</span><br><code>(arg?: string &#124; undefined) =&gt; void</code> |  | [TreeSidebarMixin](../treesidebarmixin#action-setclusterregion) |
| <span id="action-setsortrowsby">**setSortRowsBy**</span><br><code>(arg?: RowSortSpec &#124; undefined) =&gt; void</code> | <span data-pagefind-ignore>Trigger (or clear) a one-shot declarative row sort; consumed and reset by `setupRowSortAutorun`. A display's right-click item calls its own sort directly (instant, the data is already loaded); this is the session-level entry point.</span> | [TreeSidebarMixin](../treesidebarmixin#action-setsortrowsby) |
| <span id="action-sethoveredtreenode">**setHoveredTreeNode**</span><br><code>(node?: HoveredTreeNode &#124; undefined) =&gt; void</code> |  | [TreeSidebarMixin](../treesidebarmixin#action-sethoveredtreenode) |
| <span id="action-settreecanvasref">**setTreeCanvasRef**</span><br><code>(ref: HTMLCanvasElement &#124; null) =&gt; void</code> |  | [TreeSidebarMixin](../treesidebarmixin#action-settreecanvasref) |
| <span id="action-setmouseovercanvasref">**setMouseoverCanvasRef**</span><br><code>(ref: HTMLCanvasElement &#124; null) =&gt; void</code> |  | [TreeSidebarMixin](../treesidebarmixin#action-setmouseovercanvasref) |
| <span id="action-opencontextmenu">**openContextMenu**</span><br><code>(info: Info) =&gt; void</code> |  | [ContextMenuMixin](../contextmenumixin#action-opencontextmenu) |
| <span id="action-closecontextmenu">**closeContextMenu**</span><br><code>() =&gt; void</code> |  | [ContextMenuMixin](../contextmenumixin#action-closecontextmenu) |

