Spaces:
Running
§5 Folding: HTML + CSS scaffolding with 3Dmol side-by-side viewers
Browse filesReplaces the "coming soon" stub with a real section that wires up the
/fold backend to a pair of 3Dmol cartoon viewers. Layout mirrors §1's
two-track convention (carbon completion on the left, reference on the
right) so the comparison feels native to the rest of the demo.
Frontend:
- Pulls 3Dmol 2.5.1 from jsDelivr (defer) — small enough to inline-cache,
no bundler needed. Pinned version for reproducibility.
- New CSS classes (.fold-grid, .fold-viewer, .fold-viewer-label,
.fold-legend, .fold-legend-bar). Two-column at >=720px, stacked below.
- Cartoon coloured by B-factor via 3Dmol's rwb gradient — ESMFold writes
pLDDT into the B-factor column so per-residue confidence shading is
free. Legend shows the same red→white→blue map.
- Hand-rolled pill UI for gene selection (HBB / INS / LYZ), reusing the
existing .pill and .pills classes.
- Stat row (residues, pLDDT mean carbon, pLDDT mean ref, 1D identity)
reuses .stat-row / .stat-pair, so the typography matches §1-§4.
- Viewers spin (auto-rotate) once loaded, like the ↻ glyph the stub used
to promise.
Scaffolding caveat:
For this commit both viewers are fed the same PDB so we can verify the
render path, the colouring, and the stat row end-to-end with a single
NIM call. The full DNA→ORF→AA→fold pipeline that produces a real
divergence between the two viewers lands in the next commit.
Touches only the §5 section + 3 small zones (<head> script, CSS block,
JS IIFE between §4 and §7). Everything else is left alone.
Co-authored-by: Cursor <cursoragent@cursor.com>
|
@@ -7,6 +7,9 @@
|
|
| 7 |
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 8 |
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
| 9 |
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;600&family=Inter:wght@300;400;500;600&display=swap">
|
|
|
|
|
|
|
|
|
|
| 10 |
<style>
|
| 11 |
* { margin: 0; padding: 0; box-sizing: border-box; }
|
| 12 |
html { scroll-behavior: smooth; }
|
|
@@ -329,6 +332,51 @@
|
|
| 329 |
.stat-pair-val { color: #1f1f1d; font-variant-numeric: tabular-nums; }
|
| 330 |
.stat-pair-val.muted { color: #aaa; }
|
| 331 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 332 |
/* Mismatch highlighting in reference row */
|
| 333 |
.ref-mismatch { background: rgba(188, 46, 37, 0.18); color: #b00020; }
|
| 334 |
.ref-match { color: #999; }
|
|
@@ -933,22 +981,67 @@
|
|
| 933 |
</section>
|
| 934 |
|
| 935 |
<!-- ============================================================ -->
|
| 936 |
-
<!-- §5 — FOLDING (
|
| 937 |
<!-- ============================================================ -->
|
| 938 |
<section id="folding">
|
| 939 |
-
<div class="section-num">§5 ·
|
| 940 |
<div class="section-title">From sequence to structure</div>
|
| 941 |
<p class="lede">
|
| 942 |
When Carbon completes an open reading frame, the resulting bases translate to a protein —
|
| 943 |
-
a protein that folds. We
|
| 944 |
3D structure inline, alongside the same protein folded from the reference sequence so you
|
| 945 |
can see whether Carbon's continuation produced something biologically plausible.
|
| 946 |
</p>
|
| 947 |
|
| 948 |
-
<div class="
|
| 949 |
-
<div class="
|
| 950 |
-
|
| 951 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 952 |
</div>
|
| 953 |
</section>
|
| 954 |
|
|
@@ -2426,6 +2519,149 @@ function loadGenes() {
|
|
| 2426 |
window.addEventListener("resize", () => renderAll());
|
| 2427 |
})();
|
| 2428 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2429 |
// =========================================================================
|
| 2430 |
// §7 — Tokenizer (1-mer vs 6-mer)
|
| 2431 |
// =========================================================================
|
|
|
|
| 7 |
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 8 |
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
| 9 |
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;600&family=Inter:wght@300;400;500;600&display=swap">
|
| 10 |
+
<!-- 3Dmol.js: lightweight WebGL molecular viewer, used by §5 (folding) to
|
| 11 |
+
render ESMFold-predicted protein cartoons. Pinned for reproducibility. -->
|
| 12 |
+
<script defer src="https://cdn.jsdelivr.net/npm/3dmol@2.5.1/build/3Dmol-min.js"></script>
|
| 13 |
<style>
|
| 14 |
* { margin: 0; padding: 0; box-sizing: border-box; }
|
| 15 |
html { scroll-behavior: smooth; }
|
|
|
|
| 332 |
.stat-pair-val { color: #1f1f1d; font-variant-numeric: tabular-nums; }
|
| 333 |
.stat-pair-val.muted { color: #aaa; }
|
| 334 |
|
| 335 |
+
/* --- §5 Folding viewers --- */
|
| 336 |
+
/* Two square 3Dmol canvases side by side. On narrow screens (<720px) we
|
| 337 |
+
stack them vertically so each viewer keeps a comfortable size. */
|
| 338 |
+
.fold-grid {
|
| 339 |
+
display: grid; grid-template-columns: 1fr 1fr; gap: 16px;
|
| 340 |
+
margin-top: 12px;
|
| 341 |
+
}
|
| 342 |
+
.fold-viewer-col { display: flex; flex-direction: column; }
|
| 343 |
+
.fold-viewer-label {
|
| 344 |
+
font-family: "JetBrains Mono", monospace;
|
| 345 |
+
font-size: 9px; color: #888; text-transform: uppercase; letter-spacing: 1.5px;
|
| 346 |
+
margin-bottom: 4px;
|
| 347 |
+
}
|
| 348 |
+
.fold-viewer {
|
| 349 |
+
position: relative;
|
| 350 |
+
width: 100%; aspect-ratio: 1 / 1;
|
| 351 |
+
background: #fafaf7;
|
| 352 |
+
border: 1px solid #eee;
|
| 353 |
+
overflow: hidden;
|
| 354 |
+
}
|
| 355 |
+
.fold-viewer canvas { display: block; }
|
| 356 |
+
.fold-viewer .fold-empty {
|
| 357 |
+
position: absolute; inset: 0;
|
| 358 |
+
display: flex; align-items: center; justify-content: center;
|
| 359 |
+
font-family: "JetBrains Mono", monospace; font-size: 10px;
|
| 360 |
+
color: #bbb; letter-spacing: 1.5px; text-transform: uppercase;
|
| 361 |
+
pointer-events: none;
|
| 362 |
+
}
|
| 363 |
+
.fold-legend {
|
| 364 |
+
font-family: "JetBrains Mono", monospace;
|
| 365 |
+
font-size: 9px; color: #888; text-transform: uppercase; letter-spacing: 1.2px;
|
| 366 |
+
display: flex; align-items: center; gap: 8px;
|
| 367 |
+
margin-top: 10px;
|
| 368 |
+
}
|
| 369 |
+
/* pLDDT colour key: red = low confidence, white = mid, blue = high.
|
| 370 |
+
Matches the 3Dmol "rwb" gradient applied to cartoon B-factors. */
|
| 371 |
+
.fold-legend-bar {
|
| 372 |
+
width: 120px; height: 6px;
|
| 373 |
+
background: linear-gradient(to right, #b00020 0%, #f0e8e0 50%, #2c5aa0 100%);
|
| 374 |
+
border-radius: 1px;
|
| 375 |
+
}
|
| 376 |
+
@media (max-width: 720px) {
|
| 377 |
+
.fold-grid { grid-template-columns: 1fr; }
|
| 378 |
+
}
|
| 379 |
+
|
| 380 |
/* Mismatch highlighting in reference row */
|
| 381 |
.ref-mismatch { background: rgba(188, 46, 37, 0.18); color: #b00020; }
|
| 382 |
.ref-match { color: #999; }
|
|
|
|
| 981 |
</section>
|
| 982 |
|
| 983 |
<!-- ============================================================ -->
|
| 984 |
+
<!-- §5 — FOLDING (DNA → protein → 3D structure via ESMFold) -->
|
| 985 |
<!-- ============================================================ -->
|
| 986 |
<section id="folding">
|
| 987 |
+
<div class="section-num">§5 · Folding</div>
|
| 988 |
<div class="section-title">From sequence to structure</div>
|
| 989 |
<p class="lede">
|
| 990 |
When Carbon completes an open reading frame, the resulting bases translate to a protein —
|
| 991 |
+
a protein that folds. We feed the resulting ORF into ESMFold and render the
|
| 992 |
3D structure inline, alongside the same protein folded from the reference sequence so you
|
| 993 |
can see whether Carbon's continuation produced something biologically plausible.
|
| 994 |
</p>
|
| 995 |
|
| 996 |
+
<div class="demo" id="demoFold">
|
| 997 |
+
<div class="demo-toolbar">
|
| 998 |
+
<span>gene</span>
|
| 999 |
+
<span id="dfold-pills" class="pills"></span>
|
| 1000 |
+
<span class="spacer"></span>
|
| 1001 |
+
<button id="dfold-go" class="action primary">▶ fold</button>
|
| 1002 |
+
<span class="status" id="dfold-status"><span class="dot"></span><span>idle</span></span>
|
| 1003 |
+
</div>
|
| 1004 |
+
|
| 1005 |
+
<div class="gene-info" id="dfold-info">pick a gene and hit fold</div>
|
| 1006 |
+
|
| 1007 |
+
<div class="seq-label">protein sequence (translated from reference ORF)</div>
|
| 1008 |
+
<div class="seq-block" id="dfold-aa">—</div>
|
| 1009 |
+
|
| 1010 |
+
<div class="fold-grid">
|
| 1011 |
+
<div class="fold-viewer-col">
|
| 1012 |
+
<div class="fold-viewer-label">carbon completion</div>
|
| 1013 |
+
<div class="fold-viewer" id="dfold-viewer-carbon">
|
| 1014 |
+
<div class="fold-empty">— no structure yet —</div>
|
| 1015 |
+
</div>
|
| 1016 |
+
</div>
|
| 1017 |
+
<div class="fold-viewer-col">
|
| 1018 |
+
<div class="fold-viewer-label">reference</div>
|
| 1019 |
+
<div class="fold-viewer" id="dfold-viewer-ref">
|
| 1020 |
+
<div class="fold-empty">— no structure yet —</div>
|
| 1021 |
+
</div>
|
| 1022 |
+
</div>
|
| 1023 |
+
</div>
|
| 1024 |
+
|
| 1025 |
+
<div class="fold-legend">
|
| 1026 |
+
pLDDT
|
| 1027 |
+
<span class="fold-legend-bar" aria-hidden="true"></span>
|
| 1028 |
+
low → high · drag to rotate · scroll to zoom
|
| 1029 |
+
</div>
|
| 1030 |
+
|
| 1031 |
+
<div class="stat-row" id="dfold-stats">
|
| 1032 |
+
<div class="stat-pair"><span class="stat-pair-label">residues</span><span class="stat-pair-val muted" id="dfold-n">—</span></div>
|
| 1033 |
+
<div class="stat-pair"><span class="stat-pair-label">pLDDT mean (carbon)</span><span class="stat-pair-val muted" id="dfold-plddt-c">—</span></div>
|
| 1034 |
+
<div class="stat-pair"><span class="stat-pair-label">pLDDT mean (ref)</span><span class="stat-pair-val muted" id="dfold-plddt-r">—</span></div>
|
| 1035 |
+
<div class="stat-pair"><span class="stat-pair-label">identity (1D)</span><span class="stat-pair-val muted" id="dfold-id">—</span></div>
|
| 1036 |
+
</div>
|
| 1037 |
+
</div>
|
| 1038 |
+
|
| 1039 |
+
<div class="takeaway">
|
| 1040 |
+
<strong>What to look for</strong>
|
| 1041 |
+
A high <em>pLDDT</em> means ESMFold is confident the predicted structure
|
| 1042 |
+
is correct for that residue. When Carbon's completion diverges at the
|
| 1043 |
+
base level but still produces a sequence whose 3D fold matches the
|
| 1044 |
+
reference, the model has captured something deeper than memorization.
|
| 1045 |
</div>
|
| 1046 |
</section>
|
| 1047 |
|
|
|
|
| 2519 |
window.addEventListener("resize", () => renderAll());
|
| 2520 |
})();
|
| 2521 |
|
| 2522 |
+
// =========================================================================
|
| 2523 |
+
// §5 — Folding (ESMFold via /fold + 3Dmol cartoon)
|
| 2524 |
+
//
|
| 2525 |
+
// SCAFFOLDING NOTE
|
| 2526 |
+
// ----------------
|
| 2527 |
+
// For this commit we hard-code three short reference proteins (HBB, INS,
|
| 2528 |
+
// LYZ) and fold each one to populate both viewers with the same structure.
|
| 2529 |
+
// That's enough to validate the layout, the 3Dmol render path, the pLDDT
|
| 2530 |
+
// colouring, and the stat row. The full DNA→ORF→AA→fold pipeline (which
|
| 2531 |
+
// will make the two viewers actually disagree) lands in the next commit.
|
| 2532 |
+
// =========================================================================
|
| 2533 |
+
(function initDemoFold() {
|
| 2534 |
+
// Famous short proteins, hand-picked because they fit ESMFold's 1024 aa
|
| 2535 |
+
// cap with room to spare and have textbook folds that are instantly
|
| 2536 |
+
// recognisable (HBB = the 8-helix globin sandwich, INS = the disulfide
|
| 2537 |
+
// hairpin, LYZ = the α+β lysozyme architecture).
|
| 2538 |
+
const SEQS = {
|
| 2539 |
+
HBB: "MVHLTPEEKSAVTALWGKVNVDEVGGEALGRLLVVYPWTQRFFESFGDLSTPDAVMGNPKVKAHGKKVLGAFSDGLAHLDNLKGTFATLSELHCDKLHVDPENFRLLGNVLVCVLAHHFGKEFTPPVQAAYQKVVAGVANALAHKYH",
|
| 2540 |
+
INS: "MALWMRLLPLLALLALWGPDPAAAFVNQHLCGSHLVEALYLVCGERGFFYTPKTRREAEDLQVGQVELGGGPGAGSLQPLALEGSLQKRGIVEQCCTSICSLYQLENYCN",
|
| 2541 |
+
LYZ: "MKALIVLGLVLLSVTVQGKVFERCELARTLKRLGMDGYRGISLANWMCLAKWESGYNTRATNYNAGDRSTDYGIFQINSRYWCNDGKTPGAVNACHLSCSALLQDNIADAVACAKRVVRDPQGIRAWVAWRNRCQNRDVRQYVQGCGV",
|
| 2542 |
+
};
|
| 2543 |
+
|
| 2544 |
+
let currentGene = "HBB";
|
| 2545 |
+
let viewerCarbon = null;
|
| 2546 |
+
let viewerRef = null;
|
| 2547 |
+
|
| 2548 |
+
const els = {
|
| 2549 |
+
pills: document.getElementById("dfold-pills"),
|
| 2550 |
+
info: document.getElementById("dfold-info"),
|
| 2551 |
+
aa: document.getElementById("dfold-aa"),
|
| 2552 |
+
go: document.getElementById("dfold-go"),
|
| 2553 |
+
status: document.getElementById("dfold-status"),
|
| 2554 |
+
statusText: document.querySelector("#dfold-status span:last-child"),
|
| 2555 |
+
vCarbon: document.getElementById("dfold-viewer-carbon"),
|
| 2556 |
+
vRef: document.getElementById("dfold-viewer-ref"),
|
| 2557 |
+
nRes: document.getElementById("dfold-n"),
|
| 2558 |
+
plddtC: document.getElementById("dfold-plddt-c"),
|
| 2559 |
+
plddtR: document.getElementById("dfold-plddt-r"),
|
| 2560 |
+
identity: document.getElementById("dfold-id"),
|
| 2561 |
+
};
|
| 2562 |
+
|
| 2563 |
+
function renderPills() {
|
| 2564 |
+
els.pills.innerHTML = "";
|
| 2565 |
+
for (const g of Object.keys(SEQS)) {
|
| 2566 |
+
const b = document.createElement("button");
|
| 2567 |
+
b.className = "pill" + (g === currentGene ? " active" : "");
|
| 2568 |
+
b.dataset.gene = g;
|
| 2569 |
+
b.textContent = g;
|
| 2570 |
+
b.addEventListener("click", () => {
|
| 2571 |
+
currentGene = g;
|
| 2572 |
+
renderPills();
|
| 2573 |
+
renderInfo();
|
| 2574 |
+
});
|
| 2575 |
+
els.pills.appendChild(b);
|
| 2576 |
+
}
|
| 2577 |
+
}
|
| 2578 |
+
|
| 2579 |
+
function renderInfo() {
|
| 2580 |
+
const seq = SEQS[currentGene];
|
| 2581 |
+
els.info.innerHTML = `<strong>${currentGene}</strong> · ${seq.length} aa · click <em>fold</em> to predict structure`;
|
| 2582 |
+
// Wrap at 60 chars for readability — matches the seq-block widths used in §1.
|
| 2583 |
+
els.aa.textContent = seq.replace(/(.{60})/g, "$1\n");
|
| 2584 |
+
}
|
| 2585 |
+
|
| 2586 |
+
function setStatus(text, cls) {
|
| 2587 |
+
els.status.className = "status" + (cls ? " " + cls : "");
|
| 2588 |
+
els.statusText.textContent = text;
|
| 2589 |
+
}
|
| 2590 |
+
|
| 2591 |
+
async function fold(sequence) {
|
| 2592 |
+
const resp = await fetch("/fold", {
|
| 2593 |
+
method: "POST",
|
| 2594 |
+
headers: { "Content-Type": "application/json" },
|
| 2595 |
+
body: JSON.stringify({ sequence }),
|
| 2596 |
+
});
|
| 2597 |
+
return resp.json();
|
| 2598 |
+
}
|
| 2599 |
+
|
| 2600 |
+
function makeViewer(host) {
|
| 2601 |
+
if (!window.$3Dmol) return null;
|
| 2602 |
+
// Clear placeholder.
|
| 2603 |
+
host.innerHTML = "";
|
| 2604 |
+
return $3Dmol.createViewer(host, {
|
| 2605 |
+
backgroundColor: "#fafaf7",
|
| 2606 |
+
antialias: true,
|
| 2607 |
+
});
|
| 2608 |
+
}
|
| 2609 |
+
|
| 2610 |
+
function renderStructure(viewer, pdb) {
|
| 2611 |
+
if (!viewer) return;
|
| 2612 |
+
viewer.removeAllModels();
|
| 2613 |
+
viewer.addModel(pdb, "pdb");
|
| 2614 |
+
// Cartoon coloured by B-factor (pLDDT) using the rwb gradient.
|
| 2615 |
+
// ESMFold writes pLDDT into the B-factor column on every atom, so
|
| 2616 |
+
// this gives us per-residue confidence shading for free.
|
| 2617 |
+
viewer.setStyle({}, {
|
| 2618 |
+
cartoon: {
|
| 2619 |
+
colorscheme: { prop: "b", gradient: "rwb", min: 50, max: 100 },
|
| 2620 |
+
},
|
| 2621 |
+
});
|
| 2622 |
+
viewer.zoomTo();
|
| 2623 |
+
viewer.render();
|
| 2624 |
+
viewer.spin(true);
|
| 2625 |
+
}
|
| 2626 |
+
|
| 2627 |
+
async function runFold() {
|
| 2628 |
+
if (!window.$3Dmol) {
|
| 2629 |
+
setStatus("3Dmol not loaded — retry in a sec", "error");
|
| 2630 |
+
return;
|
| 2631 |
+
}
|
| 2632 |
+
const seq = SEQS[currentGene];
|
| 2633 |
+
setStatus(`folding ${currentGene}…`, "streaming");
|
| 2634 |
+
els.go.disabled = true;
|
| 2635 |
+
try {
|
| 2636 |
+
const result = await fold(seq);
|
| 2637 |
+
if (result.error) throw new Error(result.error);
|
| 2638 |
+
// Scaffolding: feed the same PDB to both viewers. Commit 4 will fold
|
| 2639 |
+
// a Carbon-generated sequence here and produce a real divergence.
|
| 2640 |
+
if (!viewerCarbon) viewerCarbon = makeViewer(els.vCarbon);
|
| 2641 |
+
if (!viewerRef) viewerRef = makeViewer(els.vRef);
|
| 2642 |
+
renderStructure(viewerCarbon, result.pdb);
|
| 2643 |
+
renderStructure(viewerRef, result.pdb);
|
| 2644 |
+
|
| 2645 |
+
els.nRes.textContent = result.n_residues ?? "—";
|
| 2646 |
+
els.plddtC.textContent = (result.plddt_mean ?? 0).toFixed(1);
|
| 2647 |
+
els.plddtR.textContent = (result.plddt_mean ?? 0).toFixed(1);
|
| 2648 |
+
els.identity.textContent = "100%";
|
| 2649 |
+
for (const el of [els.nRes, els.plddtC, els.plddtR, els.identity]) {
|
| 2650 |
+
el.classList.remove("muted");
|
| 2651 |
+
}
|
| 2652 |
+
setStatus(result.cached ? "folded (cached)" : "folded", "");
|
| 2653 |
+
} catch (e) {
|
| 2654 |
+
setStatus("error: " + (e.message || e), "error");
|
| 2655 |
+
} finally {
|
| 2656 |
+
els.go.disabled = false;
|
| 2657 |
+
}
|
| 2658 |
+
}
|
| 2659 |
+
|
| 2660 |
+
renderPills();
|
| 2661 |
+
renderInfo();
|
| 2662 |
+
els.go.addEventListener("click", runFold);
|
| 2663 |
+
})();
|
| 2664 |
+
|
| 2665 |
// =========================================================================
|
| 2666 |
// §7 — Tokenizer (1-mer vs 6-mer)
|
| 2667 |
// =========================================================================
|