$sloprun.dev

Code Explainer

demo sandbox: allow-scripts · csp: default-src 'none'

sandboxed and isolated in your browser · never enter a real password in a demo

▶ 7 ran · ✓ 0 worked
i ran it — no login needed:
share: preview embed ↗
post it anywhere:
email the card:

0 reported it broke · the ▶ count is distinct visitors who ran it, counted once each, anonymously

Paste code and read it back in plain English: an overview paragraph, then notes lined up beside the exact lines they describe, so you never have to hold a line number in your head. It opens on a 15-line reduce doing four jobs at once, already explained down to the two ways it can lie to you — +row.amount || 0 swallowing a malformed feed, and a row whose value is literally ~ colliding with a missing field. Start at the notes on lines 4 and 5, try Promise pool and Memoize for two more worked examples, then hit Copy as commented code to get the whole explanation back as a commented source file. An Anthropic key runs it on your own code and stays in the tab's memory only; with no key, the built-in explanations render through exactly the code path a live answer takes.

Embed this demo — put a runnable demo in your blog post

Paste this where you write. It renders a live, runnable demo inline anywhere raw HTML / iframes are allowed — Ghost, WordPress, Notion, Discourse, your own site.

<iframe src="https://sloprun.dev/embed/code-explainer" width="100%" height="640" loading="lazy" allow="" style="border:1px solid #E3E2DC;border-radius:10px" title="Code Explainer — a runnable demo on sloprun.dev"></iframe>
preview ↗

On Medium and dev.to the plain link becomes a rich preview card that links back here — they don't run third-party iframes, so paste the URL there and the reader clicks through to run it. https://sloprun.dev/p/code-explainer

Source

the code you see is the code that just ran raw ↗
Source — the code you see is the code that just ran 1172 lines 56.3 KB index.html
demos/code-explainer/index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="color-scheme" content="light dark">
<link rel="icon" href="data:,">
<title>Code Explainer — sloprun.dev</title>
<style>
/* ── sloprun design tokens (verbatim from demos/tokens.css) ───────────────── */
/* sloprun design tokens — inline this block into every demo (self-contained rule).
   Identity: instrument-panel. Machine facts in mono; human words in sans.
   Green is EARNED: only for "it ran / it worked" states, never decoration. */
:root {
  --bg: #F6F6F3;          /* neutral paper, not cream */
  --surface: #FFFFFF;
  --ink: #1A1D21;
  --muted: #5A6068;
  --line: #E3E2DC;
  --accent: #C05600;      /* phosphor amber, darkened for light bg */
  --accent-soft: #FFF3E6;
  --run: #1A7F37;         /* earned green */
  --run-soft: #E7F4EA;
  --danger: #C93C37;
  --radius: 10px;
  --font-sans: system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-mono: ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, monospace;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #14161A; --surface: #1C1F26; --ink: #E8E6E1; --muted: #9AA0A8;
    --line: #2A2E36; --accent: #FFB454; --accent-soft: #2A2118;
    --run: #3FB950; --run-soft: #16281B; --danger: #F47067;
  }
}
:root[data-theme="dark"] {
  --bg: #14161A; --surface: #1C1F26; --ink: #E8E6E1; --muted: #9AA0A8;
  --line: #2A2E36; --accent: #FFB454; --accent-soft: #2A2118;
  --run: #3FB950; --run-soft: #16281B; --danger: #F47067;
}
body { background: var(--bg); color: var(--ink); font-family: var(--font-sans); }
/* ── end token block ──────────────────────────────────────────────────────── */

/* Syntax palette. Derived from the tokens; deliberately contains NO green —
   green stays reserved for "it ran". Keywords borrow the amber accent, the
   other two hues are stepped far enough apart to stay separable in both
   themes and under protan/deutan simulation.
   --accent-ink is --accent taken two steps darker for the light theme only:
   #C05600 lands at 4.2:1 on --accent-soft, which is under AA for the 10-11px
   labels and inline keywords that use it. Amber bars, dots, rules and focus
   rings still use --accent itself. In dark the two are the same colour. */
:root {
  --accent-ink: #A94C00;
  --t-key: var(--accent-ink);
  --t-str: #0B6E93;
  --t-num: #7A3EA1;
  --t-fn:  #2C3138;
  --t-com: var(--muted);
  --t-pun: #656C75;
  --shadow: 0 1px 2px rgba(26,29,33,.05), 0 8px 24px rgba(26,29,33,.05);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --accent-ink: var(--accent);
    --t-str: #7FC7E8; --t-num: #C9A2F0; --t-fn: #DCD9D3; --t-pun: #8A9199;
    --shadow: 0 1px 2px rgba(0,0,0,.30), 0 8px 24px rgba(0,0,0,.28);
  }
}
:root[data-theme="dark"] {
  --accent-ink: var(--accent);
  --t-str: #7FC7E8; --t-num: #C9A2F0; --t-fn: #DCD9D3; --t-pun: #8A9199;
  --shadow: 0 1px 2px rgba(0,0,0,.30), 0 8px 24px rgba(0,0,0,.28);
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; padding: 0 16px 48px;
  line-height: 1.5; font-size: 15px;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}
.wrap { max-width: 1100px; margin: 0 auto; }
h1, h2, h3 { margin: 0; font-weight: 620; letter-spacing: -.01em; }
p { margin: 0; }
button, input, textarea, select { font: inherit; color: inherit; }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
::selection { background: var(--accent-soft); color: var(--ink); }

[hidden] { display: none !important; }
.sr {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ── header ───────────────────────────────────────────────────────────────── */
.rail {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  padding: 14px 0 12px; border-bottom: 1px solid var(--line);
  font-family: var(--font-mono); font-size: 11.5px; color: var(--muted);
  letter-spacing: .04em; text-transform: uppercase;
}
.rail .sep { opacity: .5; }
.rail .spacer { flex: 1 1 auto; }
.pulse {
  width: 7px; height: 7px; border-radius: 50%; background: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft); flex: none;
}
header.hdr { padding: 26px 0 20px; }
.hdr h1 { font-size: clamp(26px, 5.5vw, 36px); }
.hdr .lede { margin-top: 10px; max-width: 64ch; color: var(--muted); font-size: 15.5px; }
.hdr .lede b { color: var(--ink); font-weight: 600; }
.hdr .lede code { font-family: var(--font-mono); font-size: .88em; color: var(--accent-ink); }

