Skip to content

Instantly share code, notes, and snippets.

@happytomatoe
Forked from geoffreylitt/explain-diff-html.md
Last active August 20, 2026 17:13
Show Gist options
  • Select an option

  • Save happytomatoe/b045f15d415f1758c2e8791e0e8a45b8 to your computer and use it in GitHub Desktop.

Select an option

Save happytomatoe/b045f15d415f1758c2e8791e0e8a45b8 to your computer and use it in GitHub Desktop.
explain-diff
name explain-diff-html
description Use when the user asks for a rich explanation of a code change, diff, branch, PR, or entire system. Produces HTML output.

Explain Diff / System

Please make a rich, interactive explanation of the specified code change, diff, or system.

First, determine the scope: is this a diff/change explanation or a system-wide explanation? Adapt the sections accordingly.

It should have these sections:

  • Changes at a Glance (diffs only): A concise list of what changed, grouped by purpose. Gives the reader an orientation before diving deep.
  • Glossary: First section after the header. Write as if explaining to a smart junior developer who has never encountered these terms. For each term, provide 2-3 sentences: (1) what it is in plain language, (2) why it matters in the context of this explanation, and (3) optionally a brief analogy or comparison to something familiar. Avoid defining jargon with more jargon. If a definition needs to mention another glossary term, link to it. Group related terms together (e.g. all GPU terms in one cluster). Omit terms any web developer would know (API, HTTP, JSON, etc.) — include only domain-specific or easily confused terms. The goal: after reading the glossary, a junior dev should be able to follow the rest of the explanation without hitting walls.
  • Background: Explain the existing system relevant to this change or system. (You should broadly explore surrounding code for this.) We don't know how much the reader already knows, so include a deep background for beginners (note that it can be skipped if the reader is already familiar), and then a more narrow background directly relevant to the change or system.
  • Intuition: Explain the core intuition for the code change or system design. The focus here is to explain the essence, not the full details. Use concrete examples with toy data. Use figures and diagrams liberally.
  • Code: For diffs, do a high-level walkthrough of the changes, grouped by purpose. For systems, do a walkthrough of the architecture and key components, grouped by subsystem or responsibility.
  • Quiz: Five medium-difficulty multiple-choice questions (not gotchas) that test real understanding; tell the user if they were right and why. Two constraints:
    • Equal detail: all options for a question match in length and specificity — don't make the correct answer the only one with an example, and avoid strawman distractors.
    • Randomized order: don't fix the correct answer's position (it shouldn't always be B). Shuffle the options at runtime in the browser so the order varies on each load, while keeping the correct-answer marker for checking.

Check TEMPLATE.html as a refecence Format:

  • Output a single self-contained HTML file which includes CSS and JavaScript. Make the whole thing one long page with section headers and a table of contents. Don't use tabs for the top-level structure. Basic responsive styling so you can view it on a phone is nice too. Put the file in a global place on your computer outside of the code repo, and make sure the filename always starts with today's date in YYYY-MM-DD- format, because it helps keep the files time-sorted and out of version control. For example: /tmp/2026-01-12-explanation-.html. The only permitted external dependency is the highlight.js CDN (see Syntax highlighting below).

  • Please write with the clarity and flow of Martin Kleppmann, making it engaging and written in classic style. Transitions between sections should be smooth.

  • Some tips on diagrams. Use simple HTML diagrams throughout (flowcharts, architecture diagrams, etc.). Pick a small number of diagram families that can be reused across the explanation. Use the .diagram, .flow-row, .flow-box, and .flow-arrow classes from the template.

    Diagram HTML pattern — use this structure for flow diagrams:

    <div class="diagram">
      <div class="diagram-title">Fig N. Caption</div>
      <div class="flow-row">
        <div class="flow-box blue">Component A</div>
        <span class="flow-arrow"></span>
        <div class="flow-box green">Component B</div>
      </div>
    </div>

    Available flow-box colors: .blue, .green, .orange, .purple, .gray, .red

    Vertical flow: stack multiple .flow-row divs with arrows between them.

  • Don't use ASCII diagrams. Always use simple HTML diagrams for figures, HTML lists for lists of things, etc.

    • For code blocks, always use <pre> tags. If you use a custom styled div instead, it must have white-space: pre-wrap in its CSS, or the browser will collapse all newlines into a single line. Before saving the file, scan each code block in the HTML source and confirm its CSS includes white-space: pre or pre-wrap.
  • Syntax highlighting: highlight every <pre><code> block with the highlight.js snippet below. Force a language-* class on each <code> (e.g. language-javascript, or language-typescript for .ts blocks with type annotations). Always use the light theme (github.min.css).

  • Use callouts for key concepts or definitions, important edge cases, etc.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{TITLE}}</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/styles/github-dark.min.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Roboto:wght@400;700&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<style>
