# LinearMarkDisplay

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

A display declared in config: a list of bar, point and span marks, each
with an encoding from feature fields to channels, drawn in order over one
score axis from one worker fetch per region.

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

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('LinearMarkDisplay')</code> |  | LinearMarkDisplay |
| <span id="property-configuration">**configuration**</span><br><code>configuration: ConfigurationReference(configSchema)</code> |  | LinearMarkDisplay |
| <span id="property-jexlfilterssetting">**jexlFiltersSetting**</span><br><code>jexlFiltersSetting: types.maybe(types.array(types.string))</code> | The "Filter by..." dialog's override of the `jexlFilters` slot, `jexl:`-prefixed; unset follows the config. | LinearMarkDisplay |
| <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-detailsrotation">**detailsRotation**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>detailsRotation: createStopTokenRotation(self, { statusWindow:…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>detailsRotation: 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> |  | LinearMarkDisplay |
| <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>The per-region store, keyed by `displayedRegionIndex`: what a fetch asked for (the span), what it was issued under (`fetchInputs`) and what it brought back (`payload`), written as one record by `ctx.commitRegion`.<br><br>A display's own `rpcDataMap` was the payload column of this map held separately, and every hook that existed to keep the two in step — `clearDisplaySpecificData`, a `regionHasData` that answered `rpcDataMap.has(idx)`, a hand-rolled prune — was that separation's cost. A display reads the payload back through `regionPayloads`.</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 `gateViewport` key the gate last asked the adapter about, on either axis — the viewport AND the settings it asked under. 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-paintcount">**paintCount**</span><br><code>paintCount: 0</code> | <span data-pagefind-ignore>bumped after every frame the backend painted, so a consumer that reads this display's canvas — the circular view's ring, which copies the strip into a texture — knows when the pixels moved</span> | [RenderLifecycleMixin](../renderlifecyclemixin#volatile-paintcount) |
| <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 every fetch foundation composes, the same argument that put `fetchInert` below; the comparative family carried its own until ADR-105.</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, the one section ADR-105 keeps).<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-coarsetier">**coarseTier**</span><br><code>coarseTier: regionDataMap&lt;P&gt;('coarseTier')</code> | <span data-pagefind-ignore>The coarse payload by `displayedRegionIndex`, over the regions the last read was issued for. Cleared on chromosome navigation.</span> | [CoarseTierMixin](../coarsetiermixin#volatile-coarsetier) |
| <span id="volatile-coarsetierread">**coarseTierRead**</span><br><code>coarseTierRead: undefined as CoarseTierRead &#124; undefined</code> | <span data-pagefind-ignore>What the held payloads were read over — the buffered regions and the read key — so a pan or a zoom inside them re-reads nothing. Undefined until a read lands.</span> | [CoarseTierMixin](../coarsetiermixin#volatile-coarsetierread) |
| <span id="volatile-coarsetierloading">**coarseTierLoading**</span><br><code>coarseTierLoading: false</code> |  | [CoarseTierMixin](../coarsetiermixin#volatile-coarsetierloading) |
| <span id="volatile-dismissedlegendsections">**dismissedLegendSections**</span><br><code>dismissedLegendSections: [] as string[]</code> | <span data-pagefind-ignore>Ids of the scales whose section the reader closed on its own; cleared when the whole legend is shown again. Volatile where `showLegend` is config: which sections a reader collapsed in one sitting is not how the track is configured.</span> | [LegendMixin](../legendmixin#volatile-dismissedlegendsections) |
| <span id="volatile-contextmenuinfo">**contextMenuInfo**</span><br><code>contextMenuInfo: undefined as Info &#124; undefined</code> |  | [ContextMenuMixin](../contextmenumixin#volatile-contextmenuinfo) |
| <span id="volatile-storedhoveredfeature">**storedHoveredFeature**</span><br><code>storedHoveredFeature: undefined as T &#124; undefined</code> |  | [StoredHoverMixin](../storedhovermixin#volatile-storedhoveredfeature) |

## Getters

<!-- prettier-ignore -->
| Member | Description | Defined by |
| --- | --- | --- |
| <span id="getter-gateenabled">**gateEnabled**</span><br><code>boolean</code> | Opt into the byte gate: `CoreEncodeFeatures` measures the index before it downloads, so an over-budget region is refused before a feature is read, and the density tier draws in place of the refused region. | LinearMarkDisplay |
| <span id="getter-conf">**conf**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>ModelInstanceTypeProps&lt;Record&lt;…&gt;&gt; &amp; { setSubschema(slotName: st…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>ModelInstanceTypeProps&lt;Record&lt;…&gt;&gt; &amp; { setSubschema(slotName: string, data: Record&lt;string, unknown&gt;): any; setSlot(slotName: string, value: unknown): void; } &amp; IStateTreeNode&lt;...&gt;</code></pre></dialog></span> | the config typed off the concrete schema | LinearMarkDisplay |
| <span id="getter-prefersoffset">**prefersOffset**</span><br><code>boolean</code> | the track label sits above the plot so the y-axis stays on the edge | LinearMarkDisplay |
| <span id="getter-markshapes">**markShapes**</span><br><code>("bar" &#124; "point" &#124; "span")[]</code> | The declared marks' shapes, in draw order. | LinearMarkDisplay |
| <span id="getter-markentries">**markEntries**</span><br><code>MarkEntry[]</code> | Each mark's shape and zoom range, what the mark list is built from. | LinearMarkDisplay |
| <span id="getter-markview">**markView**</span><br><code>MarkView</code> | The marks at the view's zoom: whether each draws, inside its `minBpPerPx`..`maxBpPerPx` range where 0 is no bound, and the first drawing mark owning each role, -1 where none does. The shared value scale is one declaration and the menu edits it; the config schema refuses a second independent axis; the density sidecar stands in for one mark. | LinearMarkDisplay |
| <span id="getter-independentmarkindex">**independentMarkIndex**</span><br><code>number</code> | The mark reading its own axis, or -1. | LinearMarkDisplay |
| <span id="getter-valuemarkindex">**valueMarkIndex**</span><br><code>number</code> | The mark owning the display's shared value scale, or -1. | LinearMarkDisplay |
| <span id="getter-densitymarkindex">**densityMarkIndex**</span><br><code>number</code> | The mark the density sidecar stands in for, or -1. | LinearMarkDisplay |
| <span id="getter-declaredvaluescale">**declaredValueScale**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>{ scaleType: any; domain: [number &#124; undefined, number &#124; undefin…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>{ scaleType: any; domain: [number &#124; undefined, number &#124; undefined]; } &#124; undefined</code></pre></dialog></span> | `ScoreScaleMixin`'s hook: the scale type and the pinned bounds come off the owning mark's `encoding.y`, so the axis, the ticks and the shapes read one declaration. | LinearMarkDisplay |
| <span id="getter-encodings">**encodings**</span><br><code>MarkEncoding[]</code> | The declared marks' encodings, as the worker takes them. | LinearMarkDisplay |
| <span id="getter-layerrequests">**layerRequests**</span><br><code>LayerRequest[]</code> | The worker request, one layer per mark: its encoding and the lanes its shape reads. | LinearMarkDisplay |
| <span id="getter-origin">**origin**</span><br><code>number</code> |  | LinearMarkDisplay |
| <span id="getter-minwidthpx">**minWidthPx**</span><br><code>number</code> |  | LinearMarkDisplay |
| <span id="getter-configuredfilters">**configuredFilters**</span><br><code>() =&gt; string[]</code> | the `jexlFilters` slot, `jexl:`-prefixed | LinearMarkDisplay |
| <span id="getter-coarsetiermode">**coarseTierMode**</span><br><code>CoarseTierMode</code> | `CoarseTierMixin`'s hook, narrowed: with no mark declaring the sidecar there is nothing to draw the bins as, so the tier neither reads nor stands in and the banner is the answer it always was. | LinearMarkDisplay |
| <span id="getter-coarsetierstandsin">**coarseTierStandsIn**</span><br><code>boolean</code> |  | LinearMarkDisplay |
| <span id="getter-densitypayloads">**densityPayloads**</span><br><code>ReadonlyMap&lt;number, MarkRegionData&gt;</code> | The tier's bins as this display's own payload: the density mark's layer built from the sidecar's intervals, every other mark empty. Keyed off `coarseTier`, which moves once per read. | LinearMarkDisplay |
| <span id="getter-rpcdatamap">**rpcDataMap**</span><br><code>ReadonlyMap&lt;number, MarkRegionData&gt;</code> | The layers the display draws, keyed by displayedRegionIndex: the foundation's per-region store, or the density tier's bins where the gate refused the features and a mark declared the sidecar. One map, so the domain, the legend, the hover, the highlight and the SVG export read the tier through the paths they already had. | LinearMarkDisplay |
| <span id="getter-marklist">**markList**</span><br><code>DisplayMark[]</code> | The mark list the shapes declare — one `defineMark` per config entry, reading `layers[i]`, off outside its zoom range. Recomputed only when the entries move, so the component can key its backend factory on it. | LinearMarkDisplay |
| <span id="getter-visibleshapes">**visibleShapes**</span><br><code>("bar" &#124; "point" &#124; "span")[]</code> | The shapes drawing at the view's zoom. | LinearMarkDisplay |
| <span id="getter-hasbarmark">**hasBarMark**</span><br><code>boolean</code> |  | LinearMarkDisplay |
| <span id="getter-haspointmark">**hasPointMark**</span><br><code>boolean</code> |  | LinearMarkDisplay |
| <span id="getter-activefilters">**activeFilters**</span><br><code>string[]</code> | the filters actually applied, `jexl:`-prefixed | LinearMarkDisplay |
| <span id="getter-sharedmarkindices">**sharedMarkIndices**</span><br><code>number[]</code> | The marks folded into the shared y domain: those drawing at this zoom, less the one reading its own axis. | LinearMarkDisplay |
| <span id="getter-domain">**domain**</span><br><code>[number, number] &#124; undefined</code> | nice-rounded [min, max] over the visible regions' shipped extremes, widened to the origin whenever a bar mark draws, or undefined before any shared valued mark loads | LinearMarkDisplay |
| <span id="getter-independentvaluescale">**independentValueScale**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>{ domain: [number, number]; scaleType: string; field: string; }…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>{ domain: [number, number]; scaleType: string; field: string; } &#124; undefined</code></pre></dialog></span> | The independent mark's own scale, folded from its layers alone and pinned by its own `encoding.y.domain`: what the right-hand axis and that mark's shapes read. | LinearMarkDisplay |
| <span id="getter-valuescales">**valueScales**</span><br><code>ValueScale[]</code> | The y scale the chrome draws the axis from — the declared `encoding.y`, resolved: its type, and its domain autoscaled where it pins nothing. The shapes read the same pair. | LinearMarkDisplay |
| <span id="getter-rowcount">**rowCount**</span><br><code>number</code> | bands a span stacks into: the highest `row` any loaded layer carries, plus one | LinearMarkDisplay |
| <span id="getter-colorramps">**colorRamps**</span><br><code>(MarkRamp &#124; undefined)[]</code> | Each mark's quantitative colour scale: the ramp its regions carry, over the domain the legend already unioned across them. A pan that widens it writes one uniform and uploads no instance bytes, which is what resolving the ramp here rather than per region buys. | LinearMarkDisplay |
| <span id="getter-renderstate">**renderState**</span><br><code>MarkRenderState</code> | geometry and scale for the plot canvas, the same box the hit test measures in | LinearMarkDisplay |
| <span id="getter-hoverink">**hoverInk**</span><br><code>HighlightRect[]</code> | The box the hovered instance painted, for the chrome's highlight; the context menu's hit stands in while a menu is open. In the chrome's px, so the plot's inset is added to the canvas box. | LinearMarkDisplay |
| <span id="getter-densitystandinnotice">**densityStandInNotice**</span><br><code>string &#124; undefined</code> | The corner notice while the sidecar stands in, naming what is drawn and how many marks are not: past the budget the banner is gone, and nothing else on screen says the bars are the sidecar's. | LinearMarkDisplay |
| <span id="getter-skippedfeatures">**skippedFeatures**</span><br><code>SkippedFeatures</code> | What the worker left out of the loaded regions — a feature whose `y` field read as missing or not a number — for the corner notice. | LinearMarkDisplay |
| <span id="getter-legendsections">**legendSections**</span><br><code>MarkLegendSection[]</code> | the colour keys the loaded regions carry, one per scaled mark drawing at the view's zoom | LinearMarkDisplay |
| <span id="getter-colorscales">**colorScales**</span><br><code>ColorScale[]</code> | `LegendMixin`'s hook: the keys as color scales, so the chrome and the export draw the legend off the tables the worker resolved | LinearMarkDisplay |
| <span id="getter-parenttrack">**parentTrack**</span><br><code>AbstractTrackModel</code> |  | [BaseDisplay](../basedisplay#getter-parenttrack) |
| <span id="getter-renderingcomponent">**RenderingComponent**</span><br><code>FC&lt;…&gt;</code> |  | [BaseDisplay](../basedisplay#getter-renderingcomponent) |
| <span id="getter-displayblurb">**DisplayBlurb**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>FC&lt;{ model: ModelInstanceTypeProps&lt;{ id: IOptionalIType&lt;ISimple…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>FC&lt;{ model: ModelInstanceTypeProps&lt;{ id: IOptionalIType&lt;ISimpleType&lt;string&gt;, [undefined]&gt;; type: ISimpleType&lt;string&gt;; }&gt; &amp; { ...; } &amp; { ...; } &amp; IStateTreeNode&lt;...&gt;; }&gt; &#124; null</code></pre></dialog></span> |  | [BaseDisplay](../basedisplay#getter-displayblurb) |
| <span id="getter-adapterconfig">**adapterConfig**</span><br><code>Record&lt;string, unknown&gt;</code> |  | [BaseDisplay](../basedisplay#getter-adapterconfig) |
| <span id="getter-isminimized">**isMinimized**</span><br><code>boolean</code> | <span data-pagefind-ignore>Returns true if the parent track is minimized. Used to skip expensive operations like autoruns when track is not visible.</span> | [BaseDisplay](../basedisplay#getter-isminimized) |
| <span id="getter-hoveredfeature">**hoveredFeature**</span><br><code>unknown</code> | <span data-pagefind-ignore>Overridable hook (default `undefined`): what the pointer is currently over, for readers **outside** the display. `LinearGenomeViewContainer` publishes it to `session.hovered`, the view-wide "what is the user pointing at" channel a plugin can subscribe to.<br><br>Declared here because a cross-display consumer can only read a name the base declares — the same reason `FetchMixin.fetchInert` is a hook rather than a getter each display invents. The container used to read `featureUnderMouse`, which only the wiggle, alignments and Manhattan families spelled that way — canvas said `hoveredFeature`, variants `hoveredGenotype` — so the channel carried a hover from a third of the display types and nothing said which. It also asked only `displays[0]` of each track.<br><br>`unknown` because the payload genuinely differs — a read, a wiggle bin, a SNP, a genotype cell — and `session.hovered` is typed to match ("can be anything; code that wants to deal with this should examine it"). Narrow it in the override.</span> | [BaseDisplay](../basedisplay#getter-hoveredfeature) |
| <span id="getter-featurenoun">**featureNoun**</span><br><code>string</code> | <span data-pagefind-ignore>Overridable hook (default `'feature'`): the SINGULAR word for one of the things this display draws, as a menu row or a chip says it — "Hide this read", "Showing 3 variants".<br><br>Declared here for the same reason as `hoveredFeature` above: it is read across the display boundary, by chrome that has no idea which display it is drawing for (`SoloSelectionChip`, alignments' group-label overlay), and a name only the base declares is a name every such consumer can rely on. Two displays declared it independently and one of those declarations WAS this default.<br><br>**A control keeps the generic word; content takes this one.** "Variant height" reads as a different setting from "Feature height" when it is the same one, so the shared menus stay on "feature" however the display answers here, and the noun varies where it names what the user is looking at — "Showing 3 variants", "Hide this read". A display drawing something the generic word already fits is right to leave this alone.<br><br>Distinct from the per-hit noun a context menu takes off the clicked item's own `type` ("mRNA", "gene"); that names one annotation, this names what the track holds. The hit noun falls back to this.</span> | [BaseDisplay](../basedisplay#getter-featurenoun) |
| <span id="getter-featurewidgettype">**featureWidgetType**</span><br><code>{ type: string; id: string; }</code> | <span data-pagefind-ignore>The widget `openFeatureWidget` opens for one of this display's features. Displays may override it. The default is the generic feature widget, for displays drawing plain features.<br><br>Displays whose features are a specific kind (a read, a variant, a synteny block) override it, including the `id`: two displays naming one id share the drawer panel, which suits two displays showing the same kind of feature.</span> | [BaseDisplay](../basedisplay#getter-featurewidgettype) |
| <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. This getter reads it so that a display that did opt in has `self.resizing`.</span> | [TrackHeightMixin](../trackheightmixin#getter-resizing) |
| <span id="getter-scrollcontentheight">**scrollContentHeight**</span><br><code>number</code> | <span data-pagefind-ignore>Overridable hook: the height of the content that scrolls, in px.</span> | [TrackHeightMixin](../trackheightmixin#getter-scrollcontentheight) |
| <span id="getter-scrollviewportheight">**scrollViewportHeight**</span><br><code>number</code> | <span data-pagefind-ignore>Overridable hook: the height of the window it scrolls behind, in px.</span> | [TrackHeightMixin](../trackheightmixin#getter-scrollviewportheight) |
| <span id="getter-scrollableheight">**scrollableHeight**</span><br><code>number</code> | <span data-pagefind-ignore>How far the content scrolls. A sub-pixel overflow is 0: a fit mode that divides the viewport across n rows multiplies back to a few ULPs over it, and an extent of 1e-14px still draws a scrollbar and holds the wheel away from the page.</span> | [TrackHeightMixin](../trackheightmixin#getter-scrollableheight) |
| <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-settledsubpixelbinbp">**settledSubPixelBinBp**</span><br><code>number</code> | <span data-pagefind-ignore>Genomic bp one cell of a per-base pass stands for at the settled zoom: `subPixelBinBp` off the host's debounced `coarseBpPerPx`, and 1 until the view initializes. A per-base encode or fetch reads this rather than the live zoom so a wheel tick does not redo every region.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-settledsubpixelbinbp) |
| <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-renderscanvas">**rendersCanvas**</span><br><code>boolean</code> | <span data-pagefind-ignore>Fills `RenderLifecycleMixin`'s hook off `fetchInert`, as `GlobalFetchMixin` does: a display that will never fetch here shows a placeholder where its canvas would be.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-renderscanvas) |
| <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 and `dataSuperseded`, never `isCacheValid`: a phase that went `loading` on a moved `fetchInputs` 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-fetchsuspended">**fetchSuspended**</span><br><code>boolean</code> | <span data-pagefind-ignore>Overridable hook (default false), read by the fetch plan: the display is drawing something in the features' place and wants no fetch while it does. `DensityTierMixin` says it while the band is up and the gate is not blocking, so a track forced to `density` never downloads the features it will not draw, while a refused viewport keeps its measurement pass and the gate can still release.<br><br>Not `fetchInert`: that one suppresses the scrim and ends the export wait, and a display saying this still has its stand-in to load. On this foundation alone, because only this family's plan reads it.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-fetchsuspended) |
| <span id="getter-layoutready">**layoutReady**</span><br><code>boolean</code> | <span data-pagefind-ignore>Overridable hook (default false): whether a searchable feature layout currently exists. Any display defining a feature-lookup method (`searchFeatureByID`) must override it, so callers can tell "laid out, but off-display" from "no layout exists yet" — a distinction only the display can make. See packages/display-kit/CLAUDE.md §"Four readiness axes".</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-layoutready) |
| <span id="getter-zoomfetchkey">**zoomFetchKey**</span><br><code>string</code> | <span data-pagefind-ignore>Overridable hook (default `''`): the zoom-dependent term of what a fetch issued right now would produce for a region — the one axis of the fetch key the display supplies, where the settings and adapter axes are the mixin's (`fetchInputs` below). Wiggle returns `String(view.bpPerPx)` (adr-008), canvas the peptide-overlay threshold, the variant matrix its zoom in matrix mode only, alignments its per-base sampling bin.<br><br>Here and NOT in `rpcProps()`: a zoom-swinging value in the RPC payload runs `SettingsInvalidate` on every crossing — the in-flight fetch superseded, the scrim raised over the held data, and the display blanked where it drops settings-baked data — see REGION_TOO_LARGE.md §"How the verdict is built" — where a key term marks the held regions stale and lets them draw, unscrimmed, until the refetch lands.<br><br>A getter, so the observables it reads register as dependencies of `FetchVisibleRegions`; MobX runs an action untracked and the autorun would keep a stale answer.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-zoomfetchkey) |
| <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 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>Both answers a display gives about being finished read it — the export gate through `dataCurrent`, the loading scrim through `displayPhase`. The export gate is the sharper case: `awaitSvgReady` samples freshness once, and an export that samples it inside this window renders the data that is about to be replaced. GWAS's LD auto-index is that 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 — and `SettingsInvalidate` lands a tick after the write, so until it does not even `staleSettingsDrawn` has seen it.<br><br>The window is NOT invisible on screen, which this used to say while `displayPhase` took a spatial-only argument: alignments' per-base wall spends the debounce plus the RPC painting a 1 px stripe every 8 px, with nothing in the key having moved yet.<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-fetchinputs">**fetchInputs**</span><br><code>FetchInputs</code> | <span data-pagefind-ignore>What a fetch issued right now would stamp on a region: the settings tier (`rpcProps()` and the adapter config) and the zoom tier (the display's `zoomFetchArgs()` object, or its `zoomFetchKey` string where it has not been converted). `fetchRegions` captures it before the RPC goes out and stamps it beside the loaded region; `isCacheValid` compares against it.<br><br>A **value**, not a string. The inputs already exist as the object the display sends the worker, so a second serialized spelling of them is one more thing to keep in step — and `JSON.stringify`, which was that spelling, cannot tell an `undefined`-valued field from an absent one.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-fetchinputs) |
| <span id="getter-settingsfetchinputs">**settingsFetchInputs**</span><br><code>unknown</code> | <span data-pagefind-ignore>The settings tier alone, which `staleSettingsDrawn` compares: the scrim goes up on a settings or adapter change and stays down on a zoom.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-settingsfetchinputs) |
| <span id="getter-regionpayloads">**regionPayloads**</span><br><code>ReadonlyMap&lt;number, unknown&gt;</code> | <span data-pagefind-ignore>The store's payloads, keyed by `displayedRegionIndex`. A display narrows this once — `get rpcDataMap() { return self.regionPayloads as ReadonlyMap<number, MyResult> }` — and every reader it already had goes on reading a map.<br><br>MST makes a `.views()` getter a computed, so the Map is built once per store change and handed back by reference after that — which is what keeps `installUpload`'s diff a reference compare per key and a frame that changed no data free of it. **While something observes it**: MobX suspends an unobserved computed and rebuilds on every read, so a display whose only reader is a pointer handler needs the keep-alive canvas and Manhattan both install (display-kit/CLAUDE.md §"A hit test's index needs an observer"). The render lifecycle's upload autorun is that reader for every display that draws.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-regionpayloads) |
| <span id="getter-hasregiondata">**hasRegionData**</span><br><code>boolean</code> | <span data-pagefind-ignore>A fetch has landed: at least one region's payload is in the store. The render callback's first-paint gate reads this, so an empty frame before any data cannot flip `canvasDrawn`; an empty but loaded region counts, and paints its empty frame.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-hasregiondata) |
| <span id="getter-stalesettingsdrawn">**staleSettingsDrawn**</span><br><code>boolean</code> | <span data-pagefind-ignore>A visible block's held data was fetched under a settings or adapter key that has since moved: drawn, and wrong for the current settings, until the refetch `isCacheValid` already owes lands. The loading scrim's third staleness term, beside spatial coverage and `dataSuperseded` — the one that used to come from `SettingsInvalidate` emptying the coverage map, and the reason it no longer has to.<br><br>False on a zoom by construction: `LoadedRegion.settingsKey` is the key minus its zoom axis, so a moved `zoomFetchKey` raises no scrim. That is the whole distance from the declined fold, which compared the whole key and put the overlay 250 ms into every zoom.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-stalesettingsdrawn) |
| <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 a multi-region/whole-genome export waits on this getter to be complete; waiting on the first datum to arrive would export a partial set.<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 `fetchInputs` 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` takes `dataSuperseded` but NOT this term: folding a moved `fetchInputs` into the phase raises the loading scrim into every zoom, which is the trade 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>Read off the first LOADED region rather than the view's displayed ones, and defined here for that reason: 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. Returning `undefined` until the aliases load forces the caller to write its fallback.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-loadedassembly) |
| <span id="getter-phaseviewportcurrent">**phaseViewportCurrent**</span><br><code>boolean</code> | <span data-pagefind-ignore>The loading scrim's staleness argument: what is drawn answers for what is on screen. Spatial coverage, `dataSuperseded` and `staleSettingsDrawn`; NOT `isCacheValid`, which is `dataCurrent`'s and would scrim every zoom. `displayPhase` reads it, and so does a stand-in phase (`coarseTierDisplayPhase`) — one predicate, so a term added here reaches both.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-phaseviewportcurrent) |
| <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-paintsuperseded">**paintSuperseded**</span><br><code>boolean</code> | <span data-pagefind-ignore>Fills `RenderLifecycleMixin`'s hook with `staleSettingsDrawn`, so `painted` — and `data-display-drawn` through it — reads pending over a canvas painted under the previous settings until the refetch lands. `clearAllRpcData` used to reset `canvasDrawn` for the same effect; the hook says it without blanking anything.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#getter-paintsuperseded) |
| <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 `computeActivityPhase` reaches all three without being wired three times.<br><br>This family's argument is `phaseViewportCurrent`: spatial coverage AND `dataSuperseded` (data a settled fetch-input change is drawing wrong right now — alignments zooming perBaseLetter from 16 bp/px to 1 stays inside the loaded region and reported `ready` over a wall drawn as a 1 px stripe every 8 px) AND `staleSettingsDrawn`.<br><br>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-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 &#124; undefined</code> | <span data-pagefind-ignore>The display's `fetchSizeLimit` slot, from `regionTooLargeConfigSchemaFields`. `number \| undefined`, because `getConf` answers `undefined` for a slot a composing display's schema never declared and typing it `number` hid the whole failure — `resolveByteLimit` falls back closed, and says why.</span> | [RegionTooLargeMixin](../regiontoolargemixin#getter-configuredfetchsizelimit) |
| <span id="getter-densitytoolarge">**densityTooLarge**</span><br><code>boolean</code> | <span data-pagefind-ignore>The density axis's verdict, and the whole of that axis's opt-in: `CanvasFeatureGateMixin` overrides it beside the measurement that fills it, and a byte-only display leaves it false.</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 **and the settings it would be taken under**. 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, so the stamp names the settings the worker actually counted under.<br><br>The settings term is `rpcPropsCacheKey`, the axis both families already invalidate data on. It belongs in the measurement because the worker's density probe counts ADMITTED features (`densityGate`'s `admit`), so a filter admitting almost nothing is a different measurement of the same viewport — and while staleness was viewport-only, the main thread never went back to ask. The byte axis is an index read no `rpcProps` field can move; the rule is one rule rather than one per axis.</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 still describes what a fetch issued now would ask: the viewport on screen, under the settings on screen. True before any measurement. The triple's third term, the adapter tier, is not here — a tier swap drops the measurement outright (`ClearByteEstimateOnNavOrTierSwap`) rather than marking it stale.</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>Whether the density axis may act: `gateActive`, and the span is above the floor — the one axis the floor applies to. Whether it has anything to say is `densityTooLarge`.</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-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 reporting it unfinished leaves every waiter on it waiting forever.<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 run to its full timeout, and that wait swallows its own timeout without reporting it. `fetchInert` on the comparative side has the same problem: the forgotten reader 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. `paintSuperseded` is the fourth, and the one that subtracts: a canvas painted from data a settings change has made wrong is drawn and not finished. See both hooks.</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: what a hover gate wants, since neither state has a frame on screen that a hit describes. Not a phase input — `computeActivityPhase` reads the two apart, because a cancel is finished (`canceled`) where a fetch is not (`loading`).</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 has three readers.** A display that gains such a state declares it once, which covers the reader it would otherwise forget, always the one outside the display:<br><br>- the phase (`computeActivityPhase`), which otherwise parks a scrim over the placeholder, or a canceled overlay once Cancel is clicked; - the SVG export (`computeSvgReady`'s `extraTerminal`), whose `awaitSvgReady` is an unbounded `when`, so one such display hangs the whole view's export; - the retry contract check (`makeRetryContractCheck`), which would otherwise report a dead Retry on a display correctly declining to load anything.<br><br>`fetchInert` replaces 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 the global family hard-coded one of the three to `false` for a while, so LD could express only half its state. All three fetch families declare it here since the comparative one composed this mixin (ADR-105), so the retry check reads one field everywhere. ADR-082.<br><br>A hook rather than a `displayPhase` override, because overriding the getter means restating the whole loading condition. Sequence held a verbatim copy of the other terms that way, and a copy misses any term added to the condition later.<br><br>`fetchInert` 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 retry contract 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 set it, one per fetch foundation, so 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. No run is then ever judged, which exempts the display from the check. HiC does this 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-awaitingdependentdata">**awaitingDependentData**</span><br><code>boolean</code> | <span data-pagefind-ignore>Overridable hook (default false), read by `computeActivityPhase`: a load this display depends on beyond its primary fetch has not landed for the first time, so the frame the primary fetch calls current is still missing something. Multi-way synteny sets it until its lane genes and lane links first arrive, so an export or a capture never lands between the ortholog fetch and the gene models that fill the lanes.<br><br>A hook rather than a `displayPhase` override, for the reason `fetchInert` is one: that display carried the override, restating the foundation's two arguments verbatim to append one term, and a copy like that misses any term added to the foundation later.<br><br>Not `dataSuperseded`, which holds the export through every later refetch too: a display saying this wants the scrim on the first landing only, since later lane fetches redraw over lanes already on screen.</span> | [FetchMixin](../fetchmixin#getter-awaitingdependentdata) |
| <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` documents why, including why a field whose distinct states serialize identically never invalidates anything.<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-adapterconfigkey">**adapterConfigKey**</span><br><code>string</code> | <span data-pagefind-ignore>The adapter axis of the same key, watched by the same two readers as `rpcPropsCacheKey`: `SettingsInvalidate` per-region and the global family's `currentFetchKey`. A track re-pointed in the config editor is a different fetch, and until 2026-09 only the comparative family said so.</span> | [FetchMixin](../fetchmixin#getter-adapterconfigkey) |
| <span id="getter-coarseadapterslot">**coarseAdapterSlot**</span><br><code>string</code> |  | [DensityTierMixin](../densitytiermixin#getter-coarseadapterslot) |
| <span id="getter-densitytiermode">**densityTierMode**</span><br><code>"auto" &#124; "density" &#124; "features"</code> | <span data-pagefind-ignore>The `densityTier` slot's value.</span> | [DensityTierMixin](../densitytiermixin#getter-densitytiermode) |
| <span id="getter-densitytierthresholdbpperpx">**densityTierThresholdBpPerPx**</span><br><code>number</code> |  | [DensityTierMixin](../densitytiermixin#getter-densitytierthresholdbpperpx) |
| <span id="getter-coarsetierpastthreshold">**coarseTierPastThreshold**</span><br><code>boolean</code> | <span data-pagefind-ignore>`auto` also swaps from the `densityTierBpPerPx` slot outward, where a track asks for the band before the region is too large to fetch.</span> | [DensityTierMixin](../densitytiermixin#getter-coarsetierpastthreshold) |
| <span id="getter-coarsereadkey">**coarseReadKey**</span><br><code>string</code> | <span data-pagefind-ignore>The bins are read at the view's bp/px, so a real zoom re-reads at the level the sidecar keeps for it and a small one reuses what is held.</span> | [DensityTierMixin](../densitytiermixin#getter-coarsereadkey) |
| <span id="getter-coarsetiergated">**coarseTierGated**</span><br><code>boolean</code> | <span data-pagefind-ignore>Overridable hook (default false): the coarse read is a feature download the byte gate has to measure. The gate then measures the coarse adapter while the tier is up, its refusal is the banner, the detail fetch stands down outright since the coarse read is the measurement pass, and the swap is by threshold alone — the verdict is about whichever tier is up, so it cannot also pick the tier. A read bounded by construction (bins per screen pixel) leaves this off.</span> | [CoarseTierMixin](../coarsetiermixin#getter-coarsetiergated) |
| <span id="getter-coarsesourceconfig">**coarseSourceConfig**</span><br><code>unknown</code> | <span data-pagefind-ignore>The coarse source's config, read off the live track config so a re-pointed adapter follows.</span> | [CoarseTierMixin](../coarsetiermixin#getter-coarsesourceconfig) |
| <span id="getter-hascoarsesource">**hasCoarseSource**</span><br><code>boolean</code> |  | [CoarseTierMixin](../coarsetiermixin#getter-hascoarsesource) |
| <span id="getter-coarsetieractive">**coarseTierActive**</span><br><code>boolean</code> | <span data-pagefind-ignore>Whether the coarse tier stands in for the detail right now.</span> | [CoarseTierMixin](../coarsetiermixin#getter-coarsetieractive) |
| <span id="getter-gatemeasurescoarse">**gateMeasuresCoarse**</span><br><code>boolean</code> | <span data-pagefind-ignore>The byte gate is measuring the coarse read rather than the detail fetch, so its verdict is about the tier on screen.</span> | [CoarseTierMixin](../coarsetiermixin#getter-gatemeasurescoarse) |
| <span id="getter-gaterefusesdetail">**gateRefusesDetail**</span><br><code>boolean</code> | <span data-pagefind-ignore>The gate's refusal is about the detail fetch, so that fetch owes the re-measure the gate releases through.</span> | [CoarseTierMixin](../coarsetiermixin#getter-gaterefusesdetail) |
| <span id="getter-coarsetierissuekey">**coarseTierIssueKey**</span><br><code>string</code> | <span data-pagefind-ignore>The whole key a read is held under: the coarse adapter and the display's own term.</span> | [CoarseTierMixin](../coarsetiermixin#getter-coarsetierissuekey) |
| <span id="getter-drawswhentoolarge">**drawsWhenTooLarge**</span><br><code>boolean</code> | <span data-pagefind-ignore>`renderDisplaySvg`'s hook: the export paints the tier in place of the too-large note, the same swap the chrome makes on screen — unless the note is about the coarse read itself.</span> | [CoarseTierMixin](../coarsetiermixin#getter-drawswhentoolarge) |
| <span id="getter-scatterpointsize">**scatterPointSize**</span><br><code>number</code> |  | [WiggleScoreConfigMixin](../wigglescoreconfigmixin#getter-scatterpointsize) |
| <span id="getter-displaycrosshatches">**displayCrossHatches**</span><br><code>boolean</code> | <span data-pagefind-ignore>The configured cross-hatch setting the menu toggles; `showCrossHatches` is what draws.</span> | [WiggleScoreConfigMixin](../wigglescoreconfigmixin#getter-displaycrosshatches) |
| <span id="getter-isdensitymode">**isDensityMode**</span><br><code>boolean</code> | <span data-pagefind-ignore>Whether score maps to color instead of height; a display overrides it.</span> | [WiggleScoreConfigMixin](../wigglescoreconfigmixin#getter-isdensitymode) |
| <span id="getter-showcrosshatches">**showCrossHatches**</span><br><code>boolean</code> | <span data-pagefind-ignore>Whether the score-axis cross hatches draw: never in density mode, which has no height axis to rule and no toggle in its menu.</span> | [WiggleScoreConfigMixin](../wigglescoreconfigmixin#getter-showcrosshatches) |
| <span id="getter-scaletype">**scaleType**</span><br><code>string</code> |  | [ScoreScaleMixin](../scorescalemixin#getter-scaletype) |
| <span id="getter-autoscaletype">**autoscaleType**</span><br><code>string</code> |  | [ScoreScaleMixin](../scorescalemixin#getter-autoscaletype) |
| <span id="getter-numstddev">**numStdDev**</span><br><code>number</code> |  | [ScoreScaleMixin](../scorescalemixin#getter-numstddev) |
| <span id="getter-minscore">**minScore**</span><br><code>number</code> | <span data-pagefind-ignore>Raw slot value, sentinel intact — see the class comment.</span> | [ScoreScaleMixin](../scorescalemixin#getter-minscore) |
| <span id="getter-maxscore">**maxScore**</span><br><code>number</code> | <span data-pagefind-ignore>Raw slot value, sentinel intact — see the class comment.</span> | [ScoreScaleMixin](../scorescalemixin#getter-maxscore) |
| <span id="getter-defaultscoredomain">**defaultScoreDomain**</span><br><code>[number &#124; undefined, number &#124; undefined]</code> | <span data-pagefind-ignore>Overridable hook: what each end of the domain falls back to where the config leaves its bound unset. `[undefined, undefined]` — the default — means autoscale both ends, which is right for a track whose scores have no absolute meaning (a bigwig's units are its own).<br><br>A display whose scores are bounded *by construction* overrides it, so the axis stops being a function of what happens to be on screen: GC content is a fraction, so 0 and 1 are its real limits and mean the same thing at every locus. Autoscaled, the same GC value drew at different heights depending on where the user had panned, and the track could not be read across loci.<br><br>A hook rather than a config default because the answer can depend on display state — GC's does, on `gcMode` — and rather than each display re-resolving the sentinels below, which is the one thing that must not be duplicated: config bounds still win, precisely because they are checked before this is consulted.</span> | [ScoreScaleMixin](../scorescalemixin#getter-defaultscoredomain) |
| <span id="getter-manualminscore">**manualMinScore**</span><br><code>number &#124; undefined</code> | <span data-pagefind-ignore>The lower bound the config really sets, `undefined` at the sentinel.</span> | [ScoreScaleMixin](../scorescalemixin#getter-manualminscore) |
| <span id="getter-manualmaxscore">**manualMaxScore**</span><br><code>number &#124; undefined</code> | <span data-pagefind-ignore>The upper bound the config really sets, `undefined` at the sentinel.</span> | [ScoreScaleMixin](../scorescalemixin#getter-manualmaxscore) |
| <span id="getter-minscorebound">**minScoreBound**</span><br><code>number &#124; undefined</code> | <span data-pagefind-ignore>Resolved lower bound; `undefined` means autoscale this end.</span> | [ScoreScaleMixin](../scorescalemixin#getter-minscorebound) |
| <span id="getter-maxscorebound">**maxScoreBound**</span><br><code>number &#124; undefined</code> | <span data-pagefind-ignore>Resolved upper bound; `undefined` means autoscale this end.</span> | [ScoreScaleMixin](../scorescalemixin#getter-maxscorebound) |
| <span id="getter-hasmanualscorebounds">**hasManualScoreBounds**</span><br><code>boolean</code> | <span data-pagefind-ignore>Whether the user has pinned either end, which is a different question from whether either end resolved to a number: `defaultScoreDomain` fills the sentinels in, so a GC content track answers yes to the second with nothing configured. The score menu asks this one — it gates the "Clear manual min/max" row, and a Clear that writes the sentinels already there is a row that does nothing and never goes away.</span> | [ScoreScaleMixin](../scorescalemixin#getter-hasmanualscorebounds) |
| <span id="getter-axes">**axes**</span><br><code>YAxis[]</code> | <span data-pagefind-ignore>The axes, one per declared scale whose domain resolved: where each tick lands in the band's own pixel space, through `computeYTicks` unless the scale brought its own ladder.</span> | [ScoreScaleMixin](../scorescalemixin#getter-axes) |
| <span id="getter-showlegend">**showLegend**</span><br><code>boolean</code> | <span data-pagefind-ignore>Whether the legend is drawn.</span> | [LegendMixin](../legendmixin#getter-showlegend) |
| <span id="getter-legendtop">**legendTop**</span><br><code>number</code> | <span data-pagefind-ignore>Overridable hook (default 0): px the on-screen key is pushed down from its own inset. A display that already draws a control of its own in that corner — Hi-C's resolution box — answers that control's height; the chrome adds its own axis captions on top. The export draws no controls, so it does not read this.</span> | [LegendMixin](../legendmixin#getter-legendtop) |
| <span id="getter-legendspec">**legendSpec**</span><br><code>LegendSpec</code> | <span data-pagefind-ignore>The key, derived from `colorScales` less the sections the reader dismissed. `DisplayChrome` renders it on screen and `renderDisplaySvg` flattens it for the export, so the two describe one set of colors.</span> | [LegendMixin](../legendmixin#getter-legendspec) |
| <span id="getter-haslegendkey">**hasLegendKey**</span><br><code>boolean</code> | <span data-pagefind-ignore>Whether the display has a key at all. The "Show legend" row is offered only when it does. Overridable for a display whose key is only waiting for data: a scale that stays empty until a region lands must not remove the toggle in the meantime.</span> | [LegendMixin](../legendmixin#getter-haslegendkey) |

## Methods

<!-- prettier-ignore -->
| Member | Description | Defined by |
| --- | --- | --- |
| <span id="method-markdomain">**markDomain**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(indices: readonly number[], bounds: readonly [number &#124; undefin…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(indices: readonly number[], bounds: readonly [number &#124; undefined, number &#124; undefined], scaleType: string) =&gt; [number, number] &#124; undefined</code></pre></dialog></span> | The nice-rounded [min, max] the marks in `indices` fold to over the visible regions' shipped extremes, widened to the origin where one of them is a bar, or undefined before any of them loads a value. | LinearMarkDisplay |
| <span id="method-rpcprops">**rpcProps**</span><br><code>() =&gt; { layers: LayerRequest[]; transform: TransformStep[]; }</code> | the fetch inputs SettingsInvalidate watches: each mark's encoding and lanes, and the filters as transform steps, all evaluated in the worker | LinearMarkDisplay |
| <span id="method-trackmenuitems">**trackMenuItems**</span><br><code>() =&gt; MenuItem[]</code> |  | LinearMarkDisplay |
| <span id="method-contextmenuitems">**contextMenuItems**</span><br><code>() =&gt; MenuItem[]</code> |  | LinearMarkDisplay |
| <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-regionhasdata">**regionHasData**</span><br><code>(displayedRegionIndex: number) =&gt; boolean</code> | <span data-pagefind-ignore>Overridable hook, and the converted form of `zoomFetchKey` above: the zoom-derived worker arguments as an **object**, which the display spreads into its own RPC call and the foundation stamps beside every region the call loads. A display that fills this leaves `zoomFetchKey` alone; the foundation prefers this when it exists.<br><br>The key and the argument are the same fact, and declaring them separately lets them disagree. A `zoomFetchKey` that reads no observable is memoized for the display's life while the call goes on sending a live value, and a key naming a threshold while the call sends the mode behind it marks the data stale on a crossing the worker never sees.<br><br>Looked up dynamically rather than declared, so a display keeps its narrow return type through MST's `.views()` chain — the same reason `rpcProps` is not declared here. Overridable hook: whether the display can actually draw what this region is marked loaded over.<br><br>The default answers off the store — an entry a fetch committed carries what it stored — so "marked loaded with nothing behind it" is a state only a hand-written `setLoadedRegion` reaches. It used to be `true`, and the base canvas display overrode it with `rpcDataMap.has(idx)` to get this answer back.<br><br>What survives an override is the question the store cannot answer: **which of several held payloads answers**. MAF caches a summary tier and a detail tier side by side under one `displayedRegionIndex`, so crossing the threshold inside an already-loaded region changes which map has to answer — something neither the coverage bounds nor one payload slot can see. A key would refetch the summary on every zoom back out, since both tiers are still held. The multi-row display's override survives for its second half, the auto-partition reconciliation (`regionHasPinnedData`).<br><br>**What the old fail-open default was protecting is now explicit.** A byte-gate refusal never commits at all, so it is unreachable either way. The case that mattered is sequence's legitimately-empty region, which stamped without storing and which a store-derived default would have refetched forever — and a commit is a payload now, the empty record, so it stays terminal.<br><br>A view, not an action, for the reason `zoomFetchKey` is a getter.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#method-regionhasdata) |
| <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 `zoomFetchArgs` (the zoom-derived arguments a fetch now would send) and `regionHasData` (did the last one store anything), and this compares the whole input set against the one the region was fetched under.</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-svglegendwidth">**svgLegendWidth**</span><br><code>() =&gt; number</code> | <span data-pagefind-ignore>Overridable hook (default 0): the width the LGV export reserves beside the plot for this legend. A display whose plot fills its band — the contact matrix, the LD triangle — answers `svgLegendGutterWidth(self)` so the key does not cover it.</span> | [LegendMixin](../legendmixin#method-svglegendwidth) |

## Actions

<!-- prettier-ignore -->
| Member | Description | Defined by |
| --- | --- | --- |
| <span id="action-selectfeature">**selectFeature**</span><br><code>(hit: MarkHitInfo) =&gt; void</code> | Open the feature widget for a hit: the worker shipped channels, not records, so the features are read back over the hit's span and the mark's steps run again over them, which remakes a bin or a run. | LinearMarkDisplay |
| <span id="action-setrpcdata">**setRpcData**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(idx: number, data: EncodedFeaturesResult, region: Region) =&gt; v…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(idx: number, data: EncodedFeaturesResult, region: Region) =&gt; void</code></pre></dialog></span> | Stage a region as fetched, with this display's payload shape. | LinearMarkDisplay |
| <span id="action-setdeclaredbound">**setDeclaredBound**</span><br><code>(end: 0 &#124; 1, val?: number &#124; undefined) =&gt; void</code> | The score menu's pin lands on the declaration: `encoding.y` owns the value scale, so an edited bound writes there and not on a second pair of display slots. `end` is 0 for the minimum, 1 for the maximum; `undefined` reopens that end to autoscale. | LinearMarkDisplay |
| <span id="action-setjexlfilters">**setJexlFilters**</span><br><code>(filters?: string[] &#124; undefined) =&gt; void</code> |  | LinearMarkDisplay |
| <span id="action-setminscore">**setMinScore**</span><br><code>(val?: number &#124; undefined) =&gt; void</code> |  | LinearMarkDisplay |
| <span id="action-setmaxscore">**setMaxScore**</span><br><code>(val?: number &#124; undefined) =&gt; void</code> |  | LinearMarkDisplay |
| <span id="action-setscaletype">**setScaleType**</span><br><code>(scaleType: string) =&gt; void</code> | Writes the owning mark's declared scale type, the same declaration the axis and the shapes read. | LinearMarkDisplay |
| <span id="action-fetchneeded">**fetchNeeded**</span><br><code>(needed: IndexedRegion[]) =&gt; Promise&lt;void&gt;</code> |  | LinearMarkDisplay |
| <span id="action-startrenderingbackend">**startRenderingBackend**</span><br><code>(backend: MarkRenderingBackend) =&gt; void</code> | identity encode — the stored payload is what the backend uploads | LinearMarkDisplay |
| <span id="action-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> |  | LinearMarkDisplay |
| <span id="action-setstatusmessage">**setStatusMessage**</span><br><code>(status?: RpcStatus &#124; undefined) =&gt; void</code> |  | [BaseDisplay](../basedisplay#action-setstatusmessage) |
| <span id="action-seterror">**setError**</span><br><code>(error?: unknown) =&gt; void</code> |  | [BaseDisplay](../basedisplay#action-seterror) |
| <span id="action-clearhoveredfeature">**clearHoveredFeature**</span><br><code>() =&gt; void</code> | <span data-pagefind-ignore>Overridable hook (default no-op): drop whatever `hoveredFeature` reports. The writing twin of that getter, and what `installClearHoverOnViewportChange` calls.<br><br>A display that STORES its hover owes an override; one that derives it from the live pointer (MAF, Hi-C, LD) owes nothing, and the default costs it nothing. Declared here so the clear can be installed for every display rather than remembered per display — forgetting it is the failure ARCHITECTURE.md's stored-hover section is about, and it used to be six closures at six call sites, which is six chances to omit one.</span> | [BaseDisplay](../basedisplay#action-clearhoveredfeature) |
| <span id="action-reload">**reload**</span><br><code>() =&gt; void</code> | <span data-pagefind-ignore>base display reload does nothing, see specialized displays for details</span> | [BaseDisplay](../basedisplay#action-reload) |
| <span id="action-applydisplaysettings">**applyDisplaySettings**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(settings: Record&lt;…&gt;, options?: { allowSetters?: boolean &#124; unde…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(settings: Record&lt;…&gt;, options?: { allowSetters?: boolean &#124; undefined; } &#124; undefined) =&gt; { applied: string[]; unapplied: string[]; failed: { key: string; error: string; }[]; }</code></pre></dialog></span> | <span data-pagefind-ignore>Apply a set of display settings to the live display, and report which were applied. Each key runs through the display config schema's `preProcessSnapshot` (shorthand expansions and legacy-key migrations, as `showTrackGeneric` applies to a session spec's inline track keys), then writes the matching config slot. Keys that are not slots are returned in `unapplied`, so a caller can see a key that did nothing.<br><br>`allowSetters` also routes a non-slot key to a single-argument action named `set<Key>`. It is off by default because session specs, share links and embeds pass untyped JSON here, and a default fallback would let them call internal setters (`setError`, `setScrollTop`, ...) and call multi-argument setters with one argument. A caller that wants a specific action can call it directly.<br><br>A key whose write threw is reported in `failed`. Only `failed` means the caller passed a bad value and warrants a notification. At the `showTrackGeneric` call site `unapplied` also collects keys that function consumed itself (`type`) and MST display props the display snapshot already applied (`resolution`), so reporting `unapplied` keys as dropped would flag a correct call.<br><br>A per-key error does not abort the remaining keys. A caller mid-`showTrack` has already pushed the track, and one rejected value should not leave it half-configured.</span> | [BaseDisplay](../basedisplay#action-applydisplaysettings) |
| <span id="action-setscrolltop">**setScrollTop**</span><br><code>(scrollTop: number) =&gt; void</code> |  | [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 the content it is hiding, for the resize handle's double click. Goes through `resizeHeight` so grow mode's override leaves grow first.</span> | [TrackHeightMixin](../trackheightmixin#action-expandtocontentheight) |
| <span id="action-setloadedregion">**setLoadedRegion**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(displayedRegionIndex: number, region: Region, payload: {} &#124; un…</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, payload: {} &#124; undefined, fetchInputs?: FetchInputs) =&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 span itself is the bug this family spent a release fixing, and the context gives a fetch no way to express it — see RegionFetchContext. Direct callers are tests staging an already-loaded display.<br><br>The payload is named on every call, `undefined` included: this write replaces the whole record, so a re-stamp that left it off dropped the data a test had staged one line earlier, and the failure surfaced as a reader throwing three layers away. A test stages a claim with nothing behind it by saying so.<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-evictregionstore">**evictRegionStore**</span><br><code>(keep: ReadonlySet&lt;number&gt;) =&gt; void</code> | <span data-pagefind-ignore>The store's bound. Drops the entries a fetch can no longer be about: an index outside the view's buffered viewport, once the store is over `MAX_STORED_REGIONS`, oldest first.<br><br>One rule for every display, where canvas hand-rolled `pruneRpcDataMapToVisible` (prune to the buffer on every fetch) and every other display had no bound at all beyond `displayedRegions.length`. That count is the contig count, so a fragmented assembly was effectively unbounded. The cap lets a pan back onto a recently-visited region draw immediately, which the prune-to-buffer rule did not.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#action-evictregionstore) |
| <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>Overridable hook (no-op base): drop what this display holds beside the store — a second store of its own, a verdict about the viewport that was just dropped. Called by `clearAllRpcData`, which runs on a displayed-regions change, on a viewport move past an error or a cancel, and on `reload()`.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#action-cleardisplayspecificdata) |
| <span id="action-clearsettingsbakeddata">**clearSettingsBakedData**</span><br><code>() =&gt; void</code> | <span data-pagefind-ignore>Overridable hook (no-op base): drop what this display holds that is wrong under a changed setting rather than merely stale — a payload whose shape the setting decides. Called by `invalidateSettings`, where `clearDisplaySpecificData` is deliberately not: bins, reads and features fetched under the previous setting draw honestly under the scrim `staleSettingsDrawn` raises until the refetch lands, the way canvas has kept its features since ADR-006 and every display does since 2026-09.<br><br>The variant matrix overrides it, for a structural reason: it holds one payload for every visible region and the row set is a setting, so there is no per-region replacement to wait for.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#action-clearsettingsbakeddata) |
| <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-invalidatesettings">**invalidateSettings**</span><br><code>() =&gt; void</code> | <span data-pagefind-ignore>`SettingsInvalidate`'s reset: the half of `clearAllRpcData` a settings change still needs now that the settings and adapter axes are in `fetchInputs`. The in-flight fetch is superseded now rather than when its payload lands stamped stale, a blocking error or cancel is cleared so the plan is not `blocked`, and the display drops its settings-baked data. `loadedRegions` and the canvas-drawn flag stay: every held region already reads `!isCacheValid`, so the plan refetches it, and until that lands the data stays on screen under the scrim `staleSettingsDrawn` raises.</span> | [MultiRegionDisplayMixin](../multiregiondisplaymixin#action-invalidatesettings) |
| <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-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, partial?: boolean) =&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 keeps reporting status 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 overwrote the status of the other two.<br><br>`isCurrent` is required and has no "node is alive" default, because a live node is not enough: 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()`, and every display gets that through `ctx.statusCallback` unasked; 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>`runFetch`'s own slot is opened by the rotation; this is for an operation outside any fetch, the tree sidebar's clustering run.</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-beginfetch">**beginFetch**</span><br><code>(stopToken: StopToken) =&gt; void</code> | <span data-pagefind-ignore>The `onBegin` half of a fetch's bookkeeping: publish the in-flight token (`isLoading`) and clear the durable user-cancel — a load starting is the single clear point that covers every retrigger path (reload, viewport change, settings invalidate). An action of its own for the same reason `endFetch` is: `installFetch`'s lifecycle callbacks run outside any MST flow this mixin owns.</span> | [FetchMixin](../fetchmixin#action-beginfetch) |
| <span id="action-endfetch">**endFetch**</span><br><code>(current: boolean) =&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, which must not clear the loading flag the run that replaced it just set. The stop token itself is released by the rotation's own `end()`, one layer down.</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-fetchcoarsetier">**fetchCoarseTier**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(read: CoarseTierRead, ctx: FetchContext) =&gt; Promise&lt;CoarseTier…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(read: CoarseTierRead, ctx: FetchContext) =&gt; Promise&lt;CoarseTierResult&lt;FeatureDensity&gt;&gt;</code></pre></dialog></span> |  | [DensityTierMixin](../densitytiermixin#action-fetchcoarsetier) |
| <span id="action-setcoarsetier">**setCoarseTier**</span><br><code>(entries: CoarseTierEntry&lt;P&gt;[], read: CoarseTierRead) =&gt; void</code> |  | [CoarseTierMixin](../coarsetiermixin#action-setcoarsetier) |
| <span id="action-clearcoarsetier">**clearCoarseTier**</span><br><code>() =&gt; void</code> |  | [CoarseTierMixin](../coarsetiermixin#action-clearcoarsetier) |
| <span id="action-setcoarsetierloading">**setCoarseTierLoading**</span><br><code>(loading: boolean) =&gt; void</code> |  | [CoarseTierMixin](../coarsetiermixin#action-setcoarsetierloading) |
| <span id="action-togglecrosshatches">**toggleCrossHatches**</span><br><code>() =&gt; void</code> |  | [WiggleScoreConfigMixin](../wigglescoreconfigmixin#action-togglecrosshatches) |
| <span id="action-setscatterpointsize">**setScatterPointSize**</span><br><code>(val?: number &#124; undefined) =&gt; void</code> |  | [WiggleScoreConfigMixin](../wigglescoreconfigmixin#action-setscatterpointsize) |
| <span id="action-setautoscale">**setAutoscale**</span><br><code>(val?: string &#124; undefined) =&gt; void</code> |  | [ScoreScaleMixin](../scorescalemixin#action-setautoscale) |
| <span id="action-setshowlegend">**setShowLegend**</span><br><code>(arg: boolean) =&gt; void</code> | <span data-pagefind-ignore>Writes the slot, and showing the legend again restores the sections closed inside it.</span> | [LegendMixin](../legendmixin#action-setshowlegend) |
| <span id="action-dismisslegendsection">**dismissLegendSection**</span><br><code>(id: string) =&gt; void</code> | <span data-pagefind-ignore>Close one section of the legend, leaving the others up.</span> | [LegendMixin](../legendmixin#action-dismisslegendsection) |
| <span id="action-opencontextmenu">**openContextMenu**</span><br><code>(info: Info) =&gt; void</code> |  | [ContextMenuMixin](../contextmenumixin#action-opencontextmenu) |
| <span id="action-closecontextmenu">**closeContextMenu**</span><br><code>() =&gt; void</code> |  | [ContextMenuMixin](../contextmenumixin#action-closecontextmenu) |
| <span id="action-sethoveredfeature">**setHoveredFeature**</span><br><code>(hit?: T &#124; undefined) =&gt; void</code> |  | [StoredHoverMixin](../storedhovermixin#action-sethoveredfeature) |