/* ── buttons ──────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 8px 13px; border: 1px solid var(--line); border-radius: 8px;
  background: var(--surface); color: var(--ink);
  font-size: 13.5px; font-weight: 550; cursor: pointer;
  transition: border-color .12s, background .12s, color .12s, opacity .12s;
}
.btn:hover { border-color: var(--muted); }
.btn:active { transform: translateY(1px); }
.btn.primary { background: var(--ink); color: var(--bg); border-color: var(--ink); }
.btn.primary:hover { opacity: .88; border-color: var(--ink); }
.btn.small { padding: 5px 10px; font-size: 12.5px; }
.btn:disabled { opacity: .42; cursor: not-allowed; }
.btn:disabled:active { transform: none; }
.btn .k { font-family: var(--font-mono); font-size: 11.5px; opacity: .7; }

.seg { display: inline-flex; border: 1px solid var(--line); border-radius: 8px; background: var(--surface); overflow: hidden; }
.seg button {
  border: 0; border-left: 1px solid var(--line); background: transparent;
  padding: 8px 12px; font-size: 13px; font-weight: 550; cursor: pointer;
  transition: background .12s, color .12s;
}
.seg button:first-child { border-left: 0; }
.seg button:hover { background: var(--bg); }
.seg button[aria-pressed="true"] { background: var(--accent-soft); color: var(--accent-ink); }
.seg button:focus-visible { outline-offset: -2px; }

/* ── toolbar ──────────────────────────────────────────────────────────────── */
.bar { display: flex; gap: 9px; flex-wrap: wrap; align-items: center; margin: 0 0 12px; }
.bar .spacer { flex: 1 1 auto; }
.bar .lbl {
  font-family: var(--font-mono); font-size: 11px; color: var(--muted);
  letter-spacing: .05em; text-transform: uppercase;
}

.status { font-family: var(--font-mono); font-size: 12px; color: var(--muted); display: flex; align-items: center; gap: 6px; min-height: 20px; }
.status.ok { color: var(--run); }
.status.bad { color: var(--danger); }
.status .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; flex: none; }

/* ── panels ───────────────────────────────────────────────────────────────── */
.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 14px 16px;
}
.panel { margin: 0 0 14px; }
.panel h2 { font-size: 14px; }
.panel .hint { margin-top: 8px; font-size: 12.5px; color: var(--muted); line-height: 1.55; }
.panel .hint code { font-family: var(--font-mono); font-size: .92em; }

.keyhead { display: flex; gap: 10px 18px; align-items: center; flex-wrap: wrap; }
.keyhead h2 { flex: 0 0 auto; }
.keyhead .keyrow { flex: 1 1 300px; margin-top: 0; }
.keyrow { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 10px; }
.keyrow input[type="password"], .keyrow input[type="text"] {
  flex: 1 1 240px; min-width: 0;
  padding: 8px 11px; border: 1px solid var(--line); border-radius: 8px;
  background: var(--bg); font-family: var(--font-mono); font-size: 13px;
}
.keyrow input::placeholder { color: var(--muted); opacity: .8; }

.editor textarea {
  width: 100%; min-height: 190px; resize: vertical;
  padding: 11px 12px; border: 1px solid var(--line); border-radius: 8px;
  background: var(--bg); font-family: var(--font-mono); font-size: 12.6px;
  line-height: 1.6; white-space: pre; overflow: auto; margin-top: 10px;
}
.editor .foot-row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-top: 10px; }

/* ── listing ──────────────────────────────────────────────────────────────── */
.listing {
  position: relative; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; box-shadow: var(--shadow);
}
.listing .prog { position: absolute; inset: 0 0 auto 0; height: 2px; background: transparent; z-index: 2; }
.listing.busy .prog {
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  background-size: 55% 100%; background-repeat: no-repeat;
  animation: sweep 1.15s linear infinite;
}
@keyframes sweep { from { background-position: -60% 0; } to { background-position: 160% 0; } }
.listing.busy .body { opacity: .45; }
.listing .body { transition: opacity .18s; }

.ov {
  padding: 15px 18px; background: var(--accent-soft); border-bottom: 1px solid var(--line);
  display: grid; grid-template-columns: minmax(0, 1fr) 224px; gap: 20px; align-items: start;
}
.ov.solo { grid-template-columns: minmax(0, 1fr); }
.ov .tag {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .09em;
  text-transform: uppercase; color: var(--accent-ink); display: block; margin-bottom: 6px;
}
.ov p { font-size: 14.6px; line-height: 1.62; max-width: 68ch; }
.ov-side { padding-top: 2px; }
.ov-side .k {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .09em;
  text-transform: uppercase; color: var(--accent-ink); display: block;
}
.ov-side ul { list-style: none; margin: 7px 0 0; padding: 0; }
.ov-side li {
  position: relative; padding-left: 13px; margin-top: 5px;
  font-size: 12.4px; line-height: 1.5; color: var(--muted);
}
.ov-side li::before { content: ""; position: absolute; left: 0; top: .62em; width: 7px; height: 1px; background: var(--accent); }
.hint kbd, .ov-side kbd {
  font-family: var(--font-mono); font-size: 11px; color: var(--ink);
  border: 1px solid var(--line); border-radius: 4px; padding: 0 4px; background: var(--surface);
}

.banner {
  display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
  padding: 11px 18px; border-bottom: 1px solid var(--line);
  font-size: 13.5px; color: var(--muted); background: var(--bg);
}
.banner b { color: var(--ink); font-weight: 600; }
.banner .spacer { flex: 1 1 auto; }

.grp { position: relative; display: grid; grid-template-columns: minmax(0, 1.06fr) minmax(0, .94fr); border-top: 1px solid var(--line); }
.grp:first-child { border-top: 0; }
.grp::before { content: ""; position: absolute; left: 0; top: -1px; bottom: 0; width: 2px; background: transparent; }
.grp.hot::before, .grp.pin::before { background: var(--accent); }
.grp.hot .code, .grp.pin .code { background: var(--accent-soft); }
.grp .code { padding: 11px 0; border-right: 1px solid var(--line); transition: background .12s; min-width: 0; }
.ln { display: grid; grid-template-columns: 3ch minmax(0, 1fr); gap: 12px; padding: 0 14px; }
.ln .num {
  font-family: var(--font-mono); font-size: 11px; color: var(--muted);
  text-align: right; user-select: none; padding-top: .3em;
}
.ln code {
  font-family: var(--font-mono); font-size: 12.6px; line-height: 1.72;
  white-space: pre-wrap; word-break: normal; overflow-wrap: break-word;
  padding-left: 2.4ch; text-indent: -2.4ch; min-width: 0;
}
.t-key { color: var(--t-key); }
.t-str { color: var(--t-str); }
.t-num { color: var(--t-num); }
.t-com { color: var(--t-com); font-style: italic; }
.t-pun { color: var(--t-pun); }
.t-fn  { color: var(--t-fn); font-weight: 600; }

.note {
  display: block; width: 100%; text-align: left; border: 0; background: transparent;
  padding: 12px 17px 14px; cursor: pointer; font: inherit; color: inherit;
  transition: background .12s;
}
.note:hover { background: var(--bg); }
.note:focus-visible { outline-offset: -2px; }
.note .r {
  font-family: var(--font-mono); font-size: 10.5px; letter-spacing: .05em;
  color: var(--accent-ink); background: var(--accent-soft);
  padding: 2px 7px; border-radius: 999px; display: inline-block; vertical-align: 2px;
}
.note .nt { display: inline; font-size: 13.8px; font-weight: 620; letter-spacing: -.01em; margin-left: 8px; }
.note .np { display: block; margin-top: 6px; font-size: 13.5px; line-height: 1.62; color: var(--ink); }
.note.empty { cursor: default; color: var(--muted); }
.note.empty:hover { background: transparent; }
.note.empty .dash { font-family: var(--font-mono); font-size: 12px; color: var(--muted); }
.grp.stale .note .np, .grp.stale .note .nt { opacity: .7; }