:root {
--bg: #242424;
--bg-alt: #302e27;
--bg-callout: #243f4040;
--border: #524f47;
--text: #fdfdfa;
--text-muted: #9e9b94;
--accent: #44bda3;
--accent-dark: #3da892;
--accent-light: #243f40;
--green: #62d6a4;
--green-bg: #1a3a2a;
--orange: #e2a45f;
--orange-bg: #3a2e1a;
--red: #e0685e;
--red-bg: #3a1a1a;
--purple: #b392f0;
--purple-bg: #2a1a3a;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: 'Roboto', sans-serif;
color: var(--text);
background: var(--bg);
line-height: 1.7;
font-size: 1.125rem;
max-width: 860px;
margin: 0 auto;
padding: 2rem 1.5rem 4rem;
position: relative;
}
body::before {
content: '';
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
pointer-events: none;
opacity: 0.04;
background-image: url("data:image/svg+xml,%3Csvg width='4' height='4' viewBox='0 0 7 7' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M2 0H0V2H2V0Z' fill='%23ffffff'/%3E%3C/svg%3E");
background-repeat: repeat;
z-index: 0;
}
body > * { position: relative; z-index: 1; }
h1 { font-family: 'Inter', sans-serif; font-size: 2.25rem; margin-bottom: 0.5rem; line-height: 1.2; font-weight: 600; letter-spacing: -0.02em; }
h2 { font-family: 'Inter', sans-serif; font-size: 1.65rem; margin-top: 3rem; margin-bottom: 0.75rem; border-bottom: 1px solid var(--border); padding-bottom: 0.5rem; font-weight: 600; letter-spacing: -0.02em; }
h3 { font-family: 'Inter', sans-serif; font-size: 1.25rem; margin-top: 1.75rem; margin-bottom: 0.5rem; font-weight: 600; letter-spacing: -0.02em; }
h4 { font-family: 'Inter', sans-serif; font-size: 1.05rem; margin-top: 1.25rem; margin-bottom: 0.5rem; font-weight: 600; letter-spacing: -0.02em; }
p { margin-bottom: 1.25rem; }
a { color: var(--accent); text-decoration: none; font-weight: 500; }
a:hover { color: var(--accent-dark); text-decoration: underline; }
code {
font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
font-size: 0.875em;
background: color-mix(in srgb, var(--accent) 18%, var(--bg-alt));
border: 1px solid color-mix(in srgb, var(--accent) 25%, transparent);
padding: 0.15em 0.45em;
border-radius: 4px;
color: var(--accent);
}
pre {
background: var(--bg);
border: 1px solid color-mix(in srgb, var(--accent) 15%, transparent);
border-radius: 6px;
padding: 1.25rem;
overflow-x: auto;
margin: 1.75rem 0;
}
pre code {
background: none;
border: none;
padding: 0;
font-size: 0.85rem;
line-height: 1.7;
color: var(--text);
white-space: pre;
}
.toc {
background: var(--bg-alt);
border: 1px solid var(--border);
border-radius: 8px;
padding: 0.75rem 1.25rem;
margin-bottom: 2.5rem;
}
.toc h3 { margin-top: 0; margin-bottom: 0.4rem; font-size: 0.95rem; font-family: 'Inter', sans-serif; }
.toc ol { padding-left: 1.5rem; }
.toc li { margin-bottom: 0.15rem; font-size: 0.95rem; }
.callout {
border-left: 3px solid var(--accent);
background: var(--bg-callout);
padding: 0.75rem 1rem;
border-radius: 0 6px 6px 0;
margin-bottom: 1rem;
}
.callout.green { border-left-color: var(--green); background: var(--green-bg); }
.callout.orange { border-left-color: var(--orange); background: var(--orange-bg); }
.callout.red { border-left-color: var(--red); background: var(--red-bg); }
.callout.purple { border-left-color: var(--purple); background: var(--purple-bg); }
.callout strong { display: block; margin-bottom: 0.25rem; font-family: 'Inter', sans-serif; }
/* Diagram styles */
.diagram {
background: var(--bg-alt);
border: 1px solid var(--border);
border-radius: 8px;
padding: 1.5rem;
margin: 1.5rem 0;
overflow-x: auto;
}
.diagram-title {
font-size: 0.85rem;
color: var(--text-muted);
text-align: center;
margin-bottom: 1rem;
font-style: italic;
}
.figure-caption {
font-size: 0.88rem;
color: var(--text-muted);
text-align: center;
margin-top: 0.75rem;
font-style: italic;
}
.flow-row {
display: flex;
align-items: center;
justify-content: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
flex-wrap: wrap;
}
.flow-box {
padding: 0.5rem 0.75rem;
border-radius: 6px;
font-size: 0.82rem;
font-weight: 600;
text-align: center;
min-width: 100px;
white-space: nowrap;
}
.flow-box.blue { background: color-mix(in srgb, var(--accent) 15%, var(--bg-alt)); border: 1px solid var(--accent); color: var(--accent); }
.flow-box.green { background: var(--green-bg); border: 1px solid var(--green); color: var(--green); }
.flow-box.orange { background: var(--orange-bg); border: 1px solid var(--orange); color: var(--orange); }
.flow-box.purple { background: var(--purple-bg); border: 1px solid var(--purple); color: var(--purple); }
.flow-box.gray { background: #2a2a2a; border: 1px solid var(--border); color: var(--text-muted); }
.flow-box.red { background: var(--red-bg); border: 1px solid var(--red); color: var(--red); }
.flow-arrow {
font-size: 1.2rem;
color: var(--text-muted);
flex-shrink: 0;
}
.flow-label {
font-size: 0.75rem;
color: var(--text-muted);
text-align: center;
margin-top: -0.25rem;
margin-bottom: 0.5rem;
}
/* Option cards */
.option-card {
border: 1px solid var(--border);
border-radius: 8px;
padding: 1.25rem;
margin-bottom: 1.25rem;
position: relative;
background: var(--bg-alt);
}
.option-card h3 { margin-top: 0; }
.option-card .verdict {
font-size: 0.85rem;
padding: 0.35rem 0.65rem;
border-radius: 4px;
display: inline-block;
margin-top: 0.5rem;
font-weight: 600;
}
.verdict.quick { background: var(--green-bg); color: var(--green); }
.verdict.robust { background: color-mix(in srgb, var(--accent) 15%, var(--bg-alt)); color: var(--accent); }
.verdict.best { background: var(--purple-bg); color: var(--purple); }
.verdict.heavy { background: var(--orange-bg); color: var(--orange); }
/* Glossary */
.glossary {
background: var(--bg-alt);
border: 1px solid var(--border);
border-radius: 8px;
padding: 1rem 1.25rem;
margin: 1.5rem 0;
}
.glossary h3 { margin-top: 0; margin-bottom: 0.75rem; font-family: 'Inter', sans-serif; }
.glossary-list { display: flex; flex-direction: column; gap: 0; }
.glossary-item {
font-size: 0.95rem;
line-height: 1.6;
padding: 0.5rem 0;
border-bottom: 1px solid var(--border);
}
.glossary-item:last-child { border-bottom: none; }
.glossary-term { font-weight: 600; margin-bottom: 0.15rem; color: var(--text); }
.glossary-def { color: color-mix(in srgb, var(--text) 80%, transparent); }
/* Quiz */
.quiz-q {
border: 1px solid var(--border);
border-radius: 8px;
padding: 1.25rem;
margin-bottom: 1.25rem;
background: var(--bg-alt);
}
.quiz-q h4 { margin-bottom: 0.75rem; }
.quiz-options { list-style: none; padding: 0; }
.quiz-options li {
padding: 0.5rem 0.75rem;
margin-bottom: 0.4rem;
border: 1px solid var(--border);
border-radius: 6px;
cursor: pointer;
transition: background 0.15s, border-color 0.15s;
font-size: 0.92rem;
}
.quiz-options li:hover { background: color-mix(in srgb, var(--accent) 8%, transparent); }
.quiz-options li.selected { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 12%, transparent); }
.quiz-options li.correct { border-color: var(--green); background: var(--green-bg); }
.quiz-options li.wrong { border-color: var(--red); background: var(--red-bg); }
.quiz-feedback {
margin-top: 0.75rem;
padding: 0.6rem 0.8rem;
border-radius: 6px;
font-size: 0.9rem;
display: none;
}
.quiz-feedback.show { display: block; }
.quiz-feedback.correct { background: var(--green-bg); border: 1px solid var(--green); }
.quiz-feedback.wrong { background: var(--red-bg); border: 1px solid var(--red); }
ul, ol { margin-bottom: 1rem; padding-left: 1.5rem; }
li { margin-bottom: 0.3rem; }
strong { font-weight: 600; }
.subtitle { color: var(--text-muted); font-size: 1rem; margin-bottom: 2rem; }
table { width: 100%; border-collapse: collapse; font-size: 0.88rem; margin-bottom: 2rem; }
th, td { padding: 0.5rem; text-align: left; }
thead { border-bottom: 2px solid var(--border); }
tbody tr { border-bottom: 1px solid var(--border); }
th { color: var(--text-muted); font-size: 0.8rem; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 500; }
td { color: color-mix(in srgb, var(--text) 90%, transparent); }
@media (max-width: 600px) {
body { padding: 1rem; }
h1 { font-size: 1.5rem; }
h2 { font-size: 1.25rem; }
.flow-box { font-size: 0.72rem; min-width: 70px; padding: 0.35rem 0.5rem; }
pre { padding: 0.75rem; }
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js"></script>
<script>
document.addEventListener('DOMContentLoaded', () => {
hljs.highlightAll();
// Parse feedback data from hidden elements
const feedbackData = {};
document.querySelectorAll('.quiz-feedback-data').forEach(el => {
const text = el.textContent.trim();
const questionBlocks = text.split(/(q\d+)/).filter(Boolean);
for (let i = 0; i < questionBlocks.length; i += 2) {
const qId = questionBlocks[i];
const feedbackText = questionBlocks[i + 1]?.trim() || '';
const [correct, wrong] = feedbackText.split(/\n\s*\n/).map(s => s.trim()).filter(Boolean);
feedbackData[qId] = {
correct: correct || 'Correct!',
wrong: wrong || 'Not quite. Try again.'
};
}
});
document.querySelectorAll('.quiz-options').forEach(ul => {
const qId = ul.closest('.quiz-q').id;
const correctIdx = parseInt(ul.dataset.correct);
const items = Array.from(ul.children);
// Shuffle options
for (let i = items.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
ul.appendChild(items[j]);
items.splice(j, 1, items[i]);
}
ul.addEventListener('click', (e) => {
const li = e.target.closest('li');
if (!li || ul.dataset.answered) return;
ul.dataset.answered = 'true';
const chosenIdx = parseInt(li.dataset.idx);
const isCorrect = chosenIdx === correctIdx;
const fb = document.getElementById(qId + '-fb');
li.classList.add(isCorrect ? 'correct' : 'wrong');
if (!isCorrect) {
items.find(i => parseInt(i.dataset.idx) === correctIdx).classList.add('correct');
}
// Show feedback from parsed data
const qFeedback = feedbackData[qId] || {};
if (qFeedback[isCorrect ? 'correct' : 'wrong']) {
fb.textContent = qFeedback[isCorrect ? 'correct' : 'wrong'];
}
fb.className = 'quiz-feedback show ' + (isCorrect ? 'correct' : 'wrong');
});
});
});
</script>
</head>
<body>
<!-- ════════════════════════════════════════════════════════════
HEADER — Replace placeholder text below
════════════════════════════════════════════════════════════ -->
<h1>{{TITLE}}</h1>
<p class="subtitle">{{SUBTITLE — e.g. "A walkthrough of PR #123: Add rate limiting to the API gateway"}}</p>
<!-- ════════════════════════════════════════════════════════════
TABLE OF CONTENTS — Update href IDs to match your h2s
════════════════════════════════════════════════════════════ -->
<div class="toc">
<h3>Contents</h3>
<ol>
<li><a href="#glossary">Glossary</a></li>
<li><a href="#background">Background</a></li>
<li><a href="#intuition">Intuition</a></li>
<li><a href="#code">Code Walkthrough</a></li>
<li><a href="#quiz">Quiz</a></li>
</div>
<!-- ════════════════════════════════════════════════════════════
SECTION 1: GLOSSARY
════════════════════════════════════════════════════════════ -->
<h2 id="glossary">1. Glossary</h2>
<div class="glossary">
<h3>Key Terms</h3>
<div class="glossary-list">
<div class="glossary-item">
<div class="glossary-term">{{Term}}</div>
<div class="glossary-def">{{2-3 sentences: what it is, why it matters here, and optionally an analogy. Write for a junior developer who hasn't seen this term before.}}</div>
</div>
<div class="glossary-item">
<div class="glossary-term">{{Term}}</div>
<div class="glossary-def">{{2-3 sentences explaining the term in plain language.}}</div>
</div>
<!-- Add more items as needed -->
</div>
</div>
<!-- ════════════════════════════════════════════════════════════
SECTION 2: BACKGROUND
════════════════════════════════════════════════════════════ -->
<h2 id="background">2. Background</h2>
<h3>The Big Picture</h3>
<p>{{EXISTING SYSTEM — What does the code under review do today? How does it fit into the broader architecture?}}</p>
<!-- ════════════════════════════════════════════════════════════
SECTION 3: INTUITION
════════════════════════════════════════════════════════════ -->
<h2 id="intuition">3. Intuition</h2>
<p>{{CORE_INTUITION — What is the fundamental idea behind this change? Why does it work?}}</p>
<!-- ── Example diagram: vertical flow (TD) ── -->
<div class="diagram">
<div class="diagram-title">Fig 2. {{Caption explaining the example flow}}</div>
<div class="flow-row">
<div class="flow-box blue">{{Step 1}}</div>
</div>
<div class="flow-row">
<span class="flow-arrow"></span>
</div>
<div class="flow-row">
<div class="flow-box green">{{Step 2}}</div>
</div>
<div class="flow-row">
<span class="flow-arrow"></span>
</div>
<div class="flow-row">
<div class="flow-box purple">{{Step 3}}</div>
</div>
</div>
<p>{{EXPLANATION — Walk through the intuition step by step.}}</p>
<div class="callout green">
<strong>Key Insight</strong>
{{KEY_INSIGHT}}
</div>
<!-- ════════════════════════════════════════════════════════════
SECTION 3: CODE WALKTHROUGH
════════════════════════════════════════════════════════════ -->
<h2 id="code">4. Code Walkthrough</h2>
<h3>File: {{filename}}</h3>
<p>{{What changed and why}}</p>
<pre><code class="language-{{language}}">
{{code snippet}}
</code></pre>
<p>{{Explanation of the code}}</p>
<h3>File: {{filename 2}}</h3>
<p>{{What changed and why}}</p>
<pre><code class="language-{{language}}">
{{code snippet}}
</code></pre>
<p>{{Explanation of the code}}</p>
<!-- ════════════════════════════════════════════════════════════
SECTION 4: QUIZ
════════════════════════════════════════════════════════════ -->
<h2 id="quiz">5. Quiz</h2>
<p>Test your understanding. Options shuffle on each load.</p>
<!-- ── Question 1 ── -->
<div class="quiz-q" id="q1">
<h4>Q1. {{QUESTION TEXT}}</h4>
<ul class="quiz-options" data-correct="{{0-3}}">
<li data-idx="0">{{OPTION A}}</li>
<li data-idx="1">{{OPTION B}}</li>
<li data-idx="2">{{OPTION C}}</li>
<li data-idx="3">{{OPTION D}}</li>
</ul>
<div class="quiz-feedback" id="q1-fb"></div>
</div>
<!-- ── Question 2 ── -->
<div class="quiz-q" id="q2">
<h4>Q2. {{QUESTION TEXT}}</h4>
<ul class="quiz-options" data-correct="{{0-3}}">
<li data-idx="0">{{OPTION A}}</li>
<li data-idx="1">{{OPTION B}}</li>
<li data-idx="2">{{OPTION C}}</li>
<li data-idx="3">{{OPTION D}}</li>
</ul>
<div class="quiz-feedback" id="q2-fb"></div>
</div>
<!-- ── Question 3 ── -->
<div class="quiz-q" id="q3">
<h4>Q3. {{QUESTION TEXT}}</h4>
<ul class="quiz-options" data-correct="{{0-3}}">
<li data-idx="0">{{OPTION A}}</li>
<li data-idx="1">{{OPTION B}}</li>
<li data-idx="2">{{OPTION C}}</li>
<li data-idx="3">{{OPTION D}}</li>
</ul>
<div class="quiz-feedback" id="q3-fb"></div>
</div>
<!-- ── Question 4 ── -->
<div class="quiz-q" id="q4">
<h4>Q4. {{QUESTION TEXT}}</h4>
<ul class="quiz-options" data-correct="{{0-3}}">
<li data-idx="0">{{OPTION A}}</li>
<li data-idx="1">{{OPTION B}}</li>
<li data-idx="2">{{OPTION C}}</li>
<li data-idx="3">{{OPTION D}}</li>
</ul>
<div class="quiz-feedback" id="q4-fb"></div>
</div>
<!-- ── Question 5 ── -->
<div class="quiz-q" id="q5">
<h4>Q5. {{QUESTION TEXT}}</h4>
<ul class="quiz-options" data-correct="{{0-3}}">
<li data-idx="0">{{OPTION A}}</li>
<li data-idx="1">{{OPTION B}}</li>
<li data-idx="2">{{OPTION C}}</li>
<li data-idx="3">{{OPTION D}}</li>
</ul>
<div class="quiz-feedback" id="q5-fb"></div>
</div>
<!-- ════════════════════════════════════════════════════════════
QUIZ FEEDBACK DATA — Hidden, parsed by template JS
Format: q1\nCorrect feedback\n\nWrong feedback\nq2...
════════════════════════════════════════════════════════════ -->
<div class="quiz-feedback-data" style="display: none;">
q1
{{CORRECT FEEDBACK}}
{{WRONG FEEDBACK}}
q2
{{CORRECT FEEDBACK}}
{{WRONG FEEDBACK}}
q3
{{CORRECT FEEDBACK}}
{{WRONG FEEDBACK}}
q4
{{CORRECT FEEDBACK}}
{{WRONG FEEDBACK}}
q5
{{CORRECT FEEDBACK}}
{{WRONG FEEDBACK}}
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment