# LinearVariantDisplay

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
`variants` plugin.
[View source](https://github.com/GMOD/jbrowse-components/blob/main/plugins/variants/src/LinearVariantDisplay/model.ts).

## Example usage

A complete `VariantTrack` config to paste into `tracks`:

```js
{
  type: 'VariantTrack',
  trackId: 'variants',
  name: 'Variants',
  assemblyNames: ['hg38'],
  adapter: {
    type: 'VcfTabixAdapter',
    uri: 'https://example.com/variants.vcf.gz',
  },
  displays: [
    {
      type: 'LinearVariantDisplay',
      displayId: 'variants-LinearVariantDisplay',
      height: 150,
    },
  ],
}
```

GPU-accelerated variant display with custom feature widget on click.

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

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('LinearVariantDisplay')</code> |  | LinearVariantDisplay |
| <span id="property-configuration">**configuration**</span><br><code>configuration: ConfigurationReference(configSchema)</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#property-configuration) |
| <span id="property-jexlfilterssetting">**jexlFiltersSetting**</span><br><code>jexlFiltersSetting: types.maybe(types.array(types.string))</code> | <span data-pagefind-ignore>Runtime "Filter by..." override. When set (even to an empty list) it replaces the `jexlFilters` config slot; when undefined the config default applies. Stored as already-`jexl:`-prefixed expressions (runtime convention), unlike the deferred-evaluation config slot.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#property-jexlfilterssetting) |
| <span id="property-pinnedfeatureids">**pinnedFeatureIds**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>pinnedFeatureIds: types.stripDefault(types.array(types.string),…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>pinnedFeatureIds: types.stripDefault(types.array(types.string), [])</code></pre></dialog></span> | <span data-pagefind-ignore>Feature ids the user pinned to the top of the layout via the feature right-click menu. Pinned features are inserted first into the greedy row-packer, so they hold the topmost rows in their bp range across zoom re-packs (see packPreparedRef in layout.ts). stripDefault so a display with nothing pinned omits the empty array from its snapshot.<br><br>Persisted by uniqueId, which resolves back to the same feature after a plain reload of the same remote file: every adapter id is `adp-<configHash>` (idMaker over the config) plus a file byte offset (tabix/BigBed) or a deterministic full-file parse index (plain GFF3/BED/VCF). Caveat: NOT robust to editing a file read by a plain (non-tabix) adapter (the indices shift), nor to local blob files (their handleId changes each session — but a blob can't reload its data across refresh anyway). Same basis for solo/hiddenFeatureIds.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#property-pinnedfeatureids) |
| <span id="property-solofeatureids">**soloFeatureIds**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>soloFeatureIds: types.stripDefault(types.array(types.string), […</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>soloFeatureIds: types.stripDefault(types.array(types.string), [])</code></pre></dialog></span> | <span data-pagefind-ignore>"Show only these features": the collected set the user builds by ctrl+clicking features (or via the right-click menu). Only isolates the view once `soloApplied` is true — before that it's a highlighted selection that hides nothing, so the candidates stay clickable. Persistent so a view can be opened pre-focused declaratively (e.g. collapse-introns seeds it in the new view's snapshot). stripDefault so an unfocused display omits the empty array from its snapshot.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#property-solofeatureids) |
| <span id="property-soloapplied">**soloApplied**</span><br><code>soloApplied: types.stripDefault(types.boolean, false)</code> | <span data-pagefind-ignore>Whether the collected soloFeatureIds set is actually isolating the view (worker drops non-members). Decoupled from collection so building a multi-feature set doesn't hide the features mid-build.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#property-soloapplied) |
| <span id="property-hiddenfeatureids">**hiddenFeatureIds**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>hiddenFeatureIds: types.stripDefault(types.array(types.string),…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>hiddenFeatureIds: types.stripDefault(types.array(types.string), [])</code></pre></dialog></span> | <span data-pagefind-ignore>"Hide this feature" exclusion set (inverse of solo): the worker drops these from layout/drawing. Applies immediately per feature — no collect-then-apply. Persistent like the solo set, so a hidden feature stays hidden across reload/session save. stripDefault so a display with nothing hidden omits the empty array from its snapshot.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#property-hiddenfeatureids) |
| <span id="property-expandedgeneids">**expandedGeneIds**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>expandedGeneIds: types.stripDefault(types.array(types.string),…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>expandedGeneIds: types.stripDefault(types.array(types.string), [])</code></pre></dialog></span> | <span data-pagefind-ignore>Genes the user opened from the isoform badge on their own label: these draw every isoform whatever `geneGlyphMode` or the fit ladder's isoform rung would otherwise collapse them to. A per-GENE override of a track-wide setting, so the reader can open the one gene they are reading without turning every other gene on screen into a stack.<br><br>The collapse is the worker's decision, so this is an RPC cache key (see rpcProps) and a click refetches the visible regions — the same contract solo/hidden already have, and for the same reason.<br><br>Persistent and by uniqueId, on the same basis as solo/hidden/pinnedFeatureIds; stripDefault so a display with nothing opened omits the empty array from its snapshot.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#property-expandedgeneids) |
| <span id="property-featurehighlights">**featureHighlights**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>featureHighlights: types.stripDefault( types.array(FeatureHighl…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>featureHighlights: types.stripDefault(&#10;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;types.array(FeatureHighlightModel),&#10;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;[],&#10;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;)</code></pre></dialog></span> | <span data-pagefind-ignore>Declarative feature highlights, typically seeded by a text search (highlight the gene you searched for). Each entry pins a feature by its span+name signature rather than its uniqueId — a search result carries no uniqueId to persist (unlike solo/hidden/pinned, which come from a click on a rendered feature and so DO have a reload-stable id) — and is resolved against rendered features on the main thread. stripDefault so a display with no highlights omits it from snapshot.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#property-featurehighlights) |
| <span id="property-id">**id**</span><br><code>id: ElementId</code> |  | [BaseDisplay](../basedisplay#property-id) |

## Volatiles

<!-- prettier-ignore -->
| Member | Description | Defined by |
| --- | --- | --- |
| <span id="volatile-rpcdatamap">**rpcDataMap**</span><br><code>rpcDataMap: regionDataMap&lt;LoadedFeatureData&gt;('rpcDataMap')</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#volatile-rpcdatamap) |
| <span id="volatile-featureidundermouse">**featureIdUnderMouse**</span><br><code>featureIdUnderMouse: null as string &#124; null</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#volatile-featureidundermouse) |
| <span id="volatile-subfeatureidundermouse">**subfeatureIdUnderMouse**</span><br><code>subfeatureIdUnderMouse: null as string &#124; null</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#volatile-subfeatureidundermouse) |
| <span id="volatile-mouseoverextrainformation">**mouseoverExtraInformation**</span><br><code>mouseoverExtraInformation: undefined as string[] &#124; undefined</code> | <span data-pagefind-ignore>the hover tooltip's rows, each rendered as its own element — see hoverTooltipRows for why this is a list and not one HTML string</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#volatile-mouseoverextrainformation) |
| <span id="volatile-sequencehoverposition">**sequenceHoverPosition**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>sequenceHoverPosition: undefined as SequenceHoverPosition &#124; und…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>sequenceHoverPosition: undefined as SequenceHoverPosition &#124; undefined</code></pre></dialog></span> | <span data-pagefind-ignore>genomic base currently hovered in a feature sequence dialog opened from this display, read by the LGV crosshair overlay</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#volatile-sequencehoverposition) |
| <span id="volatile-contextmenuinfo">**contextMenuInfo**</span><br><code>contextMenuInfo: undefined as FeatureContextMenuInfo &#124; undefined</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#volatile-contextmenuinfo) |
| <span id="volatile-incrementallayout">**incrementalLayout**</span><br><code>incrementalLayout: createIncrementalLayout()</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#volatile-incrementallayout) |
| <span id="volatile-incrementallayoutlabelsonly">**incrementalLayoutLabelsOnly**</span><br><code>incrementalLayoutLabelsOnly: createIncrementalLayout()</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#volatile-incrementallayoutlabelsonly) |
| <span id="volatile-incrementallayoutbodiesonly">**incrementalLayoutBodiesOnly**</span><br><code>incrementalLayoutBodiesOnly: createIncrementalLayout()</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#volatile-incrementallayoutbodiesonly) |
| <span id="volatile-incrementallayoutdecimated">**incrementalLayoutDecimated**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>incrementalLayoutDecimated: createIncrementalLayout({ seedPrior…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>incrementalLayoutDecimated: createIncrementalLayout({&#10;&#160;&#160;&#160;&#160;&#160;&#160;seedPriorRows: false,&#10;&#160;&#160;&#160;&#160;})</code></pre></dialog></span> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#volatile-incrementallayoutdecimated) |
| <span id="volatile-incrementallayoutisoforms">**incrementalLayoutIsoforms**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>incrementalLayoutIsoforms: createIncrementalLayout({ seedPriorR…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>incrementalLayoutIsoforms: createIncrementalLayout({&#10;&#160;&#160;&#160;&#160;&#160;&#160;seedPriorRows: false,&#10;&#160;&#160;&#160;&#160;})</code></pre></dialog></span> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#volatile-incrementallayoutisoforms) |
| <span id="volatile-morphfromtops">**morphFromTops**</span><br><code>morphFromTops: undefined as Map&lt;string, number&gt; &#124; undefined</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#volatile-morphfromtops) |
| <span id="volatile-morphprogress">**morphProgress**</span><br><code>morphProgress: 1</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#volatile-morphprogress) |
| <span id="volatile-morphstartms">**morphStartMs**</span><br><code>morphStartMs: 0</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#volatile-morphstartms) |
| <span id="volatile-morphfrommaxy">**morphFromMaxY**</span><br><code>morphFromMaxY: 0</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#volatile-morphfrommaxy) |
| <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-densitystatsperregion">**densityStatsPerRegion**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>densityStatsPerRegion: regionDataMap&lt;RegionDensityStats&gt;( 'dens…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>densityStatsPerRegion: regionDataMap&lt;RegionDensityStats&gt;(&#10;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;'densityStatsPerRegion',&#10;&#160;&#160;&#160;&#160;&#160;&#160;)</code></pre></dialog></span> | <span data-pagefind-ignore>Per-region feature counts, keyed by `displayedRegionIndex`, so the verdict is a live max at the current `bpPerPx`. Cleared on navigation.</span> | [CanvasFeatureGateMixin](../canvasfeaturegatemixin#volatile-densitystatsperregion) |

## Getters

<!-- prettier-ignore -->
| Member | Description | Defined by |
| --- | --- | --- |
| <span id="getter-featurenoun">**featureNoun**</span><br><code>string</code> | Renames the shared canvas vocabulary for this display: every menu row, chip and indicator that names what the track holds reads this, so a variant track says "Variant height", "Hide this variant", "Showing 3 variants" instead of inheriting the gene-oriented "feature". The per-hit noun in the context menu still comes from the annotation's own type where it has one. | LinearVariantDisplay |
| <span id="getter-featurewidgettype">**featureWidgetType**</span><br><code>{ type: string; id: string; }</code> |  | LinearVariantDisplay |
| <span id="getter-colorsbyconsequenceimpact">**colorsByConsequenceImpact**</span><br><code>boolean</code> |  | LinearVariantDisplay |
| <span id="getter-colorsbysvtype">**colorsBySvType**</span><br><code>boolean</code> |  | LinearVariantDisplay |
| <span id="getter-colorlegenditems">**colorLegendItems**</span><br><code>LegendItem[]</code> |  | LinearVariantDisplay |
| <span id="getter-colorlegend">**colorLegend**</span><br><code>LegendItem[]</code> | This display's answer to the base's `colorLegend` chrome hook: the shared canvas body draws the key, so this display needs no component of its own (its `ReactComponent` is the one LinearBasicDisplay registers). | LinearVariantDisplay |
| <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> | <span data-pagefind-ignore>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>`).</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-conf) |
| <span id="getter-geneglyphnotice">**geneGlyphNotice**</span><br><code>GeneGlyphNotice &#124; undefined</code> | <span data-pagefind-ignore>Overridable hook (default absent): the isoform-collapse control the shared canvas body draws in its bottom-right chip stack, or nothing when the display has no gene glyphs. Bundled — state plus the two actions — because the real implementation reads a `geneGlyphMode` config slot that only `LinearBasicDisplay`'s schema declares; the variant display shares this body and simply doesn't answer.<br><br>Chrome a subclass owns arrives through hooks like this rather than through a per-subclass component, so one registered component serves every canvas-family display and no plugin imports another's component.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-geneglyphnotice) |
| <span id="getter-renderstate">**renderState**</span><br><code>{ scrollY: number; canvasWidth: number; canvasHeight: number; }</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-renderstate) |
| <span id="getter-labelscrollbucket">**labelScrollBucket**</span><br><code>number</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-labelscrollbucket) |
| <span id="getter-maxheight">**maxHeight**</span><br><code>number</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-maxheight) |
| <span id="getter-displaymode">**displayMode**</span><br><code>"collapsed" &#124; "compact" &#124; "normal" &#124; "superCompact"</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-displaymode) |
| <span id="getter-labelfontsize">**labelFontSize**</span><br><code>number</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-labelfontsize) |
| <span id="getter-showlabelsmode">**showLabelsMode**</span><br><code>"auto" &#124; "description" &#124; "name" &#124; "nameAndDescription" &#124; "none"</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-showlabelsmode) |
| <span id="getter-showlabels">**showLabels**</span><br><code>boolean</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-showlabels) |
| <span id="getter-showdescriptions">**showDescriptions**</span><br><code>boolean</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-showdescriptions) |
| <span id="getter-showoutline">**showOutline**</span><br><code>boolean</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-showoutline) |
| <span id="getter-featurecolor">**featureColor**</span><br><code>any</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-featurecolor) |
| <span id="getter-utrcolor">**utrColor**</span><br><code>string</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-utrcolor) |
| <span id="getter-colorbymode">**colorByMode**</span><br><code>"attribute" &#124; "solid" &#124; "strand"</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-colorbymode) |
| <span id="getter-colorbyattribute">**colorByAttribute**</span><br><code>string</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-colorbyattribute) |
| <span id="getter-effectiveshowdescriptions">**effectiveShowDescriptions**</span><br><code>boolean</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-effectiveshowdescriptions) |
| <span id="getter-selectedfeatureid">**selectedFeatureId**</span><br><code>string &#124; undefined</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-selectedfeatureid) |
| <span id="getter-colorbycds">**colorByCDS**</span><br><code>boolean</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-colorbycds) |
| <span id="getter-showaminoacids">**showAminoAcids**</span><br><code>boolean</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-showaminoacids) |
| <span id="getter-reversedregions">**reversedRegions**</span><br><code>Set&lt;number&gt;</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-reversedregions) |
| <span id="getter-pinnedfeatureidset">**pinnedFeatureIdSet**</span><br><code>ReadonlySet&lt;string&gt;</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-pinnedfeatureidset) |
| <span id="getter-expandedgeneidset">**expandedGeneIdSet**</span><br><code>ReadonlySet&lt;string&gt;</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-expandedgeneidset) |
| <span id="getter-solofeatureidset">**soloFeatureIdSet**</span><br><code>ReadonlySet&lt;string&gt;</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-solofeatureidset) |
| <span id="getter-hiddenfeaturecount">**hiddenFeatureCount**</span><br><code>number</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-hiddenfeaturecount) |
| <span id="getter-solofeaturecount">**soloFeatureCount**</span><br><code>number</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-solofeaturecount) |
| <span id="getter-pinnedfeaturecount">**pinnedFeatureCount**</span><br><code>number</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-pinnedfeaturecount) |
| <span id="getter-canonicalfeaturehighlights">**canonicalFeatureHighlights**</span><br><code>FeatureHighlight[]</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-canonicalfeaturehighlights) |
| <span id="getter-resolvedhighlights">**resolvedHighlights**</span><br><code>ResolvedHighlights</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-resolvedhighlights) |
| <span id="getter-highlightedfeatureidset">**highlightedFeatureIdSet**</span><br><code>ReadonlySet&lt;string&gt;</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-highlightedfeatureidset) |
| <span id="getter-layoutpinnedfeatureidset">**layoutPinnedFeatureIdSet**</span><br><code>ReadonlySet&lt;string&gt;</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-layoutpinnedfeatureidset) |
| <span id="getter-featurehighlightcount">**featureHighlightCount**</span><br><code>number</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-featurehighlightcount) |
| <span id="getter-layoutinputs">**layoutInputs**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>{ bpPerPx: number; reversedRegions: Set&lt;…&gt;; displayMode: "colla…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>{ bpPerPx: number; reversedRegions: Set&lt;…&gt;; displayMode: "collapsed" &#124; "compact" &#124; "normal" &#124; "superCompact"; pinnedFeatureIds: ReadonlySet&lt;…&gt;; expandedGeneIds: ReadonlySet&lt;...&gt;; }</code></pre></dialog></span> | <span data-pagefind-ignore>Layout inputs shared by the base layout and every fit-escalation layout, minus the per-config label/description reservation flags. One source so the candidate layouts can't drift on bpPerPx / orientation / display mode / pins / opened genes.<br><br>`expandedGeneIds` belongs here and not on the rungs that trim, even though only they consult it: an expanded gene arrives carrying `collapsedIsoformCount`, so EVERY rung's pack trims it back to what the mode collapsed it to, and a rung that inherits the layout inputs without the exemption re-collapses the gene the user just opened. The three trimming rungs each added it for themselves; `full` and `labels` did not, which in `grow` — where `full` is the only rung — left no rung below to recover on.<br><br>Each region's ref key is NOT here: it rides on the region itself, which is what the layout groups by (see `LayoutRegionData`).</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-layoutinputs) |
| <span id="getter-layoutready">**layoutReady**</span><br><code>boolean</code> | <span data-pagefind-ignore>Whether features can be laid out: data is fetched, in-bounds, and the view is measured. The shared readiness guard for every layout getter — an empty stack until then, so the GPU upload autorun has nothing to push and view-geometry getters aren't read before the view is measured.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-layoutready) |
| <span id="getter-onscreenfeatureids">**onScreenFeatureIds**</span><br><code>ReadonlySet&lt;string&gt; &#124; undefined</code> | <span data-pagefind-ignore>The features whose bp span touches the viewport. Why that is not the whole packed stack — and the matching rules — live with the pure `featureIdsTouchingBlocks` in layout.ts; this getter is the reactive half, deciding when to ask.<br><br>Read off `coarseDynamicBlocks` (500ms debounced), like the layout's `coarseBpPerPx`, so a pan re-measures once it settles instead of breathing the whole stack every frame. Undefined until the view has coarse blocks, which every consumer reads as "measure the whole stack".<br><br>Two things measure over it, for the same reason: the fit ladder (`fitMeasureFeatureIds`) and the scroll extent (`scrollExtentMaxY`).</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-onscreenfeatureids) |
| <span id="getter-fitmeasurefeatureids">**fitMeasureFeatureIds**</span><br><code>ReadonlySet&lt;string&gt; &#124; undefined</code> | <span data-pagefind-ignore>The features fit mode measures its stack against: the on-screen set while the fit is running, undefined otherwise (which measures the whole stack).</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-fitmeasurefeatureids) |
| <span id="getter-decimatedbaseinputs">**decimatedBaseInputs**</span><br><code>LabelRoomFactorFreeInputs</code> | <span data-pagefind-ignore>The `decimated` rung's layout inputs minus the whitespace factor. Typed without `labelRoomFactor` so the solve's shared preparation provably can't depend on it (see createContentHeightProbe).</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-decimatedbaseinputs) |
| <span id="getter-decimatedheightprobe">**decimatedHeightProbe**</span><br><code>(labelRoomFactor: number) =&gt; number</code> | <span data-pagefind-ignore>Measures the `decimated` rung's stack height at any whitespace factor, against the features the ladder measures its rungs with — so the factor the solve picks is judged on the same stack the rung is then kept or rejected on.<br><br>A getter, not a call inside the solve, because the preparation it holds (per-kind label widths, the two neighbor-room sorts — about a fifth of a layout) depends on the data and the layout inputs but NOT on the track height. Dragging the resize handle re-solves every frame; caching it here keeps those frames to the bisection's packs alone.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-decimatedheightprobe) |
| <span id="getter-isoformsbaseinputs">**isoformsBaseInputs**</span><br><code>IsoformCountFreeInputs</code> | <span data-pagefind-ignore>The `isoforms` rung's layout inputs minus the count itself, typed without it so the solve's shared preparation provably cannot depend on it. Same reservation as `labels` — names kept, descriptions dropped — because the whole point of the rung is that names survive the trim.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-isoformsbaseinputs) |
| <span id="getter-isoformsheightprobe">**isoformsHeightProbe**</span><br><code>(maxIsoforms: number) =&gt; number</code> | <span data-pagefind-ignore>Measures the `isoforms` rung's stack height at any isoform count, against the features the ladder measures its rungs with.<br><br>A getter for the reason `decimatedHeightProbe` is one: the preparation it holds depends on the data and the layout inputs but NOT on the track height, and dragging the resize handle re-solves every frame.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-isoformsheightprobe) |
| <span id="getter-maxisoformsonscreen">**maxIsoformsOnScreen**</span><br><code>number</code> | <span data-pagefind-ignore>The most isoforms any gene ON SCREEN has — the top of the solve's bracket, and the count above which a trim can take nothing away.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-maxisoformsonscreen) |
| <span id="getter-fitisoformcount">**fitIsoformCount**</span><br><code>number &#124; undefined</code> | <span data-pagefind-ignore>The isoform count the `isoforms` rung commits at: the largest whose names-kept stack fits `fitTargetHeight`, so the most transcripts are kept without giving up a name. Undefined when nothing is worth trimming; 1 when even one transcript per gene overflows, which the `decimated` and `bodies` rungs below then inherit.<br><br>Never in `grow`, whose height is its own content's — trimming there would shrink the track it was measured against.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-fitisoformcount) |
| <span id="getter-fitisoformssolved">**fitIsoformsSolved**</span><br><code>Map&lt;number, FeatureDataResult&gt;</code> | <span data-pagefind-ignore>The `isoforms` stack: every gene trimmed to `fitIsoformCount` transcripts, names intact. Falls back to the `labels` stack when there is nothing to trim.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-fitisoformssolved) |
| <span id="getter-baselaidoutdatamap">**baseLaidOutDataMap**</span><br><code>Map&lt;number, FeatureDataResult&gt;</code> | <span data-pagefind-ignore>Full reservation (names + descriptions): rendered at fit stage `full` and in non-fit modes, and the first stack `fitStage` probes.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-baselaidoutdatamap) |
| <span id="getter-fitlabelsonlylayout">**fitLabelsOnlyLayout**</span><br><code>Map&lt;number, FeatureDataResult&gt;</code> | <span data-pagefind-ignore>Names reserved, descriptions dropped — the `labels` stage's stack. With descriptions already off (config, or the auto density gate) this rung's reservation is the base one, so reuse that stack by reference rather than packing a byte-identical copy into a second memo.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-fitlabelsonlylayout) |
| <span id="getter-fitdecimatedfactor">**fitDecimatedFactor**</span><br><code>number &#124; undefined</code> | <span data-pagefind-ignore>The whitespace factor the `decimated` rung commits at: the smallest one whose packed stack fits `fitTargetHeight`, so the most names are kept. Undefined when there is nothing to decimate (names off) or when even the most aggressive factor overflows.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-fitdecimatedfactor) |
| <span id="getter-fitdecimatedsolved">**fitDecimatedSolved**</span><br><code>Map&lt;number, FeatureDataResult&gt;</code> | <span data-pagefind-ignore>The `decimated` stack: names kept only on features with at least `fitDecimatedFactor ×` their label width in neighbour whitespace (plus pinned/highlighted, always). Filling the height with as many non-overlapping names as fit, rather than snapping between a few fixed rungs, is what this rung is for; it decimates by isolation, not by any notion of feature importance. Falls back to the `labels` stack when there is nothing to decimate or no factor fits.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-fitdecimatedsolved) |
| <span id="getter-fitbodiesonlylayout">**fitBodiesOnlyLayout**</span><br><code>Map&lt;number, FeatureDataResult&gt;</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-fitbodiesonlylayout) |
| <span id="getter-fitsmallestboxpx">**fitSmallestBoxPx**</span><br><code>number</code> | <span data-pagefind-ignore>The unscaled height (px) of the shortest box on screen that the layout actually DRAWS — a UTR at its 0.65 fraction, a transcript rect inside a gene, a plain variant box — which is the one a uniform squeeze takes below a visible size first, and so the basis for the squeeze floor below. 0 when nothing is drawn, which makes that floor a no-op.<br><br>A drawn box, not a feature's laid-out extent, and the distinction is the whole floor: a gene's extent is every stacked transcript plus its label rows, so a floor built on it promised 2px boxes while letting each transcript render at a third of a pixel. See `minDrawnBoxHeight`.<br><br>Measured off the layout, never off the `featureHeight` config slot. The slot is a per-feature jexl callback slot (`contextVariable: ['feature']`), so reading it here — with no feature in scope — evaluates the callback against nothing and throws, taking the whole fit layout down with it. And even where it holds a plain number it names the plain-rect glyph's row height, which is not what a UTR or an isoform inside a gene is drawn at.<br><br>Reads the `full` rung specifically because it is the stack the ladder always materializes, so it costs nothing extra. Box HEIGHTS don't vary across rungs (only the label reservation does), but the set of boxes counted can: `minDrawnBoxHeight` skips a feature the packer left unplaced, and `bodies` — the only rung a squeeze ever runs on — packs tighter and so places features `full` pushed past the row limit. On a stack deep enough to truncate at `full`, the floor is therefore measured over a subset and can allow a squeeze slightly past the MIN_FIT_BOX_PX promise. Reading it off `bodies` instead would be circular — that layout is chosen using this scale.<br><br>Narrowed to `fitMeasureFeatureIds`, the same on-screen set every rung is measured over.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-fitsmallestboxpx) |
| <span id="getter-fitminscale">**fitMinScale**</span><br><code>number</code> | <span data-pagefind-ignore>Floor on the fit squeeze: the smallest vertical scale that still leaves every drawn box at least `MIN_FIT_BOX_PX` tall. When boxes would pack tighter than this the squeeze stops here and the surplus scrolls instead of vanishing. `squeezeFloorScale` answers both degenerate cases (nothing drawn, or boxes already at the minimum) as 1 — no squeeze available — so there is nothing to clamp or zero-check here.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-fitminscale) |
| <span id="getter-fitmaxscale">**fitMaxScale**</span><br><code>number</code> | <span data-pagefind-ignore>Ceiling on the fit grow: the largest vertical scale before a feature body exceeds the height it would have outside fit mode. A sparse stack grows to fill the track only until its bodies reach that height, so fit never makes a feature taller than the display normally draws it. In normal display mode the laid-out body already is that height, pinning the scale at 1 (no grow, surplus stays whitespace); a compact mode may grow back up to — but not past — it.<br><br>That works out to exactly `1 / multiplier`, with no body height read at all: the grow target is the unmultiplied height and the laid-out body is that height times the mode's multiplier, so it cancels whatever it was per feature and the ceiling is purely the display mode's compact ratio (1 in normal mode → no grow). Unlike the squeeze floor, which has to know the shortest actual box (see `fitSmallestBoxPx`), this bound is uniform.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-fitmaxscale) |
| <span id="getter-fitstage">**fitStage**</span><br><code>FitStage</code> | <span data-pagefind-ignore>The resolved fit outcome — which reservation `level` survived, its unscaled `layout`, and the vertical `scale` to fill the track — bundled so the three can never disagree. The ladder keeps the least reduction whose *unscaled* stack fits the track height: `full` (names + descriptions), else `labels` (drop descriptions), else `decimated` at a whitespace factor solved to the height (`fitDecimatedSolved` — keeps as many non-overlapping names as fit, filling the space continuously), else `bodies` (drop names too, pack tight) when even the tightest decimation overflows. The kept rung is then scaled to fill the track: grown up to `fitMaxScale` when it fits with room to spare, but never past the normal feature height — so in normal display mode grow is pinned at 1 and spare space stays whitespace, while a compact mode may enlarge back up to normal; or — only at the last `bodies` rung — squeezed down to `fitMinScale` and scrolled if even that overflows. Non-fit modes stay at `full`, scale 1. Read off the unscaled candidate heights so it can't feed back on its own `scale`. The ladder walk + scale math live in `resolveFitLadder`.<br><br>Every rung is measured over `fitMeasureFeatureIds` — on screen in fit mode, everything otherwise — so the rung that survives and the squeeze it gets are decided by the stack in view, not by the half-viewport of buffered features packed on either side of it.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-fitstage) |
| <span id="getter-fitscale">**fitScale**</span><br><code>number</code> | <span data-pagefind-ignore>Uniform vertical scale for fit mode; 1 unless the resolved stack is being grown to fill the track (> 1) or the bodies stack squeezed to fit (< 1).</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-fitscale) |
| <span id="getter-laidoutdatamap">**laidOutDataMap**</span><br><code>ReadonlyMap&lt;number, FeatureDataResult&gt;</code> | <span data-pagefind-ignore>What every consumer (hit test, GPU upload, React render) reads: the resolved fit layout, cloned and scaled only when grown or squeezed. A fit stack shorter than the track stays top-anchored at y=0 (the surplus is bottom whitespace), so a relayout — an isoform collapse, a filter — packs back up against the top instead of jumping to a re-centered offset. Returned by reference off the untransformed path (scale 1) so the incremental-layout upload diff and Y-morph idle check stay intact.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-laidoutdatamap) |
| <span id="getter-renderedshowdescriptions">**renderedShowDescriptions**</span><br><code>boolean</code> | <span data-pagefind-ignore>Descriptions are painted at the `full` stage, and at the `isoforms` one where a fixed-height track reached it — that ladder is `full → isoforms` and gives up transcripts rather than labels, so the rung packs the descriptions the settings asked for and this has to agree. Fit mode only reaches `isoforms` after `labels` dropped them. Every render-time consumer — label draw and the highlight/hit/SVG label-width reservation — reads this so a box never reserves width for a description it won't draw.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-renderedshowdescriptions) |
| <span id="getter-renderedshowlabels">**renderedShowLabels**</span><br><code>boolean</code> | <span data-pagefind-ignore>Names are painted at every stage short of `bodies` (and whenever fit is off), where the packer reserved row height + overhang for the names it kept so they never overlap — including the `decimated` stage, whose per-feature pruning happens inside the layout (dropped names are removed from floatingLabelsData), not via this flag. At the `bodies` stage nothing is reserved, so all names are hidden rather than drawn on top of the boxes. Every render-time consumer reads this so hidden names reserve nothing.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-renderedshowlabels) |
| <span id="getter-renderedshowsubfeaturelabels">**renderedShowSubfeatureLabels**</span><br><code>boolean</code> | <span data-pagefind-ignore>A subfeature label (a transcript name under its gene) is a worker-baked config choice rather than a fit rung — `showLabels`/`showDescriptions` govern only the feature's OWN two lines, and the packer reserves this label's row and overhang unconditionally to match. So it survives every rung the two flags above drop, including `bodies`.<br><br>What it does NOT survive is the squeeze. The rows it was reserved in are spent in `bodyHeightPx` and scaled with everything else, while the text draws at the mode's own font size — so at scale 0.3 a gene's transcript names are painted over rows a third as tall as the text, on top of each other and of the boxes. Below 1 they are hidden instead; at 1 (every non-squeezed rung, and all of fixed/grow) nothing changed.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-renderedshowsubfeaturelabels) |
| <span id="getter-fitdrops">**fitDrops**</span><br><code>FitDrops</code> | <span data-pagefind-ignore>What the ladder took from the labels the settings reserved, and how far it squeezed — the one derivation both user-facing notes read.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-fitdrops) |
| <span id="getter-fitnote">**fitNote**</span><br><code>string &#124; undefined</code> | <span data-pagefind-ignore>The track-sizing control's account of what fit mode gave up, or undefined when nothing. The ladder drops labels silently and the "Labels" radio keeps saying they are on, so without this a user has no way to tell a track with no descriptions from one whose descriptions fit mode hid.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-fitnote) |
| <span id="getter-labelsfithint">**labelsFitHint**</span><br><code>string &#124; undefined</code> | <span data-pagefind-ignore>The note on the selected "Labels" radio while the ladder is not honouring it (see `inertLabelHint`).</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-labelsfithint) |
| <span id="getter-morpheased">**morphEased**</span><br><code>number</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-morpheased) |
| <span id="getter-renderdatamap">**renderDataMap**</span><br><code>ReadonlyMap&lt;number, FeatureDataResult&gt;</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-renderdatamap) |
| <span id="getter-settledmaxy">**settledMaxY**</span><br><code>number</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-settledmaxy) |
| <span id="getter-maxy">**maxY**</span><br><code>number</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-maxy) |
| <span id="getter-scrollextentmaxy">**scrollExtentMaxY**</span><br><code>number</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-scrollextentmaxy) |
| <span id="getter-hasoverflow">**hasOverflow**</span><br><code>boolean</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-hasoverflow) |
| <span id="getter-truncatedfeaturecount">**truncatedFeatureCount**</span><br><code>number</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-truncatedfeaturecount) |
| <span id="getter-contentheight">**contentHeight**</span><br><code>number</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-contentheight) |
| <span id="getter-scrollcontentheight">**scrollContentHeight**</span><br><code>number</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-scrollcontentheight) |
| <span id="getter-scrollableheight">**scrollableHeight**</span><br><code>number</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-scrollableheight) |
| <span id="getter-growtargetheight">**growTargetHeight**</span><br><code>number</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-growtargetheight) |
| <span id="getter-featureidindex">**featureIdIndex**</span><br><code>Map&lt;string, FlatbushItem&gt;</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-featureidindex) |
| <span id="getter-subfeatureidindex">**subfeatureIdIndex**</span><br><code>Map&lt;string, SubfeatureInfo&gt;</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-subfeatureidindex) |
| <span id="getter-hoveredfeature">**hoveredFeature**</span><br><code>FlatbushItem &#124; null</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-hoveredfeature) |
| <span id="getter-hoveredsubfeature">**hoveredSubfeature**</span><br><code>SubfeatureInfo &#124; null</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-hoveredsubfeature) |
| <span id="getter-featureitemmap">**featureItemMap**</span><br><code>Map&lt;string, FeatureItemEntry&gt;</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-featureitemmap) |
| <span id="getter-flatbushindexes">**flatbushIndexes**</span><br><code>Map&lt;number, FlatbushRegionIndexes&gt;</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-flatbushindexes) |
| <span id="getter-regionfetchkey">**regionFetchKey**</span><br><code>string</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#getter-regionfetchkey) |
| <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-height">**height**</span><br><code>number</code> |  | [TrackHeightMixin](../trackheightmixin#getter-height) |
| <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-heightmode">**heightMode**</span><br><code>"fit" &#124; "fixed" &#124; "grow"</code> | <span data-pagefind-ignore>The resolved track-height strategy (`fixed`/`grow`/`fit`). Promotable sentinel slot: resolveConf walks the customized-track -> session-default -> `fixed` cascade and never returns the `inherit` sentinel.</span> | [HeightModeMixin](../heightmodemixin#getter-heightmode) |
| <span id="getter-fittargetheight">**fitTargetHeight**</span><br><code>number</code> | <span data-pagefind-ignore>The drag-resizable track height as stored in the config slot — the fit target the fit/grow layout scales or packs content into. Read there instead of the reactive `height` getter to break the grow-mode cycle (`height`->grownHeight->layout->height). Equals `height` in fixed/fit.</span> | [HeightModeMixin](../heightmodemixin#getter-fittargetheight) |
| <span id="getter-growmaxheight">**growMaxHeight**</span><br><code>number</code> | <span data-pagefind-ignore>Ceiling `grow` mode sizes the track to, in px (content past it scrolls). Lives here rather than as a constant so a track whose whole point is a deep pileup can raise it; both displays that own a `grownHeight` read this, so the two can't diverge.</span> | [HeightModeMixin](../heightmodemixin#getter-growmaxheight) |
| <span id="getter-autoheight">**autoHeight**</span><br><code>boolean</code> | <span data-pagefind-ignore>`grow` mode as a boolean, derived from the unified `heightMode` slot.</span> | [HeightModeMixin](../heightmodemixin#getter-autoheight) |
| <span id="getter-fitheighttodisplay">**fitHeightToDisplay**</span><br><code>boolean</code> | <span data-pagefind-ignore>`fit` mode as a boolean, derived from the unified `heightMode` slot.</span> | [HeightModeMixin](../heightmodemixin#getter-fitheighttodisplay) |
| <span id="getter-grownheight">**grownHeight**</span><br><code>number</code> | <span data-pagefind-ignore>Target track height for `grow`: what the content wants, capped so a deep stack doesn't grow the track to thousands of px (the remainder scrolls). What `installGrowExitBake` bakes into the slot on exit.</span> | [HeightModeMixin](../heightmodemixin#getter-grownheight) |
| <span id="getter-showlegend">**showLegend**</span><br><code>boolean</code> | <span data-pagefind-ignore>Whether the legend is drawn. Resolved through the promotable-slot tiers (`resolveConf`): an explicit track value customizes it either way, otherwise it follows the session-wide default for this display type, falling back to the slot's `promotedBase`.</span> | [LegendMixin](../legendmixin#getter-showlegend) |
| <span id="getter-showlegenddisplaytypedefault">**showLegendDisplayTypeDefault**</span><br><code>Pin</code> | <span data-pagefind-ignore>The "make the current legend visibility the default for all tracks" control. Symmetric, so it promotes whichever value the track currently shows. `showLegendCheckboxItem` takes this as its `pin`.</span> | [LegendMixin](../legendmixin#getter-showlegenddisplaytypedefault) |
| <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-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-gateenabled">**gateEnabled**</span><br><code>boolean</code> | <span data-pagefind-ignore>The opt-in. Overridden with a literal `true` by gated displays, and `check-gated-adapter-budgets` insists on a literal: this mixin returns early on it in an autorun and in `commitFetchBytes`.</span> | [RegionTooLargeMixin](../regiontoolargemixin#getter-gateenabled) |
| <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-bytegateadapterpath">**byteGateAdapterPath**</span><br><code>string[]</code> | <span data-pagefind-ignore>Where on the track config the measured adapter sits. A tiered display overrides this one hook (MAF: `['adapter', 'summaryAdapter']` while `showSummary`), and both the measurement and the budget follow it.</span> | [RegionTooLargeMixin](../regiontoolargemixin#getter-bytegateadapterpath) |
| <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-visiblefeaturedensityperpx">**visibleFeatureDensityPerPx**</span><br><code>number</code> | <span data-pagefind-ignore>Density at the debounced `coarseBpPerPx`, so the verdict shares the layout cadence. Zero before the view is measured.</span> | [CanvasFeatureGateMixin](../canvasfeaturegatemixin#getter-visiblefeaturedensityperpx) |
| <span id="getter-maxfeaturedensity">**maxFeatureDensity**</span><br><code>number &#124; undefined</code> | <span data-pagefind-ignore>The worker's density budget; undefined when the axis may not act.</span> | [CanvasFeatureGateMixin](../canvasfeaturegatemixin#getter-maxfeaturedensity) |

## Methods

<!-- prettier-ignore -->
| Member | Description | Defined by |
| --- | --- | --- |
| <span id="method-contextmenuitems">**contextMenuItems**</span><br><code>() =&gt; MenuItem[]</code> | The shared feature menu plus, on a breakend record, the row that opens the split view for it. Super-captured rather than replaced, so every generic row (details, zoom to, highlight, show/hide, copy) stays where a reader already learned it. | LinearVariantDisplay |
| <span id="method-colorbysubmenuitems">**colorBySubMenuItems**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>() =&gt; ({…} &#124; { label: string; type: "radio"; checked: boolean;…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>() =&gt; ({…} &#124; { label: string; type: "radio"; checked: boolean; onClick: () =&gt; void; keepMenuOpen?: undefined; })[]</code></pre></dialog></span> |  | LinearVariantDisplay |
| <span id="method-configuredfilters">**configuredFilters**</span><br><code>() =&gt; string[]</code> | <span data-pagefind-ignore>What the `jexlFilters` config slot alone declares, `jexl:`-prefixed.<br><br>In its own block ahead of `activeFilters` / `featureFilterCount` so both reach it through `self`: `featureFilterCount` is super-captured by subclasses and called unbound, so a same-block `this` is undefined there.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#method-configuredfilters) |
| <span id="method-activefilters">**activeFilters**</span><br><code>() =&gt; string[]</code> | <span data-pagefind-ignore>The filters actually applied, as `jexl:`-prefixed expressions — see `activeJexlFilters`, which is the shared two-tier resolution.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#method-activefilters) |
| <span id="method-rpcprops">**rpcProps**</span><br><code>() =&gt; {…}</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#method-rpcprops) |
| <span id="method-gpuprops">**gpuProps**</span><br><code>() =&gt; { colorTable: Uint32Array&lt;ArrayBuffer&gt;; }</code> | <span data-pagefind-ignore>What the main-thread encode needs beyond a region's own data: the packed color for every theme class the worker emitted.<br><br>The theme deliberately does NOT appear in `rpcProps()` above. It used to, so worker-baked CDS-frame and connector colors could follow it — and every field of that payload is an RPC cache key, so a light/dark toggle or a config `theme` edit re-downloaded and re-parsed every visible region of every canvas feature track. The worker now emits a class where it used to bake a theme color (colorClasses.ts) and this resolves it, so the same toggle is a re-encode of what is already loaded.<br><br>`session.palette`, not `session.theme`: this crosses no boundary that needs MUI, and a getter rather than a pushed volatile so the SVG export and the RPC — neither of which has a component — see a real palette (ARCHITECTURE.md, "Theme-derived render inputs are session getters").</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#method-gpuprops) |
| <span id="method-fitlayoutat">**fitLayoutAt**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(memo: (rpcDataMap: ReadonlyMap&lt;number, LayoutRegionData&gt;, inpu…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(memo: (rpcDataMap: ReadonlyMap&lt;number, LayoutRegionData&gt;, inputs: LayoutInputs) =&gt; Map&lt;number, FeatureDataResult&gt;, showLabels: boolean, showDescriptions: boolean) =&gt; Map&lt;...&gt;</code></pre></dialog></span> | <span data-pagefind-ignore>One fit-escalation candidate: the stack packed with the given label/description reservation, via that config's own memo instance so each keeps stable references across renders. Empty until initialized/in-bounds, so the GPU upload autorun has nothing to push.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#method-fitlayoutat) |
| <span id="method-decimatedlayoutinputs">**decimatedLayoutInputs**</span><br><code>(labelRoomFactor: number) =&gt; LayoutInputs</code> | <span data-pagefind-ignore>Layout inputs for the `decimated` rung at one whitespace factor. Every probe and the committed layout go through this single builder, so the stack the solve measures cannot differ from the stack it commits by a forgotten field.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#method-decimatedlayoutinputs) |
| <span id="method-solvelabelroomfactor">**solveLabelRoomFactor**</span><br><code>(trackHeight: number) =&gt; number &#124; undefined</code> | <span data-pagefind-ignore>The whitespace factor the `decimated` rung commits at: the smallest one whose packed stack fits `trackHeight` (smallest = most names kept), or undefined when even the most aggressive decimation overflows. The bisection lives in `solveLabelRoomFactor` (fitLadder.ts), next to the ladder walk it serves.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#method-solvelabelroomfactor) |
| <span id="method-morphoffsetfor">**morphOffsetFor**</span><br><code>(featureId: string) =&gt; number</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#method-morphoffsetfor) |
| <span id="method-getfeaturebyid">**getFeatureById**</span><br><code>(featureId: string) =&gt; FlatbushItem &#124; undefined</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#method-getfeaturebyid) |
| <span id="method-searchfeaturebyid">**searchFeatureByID**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(id: string) =&gt; readonly [number, number, number, number] &#124; und…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(id: string) =&gt; readonly [number, number, number, number] &#124; undefined</code></pre></dialog></span> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#method-searchfeaturebyid) |
| <span id="method-rendersvg">**renderSvg**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(opts?: ExportSvgDisplayOptions &#124; undefined) =&gt; Promise&lt;ReactEl…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(opts?: ExportSvgDisplayOptions &#124; undefined) =&gt; Promise&lt;ReactElement&lt;unknown, string &#124; JSXElementConstructor&lt;any&gt;&gt; &#124; Iterable&lt;...&gt; &#124; AwaitedReactNode&gt;</code></pre></dialog></span> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#method-rendersvg) |
| <span id="method-featurenarrowings">**featureNarrowings**</span><br><code>() =&gt; Reversibles</code> | <span data-pagefind-ignore>Everything this display is doing to narrow what the user sees, each declared once (see `Reversible`). The "Filter by... (n)" count, the undo rows inside that submenu, and what "Clear all filters" clears are all derived from this one list, so they cannot disagree — the pairing rule that used to be a comment on two separately-maintained members.<br><br>A METHOD, not a getter, because it is the subclass extension seam and a getter cannot be super-captured — `const { x } = self` on a getter evaluates it once at composition time and freezes that value forever. Same rule as every other seam here (showSubmenuMenuItems, trackMenuItems); the count this replaces carried the same note.<br><br>A subclass adds a filter by super-capturing THIS and appending one entry, rather than overriding a count and a clear and hoping the two stay in step (LinearBasicDisplay's "Show only genes" did exactly that).<br><br>A narrowing counts when its value is not the **no-op** one, which is not always its default:<br><br>- the jexl override's no-op is the CONFIG DEFAULT, not the empty list — `jexlFilterNarrowing` states that one, since all three displays with this row need it. - `soloApplied`, not `soloFeatureIds.length`: while the user is still collecting (ctrl+click) the set only draws boxes and hides nothing. The SoloSelectionChip's × is the recovery for an unapplied one. - the hidden set is ONE narrowing however many features it holds — one thing to clear, and its own row already names N.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#method-featurenarrowings) |
| <span id="method-featuremarks">**featureMarks**</span><br><code>() =&gt; Reversibles</code> | <span data-pagefind-ignore>Reversible state that MARKS features rather than hiding them — the highlight boxes and the pins holding features at the top of the layout. Same declaration shape as the narrowings above and the same undo rows, but deliberately a separate list: neither hides anything, so neither belongs in the "Filter by... (n)" count or under "Clear all filters".<br><br>They need the rows for the same reason the narrowings do. Both outlive the navigation that created them and neither is reachable from the feature itself once the user has panned away — and a pin is worse than a highlight, because nothing on screen marks a pinned feature at all.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#method-featuremarks) |
| <span id="method-featurefiltercount">**featureFilterCount**</span><br><code>() =&gt; number</code> | <span data-pagefind-ignore>How many independent things are narrowing what the display shows — the "(n)" in "Filter by... (n)", and the gate on "Clear all filters". Derived, so it cannot drift from the list it counts.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#method-featurefiltercount) |
| <span id="method-regionhasdata">**regionHasData**</span><br><code>(displayedRegionIndex: number) =&gt; boolean</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#method-regionhasdata) |
| <span id="method-showsubmenucheckboxitems">**showSubmenuCheckboxItems**</span><br><code>() =&gt; MenuItem[]</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#method-showsubmenucheckboxitems) |
| <span id="method-showsubmenuradiogroups">**showSubmenuRadioGroups**</span><br><code>() =&gt; MenuItem[]</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#method-showsubmenuradiogroups) |
| <span id="method-showsubmenumenuitems">**showSubmenuMenuItems**</span><br><code>() =&gt; MenuItem[]</code> | <span data-pagefind-ignore>Flattened "Show..." submenu: all checkbox toggles first, then the radio groups (each under its own subHeader). Composed from the two extension points above so subclasses inject toggles/groups in place without rebuilding trackMenuItems from scratch.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#method-showsubmenumenuitems) |
| <span id="method-colormenuitems">**colorMenuItems**</span><br><code>() =&gt; MenuItem[]</code> | <span data-pagefind-ignore>Color-related track menu entries: a single "Color by..." entry whose "Solid color..." choice opens the solid+UTR color picker. A subclass changing the choices overrides `colorBySubMenuItems` (variants swaps in its consequence-impact and SV-type presets); this wrapper reads that back off `self`, so it is not the seam to override.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#method-colormenuitems) |
| <span id="method-featureheightmenuitems">**featureHeightMenuItems**</span><br><code>() =&gt; MenuItem[]</code> | <span data-pagefind-ignore>One "Feature height" menu with two independent radio groups: the size presets and, under a "Track sizing" subheader, how the track responds when there are more features than fit.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#method-featureheightmenuitems) |
| <span id="method-trackmenuitems">**trackMenuItems**</span><br><code>() =&gt; MenuItem[]</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#method-trackmenuitems) |
| <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-observedmaxdensity">**observedMaxDensity**</span><br><code>(bpPerPx: number) =&gt; number</code> | <span data-pagefind-ignore>Highest features-per-pixel across the visible regions at `bpPerPx`.</span> | [CanvasFeatureGateMixin](../canvasfeaturegatemixin#method-observedmaxdensity) |

## Actions

<!-- prettier-ignore -->
| Member | Description | Defined by |
| --- | --- | --- |
| <span id="action-openfilterdialog">**openFilterDialog**</span><br><code>() =&gt; void</code> |  | LinearVariantDisplay |
| <span id="action-beginymorph">**beginYMorph**</span><br><code>(fromTops: Map&lt;string, number&gt;, fromMaxY: number) =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-beginymorph) |
| <span id="action-setmorphprogress">**setMorphProgress**</span><br><code>(t: number) =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-setmorphprogress) |
| <span id="action-endymorph">**endYMorph**</span><br><code>() =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-endymorph) |
| <span id="action-setrpcdata">**setRpcData**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(displayedRegionIndex: number, data: FeatureDataResult, region:…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(displayedRegionIndex: number, data: FeatureDataResult, region: Region) =&gt; void</code></pre></dialog></span> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-setrpcdata) |
| <span id="action-prunerpcdatamaptovisible">**pruneRpcDataMapToVisible**</span><br><code>(visibleDisplayedRegionIndices: Set&lt;number&gt;) =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-prunerpcdatamaptovisible) |
| <span id="action-startrenderingbackend">**startRenderingBackend**</span><br><code>(backend: CanvasFeatureRenderingBackend) =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-startrenderingbackend) |
| <span id="action-togglepinnedfeature">**togglePinnedFeature**</span><br><code>(featureId: string) =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-togglepinnedfeature) |
| <span id="action-clearpinnedfeatures">**clearPinnedFeatures**</span><br><code>() =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-clearpinnedfeatures) |
| <span id="action-toggleexpandedgene">**toggleExpandedGene**</span><br><code>(featureId: string) =&gt; void</code> | <span data-pagefind-ignore>Open or re-collapse one gene's isoforms, from the badge on its own label. Nothing else has to change: the trim reports what it WOULD hide for a gene in the set as well as for one out of it (see `IsoformTrimPlan.expandedHidden`), so the badge that opened a gene is the badge that closes it again.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-toggleexpandedgene) |
| <span id="action-clearexpandedgenes">**clearExpandedGenes**</span><br><code>() =&gt; void</code> | <span data-pagefind-ignore>Re-collapse every gene opened from a badge.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-clearexpandedgenes) |
| <span id="action-togglesolofeature">**toggleSoloFeature**</span><br><code>(featureId: string) =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-togglesolofeature) |
| <span id="action-applysolo">**applySolo**</span><br><code>() =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-applysolo) |
| <span id="action-solofeature">**soloFeature**</span><br><code>(featureId: string) =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-solofeature) |
| <span id="action-clearsolo">**clearSolo**</span><br><code>() =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-clearsolo) |
| <span id="action-hidefeature">**hideFeature**</span><br><code>(featureId: string) =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-hidefeature) |
| <span id="action-showallhidden">**showAllHidden**</span><br><code>() =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-showallhidden) |
| <span id="action-sethover">**setHover**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(featureId: string &#124; null, subfeatureId: string &#124; null, tooltip…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(featureId: string &#124; null, subfeatureId: string &#124; null, tooltip: string[] &#124; undefined) =&gt; void</code></pre></dialog></span> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-sethover) |
| <span id="action-clearhover">**clearHover**</span><br><code>() =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-clearhover) |
| <span id="action-opencontextmenu">**openContextMenu**</span><br><code>(info: FeatureContextMenuInfo) =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-opencontextmenu) |
| <span id="action-closecontextmenu">**closeContextMenu**</span><br><code>() =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-closecontextmenu) |
| <span id="action-setfeaturehighlights">**setFeatureHighlights**</span><br><code>(highlights: FeatureHighlight[]) =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-setfeaturehighlights) |
| <span id="action-addfeaturehighlightforitem">**addFeatureHighlightForItem**</span><br><code>(target: HighlightTarget, refName: string) =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-addfeaturehighlightforitem) |
| <span id="action-removefeaturehighlightsforid">**removeFeatureHighlightsForId**</span><br><code>(featureId: string) =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-removefeaturehighlightsforid) |
| <span id="action-clearfeaturehighlights">**clearFeatureHighlights**</span><br><code>() =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-clearfeaturehighlights) |
| <span id="action-selectfeature">**selectFeature**</span><br><code>(feature: Feature) =&gt; void</code> | <span data-pagefind-ignore>Open the feature-details widget. The adapter's header metadata (VCF INFO/FORMAT descriptions, etc.) is fetched first and passed as `descriptions` so the widget can label attribute rows and — for the variant widget — resolve the ANN/CSQ column names; without it that table renders headerless. CoreGetMetadata returns null for adapters that expose none, so this is a no-op for those tracks.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-selectfeature) |
| <span id="action-clearselection">**clearSelection**</span><br><code>() =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-clearselection) |
| <span id="action-setshowlabels">**setShowLabels**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(value: "auto" &#124; "description" &#124; "name" &#124; "nameAndDescription"…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(value: "auto" &#124; "description" &#124; "name" &#124; "nameAndDescription" &#124; "none") =&gt; void</code></pre></dialog></span> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-setshowlabels) |
| <span id="action-setjexlfilters">**setJexlFilters**</span><br><code>(filters?: string[] &#124; undefined) =&gt; void</code> | <span data-pagefind-ignore>Sets the runtime filter override (already-`jexl:`-prefixed expressions). Pass undefined to clear it and fall back to the config `jexlFilters` slot.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-setjexlfilters) |
| <span id="action-setshowoutline">**setShowOutline**</span><br><code>(value: boolean) =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-setshowoutline) |
| <span id="action-setfeaturecolor">**setFeatureColor**</span><br><code>(color?: string &#124; undefined) =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-setfeaturecolor) |
| <span id="action-setutrcolor">**setUtrColor**</span><br><code>(color?: string &#124; undefined) =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-setutrcolor) |
| <span id="action-setsequencehoverposition">**setSequenceHoverPosition**</span><br><code>(pos: SequenceHoverPosition &#124; undefined) =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-setsequencehoverposition) |
| <span id="action-setdisplaymode">**setDisplayMode**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(value: "collapsed" &#124; "compact" &#124; "normal" &#124; "superCompact") =&gt;…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(value: "collapsed" &#124; "compact" &#124; "normal" &#124; "superCompact") =&gt; void</code></pre></dialog></span> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-setdisplaymode) |
| <span id="action-opensetcolordialog">**openSetColorDialog**</span><br><code>(showUtrColor?: any) =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-opensetcolordialog) |
| <span id="action-opencolorbyattributedialog">**openColorByAttributeDialog**</span><br><code>() =&gt; void</code> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-opencolorbyattributedialog) |
| <span id="action-fetchfullfeature">**fetchFullFeature**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(featureId: string, displayedRegionIndex: number, opts?: { stop…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(featureId: string, displayedRegionIndex: number, opts?: { stopToken?: StopToken &#124; undefined; statusCallback?: StatusCallback &#124; undefined; }) =&gt; Promise&lt;SimpleFeature &#124; undefined&gt;</code></pre></dialog></span> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-fetchfullfeature) |
| <span id="action-clearallfeaturefilters">**clearAllFeatureFilters**</span><br><code>() =&gt; void</code> | <span data-pagefind-ignore>Reverse every narrowing. Derived from the same list `featureFilterCount` counts, so a subclass that adds one gets both halves at once and the menu cannot offer a recovery that doesn't recover.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-clearallfeaturefilters) |
| <span id="action-selectfeaturebyid">**selectFeatureById**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(featureId: string, subfeatureInfo: SubfeatureInfo &#124; undefined,…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(featureId: string, subfeatureInfo: SubfeatureInfo &#124; undefined, displayedRegionIndex: number) =&gt; void</code></pre></dialog></span> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-selectfeaturebyid) |
| <span id="action-reload">**reload**</span><br><code>() =&gt; void</code> | <span data-pagefind-ignore>Clears the loaded regions and fetches straight away, rather than waiting out `FetchVisibleRegions`' 600ms debounce as the rest of the family does — Retry and Force load are both clicks, and this is the display the user is most often clicking on.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-reload) |
| <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; void</code></pre></dialog></span> |  | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-fetchneeded) |
| <span id="action-clearhoveredfeature">**clearHoveredFeature**</span><br><code>() =&gt; void</code> | <span data-pagefind-ignore>Fills `BaseDisplay`'s hover-clear hook, which the fetch foundation's reaction calls on every viewport change.<br><br>The painting is a sticky canvas, so a pan or zoom under a stationary cursor fires no mousemove and no mouseleave, and the highlight box keeps naming whatever used to be under it.</span> | [LinearCanvasBaseDisplay](../linearcanvasbasedisplay#action-clearhoveredfeature) |
| <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-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-resizeheight">**resizeHeight**</span><br><code>(distance: number) =&gt; number</code> |  | [TrackHeightMixin](../trackheightmixin#action-resizeheight) |
| <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-setheightmode">**setHeightMode**</span><br><code>(mode: "fit" &#124; "fixed" &#124; "grow") =&gt; void</code> | <span data-pagefind-ignore>Set the track-height strategy by writing the unified `heightMode` slot; the modes are mutually exclusive by construction. Entering a non-`fixed` mode drops a leftover scroll offset that the reconfigured height contradicts — neither fit nor grow generally scrolls, and a sticky canvas left at an out-of-range offset paints clipped or blank with no DOM scroll event to resync it. Displays with more transient state to reset super-capture this.</span> | [HeightModeMixin](../heightmodemixin#action-setheightmode) |
| <span id="action-setshowlegend">**setShowLegend**</span><br><code>(arg: boolean) =&gt; void</code> |  | [LegendMixin](../legendmixin#action-setshowlegend) |
| <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-cleardisplayspecificdata">**clearDisplaySpecificData**</span><br><code>() =&gt; void</code> | <span data-pagefind-ignore>no-op base — subclasses override to clear rpcDataMap etc.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#action-cleardisplayspecificdata) |
| <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-setdensitystats">**setDensityStats**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(displayedRegionIndex: number, stats: RegionDensityStats) =&gt; vo…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(displayedRegionIndex: number, stats: RegionDensityStats) =&gt; void</code></pre></dialog></span> |  | [CanvasFeatureGateMixin](../canvasfeaturegatemixin#action-setdensitystats) |
| <span id="action-cleargatemeasurements">**clearGateMeasurements**</span><br><code>() =&gt; void</code> |  | [CanvasFeatureGateMixin](../canvasfeaturegatemixin#action-cleargatemeasurements) |
| <span id="action-commitgatemeasurements">**commitGateMeasurements**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(measurements: RegionGateMeasurement[], issued: GateFetchState)…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(measurements: RegionGateMeasurement[], issued: GateFetchState) =&gt; void</code></pre></dialog></span> | <span data-pagefind-ignore>Commit a batch of per-region fetch results on the density axis, judged by the tier captured at issue. The byte axis is `commitFetchBytes`.</span> | [CanvasFeatureGateMixin](../canvasfeaturegatemixin#action-commitgatemeasurements) |

