varri-js 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,247 @@
1
+ # "Free trailing ends" feature — documentation
2
+
3
+ This document describes the "Free trailing ends" feature of vaRRI-js: what it
4
+ does, the relevant parts of Fornac's internal force-layout architecture it
5
+ depends on, and the exact steps taken to implement it.
6
+
7
+ ## 1. What the feature does
8
+
9
+ vaRRI-js renders RNA/RNA-RNA-interaction structures using
10
+ [Fornac](https://github.com/ViennaRNA/fornac)'s force-directed layout
11
+ (`options.forceLayout = true`, i.e. the "Enable Fornac force-layout animation"
12
+ checkbox). Fornac's layout algorithm pulls every *loop* of the structure
13
+ (hairpins, interior loops, multiloops, and — enabled by default — the
14
+ top-level *external loop*) into a rounded/circular shape using invisible
15
+ "fake" helper nodes and links that are not part of the actual RNA structure.
16
+
17
+ For the external loop specifically, Fornac additionally links the very first
18
+ and very last nucleotide of the whole molecule together, which visually pulls
19
+ the two free/dangling ends of the sequence(s) toward each other into a closed
20
+ ring — even though these ends have no real base-pairing there.
21
+
22
+ When the **"Free trailing ends"** checkbox is enabled (only selectable while
23
+ "Enable Fornac force-layout animation" is also enabled), vaRRI-js removes this
24
+ artificial circularisation from the force simulation:
25
+
26
+ - The two sequence ends are released from being pulled together.
27
+ - The region of the structure surrounding vaRRI's inter-molecule `&` gap
28
+ (see below) is also released from its own circular pull.
29
+ - Every *other* loop of the structure (stems, hairpins, interior loops,
30
+ multiloops) keeps its normal Fornac layout behaviour completely unchanged.
31
+
32
+ The net effect: the free ends of the molecule(s) can dangle naturally instead
33
+ of being forced into a closed/circular shape, while the rest of the
34
+ structure still looks exactly like a standard Fornac rendering.
35
+
36
+ ## 2. UI integration
37
+
38
+ - **[index.html](index.html)** — a checkbox `#forceLayoutFreeTails` ("Free
39
+ trailing ends") was added directly below the existing `#forceLayout`
40
+ checkbox ("Enable Fornac force-layout animation"), unchecked by default.
41
+ - **[index.js](index.js)**:
42
+ - `syncFreeTrailingEndsControl()` disables and force-unchecks
43
+ `#forceLayoutFreeTails` whenever `#forceLayout` is unchecked (the feature
44
+ only makes sense while the force simulation is actually running), and is
45
+ wired into the `change` listener for `#forceLayout` and called once on
46
+ page load.
47
+ - `runVisualization()` reads both checkboxes and passes
48
+ `freeTrailingEnds: forceLayout && checkbox.checked` as a new option to
49
+ `vaRRI.render(...)`.
50
+
51
+ ## 3. Required background: Fornac's internal force-graph architecture
52
+
53
+ Fornac builds its force-directed layout out of a plain object graph:
54
+
55
+ ```js
56
+ container.graph = {
57
+ nodes: [ ... ], // all D3 force-simulation nodes
58
+ links: [ ... ], // all D3 force-simulation links
59
+ };
60
+ ```
61
+
62
+ `container.graph.nodes` contains far more than the visible nucleotide
63
+ circles. Relevant node kinds (`nodeType`):
64
+
65
+ | `nodeType` | Purpose | Visible in SVG? |
66
+ |---------------|----------------------------------------------------------------------|:---:|
67
+ | `"nucleotide"`| A real base of the sequence. | yes |
68
+ | `"label"` | An index label (e.g. "10", "20") shown next to certain nucleotides. | yes |
69
+ | `"middle"` | A synthetic helper node used purely to shape the force layout. | no |
70
+
71
+ ### 3.1 Per-loop "hub" nodes (`addFakeNode()`)
72
+
73
+ Fornac's `reinforceLoops()` (called once per rendered RNA, from
74
+ `recalculateElements → ... → reinforceStems → reinforceLoops → ...`) iterates
75
+ over every parsed structural loop element (stems are excluded) and calls
76
+ `addFakeNode(memberIndices)` for each one. This creates:
77
+
78
+ - One synthetic **hub node**: `{ nodeType: "middle", num: -1, elemType: "f", nucs: memberIndices, uid, ... }`.
79
+ - `nucs` is a **snapshot of the 1-based indices into `graph.nodes`** of
80
+ every member of that loop, captured at the exact moment the hub was
81
+ created. Since nodes are only ever *appended* to `graph.nodes`
82
+ afterwards, these indices remain valid/stable for the lifetime of the
83
+ graph — this makes `nucs` a reliable, hub-local record of "who belongs to
84
+ this loop", independent of link traversal.
85
+ - For **every member** `m` of the loop (skipped if `m`'s index exceeds the
86
+ real sequence length — see §3.2), **three** `linkType: "fake"` links:
87
+ 1. `member → hub` — a "spoke" pulling that member toward the hub's centre.
88
+ 2. `member → member` at `(f + 2) % length` — a short "skip" chord directly
89
+ between two nearby members, bypassing the hub.
90
+ 3. `member → member` at `(f + floor(length / 2)) % length` — a
91
+ "diameter" chord directly between two roughly-opposite members
92
+ (only added when the loop has more than 4 members).
93
+
94
+ Note that #2 and #3 connect two ordinary loop members **directly**,
95
+ without going through the hub at all. This is important: simply detaching
96
+ the hub is not enough to fully free a loop — these chord links
97
+ independently pull opposite parts of the loop together.
98
+
99
+ - Separately, `connectFakeNodes()` links neighbouring loops' hubs to each
100
+ other with `linkType: "fake_fake"` links wherever they share a boundary
101
+ nucleotide (e.g. a stem's two hubs on either side).
102
+
103
+ ### 3.2 The true external loop's "closure" nodes
104
+
105
+ `reinforceLoops()` treats the loop element classified as `"e"` (the
106
+ top-level *external* loop, containing every truly unpaired/exposed
107
+ nucleotide) specially — but only when Fornac's `circularizeExternal` option
108
+ is enabled (**the default**, and never overridden by vaRRI). For that
109
+ element only, **before** calling `addFakeNode`, it synthesises two extra
110
+ "closure" nodes and appends them to the loop's member list:
111
+
112
+ ```js
113
+ { nodeType: "middle", num: -3, elemType: "f", x: <last nucleotide's x>, y: <last nucleotide's y>, ... }
114
+ { nodeType: "middle", num: -2, elemType: "f", x: <first nucleotide's x>, y: <first nucleotide's y>, ... }
115
+ ```
116
+
117
+ These are positioned at the RNA's very first and very last nucleotide and
118
+ pushed into `graph.nodes` with indices that are, by construction, **beyond
119
+ the real sequence length**. This is exactly what implements the
120
+ "pull the two free ends together" effect described in §1.
121
+
122
+ **Key subtlety used by the implementation:** because the closure nodes'
123
+ member-list indices exceed the sequence length, `addFakeNode`'s per-member
124
+ guard (`if (!(index === 0 || index > sequenceLength)) { ...create spoke +
125
+ chords... }`) skips creating *any* link (spoke or chord) *from* a closure
126
+ node. Closure nodes are therefore **never directly linked to the hub**, and
127
+ only ever appear as the incidental *target* of a chord link (#2/#3 above)
128
+ originating from a couple of nearby real members. Trying to find "the hub"
129
+ by following links attached to a closure node is unreliable — it instead
130
+ finds those incidental real-nucleotide chord partners.
131
+
132
+ The reliable way to find the external loop's hub is instead: check which
133
+ hub's own `nucs` array contains one of the closure nodes' array indices
134
+ (§3.1) — only the external loop's hub was ever given those indices as
135
+ members.
136
+
137
+ ### 3.3 vaRRI's inter-molecule gap and its side effect on `elemType`
138
+
139
+ To render two interacting molecules, vaRRI concatenates both structures with
140
+ a `&` separator, e.g. `structure1 + "&" + structure2`. Additionally, vaRRI
141
+ inserts 3 extra unpaired `.` characters right after the `&`
142
+ (`formatStructure`/`formatSequence` in [src/vaRRI.js](src/vaRRI.js)) as a
143
+ workaround for a Fornac bug that otherwise incorrectly drops/mis-renders the
144
+ first two real nucleotides of the second molecule. These extra dot
145
+ characters and their corresponding "gap" nodes are later hidden from the DOM
146
+ by vaRRI's own `removeDummyNodes()`.
147
+
148
+ Fornac's `breakNodesToFakeNodes()` (run at the very end of the `addRNA`
149
+ pipeline) inspects every structural loop element and, **for any element that
150
+ contains a position adjacent to the `&` break**, overwrites the `elemType`
151
+ of *every* member of that element to `"e"` — the same label used for the
152
+ true external loop — **regardless of that element's real loop type**
153
+ (stem/hairpin/interior/multiloop). In other words, the loop directly
154
+ enclosing vaRRI's inter-molecule gap gets cosmetically relabelled as if it
155
+ were exterior, even though structurally it usually is not.
156
+
157
+ This is exactly why users perceive "the region around the `&` spacer" as
158
+ also being circularly constrained: it has its own hub (created earlier during
159
+ `reinforceLoops()`, under its true original loop type — this relabelling
160
+ happens too late to affect whether that loop got closure nodes) that Fornac
161
+ never intended as "external", but whose members now look "external" by
162
+ label. To fully satisfy the "free the external/trailing nodes" requirement,
163
+ this gap-adjacent loop's hub must be freed the same way as the true external
164
+ loop's hub.
165
+
166
+ ## 4. Implementation steps (in [src/vaRRI.js](src/vaRRI.js))
167
+
168
+ 1. **Identify every "freeable" hub — `getFreeableLoopScaffoldUids(graph)`**
169
+ - Find the closure nodes: `nodeType === "middle" && (num === -2 || num === -3)`.
170
+ Record their `uid`s (`closureUids`) and their current 1-based array
171
+ indices in `graph.nodes` (`closureIndices`).
172
+ - Find every hub: `nodeType === "middle" && num === -1 && Array.isArray(nucs)`.
173
+ - For each hub, resolve its `nucs` indices back to actual node objects
174
+ (`graph.nodes[idx - 1]`), and mark the hub as freeable if **either**:
175
+ - its own `nucs` contains one of the `closureIndices` (→ this is the
176
+ true external loop's hub), **or**
177
+ - any of its resolved real members has `elemType === "e"` (→ this hub's
178
+ loop touches vaRRI's inter-molecule gap, per §3.3).
179
+ - Collect the `uid`s of all freeable hubs (`hubUids`) and, for every
180
+ freeable hub, the `uid`s of *all* of its members plus the closure nodes
181
+ (`memberUids`) — this member set is what's needed to remove the direct
182
+ member-to-member chord links in the next step.
183
+ - Return `null` if nothing qualifies (e.g. structures with no exposed
184
+ exterior region at all).
185
+
186
+ 2. **Remove the identified scaffold — `relaxForceGraphScaffold(container, v)`**
187
+ - Build `removableNodeUids` = `closureUids ∪ hubUids`.
188
+ - Filter `graph.links`, dropping any `linkType === "fake" | "fake_fake"`
189
+ link where:
190
+ - either endpoint's `uid` is in `removableNodeUids` (removes hub spokes
191
+ and any link touching a closure node), **or**
192
+ - **both** endpoints' `uid`s are in `memberUids` (removes the direct
193
+ member-to-member chord links described in §3.1, which otherwise
194
+ bypass the hub entirely and keep pulling opposite loop members
195
+ together even after the hub itself is gone).
196
+ - Filter `graph.nodes`, removing only nodes whose `uid` is in
197
+ `removableNodeUids` — i.e. **only** the freed hub(s) and the closure
198
+ nodes are deleted. Real nucleotide nodes are **never** removed; only
199
+ their links to the freed hub/closures/chord-partners are pruned, so
200
+ they remain fully connected via their normal backbone/base-pair links
201
+ and any *other* loop's hub they may also belong to.
202
+ - Call `container.update()` so Fornac's D3 selections/force simulation
203
+ pick up the mutated `graph.nodes`/`graph.links` arrays, then
204
+ `container.force.resume()` (or `.start()` as a fallback) to restart the
205
+ simulation so the layout actually relaxes into the new, unconstrained
206
+ shape.
207
+
208
+ 3. **Wire it into `render(...)`**
209
+ - `render(containerId, v, options)` accepts a new
210
+ `options.freeTrailingEnds` flag (default `false`).
211
+ - Immediately after `container.addRNA(...)` builds the initial force
212
+ graph, and only when both `forceLayout` and `freeTrailingEnds` are true,
213
+ call `relaxForceGraphScaffold(container, v)` once, before any further
214
+ DOM post-processing happens.
215
+
216
+ ## 5. Why a naive "just delete DOM nodes" approach does not work
217
+
218
+ Deleting the SVG `<circle>`/`<g>` elements for the hub/closure nodes (as
219
+ `removeDummyNodes()` already does for the invisible gap nodes) only affects
220
+ what is *rendered* — it does **nothing** to Fornac's underlying force
221
+ simulation, which keeps operating on `container.graph.nodes`/`.links`
222
+ independently of the DOM. The hub and closure nodes (and their links) must be
223
+ removed from the **graph data itself**, and the D3 force layout must be
224
+ explicitly re-synced (`container.update()`) and restarted
225
+ (`container.force.resume()`) for the removal to actually change the layout.
226
+
227
+ ## 6. Correctness pitfalls encountered during implementation
228
+
229
+ These are recorded here because they are easy to reintroduce if this code is
230
+ ever refactored:
231
+
232
+ 1. **Do not infer the hub via link adjacency to the closure nodes.**
233
+ Closure nodes are only ever reached via incidental chord links from a
234
+ couple of nearby real nucleotides (§3.2); following those links
235
+ misidentifies real nucleotides as "the hub" and deletes them from the
236
+ graph, silently removing visible nucleotides from the rendering. Use the
237
+ hub's own `nucs` array instead.
238
+ 2. **Removing only the hub and closure nodes is not sufficient.**
239
+ The direct member-to-member "chord" links (§3.1, #2/#3) still connect
240
+ opposite sides of the loop even with the hub gone, and remain visually
241
+ indistinguishable from "still circularly constrained". Both hub spokes
242
+ *and* inter-member chords must be removed.
243
+ 3. **`elemType === "e"` is not exclusive to the true external loop.**
244
+ Fornac's `breakNodesToFakeNodes()` relabels *any* loop touching a
245
+ structural break (vaRRI's inter-molecule gap) to `elemType: "e"` too,
246
+ regardless of its real loop type. Only checking for the closure-node
247
+ hub misses this second region entirely; both conditions must be checked.
@@ -0,0 +1,226 @@
1
+ (function registerVaRRIExamples(root) {
2
+ 'use strict';
3
+
4
+ const featureOverviewProfile = [
5
+ '# unpaired probabilities',
6
+ '1 0.9',
7
+ '2 0.7',
8
+ '3 0.3',
9
+ '4 0.1',
10
+ '7 0.3',
11
+ '8 0.7',
12
+ '9 0.6',
13
+ ].join('\n');
14
+
15
+ const coronelTellezProfile1 = [
16
+ '61 0.6',
17
+ '62 1',
18
+ '63 0.6',
19
+ '64 0.2',
20
+ '65 0.2',
21
+ '66 1',
22
+ '67 0.2',
23
+ '68 0.2',
24
+ '69 0.2',
25
+ '70 0.2',
26
+ '71 0.6',
27
+ '72 1',
28
+ '73 0.6',
29
+ '74 0.6',
30
+ '75 1',
31
+ '76 1',
32
+ '77 0.2',
33
+ '78 0.2',
34
+ '79 0.2',
35
+ '80 0.6',
36
+ '81 0.6',
37
+ '82 0.2',
38
+ '83 0.6',
39
+ '84 0.2',
40
+ '85 0.6',
41
+ '86 0.6',
42
+ '87 0.6',
43
+ '88 0.2',
44
+ '89 0.2',
45
+ '90 0.2',
46
+ '91 0.2',
47
+ '92 0.2',
48
+ '93 0.2',
49
+ '94 0.6',
50
+ '95 0.6',
51
+ '96 0.2',
52
+ '97 0',
53
+ '98 1',
54
+ '99 0.6',
55
+ '100 0.2',
56
+ '101 1',
57
+ '102 0.6',
58
+ '103 0.2',
59
+ '104 0.2',
60
+ '105 0',
61
+ '106 0.2',
62
+ '107 0.2',
63
+ ].join('\n');
64
+
65
+ const coronelTellezProfile2 = [
66
+ '64 0.6',
67
+ '65 0.2',
68
+ '66 0.2',
69
+ '67 0',
70
+ '68 0.6',
71
+ '69 0.6',
72
+ '70 0.2',
73
+ '71 0.2',
74
+ '72 0',
75
+ '73 1',
76
+ '74 0.2',
77
+ '75 0.2',
78
+ '76 0',
79
+ '77 0.6',
80
+ '78 0.2',
81
+ '79 0.2',
82
+ '80 0.2',
83
+ '81 0.2',
84
+ '82 0.2',
85
+ '83 0.2',
86
+ '84 0.2',
87
+ '85 0.2',
88
+ '86 0.2',
89
+ '87 0.2',
90
+ '88 0.6',
91
+ '89 0.2',
92
+ '90 1',
93
+ '91 0.6',
94
+ '92 0.6',
95
+ '93 1',
96
+ '94 0.2',
97
+ '95 0.2',
98
+ '96 1',
99
+ '97 0.2',
100
+ '98 0.2',
101
+ '99 0.2',
102
+ '100 0.6',
103
+ '101 0.2',
104
+ '102 0.2',
105
+ '103 0.2',
106
+ '104 0',
107
+ '105 0',
108
+ '106 0',
109
+ '107 0.6',
110
+ ].join('\n');
111
+
112
+ const examples = {
113
+ '2mol': {
114
+ name: 'RNA–RNA interaction feature overview',
115
+ nameShort: 'All feature showcase',
116
+ description: 'Demonstrates cropping, probability profiles, region and subsequence highlights, and point mutations in one interaction.',
117
+ descriptionShort: 'Showcases all features of vaRRI-js.',
118
+ vaRRIParams: {
119
+ sequence: 'ACGAUCAUGUGGUUUAGAGCAUUUUCGACAGCAG&ACGAAAAAAAGAGCAGACAGUAG',
120
+ structure: '..<<..<<...>>>>...((....(((...((..&............)))))..))..',
121
+ startIndex1: -6,
122
+ startIndex2: 100,
123
+ coloring: 'strand',
124
+ highlighting: 'region',
125
+ backgroundhighlighting: 'basepairs',
126
+ forceLayoutLinearRRI: 1,
127
+ distinctBpTypes: 1,
128
+ cropping: 2,
129
+ forceLayout: 0,
130
+ regionHighlights: '21-25&113-114:0d00ff:0.2',
131
+ subseqHighlights: '1:15-18:338a29:1,2:117-118:1e1ee4:0.7',
132
+ mutations: '1:20G:338a29,2:115C:1e1ee4',
133
+ profileData1: featureOverviewProfile,
134
+ profileIdxRef1: 1,
135
+ profileColorRepresentsOne1: 1,
136
+ profileColorRepresentsOne2: 0,
137
+ },
138
+ },
139
+ 'coronel-tellez-2022': {
140
+ name: 'sRNA-controlled iron sparing response in Staphylococci',
141
+ nameShort: 'SHAPE annotation & cropping',
142
+ authors: 'Coronel-Tellez, et al., 2022',
143
+ doi: 'http://dx.doi.org/10.1093/nar/gkac648',
144
+ description: 'Reproduction of *Figure 6A-bottom* [(Coronel-Tellez, et al., 2022)](http://dx.doi.org/10.1093/nar/gkac648) showing an interaction with position-specific SHAPE probing data annotation and subsequence highlighting. The long input sequences are cropped to the region of interaction +3 nucleotides.',
145
+ descriptionShort: 'Position-specific SHAPE probing data annotation and cropping of long sequences to RRI region.',
146
+ vaRRIParams: {
147
+ sequence: 'AAUUCUAUCUGAAAGAUGUGUGGGGCAUCGUUAUUUUAGGUGGAUAUGAGCAAUUUAUUAAAAGUCAUUUACGGAAAAUAUAUAUAGACGGGGUGAGUAAUAUGCAAGAACAUUUGGUGGUUACACUUGAUAGCAAAGGAGAAGAACUU&UUGAAAAUGAUUAUCAAUACCACAUAGAACAUCCCCCCCACAACGUUUCGUUCUUGUUGGAUUGGUCAUUUUCAAAUAUUCCCCUUUUAUAUGCCCGUAAAAGACAAUAUACGUUAUAACAACGUUUUAUAAAAGCAGUAAACCCUUACGACACUUUAGGUUUACUGCUUUUGU',
148
+ structure: '...............................................................(((.(((((((......((((((((.((((.((((((.(((.............................................&..................................................................))))......))))))))))))))))).))))))).))).....................................................................',
149
+ colorSeq1: 'c9c1c9',
150
+ colorSeq2: 'c9c1c9',
151
+ startIndex1: 1,
152
+ startIndex2: 1,
153
+ cropping: 3,
154
+ forceLayout: 'off',
155
+ backgroundhighlighting: 'nothing',
156
+ highlighting: 'basepairs',
157
+ subseqHighlights: '1:88-93:0f50b8:1,1:102-104:0e7a06:1,2:81-84:e012dd:1,2:94-96:e012dd:1',
158
+ profileData1: coronelTellezProfile1,
159
+ profileColorRepresentsOne1: 1,
160
+ profileColor1: 'ea373c',
161
+ profileData2: coronelTellezProfile2,
162
+ profileColorRepresentsOne2: 1,
163
+ profileColor2: 'ea373c',
164
+ },
165
+ },
166
+ 'wu-2024': {
167
+ name: 'RNA interactome of hypervirulent Klebsiella pneumoniae reveals a small RNA inhibitor of capsular mucoviscosity and virulence',
168
+ nameShort: 'Mutations & highlighting',
169
+ authors: 'Wu et al., 2024',
170
+ doi: 'https://doi.org/10.1101/2024.06.23.600155',
171
+ description: 'Reproduction of Figure 4C [(Wu et al., 2024)](https://doi.org/10.1101/2024.06.23.600155) showing an interaction with 4 mutations and a subsequence highlighting within a sequence context upstream of the start codon.',
172
+ descriptionShort: 'Subsequence highlighting and mutations within a sequence context.',
173
+ vaRRIParams: {
174
+ sequence: 'AACUCGCGAAAGCCAUAAAAACCAGGGAGACA&UUCCCUGGUGUUGGCGCAGUAUUCGCGCA',
175
+ structure: '....((((((.((((.....((((((((....&.))))))))..))))......))))))..',
176
+ startIndex1: -35,
177
+ startIndex2: 2,
178
+ subseqHighlights: '1:-12--6:0dec3f:0.9',
179
+ mutations: '1:-14G:fb0bcb,1:-13G:fb0bcb,2:8C:fb0bcb,2:9C:fb0bcb',
180
+ forceLayout: 'off',
181
+ },
182
+ },
183
+ 'IntaRNA-seeds': {
184
+ name: 'Showcasing potential seed regions considered by IntaRNA',
185
+ nameShort: 'IntaRNA seed regions',
186
+ description: 'Highlighting of the two potential seed interactions considered by IntaRNA to predict the shown interaction between the two sequences. The highlighting is done using a semi-transparent purple color, which allows to show overlapping regions.',
187
+ descriptionShort: 'Opaque highlighting of multiple potential IntaRNA seed regions.',
188
+ vaRRIParams: {
189
+ sequence:'CUUAGCCGUAAUUGGAUUAGCUGAUGAACAAACUUCUCGUGAGUCUGCUGUUGACCCUGGGUCUGAC&GAGAGACCCACGCAGUCGGACUCUUCAGAUUAUCUCCUCAUCAGGCUAAUCACGGUUUUU',
190
+ colorSeq1:'#add8e6',
191
+ startIndex1:-23,
192
+ colorSeq2:'#f4bb44',
193
+ startIndex2:64,
194
+ structure:'...((((((.....(((((((((((((.......(((...((((((((((.......(((((((...&...)))))))..))).)))))))...)))........)))))).)))))))))))))...',
195
+ colorBasepair:'#ff0000',
196
+ coloring:'strand',
197
+ highlighting:'region',
198
+ colorRriNodes:'#ff0000',
199
+ forceLayoutLinearRRI: 1,
200
+ distinctBpTypes:1,
201
+ regionHighlights:'35-41&67-73:0D00FF:0.4,-9--3&108-114:0D00FF:0.4',
202
+ forceLayout: 'off',
203
+ },
204
+ },
205
+ 'crossing-rri': {
206
+ name: 'Crossing RRI showcase',
207
+ nameShort: 'Crossing RRI via force field',
208
+ descriptionShort: 'Crossing RNA–RNA interaction resolved via relaxed force-field layout.',
209
+ description: 'Crossing RNA–RNA interactions (w.r.t. the underlying joint-structure layout algorithm of fornac) are typically problematic since their base pairing forms a crossing pseudoknot structure. Some can be layouted when relaxing the force field (see Visualization Settings).',
210
+ vaRRIParams: {
211
+ sequence: 'NNNNNNNNNNNNNNNNN&NNNNNNNNNNNNN',
212
+ structure:'((..((...<<<..<<<&))))...>>>>>>',
213
+ distinctBpTypes: 0,
214
+ forceLayout: 1,
215
+ forceLayoutFreeTails: 1,
216
+ forceLayoutPullCrossing: 1,
217
+ },
218
+ },
219
+ };
220
+
221
+ root.VARRI_EXAMPLES = examples;
222
+
223
+ if (typeof module !== 'undefined' && module.exports) {
224
+ module.exports = examples;
225
+ }
226
+ })(typeof window !== 'undefined' ? window : globalThis);