code.ic {
  font-family: var(--font-mono); font-size: .9em;
  background: var(--bg); border: 1px solid var(--line);
  padding: 0 4px; border-radius: 4px;
}
.ov code.ic { background: var(--surface); border-color: transparent; }
.note:hover code.ic { background: var(--surface); }

footer.foot {
  margin-top: 30px; padding-top: 14px; border-top: 1px solid var(--line);
  font-family: var(--font-mono); font-size: 11.5px; color: var(--muted);
  display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
}
footer.foot .spacer { flex: 1 1 auto; }

@media (max-width: 820px) {
  .ov { grid-template-columns: minmax(0, 1fr); gap: 12px; }
  .grp { grid-template-columns: minmax(0, 1fr); }
  .grp .code { border-right: 0; padding-bottom: 4px; }
  .note { padding-top: 4px; padding-bottom: 15px; }
  .note::before {
    content: ""; display: block; width: 26px; height: 2px;
    background: var(--line); margin: 6px 0 9px;
  }
  .grp.hot .note::before, .grp.pin .note::before { background: var(--accent); }
}
@media (max-width: 420px) {
  body { padding: 0 11px 40px; font-size: 14.5px; }
  .ln { padding: 0 10px; gap: 8px; grid-template-columns: 2.4ch minmax(0, 1fr); }
  .ln code { font-size: 12px; }
  .ov, .banner { padding-left: 13px; padding-right: 13px; }
  .note { padding-left: 13px; padding-right: 13px; }
  .btn { padding: 8px 11px; }
}
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; transition-duration: .001ms !important; }
  .listing.busy .prog { background: var(--accent); opacity: .55; }
  .btn:active { transform: none; }
}
</style>
</head>
<body>
<div class="wrap">

  <div class="rail">
    <span class="pulse" aria-hidden="true"></span>
    <span>javascript</span>
    <span class="sep">·</span>
    <span id="railMode">example explanation</span>
    <span class="sep">·</span>
    <span>your key, your tab</span>
    <span class="spacer"></span>
    <button class="btn small" id="themeBtn" type="button" title="Toggle light / dark">
      <span aria-hidden="true">◐</span> <span id="themeLbl">Dark</span>
    </button>
  </div>

  <header class="hdr">
    <h1>Code Explainer</h1>
    <p class="lede">
      Paste code, get it in plain English: one paragraph of overview, then notes
      lined up beside the exact lines they describe. It opens on a
      <b>15-line <code>reduce</code></b> that is quietly doing four jobs at once —
      already explained, including the two ways it can lie to you. Bring an
      Anthropic key to run it on your own code.
    </p>
  </header>

  <div class="bar">
    <span class="lbl" id="presetLbl">Snippet</span>
    <div class="seg" role="group" aria-labelledby="presetLbl" id="presets">
      <button type="button" data-preset="rollup" aria-pressed="true">Reduce rollup</button>
      <button type="button" data-preset="pool" aria-pressed="false">Promise pool</button>
      <button type="button" data-preset="memo" aria-pressed="false">Memoize</button>
    </div>
    <button class="btn" id="editBtn" type="button" aria-expanded="false" aria-controls="editorPanel">Paste your own</button>
    <span class="spacer"></span>
    <button class="btn" id="copyBtn" type="button" title="Copy the code with the explanation woven in as comments">Copy as commented code</button>
    <button class="btn primary" id="explainBtn" type="button">Explain <span class="k" id="modHint" aria-hidden="true">Ctrl+Enter</span></button>
  </div>

  <div class="bar" style="margin-bottom:14px">
    <span class="status" id="status" role="status" aria-live="polite"></span>
  </div>

  <section class="card panel editor" id="editorPanel" aria-labelledby="h-edit" hidden>
    <h2 id="h-edit">Your code</h2>
    <p class="hint" style="margin-top:4px">
      Edits re-render the listing as you type. Any language works — the syntax colouring is
      tuned for JavaScript, the explanation is not.
    </p>
    <label class="sr" for="src">Source code</label>
    <textarea id="src" spellcheck="false" autocomplete="off" autocapitalize="off" autocorrect="off" wrap="off"></textarea>
    <div class="foot-row">
      <button class="btn primary" id="explainBtn2" type="button">Explain this</button>
      <button class="btn" id="restoreBtn" type="button">Restore snippet</button>
      <button class="btn" id="clearBtn" type="button">Clear</button>
      <span class="status" id="srcStats"></span>
    </div>
  </section>

  <section class="card panel" id="keyPanel" aria-labelledby="h-key" hidden>
    <div class="keyhead">
      <h2 id="h-key">Explain your own code</h2>
      <form class="keyrow" id="keyForm">
        <label class="sr" for="key">Anthropic API key</label>
        <input type="password" id="key" placeholder="sk-ant-..." autocomplete="off" spellcheck="false">
        <button class="btn primary" type="submit">Connect</button>
      </form>
    </div>
    <p class="hint" id="keyState"></p>
  </section>

  <section class="card panel editor" id="copyPanel" aria-labelledby="h-copy" hidden>
    <h2 id="h-copy">Commented source</h2>
    <p class="hint" style="margin-top:4px">
      This browser would not let the page write to your clipboard, so here it is instead — already
      selected, ready for <kbd>Ctrl</kbd>/<kbd>Cmd</kbd> + <kbd>C</kbd>.
    </p>
    <label class="sr" for="copyOut">Commented source</label>
    <textarea id="copyOut" readonly spellcheck="false"></textarea>
    <div class="foot-row"><button class="btn" id="copyClose" type="button">Close</button></div>
  </section>

  <section class="listing" id="listing" aria-labelledby="h-out">
    <h2 class="sr" id="h-out">Explanation</h2>
    <div class="prog" aria-hidden="true"></div>
    <div class="body" id="out"></div>
  </section>

  <footer class="foot">
    <span>demo · sloprun.dev</span>
    <span class="spacer"></span>
    <span id="meta"></span>
  </footer>
</div>

<script type="text/plain" id="code-rollup">
const rollup = (rows, keys) =>
  Object.values(
    rows.reduce((acc, row, i) => {
      const k = keys.map((f) => row[f] ?? "~").join("\u0001");
      const b = (acc[k] ??= { key: k, n: 0, sum: 0, min: Infinity, tags: new Set(), at: i });
      b.n += 1;
      b.sum += +row.amount || 0;
      b.min = Math.min(b.min, +row.amount || 0);
      (row.tags ?? []).forEach((t) => b.tags.add(t));
      return acc;
    }, Object.create(null))
  )
    .map(({ tags, ...rest }) => ({ ...rest, tags: [...tags].sort(), avg: rest.sum / rest.n }))
    .sort((a, b) => b.sum - a.sum || a.at - b.at)
    .slice(0, 10);
</script>

<script type="text/plain" id="code-pool">
async function pool(items, limit, worker) {
  const results = new Array(items.length);
  let cursor = 0;
  const runners = Array.from({ length: Math.min(limit, items.length) }, async () => {
    while (cursor < items.length) {
      const i = cursor++;
      try {
        results[i] = { ok: true, value: await worker(items[i], i) };
      } catch (err) {
        results[i] = { ok: false, error: err };
      }
    }
  });
  await Promise.all(runners);
  return results;
}
</script>

