# LinearSyntenyDisplay

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

## Example usage

A complete `SyntenyTrack` config to paste into `tracks`. The adapter needs the
query (first) and target (second) assembly names, matched by the track's
`assemblyNames`:

```js
{
  type: 'SyntenyTrack',
  trackId: 'hg38_vs_mm10',
  name: 'hg38 vs mm10',
  assemblyNames: ['hg38', 'mm10'],
  adapter: {
    type: 'PAFAdapter',
    uri: 'https://example.com/hg38_vs_mm10.paf',
    queryAssembly: 'hg38',
    targetAssembly: 'mm10',
  },
  displays: [
    {
      type: 'LinearSyntenyDisplay',
      displayId: 'hg38_vs_mm10-LinearSyntenyDisplay',
    },
  ],
}
```

Pure-data model. The containing LinearSyntenyView owns the shared GPU backend,
the upload autorun (which watches every display's `instanceData` and keys it by
`displayKey`), and the render autorun. This display only carries per-track state
and the `renderParams` the view reads out.

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

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('LinearSyntenyDisplay')</code> |  | LinearSyntenyDisplay |
| <span id="property-configuration">**configuration**</span><br><code>configuration: ConfigurationReference(configSchema)</code> |  | LinearSyntenyDisplay |
| <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-featuredata">**featureData**</span><br><code>featureData: undefined as SyntenyFeatureData &#124; undefined</code> |  | LinearSyntenyDisplay |
| <span id="volatile-instancedata">**instanceData**</span><br><code>instanceData: undefined as SyntenyGeometry &#124; undefined</code> | Raw GPU-instance geometry produced by the RPC. The view observes this on every display and uploads it to the shared backend keyed by `displayKey`. Clearing it (undefined) triggers backend eviction. | LinearSyntenyDisplay |
| <span id="volatile-hoveredinstanceidx">**hoveredInstanceIdx**</span><br><code>hoveredInstanceIdx: -1</code> | Index into `instanceData` of the GPU instance the pointer is over, or -1. The INSTANCE, not the feature, even though the tooltip and the highlight are both about the feature: a CIGAR-detailed ribbon is a base block plus a tile per indel, and the operator under the cursor is readable from nothing else (`getCigarOpAtInstance`). `getFeature` translates to the feature. Same choice `DotplotDisplay` makes, where the stored index is `hoveredSegmentIdx`. | LinearSyntenyDisplay |
| <span id="volatile-clickedinstanceidx">**clickedInstanceIdx**</span><br><code>clickedInstanceIdx: -1</code> | Clicked twin of `hoveredInstanceIdx` — the instance whose feature stays highlighted after the pointer leaves it. | LinearSyntenyDisplay |
| <span id="volatile-contextmenuanchor">**contextMenuAnchor**</span><br><code>contextMenuAnchor: undefined as ClickCoord &#124; undefined</code> |  | LinearSyntenyDisplay |
| <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-fetching">**fetching**</span><br><code>fetching: false</code> | <span data-pagefind-ignore>True while an RPC fetch is in-flight. Combined with `ready` it distinguishes a first load (no data yet — full overlay) from a refetch (stale content still on screen — corner indicator).</span> | [SyntenyFetchStateMixin](../syntenyfetchstatemixin#volatile-fetching) |
| <span id="volatile-loadedfetchkey">**loadedFetchKey**</span><br><code>loadedFetchKey: undefined as string &#124; undefined</code> | <span data-pagefind-ignore>Fetch-input signature the currently held data was fetched for (each display builds its own `currentFetchKey`). Compared against the live inputs in `dataCurrent` to catch data gone stale after a region/zoom change — including during the pre-refetch debounce gap, where `fetching` is still false and would otherwise report done on content drawn against the old viewport.</span> | [SyntenyFetchStateMixin](../syntenyfetchstatemixin#volatile-loadedfetchkey) |
| <span id="volatile-assembliesswapped">**assembliesSwapped**</span><br><code>assembliesSwapped: false</code> | <span data-pagefind-ignore>Set once at view load by a refName-comparison check, independent of the per-render fetch, so it never re-fires or misfires on zoom. Surfaces through each display's `warnings`.</span> | [SyntenyFetchStateMixin](../syntenyfetchstatemixin#volatile-assembliesswapped) |
| <span id="volatile-reloadcounter">**reloadCounter**</span><br><code>reloadCounter: 0</code> | <span data-pagefind-ignore>Bumped by `reload()`. Read unconditionally by `installComparativeFetchAutorun`, so it is always in the autorun's dependency set — which is the whole point: after an error the fetch inputs are unchanged, so nothing else would ever refire the autorun and the error banner's Retry would be a button that does nothing.</span> | [SyntenyFetchStateMixin](../syntenyfetchstatemixin#volatile-reloadcounter) |
| <span id="volatile-fetchcanceled">**fetchCanceled**</span><br><code>fetchCanceled: false</code> | <span data-pagefind-ignore>True from the moment the user clicks Cancel on the loading overlay (`cancelFetchByUser`) until `reload()` clears it. Durable and blocking: `installComparativeFetchAutorun` gates on it, so nothing restarts the load in the meantime — not a zoom, not a region change, and no timer.<br><br>That is the deliberate half. These displays sit on single RPCs that can run for minutes against a remote index, so a cancel any pan quietly undoes is not a cancel, and a retry that re-arms itself hammers the server that just failed. The way back is the overlay's Retry button and nothing else — `LoadingOverlay` draws it off this flag.</span> | [SyntenyFetchStateMixin](../syntenyfetchstatemixin#volatile-fetchcanceled) |
| <span id="volatile-stopactivefetch">**stopActiveFetch**</span><br><code>stopActiveFetch: () =&gt; {}</code> | <span data-pagefind-ignore>Stops the in-flight RPC. `installComparativeFetchAutorun` hands over its stop-token rotation's `cancel` at install (`setStopActiveFetch`): the rotation lives in that skeleton's closure, one per install and beside the fetch that uses it, and this mixin holds no fetch machinery of its own (ADR-054).<br><br>**A cancel that cannot reach it is not a cancel.** Nothing else rotates the token, so the run the user stopped watching stays `isCurrent()` and COMMITS its result when it lands — the plot appears, the overlay disappears, and the cancel is undone by the fetch it cancelled. Stopping the token is also the only thing that tells the worker to drop the reads still in flight, which is half of why a user clicks it.<br><br>A no-op until the skeleton installs, so a display with no fetch autorun can still be asked.</span> | [SyntenyFetchStateMixin](../syntenyfetchstatemixin#volatile-stopactivefetch) |

## Getters

<!-- prettier-ignore -->
| Member | Description | Defined by |
| --- | --- | --- |
| <span id="getter-parenthelper">**parentHelper**</span><br><code>LevelDuck</code> | The level (row gap) this display's track sits on. Found by predicate rather than by hop count — see isSyntenyLevel. | LinearSyntenyDisplay |
| <span id="getter-level">**level**</span><br><code>number</code> | Index of the level (row gap) this display draws in: between `view.views[level]` and `view.views[level + 1]`. | LinearSyntenyDisplay |
| <span id="getter-displaykey">**displayKey**</span><br><code>number</code> | Stable backend key under the view-shared backend. | LinearSyntenyDisplay |
| <span id="getter-height">**height**</span><br><code>number</code> |  | LinearSyntenyDisplay |
| <span id="getter-adapterconfig">**adapterConfig**</span><br><code>Record&lt;string, unknown&gt;</code> | The track's adapter config verbatim. The **body and return type are now identical to `BaseDisplayModel.adapterConfig`** — this override survives only to hold the note below where someone would go to re-add a key.<br><br>Byte-identical is the point: the worker's adapter cache keys on the config object, so a key the adapter never reads still forks the cache. The two decorative keys this used to add — `name`, duplicating the adapter's own `type`, and `assemblyNames`, read off the display's config schema, which declares no such slot and so always answered `undefined` — bought a second parse of the same file: one adapter for the ribbons and another for everything reading the track plainly (LGVSyntenyDisplay, the region launch's mate discovery). Both keys were inert at the adapter, which is exactly why nothing caught it. A worker-side value that doesn't belong to the adapter goes as a sibling RPC arg, the way `sequenceAdapter` does. | LinearSyntenyDisplay |
| <span id="getter-numfeats">**numFeats**</span><br><code>number</code> |  | LinearSyntenyDisplay |
| <span id="getter-offscreenmatetally">**offscreenMateTally**</span><br><code>{ refName: string; count: number; }[]</code> | The contigs this level fetched alignments to but cannot draw a ribbon for, largest first, because the facing row is not displaying them.<br><br>A getter rather than shipped as objects: the tally is one entry per contig, so sorting it is over a scaffold count, while the lanes it is built from are one entry per contig too. What the reader is shown, and what names the rows worth offering to add. | LinearSyntenyDisplay |
| <span id="getter-targetoffscreenmatetally">**targetOffscreenMateTally**</span><br><code>{ refName: string; count: number; }[]</code> | The same, for the row below: contigs of the QUERY assembly that the row above is not displaying, which alignments anchored on the target axis run to. Always empty without the bidirectional fetch, since those alignments are never requested. | LinearSyntenyDisplay |
| <span id="getter-culledribbonmates">**culledRibbonMates**</span><br><code>CulledRibbonMates &#124; undefined</code> | Every alignment this display drew geometry for, placed on both axes, so either strip can mark the ones the band is currently culling — the facing end is on a contig that row displays and has scrolled off, which no fetch-time tally can answer. ONE PER ROW, because culling is symmetric: an alignment can be undrawable with its query end off screen and its target end in plain sight, and marking it on the query axis puts it at an x the layout rejects. See `culledRibbonMates`.<br><br>LAZY BY CONSTRUCTION rather than gated on the setting: `offscreenMateStrips` reads `showOffscreenMates` before it reads this, so with the marks off nothing observes it and the pass never runs.<br><br>BOTH PERSPECTIVES ARE BUILT WHATEVER THE FETCH IS, because they are one walk — the query span is what says whether the target span is a mate at all — and whether the lower row's is DRAWN is a separate question that `laneData` answers: a row gets a strip only if the file was queried from it, or the strip stops at the fetch window's edge rather than at the data's. | LinearSyntenyDisplay |
| <span id="getter-cappedmeanalignmentpx">**cappedMeanAlignmentPx**</span><br><code>number</code> | Mean on-screen width (px, axis 0) of this display's alignment blocks with every already-wide block counted as `FADE_WIDE_BLOCK_PX`, or 0 until a fetch lands and both views connect. The fade only affects sub-pixel ribbons (perpW < 1), so a capped mean well under 1 means the view is dominated by thin ribbons — exactly what width-proportional fade declutters, and `LinearSyntenyView.fadeThinAlignments` decides 'auto' off the narrowest of these.<br><br>O(numFeats) per zoom rather than per fetch, because the cap is a px width: 4.2 ms over a million-block whole-genome PAF, where the answer is nowhere near the threshold anyway, and 0.4 ms at a hundred thousand. | LinearSyntenyDisplay |
| <span id="getter-presentcigarkinds">**presentCigarKinds**</span><br><code>number</code> | Which CIGAR indel ops are actually painted in the current geometry. The worker only emits an indel instance for an op wide enough to draw (sub-pixel indels are dropped), so a set bit means a visible-width op of that kind is on screen. The legend keys its indel chips off this rather than the coarse "file has any CIGAR" flag, so whole-genome zoom (every indel sub-pixel) shows no dead insertion/deletion swatch. | LinearSyntenyDisplay |
| <span id="getter-warnings">**warnings**</span><br><code>ComparativeWarning[]</code> | Warnings surfaced in the view header. Flags a likely reversed assembly row order, detected once at view load (only when the two assemblies have distinct chromosome names). | LinearSyntenyDisplay |
| <span id="getter-ready">**ready**</span><br><code>boolean</code> | A fetch has completed (data is present, even if it mapped zero features). Not `numFeats > 0` — an empty-but-finished fetch is ready, otherwise an empty result spins the loading overlay forever. | LinearSyntenyDisplay |
| <span id="getter-fetchinert">**fetchInert**</span><br><code>boolean</code> | Overrides `SyntenyFetchStateMixin`'s default-false hook with the two states where this display's fetch autorun deliberately never runs: minimized, or a level whose two rows aren't both showing regions. A display in one of them draws nothing (`renderParams` is undefined for exactly the same pair) and has no data coming, so anything waiting on data has to treat it as terminal rather than wait forever. One getter because four places answer it — the autorun's own gate, the loading overlay, the SVG export, and (through the mixin) `displaysSettled`. | LinearSyntenyDisplay |
| <span id="getter-fetchflags">**fetchFlags**</span><br><code>ComparativeFetchFlags</code> |  | LinearSyntenyDisplay |
| <span id="getter-loading">**loading**</span><br><code>boolean</code> | First load: no data has arrived yet. Drives the full striped LoadingOverlay. | LinearSyntenyDisplay |
| <span id="getter-refetching">**refetching**</span><br><code>boolean</code> | Refetch in-flight: a new fetch is running but stale ribbons are still on screen (e.g. zoom-out across a log2 bucket, region change). Drives a subtle corner indicator instead of the full overlay so the visible ribbons aren't masked on every viewport change. | LinearSyntenyDisplay |
| <span id="getter-regionsignature">**regionSignature**</span><br><code>string</code> | Contents, order and orientation of both connected views' displayed regions — the inputs the worker's cumBp index is built from, so a change in any of them makes held features stale. Its own getter, not inlined into `currentFetchKey`: this is O(total regions) (a whole-genome view of a scaffold-heavy assembly runs to thousands), while `currentFetchKey`'s other deps flip on every pan past the buffer and every zoom bucket. Split out, MobX memoizes it against `displayedRegions` alone instead of rebuilding the whole string per zoom step. | LinearSyntenyDisplay |
| <span id="getter-currentfetchkey">**currentFetchKey**</span><br><code>string</code> | Fetch-input signature (region set/order, snapped fetch window, zoom bucket, CIGAR draw options, LOD tier) for the view's current state — the same tracked deps the fetch autorun refetches on. Reactive: flips the instant any of them changes. Before both connected views are ready it collapses to a degenerate signature (empty region sig, no fetch-window/zoom keys) that no connected fetch can produce — a real fetch requires non-empty displayedRegions — so `dataCurrent` reads false until a real fetch lands. Non-nullable so it mirrors dotplot's. | LinearSyntenyDisplay |
| <span id="getter-datacurrent">**dataCurrent**</span><br><code>boolean</code> | True when the rendered data was fetched for the view's current inputs. Goes false the instant a region/zoom/draw-option change makes the held ribbons stale — including during the pre-refetch debounce gap where `fetching` is still false so `refetching` alone can't catch it.<br><br>This is the shared freshness hook every display foundation answers, expressed the signature-compare way (as arc and dotplot do); the per-region families answer it with spatial coverage instead. | LinearSyntenyDisplay |
| <span id="getter-svgready">**svgReady**</span><br><code>boolean</code> | Off-screen SVG export gate: "Export SVG" waits on this before drawing (see the [SVG export guide](https://jbrowse.org/jb2-staging/docs/developer_guides/svg_export)). Synteny is not an LGV display — it composes only `BaseDisplay` with its own fetch — so it gets no mixin `svgReady`, but it runs the same shared `computeSvgReady` policy so the two can't drift. Stale-safe on both axes: `dataCurrent` closes the pre-refetch debounce gap (stale window before `fetching` flips) and `!refetching` covers the in-flight RPC, so an export fired right after a zoom/pan waits for fresh ribbons instead of capturing stale ones. No `regionTooLarge` state (synteny never gates on region size).<br><br>`extraTerminal` is `fetchInert` — the states where the fetch autorun deliberately never runs — so a data-only gate can't hang the export forever on data that is never coming. `fetchCanceled` is terminal for the same reason: durable until Retry, and an export presses nothing. | LinearSyntenyDisplay |
| <span id="getter-displayphase">**displayPhase**</span><br><code>DisplayStatusPhase</code> | The display's own mutually-exclusive state, the way every LGV display publishes one — so `AppReadyMarker` counts this display's fetch, and the app stops reporting itself ready over a ribbon that is still working. Ranked by `comparativeDisplayPhase`, off the shared canvas's `surfaceReadiness` and this display's own fetch state.<br><br>`DisplayStatusPhase`, not `DisplayPhase`: the level owns the rendering backend, so this display can never be the one to report a backend failure. | LinearSyntenyDisplay |
| <span id="getter-view">**view**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>ModelInstanceTypeProps&lt;_OverrideProps&lt;_OverrideProps&lt;Omit&lt;_Over…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>ModelInstanceTypeProps&lt;_OverrideProps&lt;_OverrideProps&lt;Omit&lt;_OverrideProps&lt;…&gt;, never&gt;, { ...; }&gt;, { ...; }&gt;&gt; &amp; ... 27 more ... &amp; IStateTreeNode&lt;...&gt;</code></pre></dialog></span> |  | LinearSyntenyDisplay |
| <span id="getter-computedcolors">**computedColors**</span><br><code>Uint32Array&lt;ArrayBuffer&gt; &#124; undefined</code> | Main-thread-computed per-instance colors. Recomputes whenever colorBy, featureData, or instanceData descriptors change — this is the gpuProps half of the rpcProps/gpuProps split. colorBy changes flow through here without touching the RPC.<br><br>`drawLocationMarkers` rides the same lane, which is what keeps it out of `currentFetchKey`: the worker always emits the ticks, and a zero alpha here is what "off" means. So the toggle costs one color-lane patch (`SYNTENY_INSTANCE_CACHE`) rather than a refetch of the whole track. | LinearSyntenyDisplay |
| <span id="getter-paintedchromosomeorder">**paintedChromosomeOrder**</span><br><code>readonly string[] &#124; undefined</code> | The chromosome order the chromosome-painting modes color by: the refNames of whichever of this level's two assemblies `effectiveColorBy` resolved to, in the assembly's own order. Undefined for every other mode, and while the assembly is still loading — the color function falls back to its hash there.<br><br>It has to come from the assembly rather than from the features, because a color must not change with which chromosomes happen to be in view. | LinearSyntenyDisplay |
| <span id="getter-trackid">**trackId**</span><br><code>string</code> |  | LinearSyntenyDisplay |
| <span id="getter-trackcolor">**trackColor**</span><br><code>string</code> | This track's slot in the view's palette, used by `colorBy: 'track'`. Assigned by the view, not locally: pinning a color on one track shifts which automatic slots its siblings can take. | LinearSyntenyDisplay |
| <span id="getter-colorbymode">**colorByMode**</span><br><code>SyntenyColorBy</code> | The mode this track renders with, before the per-level 'reference' remap: its own override if the user set one, else the view-wide mode. This is the user-facing answer — menus and the legend title read it, so a uniform 'reference' view reports 'reference' rather than the query/target each level resolved it to. | LinearSyntenyDisplay |
| <span id="getter-effectivecolorby">**effectiveColorBy**</span><br><code>SyntenyColorBy</code> | `colorByMode` resolved for this specific level, for the renderer. 'reference' is a stacked-view mode that colors every level by the shared anchor assembly's chromosome names; each level maps it to 'query' or 'target' depending on which of its two assemblies is the anchor, so the coloring stays consistent across levels. Every other mode passes through. | LinearSyntenyDisplay |
| <span id="getter-renderinstancedata">**renderInstanceData**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>{ colors: Uint32Array&lt;ArrayBuffer&gt;; bp1: Float32Array&lt;ArrayBuff…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>{ colors: Uint32Array&lt;ArrayBuffer&gt;; bp1: Float32Array&lt;ArrayBufferLike&gt;; bp2: Float32Array&lt;ArrayBufferLike&gt;; ... 7 more ...; instanceCount: number; } &#124; undefined</code></pre></dialog></span> | Instance data with main-thread-computed colors substituted in. The view's upload autorun reads this, so any colorBy change re-fires upload without an RPC round-trip. | LinearSyntenyDisplay |
| <span id="getter-tooltiplines">**tooltipLines**</span><br><code>string[] &#124; undefined</code> | The hovered ribbon's tooltip, as lines, or undefined when nothing is hovered. Lines rather than an HTML string — see `getTooltipLines`, and `DotplotDisplay.tooltipLines` for the twin. | LinearSyntenyDisplay |
| <span id="getter-connectedviews">**connectedViews**</span><br><code>{…} &#124; undefined</code> | The two adjacent genome views this level draws between, or undefined until both are initialized with regions. A level draws between an adjacent pair, so both render and fetch depend only on those two views, not the whole stack. Single source of truth for that gate. | LinearSyntenyDisplay |
| <span id="getter-bpperpxbucketkey">**bpPerPxBucketKey**</span><br><code>string &#124; undefined</code> | Stable key over the log2 zoom bucket of both connected views. The fetch autorun tracks this (a computed compares its string output) instead of raw bpPerPx, so it only refetches when zoom crosses a doubling rather than on every settled zoom within a bucket. | LinearSyntenyDisplay |
| <span id="getter-lodtier">**lodTier**</span><br><code>LodTier</code> | The detail tier this level's fetch asks the adapter for, resolved here on the main thread so it can enter `currentFetchKey`.<br><br>It cannot be resolved adapter-side from `bpPerPx`: the refetch key carries only `bpPerPxBucketKey`, a log2 bucket, and the default 10000 threshold sits *inside* bucket 13 (8192..16384). Zooming across the threshold within one bucket therefore changed nothing the key could see, and the view kept drawing the coarse tier's gap-free ribbons while reporting itself current.<br><br>The zoom fed in is `min` of both axes, because CIGAR detail is worth drawing when the band is wide on EITHER axis — buildSyntenyGeometry's MIN_CIGAR_PX_WIDTH gate uses `max(widthPx0, widthPx1)` — so dropping to coarse is only safe once BOTH axes are past the threshold. Taking the query axis alone lost indel detail on a band whose query was zoomed out but whose target was zoomed in. | LinearSyntenyDisplay |
| <span id="getter-fetchregions">**fetchRegions**</span><br><code>Region[]</code> | The query axis's (v0) fetch window, and the regions the fetch actually sends: the visible content blocks expanded by the shared pan buffer and snapped outward to a buffer-sized grid, so a pan within the buffer neither refetches nor exposes an unfetched strip. The target axis is not scoped — the fetch is one-dimensional (query regions in, every mate out) — it only contributes its cumBp index, so it appears in `fetchRegionsKey` but not here. | LinearSyntenyDisplay |
| <span id="getter-targetfetchregions">**targetFetchRegions**</span><br><code>Region[]</code> | The target axis's (v1) fetch window, or [] unless the view asked for the bidirectional fetch — in which case the worker queries it too, and recovers the alignments anchored there whose query end is on a contig the row above is not displaying. Empty is the signal, so the RPC argument carries nothing when the setting is off. | LinearSyntenyDisplay |
| <span id="getter-fetchregionskey">**fetchRegionsKey**</span><br><code>string &#124; undefined</code> | Stable key over the *snapped* fetch window of both connected views. The fetch autorun tracks this (through `currentFetchKey`) so a scroll/zoom that moves either snapped window refetches, while a sub-buffer pan (identical snapped windows) does not — a MobX computed only notifies when its string output changes. Built from the same `fetchRegions` the worker is handed, so the key can't describe a window the fetch didn't use. | LinearSyntenyDisplay |
| <span id="getter-renderparams">**renderParams**</span><br><code>{…} &#124; undefined</code> | Per-track render params consumed by the view's aggregator. The view substitutes yTop before handing this to the backend. | LinearSyntenyDisplay |
| <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-isminimized">**isMinimized**</span><br><code>boolean</code> | <span data-pagefind-ignore>Returns true if the parent track is minimized. Used to skip expensive operations like autoruns when track is not visible.</span> | [BaseDisplay](../basedisplay#getter-isminimized) |
| <span id="getter-hoveredfeature">**hoveredFeature**</span><br><code>unknown</code> | <span data-pagefind-ignore>Overridable hook (default `undefined`): what the pointer is currently over, for readers **outside** the display. `LinearGenomeViewContainer` publishes it to `session.hovered`, the view-wide "what is the user pointing at" channel a plugin can subscribe to.<br><br>Declared here because a cross-display consumer can only read a name the base declares — the same reason `SyntenyFetchStateMixin.fetchInert` is a hook rather than a getter each display invents. The container used to read `featureUnderMouse`, which only the wiggle, alignments and Manhattan families spelled that way — canvas said `hoveredFeature`, variants `hoveredGenotype` — so the channel carried a hover from a third of the display types and nothing said which. It also asked only `displays[0]` of each track.<br><br>`unknown` because the payload genuinely differs — a read, a wiggle bin, a SNP, a genotype cell — and `session.hovered` is typed to match ("can be anything; code that wants to deal with this should examine it"). Narrow it in the override.</span> | [BaseDisplay](../basedisplay#getter-hoveredfeature) |
| <span id="getter-featurenoun">**featureNoun**</span><br><code>string</code> | <span data-pagefind-ignore>Overridable hook (default `'feature'`): the SINGULAR word for one of the things this display draws, as a menu row or a chip says it — "Hide this read", "Showing 3 variants".<br><br>Declared here for the same reason as `hoveredFeature` above: it is read across the display boundary, by chrome that has no idea which display it is drawing for (`SoloSelectionChip`, alignments' group-label overlay), and a name only the base declares is a name every such consumer can rely on. Two displays declared it independently and one of those declarations WAS this default.<br><br>**A control keeps the generic word; content takes this one.** "Variant height" reads as a different setting from "Feature height" when it is the same one, so the shared menus stay on "feature" however the display answers here, and the noun varies where it names what the user is looking at — "Showing 3 variants", "Hide this read". A display drawing something the generic word already fits is right to leave this alone.<br><br>Distinct from the per-hit noun a context menu takes off the clicked item's own `type` ("mRNA", "gene"); that names one annotation, this names what the track holds. The hit noun falls back to this.</span> | [BaseDisplay](../basedisplay#getter-featurenoun) |
| <span id="getter-featurewidgettype">**featureWidgetType**</span><br><code>{ type: string; id: string; }</code> | <span data-pagefind-ignore>Overridable hook: which widget `openFeatureWidget` opens for one of this display's features. The default is the generic one, which is what a display drawing plain features wants and what the canvas base spelled out by hand.<br><br>An override is a display whose features have a vocabulary of their own — a read, a variant, a synteny block — and the `id` is deliberately part of it: two displays naming one id share the drawer panel, which is the behaviour when the two are showing the same kind of thing.</span> | [BaseDisplay](../basedisplay#getter-featurewidgettype) |

## Methods

<!-- prettier-ignore -->
| Member | Description | Defined by |
| --- | --- | --- |
| <span id="method-getfeature">**getFeature**</span><br><code>(index: number) =&gt; FeatPos &#124; undefined</code> | The parent feature under an INSTANCE index (what the pick engine and the hover/click state carry). Without instanceData the two spaces coincide. Deliberately not `instanceFeatureIdx[index] ?? index`: an out-of-range instance index reads `undefined` there, and falling back to the raw index would silently return a different feature rather than nothing. | LinearSyntenyDisplay |
| <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-trackmenuitems">**trackMenuItems**</span><br><code>() =&gt; MenuItem[]</code> |  | [BaseDisplay](../basedisplay#method-trackmenuitems) |

## Actions

<!-- prettier-ignore -->
| Member | Description | Defined by |
| --- | --- | --- |
| <span id="action-setrpcdata">**setRpcData**</span><br><span class="cell-more"><button type="button" class="cell-more-trigger"><code>(featureData: SyntenyFeatureData &#124; undefined, instanceData: Syn…</code></button><dialog class="cell-dialog"><form method="dialog"><button class="cell-dialog-close" aria-label="Close">✕</button></form><pre><code>(featureData: SyntenyFeatureData &#124; undefined, instanceData: SyntenyGeometry &#124; undefined, fetchKey: string) =&gt; void</code></pre></dialog></span> | Set both feature and instance data in one MST action so downstream autoruns (upload, render) fire once per RPC completion, not twice.<br><br>The hover/click indices address the OUTGOING instanceData, so they are meaningless against the incoming arrays and must be dropped here — a surviving index either highlights an unrelated ribbon (still in range) or writes NaN into the clickedFeatureId uniform (out of range). A refetch is a zoom/pan/mode change, after which the pointer is no longer over whatever it was hovering anyway.<br><br>An open context menu goes with them, for the same reason one step further along. It does not hold an index — it holds a resolved feature and the window a panel was showing — but both describe the fetch that has just been replaced, and its items act on them ASYNCHRONOUSLY, after a click. Feature ids are not comparable across a tiered PIF's two tiers, so a menu that outlived a tier flip would ask the worker to resolve an id the new tier does not have, and get back the same `undefined` a CIGAR-less block gives — which is what `moveMatchingPanel` then reports it as. | LinearSyntenyDisplay |
| <span id="action-sethoveredinstanceidx">**setHoveredInstanceIdx**</span><br><code>(idx: number) =&gt; void</code> | Point the hover at one GPU instance, or -1 for none. The level's `setHoveredFeature` is what calls this, from a pick hit. | LinearSyntenyDisplay |
| <span id="action-setclickedinstanceidx">**setClickedInstanceIdx**</span><br><code>(idx: number) =&gt; void</code> |  | LinearSyntenyDisplay |
| <span id="action-opencontextmenu">**openContextMenu**</span><br><code>(anchor: ClickCoord) =&gt; void</code> |  | LinearSyntenyDisplay |
| <span id="action-closecontextmenu">**closeContextMenu**</span><br><code>() =&gt; void</code> |  | LinearSyntenyDisplay |
| <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-setfetching">**setFetching**</span><br><code>(arg: boolean) =&gt; void</code> |  | [SyntenyFetchStateMixin](../syntenyfetchstatemixin#action-setfetching) |
| <span id="action-setassembliesswapped">**setAssembliesSwapped**</span><br><code>(arg: boolean) =&gt; void</code> |  | [SyntenyFetchStateMixin](../syntenyfetchstatemixin#action-setassembliesswapped) |
| <span id="action-setstopactivefetch">**setStopActiveFetch**</span><br><code>(stop: () =&gt; void) =&gt; void</code> | <span data-pagefind-ignore>Install-time wiring, called once by `installComparativeFetchAutorun` — see `stopActiveFetch` for why the stop arrives from there rather than being built here.</span> | [SyntenyFetchStateMixin](../syntenyfetchstatemixin#action-setstopactivefetch) |
| <span id="action-cancelfetchbyuser">**cancelFetchByUser**</span><br><code>() =&gt; void</code> | <span data-pagefind-ignore>The loading overlay's Cancel. Stops the in-flight RPC and lands in the durable `fetchCanceled` state, so the fetch autorun's gate holds until `reload()` reopens it.<br><br>Same name as `FetchMixin`'s, which is what lets one overlay set serve all three fetch families (`DisplayLoadingOverlayModel` names it). What has no twin here is the *internal* half of that split, `cancelFetch` — stop, clear the flag, bump a generation to retrigger — because it exists there for `clearAllRpcData`, and this family has nothing that resets a display behind the user's back. `reload()` is the only thing that reopens the gate, which is exactly the constraint: retry is a button, never an automatic re-arm.<br><br>Clears `fetching` itself, because nothing else will: the in-flight run's `finally` writes it only while `isCurrent()`, and the stop above just closed that guard.</span> | [SyntenyFetchStateMixin](../syntenyfetchstatemixin#action-cancelfetchbyuser) |