<script type="text/plain" id="code-memo">
const memo = new WeakMap();
function memoizeByNode(fn) {
  return function cached(node, ...args) {
    let perNode = memo.get(node);
    if (!perNode) memo.set(node, (perNode = new Map()));
    const key = args.length ? JSON.stringify(args) : "";
    if (perNode.has(key)) return perNode.get(key);
    const value = fn.call(this, node, ...args);
    perNode.set(key, value);
    if (perNode.size > 64) {
      const oldest = perNode.keys().next().value;
      perNode.delete(oldest);
    }
    return value;
  };
}
</script>

<script>
(function () {
  "use strict";

  /* ── canned explanations ─────────────────────────────────────────────────
     Shown before any key is connected, so the demo is worth reading with no
     setup at all. Same JSON shape the model is asked to return. */

  var EXPL = {};

  EXPL.rollup = {
    overview:
      "This is a group-by folded into a single `reduce`. It walks a list of records once, " +
      "buckets them by a composite key built from whatever fields you hand it, and accumulates " +
      "a count, a sum, a running minimum and a set of tags per bucket. Everything after the " +
      "reduce is presentation: turn the lookup table back into an array, tidy each bucket, rank " +
      "by total, keep the top ten. The clever parts live on lines 4 and 5 — and so do the two " +
      "ways this can quietly lie to you.",
    groups: [
      { start: 1, end: 2, title: "The shape of the thing",
        text: "One expression, no statements: `rollup` takes rows plus a list of field names and hands back an array. `Object.values` runs last but reads first — the reduce underneath builds a keyed lookup object, and this unwraps it into a plain array of buckets." },
      { start: 3, end: 3, title: "reduce standing in for group-by",
        text: "`acc` is not a running total here, it is a dictionary that gets mutated on every pass. The third parameter `i` is the row's original position, stashed away so that ties can later be broken by input order instead of arbitrarily." },
      { start: 4, end: 4, title: "Many fields, one key",
        text: "Each requested field is read off the row and joined into a single string key. `??` substitutes `~` only for `null` and `undefined`, so a legitimate `0` or empty string survives — which is usually what you want. The separator is U+0001, a control character picked because real data almost never contains it. Almost: a row whose value is literally `~` is now indistinguishable from a row that was missing that field." },
      { start: 5, end: 5, title: "Get-or-create in one move",
        text: "`??=` assigns the fresh bucket only when `acc[k]` is absent. Wrapping it in parentheses turns the whole thing into an expression that evaluates to the bucket, so `b` points at the right object whether it was just created or already there. Two lookups' worth of intent, one line." },
      { start: 6, end: 9, title: "The accumulation itself",
        text: "Count, sum, running minimum, and a union of tags via a `Set`. `+row.amount || 0` is doing two jobs: unary `+` coerces the string `42` into the number 42, and `|| 0` swallows the `NaN` that a value like `42 USD` produces. Convenient — and the reason a malformed feed shows up as a suspiciously round total rather than an error." },
      { start: 10, end: 12, title: "Hand back, and the seed",
        text: "`return acc` on every pass is not optional; forget it and the next iteration receives `undefined`. The seed is `Object.create(null)` rather than `{}`, so a group key of `constructor` or `__proto__` is just a key and cannot collide with anything inherited from `Object.prototype`." },
      { start: 13, end: 13, title: "Tidy each bucket",
        text: "Destructuring with rest pulls the `Set` out and spreads everything else back — the idiomatic way to say the same record, minus this field. The set becomes a sorted array so the output is stable and JSON-serialisable, and the average is derived at the end instead of being carried along." },
      { start: 14, end: 15, title: "Rank, then cut",
        text: "`b.sum - a.sum || a.at - b.at` reads as: by total, descending; if exactly equal, whoever appeared first wins. The `||` only fires when the first comparison is `0`. The slice happens after the sort, so this is a genuine top ten rather than the first ten it happened to see." }
    ]
  };

  EXPL.pool = {
    overview:
      "A concurrency limiter: run `worker` over every item, but never more than `limit` of them " +
      "in flight at once. Instead of chopping the list into batches — which stalls on the slowest " +
      "item in each batch — it starts a fixed number of workers that each pull the next index off " +
      "a shared cursor until the list runs dry. Results come back in input order, with failures " +
      "captured as values rather than thrown.",
    groups: [
      { start: 1, end: 3, title: "Signature and shared state",
        text: "`results` is pre-sized to the input length so every slot has a fixed home, which is what preserves input order later. `cursor` is the single piece of state that all the workers will share." },
      { start: 4, end: 4, title: "N workers, not N batches",
        text: "`Array.from` with a `length` object builds exactly `limit` async functions, capped at the item count so a three-item list never spawns ten idle workers. Calling them produces an array of promises that are already running." },
      { start: 5, end: 6, title: "The claim, and why it is safe",
        text: "`cursor++` reads the value and increments it. Because JavaScript is single-threaded and there is no `await` between the read and the write, two workers can never claim the same index. That is the entire trick: a work queue with no queue." },
      { start: 7, end: 11, title: "Failures become values",
        text: "The `try` sits inside the loop, not around it. If it wrapped the whole `while`, the first rejected item would kill that worker for good and silently reduce your concurrency for the rest of the run. Instead each result is tagged `ok: true` or `ok: false` and the worker keeps pulling." },
      { start: 12, end: 16, title: "Drain, then return in order",
        text: "Once the cursor passes the end, every runner falls out of its loop and resolves. `Promise.all` waits for all of them and cannot reject here, since every error was already boxed up. The caller gets one array in the original order, each slot saying for itself whether it worked." }
    ]
  };

  EXPL.memo = {
    overview:
      "A memoiser for functions whose first argument is a DOM node. It caches results per node, " +
      "then per argument list, and evicts the oldest entry once a node accumulates more than 64 " +
      "of them. The interesting choices are the two map types: a `WeakMap` on the outside so " +
      "detached nodes can be collected, and an ordinary `Map` on the inside because insertion " +
      "order is load-bearing.",
    groups: [
      { start: 1, end: 1, title: "WeakMap so nodes can die",
        text: "A `WeakMap` holds its keys weakly: once the rest of the page drops that node, the entry goes with it. With a plain `Map` here, every node this wrapper ever touched would be pinned in memory forever — a textbook leak in long-lived single-page apps." },
      { start: 2, end: 3, title: "A wrapper that keeps its receiver",
        text: "The returned value is a `function` declaration rather than an arrow, on purpose: it needs its own `this` so the wrapper can be used as a method. Rest parameters split the node off from whatever else the caller passed." },
      { start: 4, end: 5, title: "Two-level cache, created lazily",
        text: "Outer level is node to `Map`, inner is argument-key to value. The assignment nested inside the `set` call both stores the new `Map` and leaves `perNode` pointing at it — compact, and a common source of a double-take on review." },
      { start: 6, end: 6, title: "The fragile part",
        text: "`JSON.stringify` as a cache key is order-sensitive and lossy: `{a:1,b:2}` and `{b:2,a:1}` are different keys, `undefined` and functions vanish, and anything cyclic throws outright. It is fine for primitives and shallow options objects, and a bug waiting to happen for anything richer." },
      { start: 7, end: 7, title: "has before get",
        text: "Checking `has` rather than testing the result of `get` is deliberate: a genuinely cached `undefined` still counts as a hit. Written the obvious way, any function that returns `undefined` would be recomputed on every single call." },
      { start: 8, end: 9, title: "Call through, then store",
        text: "`fn.call(this, ...)` forwards the receiver captured above so a memoised method still sees the object it was called on. The result is stored only after a successful call — a throw leaves the cache untouched, so failures are not memoised." },
      { start: 10, end: 13, title: "FIFO, sold as LRU",
        text: "A `Map` iterates in insertion order, so `keys().next().value` is the oldest inserted key. Note what this does not do: reading an entry never moves it, so the hottest key in the cache is still evicted first once it is the oldest. It is a first-in-first-out bound, not a least-recently-used one — the gap most readers assume is not there." },
      { start: 14, end: 16, title: "Return the fresh value",
        text: "The freshly computed value is returned directly rather than read back out of the map, which also means a value evicted by the line above is still handed to this caller correctly." }
    ]
  };

  /* ── snippets ────────────────────────────────────────────────────────────── */
  function txt(id) {
    var el = document.getElementById(id);
    return el ? el.textContent.replace(/^\n/, "").replace(/\s+$/, "") : "";
  }
  var PRESETS = {
    rollup: { label: "Reduce rollup", code: txt("code-rollup"), expl: EXPL.rollup },
    pool:   { label: "Promise pool",  code: txt("code-pool"),   expl: EXPL.pool },
    memo:   { label: "Memoize",       code: txt("code-memo"),   expl: EXPL.memo }
  };

  /* ── elements ────────────────────────────────────────────────────────────── */
  function $(id) { return document.getElementById(id); }
  var out = $("out"), listing = $("listing"), statusEl = $("status"), metaEl = $("meta");
  var srcEl = $("src"), srcStats = $("srcStats"), editorPanel = $("editorPanel"), editBtn = $("editBtn");
  var keyPanel = $("keyPanel"), keyForm = $("keyForm"), keyInput = $("key"), keyState = $("keyState");
  var explainBtn = $("explainBtn"), explainBtn2 = $("explainBtn2"), copyBtn = $("copyBtn");
  var railMode = $("railMode"), themeBtn = $("themeBtn"), themeLbl = $("themeLbl");
  var copyPanel = $("copyPanel"), copyOut = $("copyOut");
  var restoreBtn = $("restoreBtn"), clearBtn = $("clearBtn");

  var state = { preset: "rollup", code: "", expl: null, explFor: "", source: "example", pinned: -1 };
  var busy = false, tick = null;

  /* the shortcut handler accepts both modifiers, so the label should match the
     keyboard the visitor is actually looking at */
  var MODKEY = /Mac|iPhone|iPad|iPod/i.test((navigator.platform || "") + " " + (navigator.userAgent || ""))
    ? "\u2318" : "Ctrl";

  /* ── theme: prefers-color-scheme by default, platform postMessage wins ───── */
  var root = document.documentElement;
  function effectiveTheme() {
    var set = root.getAttribute("data-theme");
    if (set === "dark" || set === "light") return set;
    return window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
  }
  function applyTheme(t) {
    if (t === "dark" || t === "light") root.setAttribute("data-theme", t);
    else root.removeAttribute("data-theme");
    themeLbl.textContent = effectiveTheme() === "dark" ? "Light" : "Dark";
  }
  themeBtn.addEventListener("click", function () {
    applyTheme(effectiveTheme() === "dark" ? "light" : "dark");
  });
  window.addEventListener("message", function (e) {
    var d = e && e.data;
    if (d && d.type === "sloprun:theme") applyTheme(d.theme);
  });
  if (window.matchMedia) {
    var mq = window.matchMedia("(prefers-color-scheme: dark)");
    var onScheme = function () { applyTheme(root.getAttribute("data-theme")); };
    if (mq.addEventListener) mq.addEventListener("change", onScheme);
    else if (mq.addListener) mq.addListener(onScheme);
  }
  try { if (window.parent !== window) window.parent.postMessage({ type: "sloprun:ready" }, "*"); } catch (e) {}

  /* ── text helpers ────────────────────────────────────────────────────────── */
  function esc(s) {
    return String(s).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
  }
  function md(s) {
    return esc(s).replace(/`([^`]+)`/g, function (_, c) { return '<code class="ic">' + c + "</code>"; });
  }
  function secs(ms) { return (ms / 1000).toFixed(1) + "s"; }
  function rangeLabel(g) { return g.start === g.end ? "L" + g.start : "L" + g.start + "\u2013" + g.end; }

  function wrapText(s, width) {
    var words = String(s).replace(/`/g, "").split(/\s+/), out = [], cur = "";
    for (var i = 0; i < words.length; i++) {
      if (!words[i]) continue;
      if (!cur.length) cur = words[i];
      else if (cur.length + 1 + words[i].length <= width) cur += " " + words[i];
      else { out.push(cur); cur = words[i]; }
    }
    if (cur.length) out.push(cur);
    return out;
  }

  /* ── a small JavaScript highlighter (per line, block-comment aware) ──────── */
  var KW = /^(?:const|let|var|function|return|if|else|for|of|in|while|do|new|class|extends|async|await|typeof|instanceof|null|undefined|true|false|this|import|export|from|default|try|catch|finally|throw|switch|case|break|continue|yield|delete|void|super|static)$/;
  var TOK = /(\/\*[\s\S]*?\*\/)|(\/\*[\s\S]*$)|(\/\/.*$)|("(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|`[^`]*`)|(\b0[xX][0-9a-fA-F]+\b|\b\d+(?:\.\d+)?(?:[eE][+-]?\d+)?\b)|([A-Za-z_$][A-Za-z0-9_$]*)|(\s+)|([^\w\s$"'`\u0080-\uFFFF]+)/g;

  function hiLine(line, st) {
    var pre = "", rest = line;
    if (st.block) {
      var e = rest.indexOf("*/");
      if (e === -1) return '<span class="t-com">' + esc(rest) + "</span>";
      pre = '<span class="t-com">' + esc(rest.slice(0, e + 2)) + "</span>";
      st.block = false;
      rest = rest.slice(e + 2);
    }
    var html = "", last = 0, prevSig = "", m;
    TOK.lastIndex = 0;
    while ((m = TOK.exec(rest)) !== null) {
      if (m.index > last) html += esc(rest.slice(last, m.index));
      last = TOK.lastIndex;
      if (m[1] || m[3]) html += '<span class="t-com">' + esc(m[1] || m[3]) + "</span>";
      else if (m[2]) { html += '<span class="t-com">' + esc(m[2]) + "</span>"; st.block = true; }
      else if (m[4]) html += '<span class="t-str">' + esc(m[4]) + "</span>";
      else if (m[5]) html += '<span class="t-num">' + esc(m[5]) + "</span>";
      else if (m[6]) {
        var cls = "";
        if (KW.test(m[6]) && prevSig !== ".") cls = "t-key";
        else if (/^\s*\(/.test(rest.slice(last))) cls = "t-fn";
        html += cls ? '<span class="' + cls + '">' + esc(m[6]) + "</span>" : esc(m[6]);
      }
      else if (m[7]) html += m[7];
      else if (m[8]) html += '<span class="t-pun">' + esc(m[8]) + "</span>";
      var trimmed = m[0].replace(/\s+$/, "");
      if (trimmed) prevSig = trimmed.charAt(trimmed.length - 1);
      if (TOK.lastIndex === m.index) TOK.lastIndex++;
    }
    if (last < rest.length) html += esc(rest.slice(last));
    return pre + html;
  }

  function highlightAll(lines) {
    var st = { block: false }, out = [];
    for (var i = 0; i < lines.length; i++) out.push(hiLine(lines[i], st));
    return out;
  }

  /* ── group normalisation: whatever comes back, the listing stays sane ────── */
  function displayLines() {
    var l = state.code.replace(/\r\n?/g, "\n").split("\n");
    while (l.length > 1 && l[l.length - 1].trim() === "") l.pop();
    return l;
  }
  function normalize(groups, n) {
    var clean = [];
    (groups || []).forEach(function (g) {
      if (!g) return;
      var s = Math.round(Number(g.start)), e = Math.round(Number(g.end));
      if (!isFinite(s)) return;
      if (!isFinite(e)) e = s;
      s = Math.max(1, Math.min(n, s));
      e = Math.max(s, Math.min(n, e));
      clean.push({ start: s, end: e, title: String(g.title || "").trim(), text: String(g.text || "").trim() });
    });
    clean.sort(function (a, b) { return a.start - b.start || a.end - b.end; });
    var out = [], cursor = 1;
    clean.forEach(function (g) {
      if (g.start > cursor) out.push({ start: cursor, end: g.start - 1 });
      if (g.start < cursor) g.start = cursor;
      if (g.end < g.start) return;
      if (!g.title && !g.text) { out.push({ start: g.start, end: g.end }); }
      else out.push(g);
      cursor = g.end + 1;
    });
    if (cursor <= n) out.push({ start: cursor, end: n });
    return out;
  }

  /* ── render ──────────────────────────────────────────────────────────────── */
  function isStale() { return !!state.expl && state.explFor !== state.code; }

  function render() {
    var L = displayLines();
    var empty = state.code.trim() === "";
    var hl = highlightAll(L);
    var groups = empty ? [] : normalize(state.expl ? state.expl.groups : [], L.length);
    var html = "";

    if (state.expl) {
      html += '<div class="ov"><div><span class="tag">Overview · ' +
        (state.source === "live" ? "generated" : "example") + "</span><p>" + md(state.expl.overview) + "</p></div>" +
        '<aside class="ov-side"><span class="k">How to read this</span><ul>' +
        "<li>Every note sits beside the exact lines it is about.</li>" +
        "<li>Hover a note — or tab to it — and its lines light up.</li>" +
        "<li>Click a note to pin the highlight while you read.</li>" +
        "<li><kbd>" + MODKEY + "</kbd> + <kbd>Enter</kbd> re-explains the current code.</li>" +
        "</ul></aside></div>";
    } else {
      html += '<div class="ov solo"><div><span class="tag">Overview</span><p>' +
        (empty
          ? "Nothing to explain yet — paste some code into the editor above."
          : "This code has not been explained yet. Press <b>Explain</b> and the overview lands here, with a note beside every group of lines.") +
        "</p></div></div>";
    }

    if (isStale()) {
      html += '<div class="banner"><b>The code changed since this explanation was written.</b>' +
        "<span>The notes below still describe the old version, clamped onto the new line numbers.</span>" +
        '<span class="spacer"></span></div>';
    }

    if (empty) {
      html += '<div class="banner"><span>The listing appears here as soon as there is code to list.</span></div>';
      out.innerHTML = html;
      updateMeta(0, 0);
      return;
    }

    groups.forEach(function (g, gi) {
      var code = "";
      for (var i = g.start; i <= g.end; i++) {
        code += '<div class="ln"><span class="num" aria-hidden="true">' + i + "</span>" +
          "<code>" + (hl[i - 1] === "" ? "&nbsp;" : hl[i - 1]) + "</code></div>";
      }
      var note;
      if (g.title || g.text) {
        note = '<button class="note" type="button" aria-pressed="false" data-g="' + gi + '">' +
          '<span class="r">' + rangeLabel(g) + "</span>" +
          '<span class="nt">' + esc(g.title || "Note") + "</span>" +
          '<span class="np">' + md(g.text) + "</span></button>";
      } else {
        note = '<div class="note empty"><span class="dash">' + rangeLabel(g) + " · no note</span></div>";
      }
      html += '<div class="grp' + (isStale() ? " stale" : "") + '" data-g="' + gi + '">' +
        '<div class="code">' + code + "</div>" + note + "</div>";
    });

    out.innerHTML = html;
    state.pinned = -1;
    updateMeta(L.length, groups.filter(function (g) { return g.title || g.text; }).length);
  }

  function updateMeta(nLines, nNotes) {
    var chars = state.code.length;
    metaEl.textContent = "LINES " + nLines + " · CHARS " + chars + " · NOTES " + nNotes +
      " · SOURCE " + (state.expl ? state.source.toUpperCase() : "NONE");
    srcStats.textContent = nLines + " lines · " + chars + " chars";
    copyBtn.disabled = !state.expl || state.code.trim() === "";
  }

  function setStatus(kind, text) {
    statusEl.className = "status" + (kind ? " " + kind : "");
    statusEl.innerHTML = text ? '<span class="dot" aria-hidden="true"></span><span>' + esc(text) + "</span>" : "";
  }

  function setBusy(on) {
    busy = on;
    listing.classList.toggle("busy", on);
    listing.setAttribute("aria-busy", on ? "true" : "false");
    explainBtn.disabled = on; explainBtn2.disabled = on;
    restoreBtn.disabled = on; clearBtn.disabled = on;
    explainBtn.firstChild.nodeValue = on ? "Explaining " : "Explain ";
    Array.prototype.forEach.call(document.querySelectorAll("#presets button"), function (b) { b.disabled = on; });
  }

  /* ── highlight linking: hover, focus, and click-to-pin ───────────────────── */
  function grpFor(el) { return el && el.closest ? el.closest(".grp") : null; }
  out.addEventListener("mouseover", function (e) {
    var g = grpFor(e.target);
    if (g) g.classList.add("hot");
  });
  out.addEventListener("mouseout", function (e) {
    var g = grpFor(e.target);
    if (g && !g.classList.contains("pin")) g.classList.remove("hot");
  });
  out.addEventListener("focusin", function (e) {
    var g = grpFor(e.target);
    if (g) g.classList.add("hot");
  });
  out.addEventListener("focusout", function (e) {
    var g = grpFor(e.target);
    if (g && !g.classList.contains("pin")) g.classList.remove("hot");
  });
  out.addEventListener("click", function (e) {
    var btn = e.target.closest ? e.target.closest(".note") : null;
    if (!btn || btn.tagName !== "BUTTON") return;
    var g = grpFor(btn), on = !g.classList.contains("pin");
    Array.prototype.forEach.call(out.querySelectorAll(".grp.pin"), function (o) {
      o.classList.remove("pin", "hot");
      var b = o.querySelector(".note[aria-pressed]");
      if (b) b.setAttribute("aria-pressed", "false");
    });
    /* the clicked group is under the pointer (or holds focus) either way, so it
       keeps its hover highlight even when the click was an un-pin */
    g.classList.add("hot");
    if (on) { g.classList.add("pin"); btn.setAttribute("aria-pressed", "true"); }
  });

  /* ── copy as commented code ──────────────────────────────────────────────── */
  function commentify() {
    var L = displayLines();
    var groups = normalize(state.expl ? state.expl.groups : [], L.length);
    var lines = [];
    if (state.expl && state.expl.overview) {
      lines.push("/**");
      wrapText(state.expl.overview, 74).forEach(function (l) { lines.push(" * " + l); });
      lines.push(" */");
    }
    groups.forEach(function (g, i) {
      if (g.title || g.text) {
        var first = L[g.start - 1] || "";
        var indent = (first.match(/^[ \t]*/) || [""])[0];
        if (i > 0) lines.push("");
        lines.push(indent + "// " + (g.title || "Note").toUpperCase() + "  (" + rangeLabel(g) + ")");
        wrapText(g.text, Math.max(40, 74 - indent.length)).forEach(function (l) { lines.push(indent + "// " + l); });
      }
      for (var n = g.start; n <= g.end; n++) lines.push(L[n - 1]);
    });
    lines.push("");
    lines.push("// explained by " + (state.source === "live" ? MODEL : "the built-in example explanation") +
      " · code-explainer · sloprun.dev");
    return lines.join("\n");
  }

  function legacyCopy(t) {
    try {
      var ta = document.createElement("textarea");
      ta.value = t; ta.setAttribute("readonly", "");
      ta.style.position = "fixed"; ta.style.top = "-1000px"; ta.style.opacity = "0";
      document.body.appendChild(ta);
      ta.select();
      var ok = document.execCommand("copy");
      document.body.removeChild(ta);
      return ok;
    } catch (err) { return false; }
  }

  copyBtn.addEventListener("click", function () {
    if (copyBtn.disabled) return;
    var text = commentify();
    var n = text.split("\n").length;
    var done = function () {
      copyPanel.hidden = true;
      setStatus("ok", "copied · " + n + " lines of commented source");
    };
    var fail = function () {
      copyPanel.hidden = false;
      copyOut.value = text;
      copyOut.focus(); copyOut.select();
      setStatus("bad", "clipboard blocked here — the commented source is in the panel above, ready to copy by hand");
    };
    if (navigator.clipboard && navigator.clipboard.writeText) {
      navigator.clipboard.writeText(text).then(done, function () { if (legacyCopy(text)) done(); else fail(); });
    } else if (legacyCopy(text)) done();
    else fail();
  });

  document.getElementById("copyClose").addEventListener("click", function () {
    copyPanel.hidden = true;
    copyBtn.focus();
  });

  /* ── editor + snippet controls ───────────────────────────────────────────── */
  function openEditor(open) {
    var want = open === undefined ? editorPanel.hidden : open;
    editorPanel.hidden = !want;
    editBtn.setAttribute("aria-expanded", want ? "true" : "false");
    editBtn.textContent = want ? "Hide editor" : "Paste your own";
  }
  editBtn.addEventListener("click", function () {
    openEditor();
    if (!editorPanel.hidden) srcEl.focus();
  });

  var typing = null;
  srcEl.addEventListener("input", function () {
    if (typing) clearTimeout(typing);
    typing = setTimeout(function () {
      typing = null;
      state.code = srcEl.value;
      render();
      if (state.code.trim() === "") setStatus("", "editor is empty");
      else if (isStale()) setStatus("", "code edited · press Explain to re-explain it");
      else setStatus("", "back to the explained version of this snippet");
    }, 180);
  });

  function loadPreset(id, quiet) {
    var p = PRESETS[id];
    if (!p) return;
    /* a debounce from the editor is still in flight after a preset switch; let
       it land and it overwrites the status line we are about to set */
    if (typing) { clearTimeout(typing); typing = null; }
    state.preset = id;
    state.code = p.code;
    state.expl = p.expl;
    state.explFor = p.code;
    state.source = "example";
    srcEl.value = p.code;
    Array.prototype.forEach.call(document.querySelectorAll("#presets button"), function (b) {
      b.setAttribute("aria-pressed", b.getAttribute("data-preset") === id ? "true" : "false");
    });
    setRail();
    render();
    if (!quiet) {
      setStatus("", HOST || apiKey
        ? "showing the worked example · press Explain to generate a fresh one"
        : "showing the worked example · no key needed");
    }
  }

  document.getElementById("presets").addEventListener("click", function (e) {
    var b = e.target.closest ? e.target.closest("button[data-preset]") : null;
    if (!b || b.disabled) return;
    loadPreset(b.getAttribute("data-preset"));
  });

  restoreBtn.addEventListener("click", function () {
    loadPreset(state.preset);
    srcEl.focus();
  });
  clearBtn.addEventListener("click", function () {
    if (typing) { clearTimeout(typing); typing = null; }
    state.code = ""; state.expl = null; state.explFor = ""; state.source = "example";
    srcEl.value = "";
    render();
    setStatus("", "cleared · paste code and press Explain");
    openEditor(true);
    srcEl.focus();
  });

  function setRail() {
    railMode.textContent = state.source === "live" ? "live explanation"
      : HOST ? "sloprun runs the model"
      : apiKey ? "key connected"
      : "example explanation";
  }

  /* ── BYOK ────────────────────────────────────────────────────────────────── */
  var MODEL = "claude-sonnet-5";
  var HOST = !!(window.sloprun && window.sloprun.ai && typeof window.sloprun.ai.ask === "function");
  var apiKey = "";

  var SYS = [
    "You explain code to a competent developer who has never seen this snippet before.",
    "Reply with ONE JSON object and nothing else. No prose, no markdown fences.",
    'Schema: {"overview": string, "groups": [{"start": number, "end": number, "title": string, "text": string}]}',
    "Rules:",
    "- overview: 2 to 4 sentences. What the code is for, and the one idea a reader has to hold in their head.",
    "- groups: consecutive, non-overlapping line ranges, in order, starting at line 1 and together covering every line. Between 4 and 10 of them. Split where the purpose changes, not on every line.",
    "- title: five words or fewer, no trailing period.",
    "- text: 1 to 3 sentences of plain English. Say what it does and why it is written that way. Call out gotchas, silent failure modes and non-obvious language behaviour explicitly.",
    "- Inline code in single backticks is fine. No other markdown.",
    "- Never invent APIs or behaviour that is not in the snippet."
  ].join("\n");

  function numbered(code) {
    return code.replace(/\r\n?/g, "\n").split("\n").map(function (l, i) {
      return (i + 1) + "\t" + l;
    }).join("\n");
  }

  function ask(prompt) {
    if (HOST) {
      try { return Promise.resolve(window.sloprun.ai.ask(prompt, { system: SYS })); }
      catch (err) { return Promise.reject(err); }
    }
    return fetch("https://api.anthropic.com/v1/messages", {
      method: "POST",
      headers: {
        "content-type": "application/json",
        "x-api-key": apiKey,
        "anthropic-version": "2023-06-01",
        "anthropic-dangerous-direct-browser-access": "true"
      },
      body: JSON.stringify({
        model: MODEL,
        max_tokens: 4000,
        system: SYS,
        messages: [{ role: "user", content: prompt }]
      })
    }).then(function (r) {
      return r.text().then(function (raw) {
        var d = null;
        try { d = JSON.parse(raw); } catch (err) { d = null; }
        if (!r.ok || !d || d.error) {
          throw new Error((d && d.error && d.error.message) || ("HTTP " + r.status + " from api.anthropic.com"));
        }
        return (d.content || []).map(function (b) { return b && b.text ? b.text : ""; }).join("");
      });
    }, function () {
      throw new Error("could not reach api.anthropic.com — check the key, the network, or the browser blocking it");
    });
  }

  function parseExpl(raw) {
    var t = String(raw == null ? "" : raw).trim();
    t = t.replace(/^```(?:json)?\s*/i, "").replace(/```\s*$/, "").trim();
    var a = t.indexOf("{"), b = t.lastIndexOf("}");
    if (a === -1 || b <= a) return null;
    var o = null;
    try { o = JSON.parse(t.slice(a, b + 1)); } catch (err) { return null; }
    if (!o || typeof o !== "object" || !Array.isArray(o.groups)) return null;
    return {
      overview: String(o.overview || "").trim() || "(the model returned no overview)",
      groups: o.groups
    };
  }

  function explain() {
    if (busy) return;
    if (state.code.trim() === "") {
      openEditor(true); srcEl.focus();
      setStatus("bad", "nothing to explain — paste some code first");
      return;
    }
    if (!HOST && !apiKey) {
      keyPanel.hidden = false;
      setStatus("bad", "connect an Anthropic key to explain this for real");
      keyInput.focus();
      return;
    }
    setBusy(true);
    var t0 = Date.now();
    /* the label is written once so the live region announces it once; the
       ticking seconds live in an aria-hidden span so screen readers are not
       read a new status ten times a second */
    statusEl.className = "status";
    statusEl.setAttribute("aria-live", "off");
    statusEl.innerHTML = '<span class="dot" aria-hidden="true"></span><span>calling ' +
      esc(MODEL) + '<span class="tk" aria-hidden="true"></span></span>';
    var tickEl = statusEl.querySelector(".tk");
    var pending = function () { tickEl.textContent = " \u00b7 " + secs(Date.now() - t0); };
    pending();
    tick = setInterval(pending, 100);
    var stop = function () {
      if (tick) { clearInterval(tick); tick = null; }
      statusEl.setAttribute("aria-live", "polite");
      setBusy(false);
    };
    var snapshot = state.code;

    ask("Explain this code.\n\nLines are prefixed with their number and a tab; do not include the prefixes in your answer.\n\n" + numbered(snapshot))
      .then(function (reply) {
        stop();
        var elapsed = secs(Date.now() - t0);
        var parsed = parseExpl(reply);
        state.explFor = snapshot;
        state.source = "live";
        setRail();
        if (parsed) {
          state.expl = parsed;
          render();
          var n = out.querySelectorAll(".note[data-g]").length;
          setStatus("ok", "explained · " + elapsed + " · " + n + " notes · " + MODEL);
        } else {
          state.expl = { overview: String(reply).slice(0, 1500), groups: [] };
          render();
          setStatus("bad", "the model answered in prose instead of JSON — showing it as the overview");
        }
      })
      .catch(function (err) {
        stop();
        setStatus("bad", (err && err.message) ? err.message : "the request failed");
      });
  }

  explainBtn.addEventListener("click", explain);
  explainBtn2.addEventListener("click", explain);
  document.addEventListener("keydown", function (e) {
    if (!(e.metaKey || e.ctrlKey) || e.key !== "Enter") return;
    e.preventDefault();
    /* in the key field the shortcut means "connect", not "explain with no key" */
    if (e.target === keyInput) keyForm.dispatchEvent(new Event("submit", { cancelable: true, bubbles: true }));
    else explain();
  });

  /* ── key panel ───────────────────────────────────────────────────────────── */
  var keyDone = document.createElement("div");
  keyDone.className = "keyrow";
  keyDone.hidden = true;
  var keyDoneLbl = document.createElement("span");
  keyDoneLbl.className = "status";
  var forgetBtn = document.createElement("button");
  forgetBtn.type = "button";
  forgetBtn.className = "btn small";
  forgetBtn.textContent = "Forget key";
  keyDone.appendChild(keyDoneLbl);
  keyDone.appendChild(forgetBtn);
  keyPanel.querySelector(".keyhead").appendChild(keyDone);

  function setKeyState(connected) {
    keyState.innerHTML = connected
      ? "Key held in this tab\u2019s memory only \u2014 never written to storage, posted nowhere except " +
        "<code>api.anthropic.com</code>, and gone the moment you reload. Press <b>Explain</b> to run it on the code above."
      : "No key connected \u2014 everything below is the built-in worked example, rendered by the same code " +
      "that renders a live answer. A key is held in this tab\u2019s memory only, never written to storage, and posted nowhere " +
      "except <code>api.anthropic.com</code>. Reload the page and it is gone.";
  }

  keyForm.addEventListener("submit", function (e) {
    e.preventDefault();
    var v = keyInput.value.trim();
    if (!v) { setStatus("bad", "paste a key first"); keyInput.focus(); return; }
    apiKey = v;
    keyInput.value = "";
    keyForm.hidden = true;
    keyDone.hidden = false;
    keyDoneLbl.textContent = "KEY IN MEMORY · ends " + v.slice(-4) + " · never stored, gone on reload";
    setKeyState(true);
    setRail();
    explain();
  });
  forgetBtn.addEventListener("click", function () {
    apiKey = "";
    keyForm.hidden = false;
    keyDone.hidden = true;
    setKeyState(false);
    keyInput.focus();
    setRail();
    setStatus("", "key forgotten · this tab no longer holds it");
  });

  /* ── init ────────────────────────────────────────────────────────────────── */
  if (HOST) {
    keyPanel.hidden = true;
  } else {
    keyPanel.hidden = false;
    setKeyState(false);
  }
  document.getElementById("modHint").textContent = MODKEY + "+Enter";
  applyTheme(root.getAttribute("data-theme"));
  loadPreset("rollup", true);
  setStatus("", HOST
    ? "worked example loaded · press Explain to generate a fresh one"
    : "worked example loaded · no key needed to read it");
})();
</script>
</body>
</html>

source-visible by construction · nothing is published here without its code

Comments

0 total

No comments yet. If you ran it, say what happened.

Report this post

Goes straight to the moderation queue. Enough independent reports and the post is suspended automatically until a human looks.

what is wrong