← Commit history
back.pngadded
⋯ 1 unchanged line ⋯
color.pngadded
⋯ 1 unchanged line ⋯
dom.htmladded+358
@@ -0,0 +1,358 @@+<!DOCTYPE html>+<html lang="en"><head>+<meta charset="utf-8">+<meta name="viewport" content="width=device-width, initial-scale=1">+<title>Resistor Flash Cards</title>+<style>+  :root {+    --bg: #0b0f14; --panel: #121821; --panel2: #18202b; --line: #243040;+    --text: #e6edf3; --muted: #93a1b3; --teal: #14b8a6; --blue: #3b82f6; --purple: #8b5cf6;+    --good: #22c55e; --bad: #f97316;+  }+  * { box-sizing: border-box; }+  html, body { margin: 0; background: var(--bg); color: var(--text);+    font: 15px/1.5 Inter, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }+  .wrap { max-width: 880px; margin: 0 auto; padding: 20px 16px 28px; }+  h1 { font-size: 22px; margin: 0 0 4px; letter-spacing: -0.01em; }+  .sub { color: var(--muted); margin: 0 0 14px; font-size: 14px; }+  .chips { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }+  .chip { border: 1px solid var(--line); background: var(--panel); color: var(--muted); border-radius: 999px;+    padding: 6px 12px; cursor: pointer; font-size: 13px; user-select: none; }+  .chip.on { color: #fff; border-color: transparent;+    background: linear-gradient(90deg, var(--teal), var(--blue) 60%, var(--purple)); }+  .stage { perspective: 1400px; }+  .card { position: relative; min-height: 340px; cursor: pointer; transform-style: preserve-3d;+    transition: transform .45s cubic-bezier(.2,.8,.2,1); }+  .card.flipped { transform: rotateY(180deg); }+  .face { position: absolute; inset: 0; backface-visibility: hidden; -webkit-backface-visibility: hidden;+    background: var(--panel); border: 1px solid var(--line); border-radius: 16px; padding: 22px 24px;+    display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; gap: 12px; }+  .face.back { transform: rotateY(180deg); background: var(--panel2); }+  .tag { position: absolute; top: 14px; left: 18px; font-size: 12px; color: var(--muted); letter-spacing: .04em; text-transform: uppercase; }+  .hint { position: absolute; bottom: 12px; right: 18px; font-size: 12px; color: var(--muted); }+  .q { font-size: 20px; font-weight: 600; max-width: 640px; }+  .a { font-size: 26px; font-weight: 700; max-width: 640px; }+  .a.small { font-size: 18px; font-weight: 500; }+  .note { color: var(--muted); font-size: 14px; max-width: 640px; }+  .big { font-size: 40px; font-weight: 800; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; letter-spacing: .04em; }+  .mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }+  .bands { display: flex; gap: 6px; flex-wrap: wrap; justify-content: center; }+  .band { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; border-radius: 8px; background: #0f141b; border: 1px solid var(--line); font-size: 14px; }+  .sw { width: 14px; height: 14px; border-radius: 3px; border: 1px solid rgba(255,255,255,.15); }+  svg.res { width: 340px; max-width: 100%; height: auto; }+  .bar { display: flex; gap: 10px; align-items: center; margin-top: 14px; flex-wrap: wrap; }+  button { border: 1px solid var(--line); background: var(--panel); color: var(--text); border-radius: 10px;+    padding: 10px 16px; font-size: 14px; cursor: pointer; min-height: 44px; }+  button:hover { border-color: #3a4a60; }+  button.primary { background: linear-gradient(90deg, var(--teal), var(--blue)); border-color: transparent; color: #fff; font-weight: 600; }+  button.good { border-color: var(--good); color: var(--good); }+  button.bad { border-color: var(--bad); color: var(--bad); }+  .spacer { flex: 1; }+  .prog { color: var(--muted); font-size: 13px; }+  .meter { height: 6px; background: var(--panel); border: 1px solid var(--line); border-radius: 999px; overflow: hidden; margin-top: 10px; }+  .meter i { display: block; height: 100%; width: 0; background: linear-gradient(90deg, var(--teal), var(--blue), var(--purple)); transition: width .3s; }+  .keys { color: var(--muted); font-size: 12px; margin-top: 10px; }+  kbd { border: 1px solid var(--line); border-bottom-width: 2px; border-radius: 4px; padding: 0 5px; font-size: 11px; background: var(--panel); }+  details { margin-top: 20px; border: 1px solid var(--line); border-radius: 12px; background: var(--panel); padding: 10px 16px; }+  summary { cursor: pointer; font-weight: 600; }+  table { border-collapse: collapse; width: 100%; margin-top: 10px; font-size: 14px; }+  th, td { text-align: left; padding: 6px 8px; border-bottom: 1px solid var(--line); }+  th { color: var(--muted); font-weight: 500; }+  .done .q { color: var(--teal); }+</style>+</head>+<body>+<div class="wrap">+  <h1>Resistor Flash Cards</h1>+  <p class="sub">Color codes, SMD markings, formulas, and quick calculations. Click a card to flip it, then mark whether you got it.</p>++  <div class="chips" id="chips"><span class="chip on">All</span><span class="chip">Color code</span><span class="chip">Value to bands</span><span class="chip">SMD codes</span><span class="chip">Formulas</span><span class="chip">Calculations</span></div>++  <div class="stage">+    <div class="card" id="card">+      <div class="face front"><span class="tag" id="tagF">SMD codes · 1 of 103</span><div id="front"><div class="big">472</div><div class="q">Value of this SMD marking?</div></div><span class="hint">click or press space to flip</span></div>+      <div class="face back"><span class="tag" id="tagB">SMD codes · 1 of 103</span><div id="back"><div class="a">4.7 kΩ</div><div class="note">47 × 10²</div></div></div>+    </div>+  </div>++  <div class="bar">+    <button id="prev">Prev</button>+    <button id="flip" class="primary">Flip</button>+    <button id="next">Next</button>+    <span class="spacer"></span>+    <button id="again" class="bad">Again</button>+    <button id="got" class="good">Got it</button>+    <button id="shuffle">Shuffle</button>+  </div>+  <div class="meter"><i id="meter" style="width: 0%;"></i></div>+  <div class="bar"><span class="prog" id="prog">0 of 103 marked "got it", 103 left in the queue</span></div>+  <div class="keys"><kbd>space</kbd> flip · <kbd>←</kbd> <kbd>→</kbd> prev / next · <kbd>1</kbd> again · <kbd>2</kbd> got it · <kbd>s</kbd> shuffle</div>++  <details>+    <summary>Color code cheat sheet</summary>+    <table id="cheat"><tbody><tr><th>Color</th><th>Digit</th><th>Multiplier</th><th>Tolerance</th></tr><tr><td><span class="band"><i class="sw" style="background:#111111"></i>Black</span></td><td>0</td><td>×1</td><td></td></tr><tr><td><span class="band"><i class="sw" style="background:#8b4513"></i>Brown</span></td><td>1</td><td>×10</td><td>±1%</td></tr><tr><td><span class="band"><i class="sw" style="background:#e0201a"></i>Red</span></td><td>2</td><td>×100</td><td>±2%</td></tr><tr><td><span class="band"><i class="sw" style="background:#f28c1a"></i>Orange</span></td><td>3</td><td>×1,000</td><td></td></tr><tr><td><span class="band"><i class="sw" style="background:#f2d21a"></i>Yellow</span></td><td>4</td><td>×10,000</td><td></td></tr><tr><td><span class="band"><i class="sw" style="background:#21a04b"></i>Green</span></td><td>5</td><td>×100,000</td><td>±0.5%</td></tr><tr><td><span class="band"><i class="sw" style="background:#2260d8"></i>Blue</span></td><td>6</td><td>×1,000,000</td><td>±0.25%</td></tr><tr><td><span class="band"><i class="sw" style="background:#8a3fd1"></i>Violet</span></td><td>7</td><td>×10,000,000</td><td>±0.1%</td></tr><tr><td><span class="band"><i class="sw" style="background:#8f8f8f"></i>Gray</span></td><td>8</td><td>×100,000,000</td><td>±0.05%</td></tr><tr><td><span class="band"><i class="sw" style="background:#f4f4f4"></i>White</span></td><td>9</td><td>×1,000,000,000</td><td></td></tr><tr><td><span class="band"><i class="sw" style="background:#d4a017"></i>Gold</span></td><td></td><td>×0.1</td><td>±5%</td></tr><tr><td><span class="band"><i class="sw" style="background:#c0c0c0"></i>Silver</span></td><td></td><td>×0.01</td><td>±10%</td></tr></tbody></table>+    <p class="note" style="margin-top:10px">Read with the tolerance band (gold, silver, or the band spaced farthest from the others) on the right. 4-band: digit, digit, multiplier, tolerance. 5-band: digit, digit, digit, multiplier, tolerance. 6-band adds a temperature coefficient band.</p>+  </details>+</div>++<script>+(function () {+  // ---------- reference data ----------+  var COLORS = [+    { n: 'Black',  hex: '#111111', d: 0, m: 1 },+    { n: 'Brown',  hex: '#8b4513', d: 1, m: 10,   t: 1 },+    { n: 'Red',    hex: '#e0201a', d: 2, m: 100,  t: 2 },+    { n: 'Orange', hex: '#f28c1a', d: 3, m: 1e3 },+    { n: 'Yellow', hex: '#f2d21a', d: 4, m: 1e4 },+    { n: 'Green',  hex: '#21a04b', d: 5, m: 1e5,  t: 0.5 },+    { n: 'Blue',   hex: '#2260d8', d: 6, m: 1e6,  t: 0.25 },+    { n: 'Violet', hex: '#8a3fd1', d: 7, m: 1e7,  t: 0.1 },+    { n: 'Gray',   hex: '#8f8f8f', d: 8, m: 1e8,  t: 0.05 },+    { n: 'White',  hex: '#f4f4f4', d: 9, m: 1e9 },+    { n: 'Gold',   hex: '#d4a017', m: 0.1,  t: 5 },+    { n: 'Silver', hex: '#c0c0c0', m: 0.01, t: 10 }+  ];+  var BY = {}; COLORS.forEach(function (c) { BY[c.n] = c; });+  var E12 = [10, 12, 15, 18, 22, 27, 33, 39, 47, 56, 68, 82];+  var E24 = [10, 11, 12, 13, 15, 16, 18, 20, 22, 24, 27, 30, 33, 36, 39, 43, 47, 51, 56, 62, 68, 75, 82, 91];+  var E96s = [100, 121, 150, 182, 221, 249, 274, 332, 402, 475, 549, 681, 825, 976];++  function fmt(ohms) {+    var u = 'Ω', v = ohms;+    if (ohms >= 1e6) { v = ohms / 1e6; u = 'MΩ'; }+    else if (ohms >= 1e3) { v = ohms / 1e3; u = 'kΩ'; }+    v = +v.toPrecision(3);+    return v + ' ' + u;+  }+  function esc(s) { return String(s).replace(/[&<>]/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;' }[c]; }); }+  function rnd(n) { return Math.floor(Math.random() * n); }+  function pick(a) { return a[rnd(a.length)]; }+  function shuffleArr(a) { for (var i = a.length - 1; i > 0; i--) { var j = rnd(i + 1); var t = a[i]; a[i] = a[j]; a[j] = t; } return a; }++  // ---------- resistor drawing ----------+  function resistorSVG(bandColors) {+    var n = bandColors.length;+    var xs = n === 4 ? [92, 116, 140, 196] : n === 5 ? [84, 106, 128, 150, 200] : [80, 100, 120, 140, 160, 205];+    var s = '<svg class="res" viewBox="0 0 340 90" xmlns="http://www.w3.org/2000/svg">';+    s += '<line x1="10" y1="45" x2="330" y2="45" stroke="#b8c0cc" stroke-width="5" stroke-linecap="round"/>';+    s += '<rect x="60" y="18" width="220" height="54" rx="22" fill="#d9c9a3" stroke="#6b5b3a" stroke-width="2"/>';+    s += '<rect x="66" y="22" width="208" height="14" rx="10" fill="rgba(255,255,255,.28)"/>';+    bandColors.forEach(function (c, i) {+      s += '<rect x="' + xs[i] + '" y="19" width="14" height="52" rx="2" fill="' + BY[c].hex + '" stroke="rgba(0,0,0,.25)"/>';+    });+    return s + '</svg>';+  }+  function bandList(names, roles) {+    return '<div class="bands">' + names.map(function (n, i) {+      return '<span class="band"><i class="sw" style="background:' + BY[n].hex + '"></i>' + n + (roles ? ' <span class="note">' + roles[i] + '</span>' : '') + '</span>';+    }).join('') + '</div>';+  }+  function bandsFor(sig, mult, tol) {+    var digits = String(sig).split('').map(function (d) { return COLORS[+d].n; });+    var mName = COLORS.filter(function (c) { return c.m === mult; })[0].n;+    var tName = COLORS.filter(function (c) { return c.t === tol; })[0].n;+    return digits.concat([mName, tName]);+  }+  function tolRange(ohms, tol) { return fmt(ohms * (1 - tol / 100)) + ' to ' + fmt(ohms * (1 + tol / 100)); }++  // ---------- generated decks ----------+  function colorCards(count) {+    var out = [];+    for (var i = 0; i < count; i++) {+      var five = i % 3 === 2;+      var sig = five ? pick(E96s) : pick(E24);+      var mExp = five ? rnd(5) : rnd(6);+      var mult = Math.pow(10, mExp);+      var tol = five ? 1 : pick([5, 10, 5, 1]);+      var ohms = sig * mult;+      var bands = bandsFor(sig, mult, tol);+      var roles = five ? ['1st digit', '2nd digit', '3rd digit', 'multiplier', 'tolerance'] : ['1st digit', '2nd digit', 'multiplier', 'tolerance'];+      out.push({+        deck: 'color',+        front: resistorSVG(bands) + '<div class="q">What is the value and tolerance?</div>',+        back: '<div class="a">' + fmt(ohms) + ' ±' + tol + '%</div>' + bandList(bands, roles) ++              '<div class="note">Acceptable range: ' + tolRange(ohms, tol) + '</div>'+      });+    }+    return out;+  }+  function reverseCards(count) {+    var out = [];+    for (var i = 0; i < count; i++) {+      var sig = pick(E12), mExp = rnd(6), mult = Math.pow(10, mExp), tol = pick([5, 10]);+      var ohms = sig * mult, bands = bandsFor(sig, mult, tol);+      out.push({+        deck: 'reverse',+        front: '<div class="big">' + fmt(ohms) + ' ±' + tol + '%</div><div class="q">Name the four color bands.</div>',+        back: resistorSVG(bands) + bandList(bands, ['1st digit', '2nd digit', 'multiplier', 'tolerance'])+      });+    }+    return out;+  }+  function digitCards() {+    var out = [];+    COLORS.slice(0, 10).forEach(function (c) {+      out.push({ deck: 'color',+        front: '<div class="bands"><span class="band" style="font-size:20px;padding:10px 18px"><i class="sw" style="width:22px;height:22px;background:' + c.hex + '"></i>' + c.n + '</span></div><div class="q">What digit is this band, and what multiplier?</div>',+        back: '<div class="a">Digit ' + c.d + ' · multiplier ×' + (c.m >= 1000 ? c.m.toLocaleString() : c.m) + '</div>' + (c.t ? '<div class="note">As a tolerance band: ±' + c.t + '%</div>' : '') });+    });+    out.push({ deck: 'color', front: '<div class="q">Gold as a multiplier band? As a tolerance band?</div>', back: '<div class="a">×0.1 · ±5%</div><div class="note">Silver is ×0.01 and ±10%. No tolerance band at all means ±20%.</div>' });+    out.push({ deck: 'color', front: '<div class="q">Mnemonic for Black through White?</div>', back: '<div class="a small">Better Be Right Or Your Great Big Venture Goes Wrong</div><div class="note">Black 0, Brown 1, Red 2, Orange 3, Yellow 4, Green 5, Blue 6, Violet 7, Gray 8, White 9</div>' });+    out.push({ deck: 'color', front: '<div class="q">Which end of the resistor do you read from?</div>', back: '<div class="a small">Tolerance band (gold or silver, or the band with the wider gap) goes on the RIGHT. Read left to right.</div>' });+    out.push({ deck: 'color', front: resistorSVG(['Black']) + '<div class="q">A resistor with a single black band?</div>', back: '<div class="a">0 Ω jumper</div><div class="note">Used as a configurable link on a PCB so the pick-and-place machine can place it like any other part.</div>' });+    out.push({ deck: 'color', front: '<div class="q">What does the sixth band on a 6-band resistor mean?</div>', back: '<div class="a small">Temperature coefficient (ppm/°C)</div><div class="note">Brown 100, Red 50, Orange 15, Yellow 25, Blue 10, Violet 5 ppm/°C</div>' });+    return out;+  }+  function smdCards() {+    var rows = [+      ['103', '10 kΩ', '3-digit: two digits then a power of ten. 10 × 10³'],+      ['472', '4.7 kΩ', '47 × 10²'],+      ['220', '22 Ω', '22 × 10⁰. Not 220 Ω, a common trap.'],+      ['221', '220 Ω', '22 × 10¹'],+      ['1R0', '1.0 Ω', 'R marks the decimal point'],+      ['4R7', '4.7 Ω', 'R marks the decimal point'],+      ['R47', '0.47 Ω', 'R marks the decimal point'],+      ['000', '0 Ω', 'Jumper'],+      ['1002', '10 kΩ', '4-digit (1% parts): three digits then a power of ten. 100 × 10²'],+      ['4701', '4.7 kΩ', '470 × 10¹'],+      ['3301', '3.3 kΩ', '330 × 10¹'],+      ['01C', '10 kΩ', 'EIA-96: code 01 = 100, letter C = ×100'],+      ['22A', '165 Ω', 'EIA-96: code 22 = 165, letter A = ×1'],+      ['01B', '1 kΩ', 'EIA-96: code 01 = 100, letter B = ×10']+    ];+    return rows.map(function (r) {+      return { deck: 'smd', front: '<div class="big">' + r[0] + '</div><div class="q">Value of this SMD marking?</div>', back: '<div class="a">' + r[1] + '</div><div class="note">' + esc(r[2]) + '</div>' };+    });+  }+  function formulaCards() {+    var rows = [+      ["Ohm's law", 'V = I·R, so I = V/R and R = V/I'],+      ['Power dissipated in a resistor', 'P = V·I = I²·R = V²/R'],+      ['Resistors in series', 'R<sub>total</sub> = R₁ + R₂ + … ; same current through each, voltages add'],+      ['Resistors in parallel', '1/R<sub>total</sub> = 1/R₁ + 1/R₂ + … ; same voltage across each, currents add'],+      ['Two resistors in parallel (product over sum)', 'R<sub>total</sub> = R₁·R₂ / (R₁ + R₂)'],+      ['N equal resistors R in parallel', 'R / N'],+      ['Voltage divider output', 'V<sub>out</sub> = V<sub>in</sub> · R₂ / (R₁ + R₂), with R₂ across the output'],+      ['Current divider (two branches)', 'I₁ = I<sub>total</sub> · R₂ / (R₁ + R₂). The current takes the smaller resistance more.'],+      ["Kirchhoff's voltage law", 'The sum of voltages around any closed loop is zero'],+      ["Kirchhoff's current law", 'The sum of currents entering a node equals the sum leaving it'],+      ['Wheatstone bridge balance condition', 'R₁/R₂ = R₃/R₄ (no current through the meter)'],+      ['Conductance', 'G = 1/R, measured in siemens (S). Parallel conductances add.'],+      ['Resistance of a wire', 'R = ρ·L / A (resistivity × length ÷ cross-section area)'],+      ['What does ±5% tolerance mean for 4.7 kΩ?', 'Actual value lies between 4.465 kΩ and 4.935 kΩ'],+      ['E12 series values', '10, 12, 15, 18, 22, 27, 33, 39, 47, 56, 68, 82 (each ~20% apart, made for ±10% parts)'],+      ['E24 series values', 'E12 plus 11, 13, 16, 20, 24, 30, 36, 43, 47…: 24 per decade, made for ±5% parts'],+      ['Why are standard values spaced logarithmically?', 'So adjacent values overlap at their tolerance and every resistance is covered with the fewest parts'],+      ['Typical power ratings', 'Through-hole: 1/8 W, 1/4 W, 1/2 W. SMD: 0402 ≈ 1/16 W, 0603 ≈ 1/10 W, 0805 ≈ 1/8 W, 1206 ≈ 1/4 W'],+      ['Derating', 'Above about 70 °C ambient the allowed power drops linearly toward zero at the max temperature. Run resistors at half their rating.'],+      ['Temperature coefficient, 100 ppm/°C', 'Resistance changes 0.01% per °C. A 10 kΩ part drifts 1 Ω per °C.'],+      ['Carbon film vs metal film', 'Carbon film: cheap, ±5%, noisier. Metal film: ±1% or better, low noise, low tempco. Default choice for signal work.'],+      ['Wirewound resistors', 'High power, very precise, but inductive: avoid in high-frequency paths'],+      ['Potentiometer vs rheostat', 'Potentiometer: three terminals, a variable voltage divider. Rheostat: two terminals, a variable resistance.'],+      ['Pull-up resistor', 'Ties a signal to V<sub>cc</sub> through a resistor (often 4.7 kΩ to 10 kΩ) so it reads high when nothing drives it'],+      ['LED current-limiting resistor', 'R = (V<sub>supply</sub> − V<sub>forward</sub>) / I<sub>LED</sub>'],+      ['Thermal noise (Johnson) of a resistor', 'v<sub>n</sub> = √(4·k·T·R·Δf). Bigger R means more noise.']+    ];+    return rows.map(function (r) { return { deck: 'formula', front: '<div class="q">' + r[0] + '</div>', back: '<div class="a small">' + r[1] + '</div>' }; });+  }+  function calcCards(count) {+    var out = [];+    for (var i = 0; i < count; i++) {+      var kind = i % 6, r1 = pick(E12) * Math.pow(10, 1 + rnd(3)), r2 = pick(E12) * Math.pow(10, 1 + rnd(3)), v = pick([3.3, 5, 9, 12, 24]);+      if (kind === 0) out.push({ deck: 'calc', front: '<div class="q">' + fmt(r1) + ' and ' + fmt(r2) + ' in series?</div>', back: '<div class="a">' + fmt(r1 + r2) + '</div><div class="note">Series resistances add.</div>' });+      else if (kind === 1) out.push({ deck: 'calc', front: '<div class="q">Two ' + fmt(r1) + ' resistors in parallel?</div>', back: '<div class="a">' + fmt(r1 / 2) + '</div><div class="note">Equal resistors in parallel: R / N.</div>' });+      else if (kind === 2) out.push({ deck: 'calc', front: '<div class="q">' + fmt(r1) + ' and ' + fmt(r2) + ' in parallel?</div>', back: '<div class="a">' + fmt(r1 * r2 / (r1 + r2)) + '</div><div class="note">Product over sum. The result is always smaller than the smaller resistor.</div>' });+      else if (kind === 3) out.push({ deck: 'calc', front: '<div class="q">Voltage divider: ' + v + ' V across ' + fmt(r1) + ' (top) and ' + fmt(r2) + ' (bottom). V<sub>out</sub> across the bottom?</div>', back: '<div class="a">' + (+(v * r2 / (r1 + r2)).toPrecision(3)) + ' V</div><div class="note">V<sub>out</sub> = V<sub>in</sub> · R₂ / (R₁ + R₂)</div>' });+      else if (kind === 4) { var iA = v / r1; out.push({ deck: 'calc', front: '<div class="q">' + v + ' V across ' + fmt(r1) + '. Current?</div>', back: '<div class="a">' + (iA >= 1e-3 ? +(iA * 1e3).toPrecision(3) + ' mA' : +(iA * 1e6).toPrecision(3) + ' µA') + '</div><div class="note">I = V / R</div>' }); }+      else { var p = v * v / r1; out.push({ deck: 'calc', front: '<div class="q">' + v + ' V across ' + fmt(r1) + '. Power dissipated? Is a 1/4 W part OK?</div>', back: '<div class="a">' + (p >= 1 ? +p.toPrecision(3) + ' W' : +(p * 1e3).toPrecision(3) + ' mW') + '</div><div class="note">P = V² / R. ' + (p <= 0.125 ? 'Yes, under half of 1/4 W.' : p <= 0.25 ? 'Marginal: within rating but over half of it.' : 'No, exceeds 1/4 W.') + '</div>' }); }+    }+    return out;+  }++  var DECKS = [+    { id: 'all', label: 'All' },+    { id: 'color', label: 'Color code' },+    { id: 'reverse', label: 'Value to bands' },+    { id: 'smd', label: 'SMD codes' },+    { id: 'formula', label: 'Formulas' },+    { id: 'calc', label: 'Calculations' }+  ];+  var ALL = [];+  function build() {+    ALL = shuffleArr(digitCards().concat(colorCards(18), reverseCards(12), smdCards(), formulaCards(), calcCards(18)));+  }++  // ---------- state ----------+  var deck = 'all', queue = [], idx = 0, flipped = false, done = 0, total = 0;+  var card = document.getElementById('card'), front = document.getElementById('front'), back = document.getElementById('back');+  var tagF = document.getElementById('tagF'), tagB = document.getElementById('tagB'), prog = document.getElementById('prog'), meter = document.getElementById('meter');+  function label(id) { return DECKS.filter(function (d) { return d.id === id; })[0].label; }++  function load() {+    queue = ALL.filter(function (c) { return deck === 'all' || c.deck === deck; });+    idx = 0; done = 0; total = queue.length; render();+  }+  function render() {+    flipped = false; card.classList.remove('flipped');+    if (!queue.length) {+      card.classList.add('done');+      front.innerHTML = '<div class="q">Deck complete. Shuffle to run it again.</div>'; back.innerHTML = '';+      tagF.textContent = label(deck); tagB.textContent = '';+    } else {+      card.classList.remove('done');+      var c = queue[idx];+      front.innerHTML = c.front; back.innerHTML = c.back;+      tagF.textContent = label(c.deck) + ' · ' + (idx + 1) + ' of ' + queue.length; tagB.textContent = tagF.textContent;+    }+    prog.textContent = done + ' of ' + total + ' marked "got it"' + (queue.length ? ', ' + queue.length + ' left in the queue' : '');+    meter.style.width = (total ? Math.round(done / total * 100) : 0) + '%';+    fit();+  }+  function flip() { if (!queue.length) return; flipped = !flipped; card.classList.toggle('flipped', flipped); }+  function next() { if (!queue.length) return; idx = (idx + 1) % queue.length; render(); }+  function prev() { if (!queue.length) return; idx = (idx - 1 + queue.length) % queue.length; render(); }+  function got() { if (!queue.length) return; queue.splice(idx, 1); done++; if (idx >= queue.length) idx = 0; render(); }+  function again() { if (queue.length < 2) { flipped = false; card.classList.remove('flipped'); return; } var c = queue.splice(idx, 1)[0]; queue.push(c); if (idx >= queue.length) idx = 0; render(); }+  function reshuffle() { build(); load(); }++  // ---------- UI wiring ----------+  var chips = document.getElementById('chips');+  DECKS.forEach(function (d) {+    var b = document.createElement('span'); b.className = 'chip' + (d.id === deck ? ' on' : ''); b.textContent = d.label;+    b.onclick = function () { deck = d.id; Array.prototype.forEach.call(chips.children, function (x) { x.classList.remove('on'); }); b.classList.add('on'); load(); };+    chips.appendChild(b);+  });+  card.onclick = flip;+  document.getElementById('flip').onclick = flip;+  document.getElementById('next').onclick = next;+  document.getElementById('prev').onclick = prev;+  document.getElementById('got').onclick = got;+  document.getElementById('again').onclick = again;+  document.getElementById('shuffle').onclick = reshuffle;+  document.addEventListener('keydown', function (e) {+    if (e.target && /input|textarea/i.test(e.target.tagName)) return;+    if (e.key === ' ') { e.preventDefault(); flip(); }+    else if (e.key === 'ArrowRight') next();+    else if (e.key === 'ArrowLeft') prev();+    else if (e.key === '1') again();+    else if (e.key === '2') got();+    else if (e.key === 's' || e.key === 'S') reshuffle();+  });++  // cheat sheet+  var cheat = document.getElementById('cheat');+  cheat.innerHTML = '<tr><th>Color</th><th>Digit</th><th>Multiplier</th><th>Tolerance</th></tr>' + COLORS.map(function (c) {+    return '<tr><td><span class="band"><i class="sw" style="background:' + c.hex + '"></i>' + c.n + '</span></td><td>' + (c.d === undefined ? '' : c.d) + '</td><td>×' + (c.m >= 1000 ? c.m.toLocaleString() : c.m) + '</td><td>' + (c.t ? '±' + c.t + '%' : '') + '</td></tr>';+  }).join('');++  // sandboxed-iframe height reporter+  function fit() { try { parent.postMessage({ type: 'readme-height', height: document.documentElement.scrollHeight }, '*'); } catch (e) {} }+  addEventListener('load', fit);+  if (window.ResizeObserver) new ResizeObserver(fit).observe(document.documentElement);++  build(); load();+})();+</script>+++</body></html>
front.pngadded
⋯ 1 unchanged line ⋯
install.sh

  
page.json+37−5
@@ -14,11 +14,37 @@     "name": "Colby Knox",     "email": "[email protected]"   },-  "tags": [],+  "tags": [+    "education",+    "resistors",+    "circuits",+    "flash-cards",+    "study"+  ],   "license": "proprietary",-  "sample_prompts": [],-  "discovery_triggers": [],-  "discovery_pitch": null,+  "sample_prompts": [+    {+      "label": "Color codes",+      "prompt": "Quiz me on resistor color codes"+    },+    {+      "label": "SMD markings",+      "prompt": "Help me practice reading SMD resistor codes"+    },+    {+      "label": "Formulas",+      "prompt": "Drill me on series and parallel resistor formulas for my circuits exam"+    }+  ],+  "discovery_triggers": [+    "resistor flash cards",+    "quiz me on resistor color codes",+    "practice reading resistors",+    "study for my circuits class",+    "what does this SMD resistor code mean",+    "drill me on series and parallel resistors"+  ],+  "discovery_pitch": "Open when someone wants to study or quiz themselves on resistor color codes, SMD markings, or basic circuit formulas.",   "metadata": {},   "created_at": "2026-09-18T22:11:59.736Z",   "updated_at": "2026-09-18T22:11:59.736Z",@@ -29,5 +55,11 @@     "version_cmd": ""   },   "skills": [],-  "org": "test5"+  "org": "test5",+  "description": "Interactive flash cards for a circuits class: read 4-band and 5-band resistor color codes, decode SMD markings, drill Ohm's law, power, series and parallel formulas, and work randomly generated practice problems. The deck runs on the wiki page itself, nothing to install.",+  "dependencies": {},+  "scripts": {+    "install": "./install.sh",+    "uninstall": "./uninstall.sh"+  } }\ No newline at end of file
pose-err.logadded+30
@@ -0,0 +1,30 @@+local package subject: Resistor Flash Cards (no local image candidate(s))+live page: "Resistor Flash Cards" (local package fields win for this pose)+brand guide for test5: STARTER (not yet confirmed by a human) (v0.1.0 8b433fd)+  guide: https://wiki.adom.inc/test5/brand+  hint: [BRAND_GUIDE_STARTER] test5/brand is a starter guide nobody has approved yet. Show it to a member of test5 to review and confirm before generating heroes with it.+  hint: [BRAND_EDITORS] Any member of the test5 org can edit test5/brand, like the org's other pages.+  who may edit: Any member of the test5 org can edit test5/brand, like the org's other pages.+  the wizard opens on a Brand step; the guide is confirmed by a human there, never by a thread++REPRIMAND [SHOWCASE_IS_GENERIC]: the showcase is showing the GENERIC MOCK.+  CANDIDATES for test5/resistor-flash-cards (app), best first:+    [page_surface] wiki.adom.inc/test5/resistor-flash-cards+        why: last resort: the page as rendered. Weaker than real UI, but truthful and always available+        capture the page at the size the left panel shows, then: hero-studio showcase --file <shot.png>+  this page has no usable image of its own: capture one. The generic mock must not ship as a hero+  Pick one and load it YOURSELF; do not ask the human to find a screenshot.++  You MUST capture a real screenshot of test5/resistor-flash-cards's actual UI and load it:+  1. open the app in a pup window and size the capture to the size shown in the left panel so nothing crops:+     adom-desktop browser_open_window '{"sessionId":"showcase-shot","profile":"showcase-shot","url":"<the app's URL>"}'+     adom-desktop browser_eval '{"sessionId":"showcase-shot","expr":"window.resizeTo(1000,640)"}'+     adom-desktop browser_screenshot '{"sessionId":"showcase-shot"}'+  2. load it into the studio: hero-studio showcase --file <that screenshot.png>+  Do NOT let the human generate over the generic mock unless the page truly has no UI.++studio open (webview, :8851, tab "Hero Studio"), posed for test5/resistor-flash-cards. Waiting for a human to click Generate (timeout 3600s)...+NOTE: the human made changes at the gate (see .changes in the JSON above).+Sync the local package (page.json / package.json / README) to match, or the+next publish silently reverts what the human decided.+exit=0
pose-out.jsonadded+1
@@ -0,0 +1 @@+{"ok":true,"ref":"test5/resistor-flash-cards","port":8851,"file":"hero-resistor-flash-cards-1789771436143.png","path":"/home/adom/project/adom_modules/adom/hero-studio/generated/hero-resistor-flash-cards-1789771436143.png","latest":"/home/adom/project/adom_modules/adom/hero-studio/generated/latest.png","changes":{"ref":"test5/resistor-flash-cards","page":{},"pose":{"theme":{"from":"midnight","to":"grid"},"subtitle":{"from":"","to":"Color codes, SMD marks, and formulas until they stick"}},"applied":null,"dirty":0}}
preview.pngadded
⋯ 1 unchanged line ⋯
preview2.pngadded
⋯ 1 unchanged line ⋯
preview3.pngadded
⋯ 1 unchanged line ⋯
preview4.pngadded
⋯ 1 unchanged line ⋯
preview5.pngadded
⋯ 1 unchanged line ⋯
preview6.pngadded
⋯ 1 unchanged line ⋯
preview7.pngadded
⋯ 1 unchanged line ⋯
preview8.pngadded
⋯ 1 unchanged line ⋯
showcase.pngadded
⋯ 1 unchanged line ⋯
t_back.htmladded+358
@@ -0,0 +1,358 @@+<!doctype html>+<html lang="en">+<head>+<meta charset="utf-8">+<meta name="viewport" content="width=device-width, initial-scale=1">+<title>Resistor Flash Cards</title>+<style>+  :root {+    --bg: #0b0f14; --panel: #121821; --panel2: #18202b; --line: #243040;+    --text: #e6edf3; --muted: #93a1b3; --teal: #14b8a6; --blue: #3b82f6; --purple: #8b5cf6;+    --good: #22c55e; --bad: #f97316;+  }+  * { box-sizing: border-box; }+  html, body { margin: 0; background: var(--bg); color: var(--text);+    font: 15px/1.5 Inter, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }+  .wrap { max-width: 880px; margin: 0 auto; padding: 20px 16px 28px; }+  h1 { font-size: 22px; margin: 0 0 4px; letter-spacing: -0.01em; }+  .sub { color: var(--muted); margin: 0 0 14px; font-size: 14px; }+  .chips { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }+  .chip { border: 1px solid var(--line); background: var(--panel); color: var(--muted); border-radius: 999px;+    padding: 6px 12px; cursor: pointer; font-size: 13px; user-select: none; }+  .chip.on { color: #fff; border-color: transparent;+    background: linear-gradient(90deg, var(--teal), var(--blue) 60%, var(--purple)); }+  .stage { perspective: 1400px; }+  .card { position: relative; min-height: 340px; cursor: pointer; transform-style: preserve-3d;+    transition: transform .45s cubic-bezier(.2,.8,.2,1); }+  .card.flipped { transform: rotateY(180deg); }+  .face { position: absolute; inset: 0; backface-visibility: hidden; -webkit-backface-visibility: hidden;+    background: var(--panel); border: 1px solid var(--line); border-radius: 16px; padding: 22px 24px;+    display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; gap: 12px; }+  .face.back { transform: rotateY(180deg); background: var(--panel2); }+  .tag { position: absolute; top: 14px; left: 18px; font-size: 12px; color: var(--muted); letter-spacing: .04em; text-transform: uppercase; }+  .hint { position: absolute; bottom: 12px; right: 18px; font-size: 12px; color: var(--muted); }+  .q { font-size: 20px; font-weight: 600; max-width: 640px; }+  .a { font-size: 26px; font-weight: 700; max-width: 640px; }+  .a.small { font-size: 18px; font-weight: 500; }+  .note { color: var(--muted); font-size: 14px; max-width: 640px; }+  .big { font-size: 40px; font-weight: 800; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; letter-spacing: .04em; }+  .mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }+  .bands { display: flex; gap: 6px; flex-wrap: wrap; justify-content: center; }+  .band { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; border-radius: 8px; background: #0f141b; border: 1px solid var(--line); font-size: 14px; }+  .sw { width: 14px; height: 14px; border-radius: 3px; border: 1px solid rgba(255,255,255,.15); }+  svg.res { width: 340px; max-width: 100%; height: auto; }+  .bar { display: flex; gap: 10px; align-items: center; margin-top: 14px; flex-wrap: wrap; }+  button { border: 1px solid var(--line); background: var(--panel); color: var(--text); border-radius: 10px;+    padding: 10px 16px; font-size: 14px; cursor: pointer; min-height: 44px; }+  button:hover { border-color: #3a4a60; }+  button.primary { background: linear-gradient(90deg, var(--teal), var(--blue)); border-color: transparent; color: #fff; font-weight: 600; }+  button.good { border-color: var(--good); color: var(--good); }+  button.bad { border-color: var(--bad); color: var(--bad); }+  .spacer { flex: 1; }+  .prog { color: var(--muted); font-size: 13px; }+  .meter { height: 6px; background: var(--panel); border: 1px solid var(--line); border-radius: 999px; overflow: hidden; margin-top: 10px; }+  .meter i { display: block; height: 100%; width: 0; background: linear-gradient(90deg, var(--teal), var(--blue), var(--purple)); transition: width .3s; }+  .keys { color: var(--muted); font-size: 12px; margin-top: 10px; }+  kbd { border: 1px solid var(--line); border-bottom-width: 2px; border-radius: 4px; padding: 0 5px; font-size: 11px; background: var(--panel); }+  details { margin-top: 20px; border: 1px solid var(--line); border-radius: 12px; background: var(--panel); padding: 10px 16px; }+  summary { cursor: pointer; font-weight: 600; }+  table { border-collapse: collapse; width: 100%; margin-top: 10px; font-size: 14px; }+  th, td { text-align: left; padding: 6px 8px; border-bottom: 1px solid var(--line); }+  th { color: var(--muted); font-weight: 500; }+  .done .q { color: var(--teal); }+</style>+</head>+<body>+<div class="wrap">+  <h1>Resistor Flash Cards</h1>+  <p class="sub">Color codes, SMD markings, formulas, and quick calculations. Click a card to flip it, then mark whether you got it.</p>++  <div class="chips" id="chips"></div>++  <div class="stage">+    <div class="card" id="card">+      <div class="face front"><span class="tag" id="tagF"></span><div id="front"></div><span class="hint">click or press space to flip</span></div>+      <div class="face back"><span class="tag" id="tagB"></span><div id="back"></div></div>+    </div>+  </div>++  <div class="bar">+    <button id="prev">Prev</button>+    <button id="flip" class="primary">Flip</button>+    <button id="next">Next</button>+    <span class="spacer"></span>+    <button id="again" class="bad">Again</button>+    <button id="got" class="good">Got it</button>+    <button id="shuffle">Shuffle</button>+  </div>+  <div class="meter"><i id="meter"></i></div>+  <div class="bar"><span class="prog" id="prog"></span></div>+  <div class="keys"><kbd>space</kbd> flip · <kbd>&larr;</kbd> <kbd>&rarr;</kbd> prev / next · <kbd>1</kbd> again · <kbd>2</kbd> got it · <kbd>s</kbd> shuffle</div>++  <details>+    <summary>Color code cheat sheet</summary>+    <table id="cheat"></table>+    <p class="note" style="margin-top:10px">Read with the tolerance band (gold, silver, or the band spaced farthest from the others) on the right. 4-band: digit, digit, multiplier, tolerance. 5-band: digit, digit, digit, multiplier, tolerance. 6-band adds a temperature coefficient band.</p>+  </details>+</div>++<script>+(function () {+  // ---------- reference data ----------+  var COLORS = [+    { n: 'Black',  hex: '#111111', d: 0, m: 1 },+    { n: 'Brown',  hex: '#8b4513', d: 1, m: 10,   t: 1 },+    { n: 'Red',    hex: '#e0201a', d: 2, m: 100,  t: 2 },+    { n: 'Orange', hex: '#f28c1a', d: 3, m: 1e3 },+    { n: 'Yellow', hex: '#f2d21a', d: 4, m: 1e4 },+    { n: 'Green',  hex: '#21a04b', d: 5, m: 1e5,  t: 0.5 },+    { n: 'Blue',   hex: '#2260d8', d: 6, m: 1e6,  t: 0.25 },+    { n: 'Violet', hex: '#8a3fd1', d: 7, m: 1e7,  t: 0.1 },+    { n: 'Gray',   hex: '#8f8f8f', d: 8, m: 1e8,  t: 0.05 },+    { n: 'White',  hex: '#f4f4f4', d: 9, m: 1e9 },+    { n: 'Gold',   hex: '#d4a017', m: 0.1,  t: 5 },+    { n: 'Silver', hex: '#c0c0c0', m: 0.01, t: 10 }+  ];+  var BY = {}; COLORS.forEach(function (c) { BY[c.n] = c; });+  var E12 = [10, 12, 15, 18, 22, 27, 33, 39, 47, 56, 68, 82];+  var E24 = [10, 11, 12, 13, 15, 16, 18, 20, 22, 24, 27, 30, 33, 36, 39, 43, 47, 51, 56, 62, 68, 75, 82, 91];+  var E96s = [100, 121, 150, 182, 221, 249, 274, 332, 402, 475, 549, 681, 825, 976];++  function fmt(ohms) {+    var u = 'Ω', v = ohms;+    if (ohms >= 1e6) { v = ohms / 1e6; u = 'MΩ'; }+    else if (ohms >= 1e3) { v = ohms / 1e3; u = 'kΩ'; }+    v = +v.toPrecision(3);+    return v + ' ' + u;+  }+  function esc(s) { return String(s).replace(/[&<>]/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;' }[c]; }); }+  function rnd(n) { return Math.floor(Math.random() * n); }+  function pick(a) { return a[rnd(a.length)]; }+  function shuffleArr(a) { for (var i = a.length - 1; i > 0; i--) { var j = rnd(i + 1); var t = a[i]; a[i] = a[j]; a[j] = t; } return a; }++  // ---------- resistor drawing ----------+  function resistorSVG(bandColors) {+    var n = bandColors.length;+    var xs = n === 4 ? [92, 116, 140, 196] : n === 5 ? [84, 106, 128, 150, 200] : [80, 100, 120, 140, 160, 205];+    var s = '<svg class="res" viewBox="0 0 340 90" xmlns="http://www.w3.org/2000/svg">';+    s += '<line x1="10" y1="45" x2="330" y2="45" stroke="#b8c0cc" stroke-width="5" stroke-linecap="round"/>';+    s += '<rect x="60" y="18" width="220" height="54" rx="22" fill="#d9c9a3" stroke="#6b5b3a" stroke-width="2"/>';+    s += '<rect x="66" y="22" width="208" height="14" rx="10" fill="rgba(255,255,255,.28)"/>';+    bandColors.forEach(function (c, i) {+      s += '<rect x="' + xs[i] + '" y="19" width="14" height="52" rx="2" fill="' + BY[c].hex + '" stroke="rgba(0,0,0,.25)"/>';+    });+    return s + '</svg>';+  }+  function bandList(names, roles) {+    return '<div class="bands">' + names.map(function (n, i) {+      return '<span class="band"><i class="sw" style="background:' + BY[n].hex + '"></i>' + n + (roles ? ' <span class="note">' + roles[i] + '</span>' : '') + '</span>';+    }).join('') + '</div>';+  }+  function bandsFor(sig, mult, tol) {+    var digits = String(sig).split('').map(function (d) { return COLORS[+d].n; });+    var mName = COLORS.filter(function (c) { return c.m === mult; })[0].n;+    var tName = COLORS.filter(function (c) { return c.t === tol; })[0].n;+    return digits.concat([mName, tName]);+  }+  function tolRange(ohms, tol) { return fmt(ohms * (1 - tol / 100)) + ' to ' + fmt(ohms * (1 + tol / 100)); }++  // ---------- generated decks ----------+  function colorCards(count) {+    var out = [];+    for (var i = 0; i < count; i++) {+      var five = i % 3 === 2;+      var sig = five ? pick(E96s) : pick(E24);+      var mExp = five ? rnd(5) : rnd(6);+      var mult = Math.pow(10, mExp);+      var tol = five ? 1 : pick([5, 10, 5, 1]);+      var ohms = sig * mult;+      var bands = bandsFor(sig, mult, tol);+      var roles = five ? ['1st digit', '2nd digit', '3rd digit', 'multiplier', 'tolerance'] : ['1st digit', '2nd digit', 'multiplier', 'tolerance'];+      out.push({+        deck: 'color',+        front: resistorSVG(bands) + '<div class="q">What is the value and tolerance?</div>',+        back: '<div class="a">' + fmt(ohms) + ' ±' + tol + '%</div>' + bandList(bands, roles) ++              '<div class="note">Acceptable range: ' + tolRange(ohms, tol) + '</div>'+      });+    }+    return out;+  }+  function reverseCards(count) {+    var out = [];+    for (var i = 0; i < count; i++) {+      var sig = pick(E12), mExp = rnd(6), mult = Math.pow(10, mExp), tol = pick([5, 10]);+      var ohms = sig * mult, bands = bandsFor(sig, mult, tol);+      out.push({+        deck: 'reverse',+        front: '<div class="big">' + fmt(ohms) + ' ±' + tol + '%</div><div class="q">Name the four color bands.</div>',+        back: resistorSVG(bands) + bandList(bands, ['1st digit', '2nd digit', 'multiplier', 'tolerance'])+      });+    }+    return out;+  }+  function digitCards() {+    var out = [];+    COLORS.slice(0, 10).forEach(function (c) {+      out.push({ deck: 'color',+        front: '<div class="bands"><span class="band" style="font-size:20px;padding:10px 18px"><i class="sw" style="width:22px;height:22px;background:' + c.hex + '"></i>' + c.n + '</span></div><div class="q">What digit is this band, and what multiplier?</div>',+        back: '<div class="a">Digit ' + c.d + ' · multiplier ×' + (c.m >= 1000 ? c.m.toLocaleString() : c.m) + '</div>' + (c.t ? '<div class="note">As a tolerance band: ±' + c.t + '%</div>' : '') });+    });+    out.push({ deck: 'color', front: '<div class="q">Gold as a multiplier band? As a tolerance band?</div>', back: '<div class="a">×0.1 · ±5%</div><div class="note">Silver is ×0.01 and ±10%. No tolerance band at all means ±20%.</div>' });+    out.push({ deck: 'color', front: '<div class="q">Mnemonic for Black through White?</div>', back: '<div class="a small">Better Be Right Or Your Great Big Venture Goes Wrong</div><div class="note">Black 0, Brown 1, Red 2, Orange 3, Yellow 4, Green 5, Blue 6, Violet 7, Gray 8, White 9</div>' });+    out.push({ deck: 'color', front: '<div class="q">Which end of the resistor do you read from?</div>', back: '<div class="a small">Tolerance band (gold or silver, or the band with the wider gap) goes on the RIGHT. Read left to right.</div>' });+    out.push({ deck: 'color', front: resistorSVG(['Black']) + '<div class="q">A resistor with a single black band?</div>', back: '<div class="a">0 Ω jumper</div><div class="note">Used as a configurable link on a PCB so the pick-and-place machine can place it like any other part.</div>' });+    out.push({ deck: 'color', front: '<div class="q">What does the sixth band on a 6-band resistor mean?</div>', back: '<div class="a small">Temperature coefficient (ppm/°C)</div><div class="note">Brown 100, Red 50, Orange 15, Yellow 25, Blue 10, Violet 5 ppm/°C</div>' });+    return out;+  }+  function smdCards() {+    var rows = [+      ['103', '10 kΩ', '3-digit: two digits then a power of ten. 10 × 10³'],+      ['472', '4.7 kΩ', '47 × 10²'],+      ['220', '22 Ω', '22 × 10⁰. Not 220 Ω, a common trap.'],+      ['221', '220 Ω', '22 × 10¹'],+      ['1R0', '1.0 Ω', 'R marks the decimal point'],+      ['4R7', '4.7 Ω', 'R marks the decimal point'],+      ['R47', '0.47 Ω', 'R marks the decimal point'],+      ['000', '0 Ω', 'Jumper'],+      ['1002', '10 kΩ', '4-digit (1% parts): three digits then a power of ten. 100 × 10²'],+      ['4701', '4.7 kΩ', '470 × 10¹'],+      ['3301', '3.3 kΩ', '330 × 10¹'],+      ['01C', '10 kΩ', 'EIA-96: code 01 = 100, letter C = ×100'],+      ['22A', '165 Ω', 'EIA-96: code 22 = 165, letter A = ×1'],+      ['01B', '1 kΩ', 'EIA-96: code 01 = 100, letter B = ×10']+    ];+    return rows.map(function (r) {+      return { deck: 'smd', front: '<div class="big">' + r[0] + '</div><div class="q">Value of this SMD marking?</div>', back: '<div class="a">' + r[1] + '</div><div class="note">' + esc(r[2]) + '</div>' };+    });+  }+  function formulaCards() {+    var rows = [+      ["Ohm's law", 'V = I·R, so I = V/R and R = V/I'],+      ['Power dissipated in a resistor', 'P = V·I = I²·R = V²/R'],+      ['Resistors in series', 'R<sub>total</sub> = R₁ + R₂ + … ; same current through each, voltages add'],+      ['Resistors in parallel', '1/R<sub>total</sub> = 1/R₁ + 1/R₂ + … ; same voltage across each, currents add'],+      ['Two resistors in parallel (product over sum)', 'R<sub>total</sub> = R₁·R₂ / (R₁ + R₂)'],+      ['N equal resistors R in parallel', 'R / N'],+      ['Voltage divider output', 'V<sub>out</sub> = V<sub>in</sub> · R₂ / (R₁ + R₂), with R₂ across the output'],+      ['Current divider (two branches)', 'I₁ = I<sub>total</sub> · R₂ / (R₁ + R₂). The current takes the smaller resistance more.'],+      ["Kirchhoff's voltage law", 'The sum of voltages around any closed loop is zero'],+      ["Kirchhoff's current law", 'The sum of currents entering a node equals the sum leaving it'],+      ['Wheatstone bridge balance condition', 'R₁/R₂ = R₃/R₄ (no current through the meter)'],+      ['Conductance', 'G = 1/R, measured in siemens (S). Parallel conductances add.'],+      ['Resistance of a wire', 'R = ρ·L / A (resistivity × length ÷ cross-section area)'],+      ['What does ±5% tolerance mean for 4.7 kΩ?', 'Actual value lies between 4.465 kΩ and 4.935 kΩ'],+      ['E12 series values', '10, 12, 15, 18, 22, 27, 33, 39, 47, 56, 68, 82 (each ~20% apart, made for ±10% parts)'],+      ['E24 series values', 'E12 plus 11, 13, 16, 20, 24, 30, 36, 43, 47…: 24 per decade, made for ±5% parts'],+      ['Why are standard values spaced logarithmically?', 'So adjacent values overlap at their tolerance and every resistance is covered with the fewest parts'],+      ['Typical power ratings', 'Through-hole: 1/8 W, 1/4 W, 1/2 W. SMD: 0402 ≈ 1/16 W, 0603 ≈ 1/10 W, 0805 ≈ 1/8 W, 1206 ≈ 1/4 W'],+      ['Derating', 'Above about 70 °C ambient the allowed power drops linearly toward zero at the max temperature. Run resistors at half their rating.'],+      ['Temperature coefficient, 100 ppm/°C', 'Resistance changes 0.01% per °C. A 10 kΩ part drifts 1 Ω per °C.'],+      ['Carbon film vs metal film', 'Carbon film: cheap, ±5%, noisier. Metal film: ±1% or better, low noise, low tempco. Default choice for signal work.'],+      ['Wirewound resistors', 'High power, very precise, but inductive: avoid in high-frequency paths'],+      ['Potentiometer vs rheostat', 'Potentiometer: three terminals, a variable voltage divider. Rheostat: two terminals, a variable resistance.'],+      ['Pull-up resistor', 'Ties a signal to V<sub>cc</sub> through a resistor (often 4.7 kΩ to 10 kΩ) so it reads high when nothing drives it'],+      ['LED current-limiting resistor', 'R = (V<sub>supply</sub> − V<sub>forward</sub>) / I<sub>LED</sub>'],+      ['Thermal noise (Johnson) of a resistor', 'v<sub>n</sub> = √(4·k·T·R·Δf). Bigger R means more noise.']+    ];+    return rows.map(function (r) { return { deck: 'formula', front: '<div class="q">' + r[0] + '</div>', back: '<div class="a small">' + r[1] + '</div>' }; });+  }+  function calcCards(count) {+    var out = [];+    for (var i = 0; i < count; i++) {+      var kind = i % 6, r1 = pick(E12) * Math.pow(10, 1 + rnd(3)), r2 = pick(E12) * Math.pow(10, 1 + rnd(3)), v = pick([3.3, 5, 9, 12, 24]);+      if (kind === 0) out.push({ deck: 'calc', front: '<div class="q">' + fmt(r1) + ' and ' + fmt(r2) + ' in series?</div>', back: '<div class="a">' + fmt(r1 + r2) + '</div><div class="note">Series resistances add.</div>' });+      else if (kind === 1) out.push({ deck: 'calc', front: '<div class="q">Two ' + fmt(r1) + ' resistors in parallel?</div>', back: '<div class="a">' + fmt(r1 / 2) + '</div><div class="note">Equal resistors in parallel: R / N.</div>' });+      else if (kind === 2) out.push({ deck: 'calc', front: '<div class="q">' + fmt(r1) + ' and ' + fmt(r2) + ' in parallel?</div>', back: '<div class="a">' + fmt(r1 * r2 / (r1 + r2)) + '</div><div class="note">Product over sum. The result is always smaller than the smaller resistor.</div>' });+      else if (kind === 3) out.push({ deck: 'calc', front: '<div class="q">Voltage divider: ' + v + ' V across ' + fmt(r1) + ' (top) and ' + fmt(r2) + ' (bottom). V<sub>out</sub> across the bottom?</div>', back: '<div class="a">' + (+(v * r2 / (r1 + r2)).toPrecision(3)) + ' V</div><div class="note">V<sub>out</sub> = V<sub>in</sub> · R₂ / (R₁ + R₂)</div>' });+      else if (kind === 4) { var iA = v / r1; out.push({ deck: 'calc', front: '<div class="q">' + v + ' V across ' + fmt(r1) + '. Current?</div>', back: '<div class="a">' + (iA >= 1e-3 ? +(iA * 1e3).toPrecision(3) + ' mA' : +(iA * 1e6).toPrecision(3) + ' µA') + '</div><div class="note">I = V / R</div>' }); }+      else { var p = v * v / r1; out.push({ deck: 'calc', front: '<div class="q">' + v + ' V across ' + fmt(r1) + '. Power dissipated? Is a 1/4 W part OK?</div>', back: '<div class="a">' + (p >= 1 ? +p.toPrecision(3) + ' W' : +(p * 1e3).toPrecision(3) + ' mW') + '</div><div class="note">P = V² / R. ' + (p <= 0.125 ? 'Yes, under half of 1/4 W.' : p <= 0.25 ? 'Marginal: within rating but over half of it.' : 'No, exceeds 1/4 W.') + '</div>' }); }+    }+    return out;+  }++  var DECKS = [+    { id: 'all', label: 'All' },+    { id: 'color', label: 'Color code' },+    { id: 'reverse', label: 'Value to bands' },+    { id: 'smd', label: 'SMD codes' },+    { id: 'formula', label: 'Formulas' },+    { id: 'calc', label: 'Calculations' }+  ];+  var ALL = [];+  function build() {+    ALL = shuffleArr(digitCards().concat(colorCards(18), reverseCards(12), smdCards(), formulaCards(), calcCards(18)));+  }++  // ---------- state ----------+  var deck = 'all', queue = [], idx = 0, flipped = false, done = 0, total = 0;+  var card = document.getElementById('card'), front = document.getElementById('front'), back = document.getElementById('back');+  var tagF = document.getElementById('tagF'), tagB = document.getElementById('tagB'), prog = document.getElementById('prog'), meter = document.getElementById('meter');+  function label(id) { return DECKS.filter(function (d) { return d.id === id; })[0].label; }++  function load() {+    queue = ALL.filter(function (c) { return deck === 'all' || c.deck === deck; });+    idx = 0; done = 0; total = queue.length; render();+  }+  function render() {+    flipped = false; card.classList.remove('flipped');+    if (!queue.length) {+      card.classList.add('done');+      front.innerHTML = '<div class="q">Deck complete. Shuffle to run it again.</div>'; back.innerHTML = '';+      tagF.textContent = label(deck); tagB.textContent = '';+    } else {+      card.classList.remove('done');+      var c = queue[idx];+      front.innerHTML = c.front; back.innerHTML = c.back;+      tagF.textContent = label(c.deck) + ' · ' + (idx + 1) + ' of ' + queue.length; tagB.textContent = tagF.textContent;+    }+    prog.textContent = done + ' of ' + total + ' marked "got it"' + (queue.length ? ', ' + queue.length + ' left in the queue' : '');+    meter.style.width = (total ? Math.round(done / total * 100) : 0) + '%';+    fit();+  }+  function flip() { if (!queue.length) return; flipped = !flipped; card.classList.toggle('flipped', flipped); }+  function next() { if (!queue.length) return; idx = (idx + 1) % queue.length; render(); }+  function prev() { if (!queue.length) return; idx = (idx - 1 + queue.length) % queue.length; render(); }+  function got() { if (!queue.length) return; queue.splice(idx, 1); done++; if (idx >= queue.length) idx = 0; render(); }+  function again() { if (queue.length < 2) { flipped = false; card.classList.remove('flipped'); return; } var c = queue.splice(idx, 1)[0]; queue.push(c); if (idx >= queue.length) idx = 0; render(); }+  function reshuffle() { build(); load(); }++  // ---------- UI wiring ----------+  var chips = document.getElementById('chips');+  DECKS.forEach(function (d) {+    var b = document.createElement('span'); b.className = 'chip' + (d.id === deck ? ' on' : ''); b.textContent = d.label;+    b.onclick = function () { deck = d.id; Array.prototype.forEach.call(chips.children, function (x) { x.classList.remove('on'); }); b.classList.add('on'); load(); };+    chips.appendChild(b);+  });+  card.onclick = flip;+  document.getElementById('flip').onclick = flip;+  document.getElementById('next').onclick = next;+  document.getElementById('prev').onclick = prev;+  document.getElementById('got').onclick = got;+  document.getElementById('again').onclick = again;+  document.getElementById('shuffle').onclick = reshuffle;+  document.addEventListener('keydown', function (e) {+    if (e.target && /input|textarea/i.test(e.target.tagName)) return;+    if (e.key === ' ') { e.preventDefault(); flip(); }+    else if (e.key === 'ArrowRight') next();+    else if (e.key === 'ArrowLeft') prev();+    else if (e.key === '1') again();+    else if (e.key === '2') got();+    else if (e.key === 's' || e.key === 'S') reshuffle();+  });++  // cheat sheet+  var cheat = document.getElementById('cheat');+  cheat.innerHTML = '<tr><th>Color</th><th>Digit</th><th>Multiplier</th><th>Tolerance</th></tr>' + COLORS.map(function (c) {+    return '<tr><td><span class="band"><i class="sw" style="background:' + c.hex + '"></i>' + c.n + '</span></td><td>' + (c.d === undefined ? '' : c.d) + '</td><td>×' + (c.m >= 1000 ? c.m.toLocaleString() : c.m) + '</td><td>' + (c.t ? '±' + c.t + '%' : '') + '</td></tr>';+  }).join('');++  // sandboxed-iframe height reporter+  function fit() { try { parent.postMessage({ type: 'readme-height', height: document.documentElement.scrollHeight }, '*'); } catch (e) {} }+  addEventListener('load', fit);+  if (window.ResizeObserver) new ResizeObserver(fit).observe(document.documentElement);++  build(); load();+})();+</script>+<script>document.querySelectorAll(".chip")[1].click();document.getElementById("card").style.transition="none";document.getElementById("flip").click();</script></body>+</html>
t_color.htmladded+358
@@ -0,0 +1,358 @@+<!doctype html>+<html lang="en">+<head>+<meta charset="utf-8">+<meta name="viewport" content="width=device-width, initial-scale=1">+<title>Resistor Flash Cards</title>+<style>+  :root {+    --bg: #0b0f14; --panel: #121821; --panel2: #18202b; --line: #243040;+    --text: #e6edf3; --muted: #93a1b3; --teal: #14b8a6; --blue: #3b82f6; --purple: #8b5cf6;+    --good: #22c55e; --bad: #f97316;+  }+  * { box-sizing: border-box; }+  html, body { margin: 0; background: var(--bg); color: var(--text);+    font: 15px/1.5 Inter, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; }+  .wrap { max-width: 880px; margin: 0 auto; padding: 20px 16px 28px; }+  h1 { font-size: 22px; margin: 0 0 4px; letter-spacing: -0.01em; }+  .sub { color: var(--muted); margin: 0 0 14px; font-size: 14px; }+  .chips { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px; }+  .chip { border: 1px solid var(--line); background: var(--panel); color: var(--muted); border-radius: 999px;+    padding: 6px 12px; cursor: pointer; font-size: 13px; user-select: none; }+  .chip.on { color: #fff; border-color: transparent;+    background: linear-gradient(90deg, var(--teal), var(--blue) 60%, var(--purple)); }+  .stage { perspective: 1400px; }+  .card { position: relative; min-height: 340px; cursor: pointer; transform-style: preserve-3d;+    transition: transform .45s cubic-bezier(.2,.8,.2,1); }+  .card.flipped { transform: rotateY(180deg); }+  .face { position: absolute; inset: 0; backface-visibility: hidden; -webkit-backface-visibility: hidden;+    background: var(--panel); border: 1px solid var(--line); border-radius: 16px; padding: 22px 24px;+    display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; gap: 12px; }+  .face.back { transform: rotateY(180deg); background: var(--panel2); }+  .tag { position: absolute; top: 14px; left: 18px; font-size: 12px; color: var(--muted); letter-spacing: .04em; text-transform: uppercase; }+  .hint { position: absolute; bottom: 12px; right: 18px; font-size: 12px; color: var(--muted); }+  .q { font-size: 20px; font-weight: 600; max-width: 640px; }+  .a { font-size: 26px; font-weight: 700; max-width: 640px; }+  .a.small { font-size: 18px; font-weight: 500; }+  .note { color: var(--muted); font-size: 14px; max-width: 640px; }+  .big { font-size: 40px; font-weight: 800; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; letter-spacing: .04em; }+  .mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }+  .bands { display: flex; gap: 6px; flex-wrap: wrap; justify-content: center; }+  .band { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; border-radius: 8px; background: #0f141b; border: 1px solid var(--line); font-size: 14px; }+  .sw { width: 14px; height: 14px; border-radius: 3px; border: 1px solid rgba(255,255,255,.15); }+  svg.res { width: 340px; max-width: 100%; height: auto; }+  .bar { display: flex; gap: 10px; align-items: center; margin-top: 14px; flex-wrap: wrap; }+  button { border: 1px solid var(--line); background: var(--panel); color: var(--text); border-radius: 10px;+    padding: 10px 16px; font-size: 14px; cursor: pointer; min-height: 44px; }+  button:hover { border-color: #3a4a60; }+  button.primary { background: linear-gradient(90deg, var(--teal), var(--blue)); border-color: transparent; color: #fff; font-weight: 600; }+  button.good { border-color: var(--good); color: var(--good); }+  button.bad { border-color: var(--bad); color: var(--bad); }+  .spacer { flex: 1; }+  .prog { color: var(--muted); font-size: 13px; }+  .meter { height: 6px; background: var(--panel); border: 1px solid var(--line); border-radius: 999px; overflow: hidden; margin-top: 10px; }+  .meter i { display: block; height: 100%; width: 0; background: linear-gradient(90deg, var(--teal), var(--blue), var(--purple)); transition: width .3s; }+  .keys { color: var(--muted); font-size: 12px; margin-top: 10px; }+  kbd { border: 1px solid var(--line); border-bottom-width: 2px; border-radius: 4px; padding: 0 5px; font-size: 11px; background: var(--panel); }+  details { margin-top: 20px; border: 1px solid var(--line); border-radius: 12px; background: var(--panel); padding: 10px 16px; }+  summary { cursor: pointer; font-weight: 600; }+  table { border-collapse: collapse; width: 100%; margin-top: 10px; font-size: 14px; }+  th, td { text-align: left; padding: 6px 8px; border-bottom: 1px solid var(--line); }+  th { color: var(--muted); font-weight: 500; }+  .done .q { color: var(--teal); }+</style>+</head>+<body>+<div class="wrap">+  <h1>Resistor Flash Cards</h1>+  <p class="sub">Color codes, SMD markings, formulas, and quick calculations. Click a card to flip it, then mark whether you got it.</p>++  <div class="chips" id="chips"></div>++  <div class="stage">+    <div class="card" id="card">+      <div class="face front"><span class="tag" id="tagF"></span><div id="front"></div><span class="hint">click or press space to flip</span></div>+      <div class="face back"><span class="tag" id="tagB"></span><div id="back"></div></div>+    </div>+  </div>++  <div class="bar">+    <button id="prev">Prev</button>+    <button id="flip" class="primary">Flip</button>+    <button id="next">Next</button>+    <span class="spacer"></span>+    <button id="again" class="bad">Again</button>+    <button id="got" class="good">Got it</button>+    <button id="shuffle">Shuffle</button>+  </div>+  <div class="meter"><i id="meter"></i></div>+  <div class="bar"><span class="prog" id="prog"></span></div>+  <div class="keys"><kbd>space</kbd> flip · <kbd>&larr;</kbd> <kbd>&rarr;</kbd> prev / next · <kbd>1</kbd> again · <kbd>2</kbd> got it · <kbd>s</kbd> shuffle</div>++  <details>+    <summary>Color code cheat sheet</summary>+    <table id="cheat"></table>+    <p class="note" style="margin-top:10px">Read with the tolerance band (gold, silver, or the band spaced farthest from the others) on the right. 4-band: digit, digit, multiplier, tolerance. 5-band: digit, digit, digit, multiplier, tolerance. 6-band adds a temperature coefficient band.</p>+  </details>+</div>++<script>+(function () {+  // ---------- reference data ----------+  var COLORS = [+    { n: 'Black',  hex: '#111111', d: 0, m: 1 },+    { n: 'Brown',  hex: '#8b4513', d: 1, m: 10,   t: 1 },+    { n: 'Red',    hex: '#e0201a', d: 2, m: 100,  t: 2 },+    { n: 'Orange', hex: '#f28c1a', d: 3, m: 1e3 },+    { n: 'Yellow', hex: '#f2d21a', d: 4, m: 1e4 },+    { n: 'Green',  hex: '#21a04b', d: 5, m: 1e5,  t: 0.5 },+    { n: 'Blue',   hex: '#2260d8', d: 6, m: 1e6,  t: 0.25 },+    { n: 'Violet', hex: '#8a3fd1', d: 7, m: 1e7,  t: 0.1 },+    { n: 'Gray',   hex: '#8f8f8f', d: 8, m: 1e8,  t: 0.05 },+    { n: 'White',  hex: '#f4f4f4', d: 9, m: 1e9 },+    { n: 'Gold',   hex: '#d4a017', m: 0.1,  t: 5 },+    { n: 'Silver', hex: '#c0c0c0', m: 0.01, t: 10 }+  ];+  var BY = {}; COLORS.forEach(function (c) { BY[c.n] = c; });+  var E12 = [10, 12, 15, 18, 22, 27, 33, 39, 47, 56, 68, 82];+  var E24 = [10, 11, 12, 13, 15, 16, 18, 20, 22, 24, 27, 30, 33, 36, 39, 43, 47, 51, 56, 62, 68, 75, 82, 91];+  var E96s = [100, 121, 150, 182, 221, 249, 274, 332, 402, 475, 549, 681, 825, 976];++  function fmt(ohms) {+    var u = 'Ω', v = ohms;+    if (ohms >= 1e6) { v = ohms / 1e6; u = 'MΩ'; }+    else if (ohms >= 1e3) { v = ohms / 1e3; u = 'kΩ'; }+    v = +v.toPrecision(3);+    return v + ' ' + u;+  }+  function esc(s) { return String(s).replace(/[&<>]/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;' }[c]; }); }+  function rnd(n) { return Math.floor(Math.random() * n); }+  function pick(a) { return a[rnd(a.length)]; }+  function shuffleArr(a) { for (var i = a.length - 1; i > 0; i--) { var j = rnd(i + 1); var t = a[i]; a[i] = a[j]; a[j] = t; } return a; }++  // ---------- resistor drawing ----------+  function resistorSVG(bandColors) {+    var n = bandColors.length;+    var xs = n === 4 ? [92, 116, 140, 196] : n === 5 ? [84, 106, 128, 150, 200] : [80, 100, 120, 140, 160, 205];+    var s = '<svg class="res" viewBox="0 0 340 90" xmlns="http://www.w3.org/2000/svg">';+    s += '<line x1="10" y1="45" x2="330" y2="45" stroke="#b8c0cc" stroke-width="5" stroke-linecap="round"/>';+    s += '<rect x="60" y="18" width="220" height="54" rx="22" fill="#d9c9a3" stroke="#6b5b3a" stroke-width="2"/>';+    s += '<rect x="66" y="22" width="208" height="14" rx="10" fill="rgba(255,255,255,.28)"/>';+    bandColors.forEach(function (c, i) {+      s += '<rect x="' + xs[i] + '" y="19" width="14" height="52" rx="2" fill="' + BY[c].hex + '" stroke="rgba(0,0,0,.25)"/>';+    });+    return s + '</svg>';+  }+  function bandList(names, roles) {+    return '<div class="bands">' + names.map(function (n, i) {+      return '<span class="band"><i class="sw" style="background:' + BY[n].hex + '"></i>' + n + (roles ? ' <span class="note">' + roles[i] + '</span>' : '') + '</span>';+    }).join('') + '</div>';+  }+  function bandsFor(sig, mult, tol) {+    var digits = String(sig).split('').map(function (d) { return COLORS[+d].n; });+    var mName = COLORS.filter(function (c) { return c.m === mult; })[0].n;+    var tName = COLORS.filter(function (c) { return c.t === tol; })[0].n;+    return digits.concat([mName, tName]);+  }+  function tolRange(ohms, tol) { return fmt(ohms * (1 - tol / 100)) + ' to ' + fmt(ohms * (1 + tol / 100)); }++  // ---------- generated decks ----------+  function colorCards(count) {+    var out = [];+    for (var i = 0; i < count; i++) {+      var five = i % 3 === 2;+      var sig = five ? pick(E96s) : pick(E24);+      var mExp = five ? rnd(5) : rnd(6);+      var mult = Math.pow(10, mExp);+      var tol = five ? 1 : pick([5, 10, 5, 1]);+      var ohms = sig * mult;+      var bands = bandsFor(sig, mult, tol);+      var roles = five ? ['1st digit', '2nd digit', '3rd digit', 'multiplier', 'tolerance'] : ['1st digit', '2nd digit', 'multiplier', 'tolerance'];+      out.push({+        deck: 'color',+        front: resistorSVG(bands) + '<div class="q">What is the value and tolerance?</div>',+        back: '<div class="a">' + fmt(ohms) + ' ±' + tol + '%</div>' + bandList(bands, roles) ++              '<div class="note">Acceptable range: ' + tolRange(ohms, tol) + '</div>'+      });+    }+    return out;+  }+  function reverseCards(count) {+    var out = [];+    for (var i = 0; i < count; i++) {+      var sig = pick(E12), mExp = rnd(6), mult = Math.pow(10, mExp), tol = pick([5, 10]);+      var ohms = sig * mult, bands = bandsFor(sig, mult, tol);+      out.push({+        deck: 'reverse',+        front: '<div class="big">' + fmt(ohms) + ' ±' + tol + '%</div><div class="q">Name the four color bands.</div>',+        back: resistorSVG(bands) + bandList(bands, ['1st digit', '2nd digit', 'multiplier', 'tolerance'])+      });+    }+    return out;+  }+  function digitCards() {+    var out = [];+    COLORS.slice(0, 10).forEach(function (c) {+      out.push({ deck: 'color',+        front: '<div class="bands"><span class="band" style="font-size:20px;padding:10px 18px"><i class="sw" style="width:22px;height:22px;background:' + c.hex + '"></i>' + c.n + '</span></div><div class="q">What digit is this band, and what multiplier?</div>',+        back: '<div class="a">Digit ' + c.d + ' · multiplier ×' + (c.m >= 1000 ? c.m.toLocaleString() : c.m) + '</div>' + (c.t ? '<div class="note">As a tolerance band: ±' + c.t + '%</div>' : '') });+    });+    out.push({ deck: 'color', front: '<div class="q">Gold as a multiplier band? As a tolerance band?</div>', back: '<div class="a">×0.1 · ±5%</div><div class="note">Silver is ×0.01 and ±10%. No tolerance band at all means ±20%.</div>' });+    out.push({ deck: 'color', front: '<div class="q">Mnemonic for Black through White?</div>', back: '<div class="a small">Better Be Right Or Your Great Big Venture Goes Wrong</div><div class="note">Black 0, Brown 1, Red 2, Orange 3, Yellow 4, Green 5, Blue 6, Violet 7, Gray 8, White 9</div>' });+    out.push({ deck: 'color', front: '<div class="q">Which end of the resistor do you read from?</div>', back: '<div class="a small">Tolerance band (gold or silver, or the band with the wider gap) goes on the RIGHT. Read left to right.</div>' });+    out.push({ deck: 'color', front: resistorSVG(['Black']) + '<div class="q">A resistor with a single black band?</div>', back: '<div class="a">0 Ω jumper</div><div class="note">Used as a configurable link on a PCB so the pick-and-place machine can place it like any other part.</div>' });+    out.push({ deck: 'color', front: '<div class="q">What does the sixth band on a 6-band resistor mean?</div>', back: '<div class="a small">Temperature coefficient (ppm/°C)</div><div class="note">Brown 100, Red 50, Orange 15, Yellow 25, Blue 10, Violet 5 ppm/°C</div>' });+    return out;+  }+  function smdCards() {+    var rows = [+      ['103', '10 kΩ', '3-digit: two digits then a power of ten. 10 × 10³'],+      ['472', '4.7 kΩ', '47 × 10²'],+      ['220', '22 Ω', '22 × 10⁰. Not 220 Ω, a common trap.'],+      ['221', '220 Ω', '22 × 10¹'],+      ['1R0', '1.0 Ω', 'R marks the decimal point'],+      ['4R7', '4.7 Ω', 'R marks the decimal point'],+      ['R47', '0.47 Ω', 'R marks the decimal point'],+      ['000', '0 Ω', 'Jumper'],+      ['1002', '10 kΩ', '4-digit (1% parts): three digits then a power of ten. 100 × 10²'],+      ['4701', '4.7 kΩ', '470 × 10¹'],+      ['3301', '3.3 kΩ', '330 × 10¹'],+      ['01C', '10 kΩ', 'EIA-96: code 01 = 100, letter C = ×100'],+      ['22A', '165 Ω', 'EIA-96: code 22 = 165, letter A = ×1'],+      ['01B', '1 kΩ', 'EIA-96: code 01 = 100, letter B = ×10']+    ];+    return rows.map(function (r) {+      return { deck: 'smd', front: '<div class="big">' + r[0] + '</div><div class="q">Value of this SMD marking?</div>', back: '<div class="a">' + r[1] + '</div><div class="note">' + esc(r[2]) + '</div>' };+    });+  }+  function formulaCards() {+    var rows = [+      ["Ohm's law", 'V = I·R, so I = V/R and R = V/I'],+      ['Power dissipated in a resistor', 'P = V·I = I²·R = V²/R'],+      ['Resistors in series', 'R<sub>total</sub> = R₁ + R₂ + … ; same current through each, voltages add'],+      ['Resistors in parallel', '1/R<sub>total</sub> = 1/R₁ + 1/R₂ + … ; same voltage across each, currents add'],+      ['Two resistors in parallel (product over sum)', 'R<sub>total</sub> = R₁·R₂ / (R₁ + R₂)'],+      ['N equal resistors R in parallel', 'R / N'],+      ['Voltage divider output', 'V<sub>out</sub> = V<sub>in</sub> · R₂ / (R₁ + R₂), with R₂ across the output'],+      ['Current divider (two branches)', 'I₁ = I<sub>total</sub> · R₂ / (R₁ + R₂). The current takes the smaller resistance more.'],+      ["Kirchhoff's voltage law", 'The sum of voltages around any closed loop is zero'],+      ["Kirchhoff's current law", 'The sum of currents entering a node equals the sum leaving it'],+      ['Wheatstone bridge balance condition', 'R₁/R₂ = R₃/R₄ (no current through the meter)'],+      ['Conductance', 'G = 1/R, measured in siemens (S). Parallel conductances add.'],+      ['Resistance of a wire', 'R = ρ·L / A (resistivity × length ÷ cross-section area)'],+      ['What does ±5% tolerance mean for 4.7 kΩ?', 'Actual value lies between 4.465 kΩ and 4.935 kΩ'],+      ['E12 series values', '10, 12, 15, 18, 22, 27, 33, 39, 47, 56, 68, 82 (each ~20% apart, made for ±10% parts)'],+      ['E24 series values', 'E12 plus 11, 13, 16, 20, 24, 30, 36, 43, 47…: 24 per decade, made for ±5% parts'],+      ['Why are standard values spaced logarithmically?', 'So adjacent values overlap at their tolerance and every resistance is covered with the fewest parts'],+      ['Typical power ratings', 'Through-hole: 1/8 W, 1/4 W, 1/2 W. SMD: 0402 ≈ 1/16 W, 0603 ≈ 1/10 W, 0805 ≈ 1/8 W, 1206 ≈ 1/4 W'],+      ['Derating', 'Above about 70 °C ambient the allowed power drops linearly toward zero at the max temperature. Run resistors at half their rating.'],+      ['Temperature coefficient, 100 ppm/°C', 'Resistance changes 0.01% per °C. A 10 kΩ part drifts 1 Ω per °C.'],+      ['Carbon film vs metal film', 'Carbon film: cheap, ±5%, noisier. Metal film: ±1% or better, low noise, low tempco. Default choice for signal work.'],+      ['Wirewound resistors', 'High power, very precise, but inductive: avoid in high-frequency paths'],+      ['Potentiometer vs rheostat', 'Potentiometer: three terminals, a variable voltage divider. Rheostat: two terminals, a variable resistance.'],+      ['Pull-up resistor', 'Ties a signal to V<sub>cc</sub> through a resistor (often 4.7 kΩ to 10 kΩ) so it reads high when nothing drives it'],+      ['LED current-limiting resistor', 'R = (V<sub>supply</sub> − V<sub>forward</sub>) / I<sub>LED</sub>'],+      ['Thermal noise (Johnson) of a resistor', 'v<sub>n</sub> = √(4·k·T·R·Δf). Bigger R means more noise.']+    ];+    return rows.map(function (r) { return { deck: 'formula', front: '<div class="q">' + r[0] + '</div>', back: '<div class="a small">' + r[1] + '</div>' }; });+  }+  function calcCards(count) {+    var out = [];+    for (var i = 0; i < count; i++) {+      var kind = i % 6, r1 = pick(E12) * Math.pow(10, 1 + rnd(3)), r2 = pick(E12) * Math.pow(10, 1 + rnd(3)), v = pick([3.3, 5, 9, 12, 24]);+      if (kind === 0) out.push({ deck: 'calc', front: '<div class="q">' + fmt(r1) + ' and ' + fmt(r2) + ' in series?</div>', back: '<div class="a">' + fmt(r1 + r2) + '</div><div class="note">Series resistances add.</div>' });+      else if (kind === 1) out.push({ deck: 'calc', front: '<div class="q">Two ' + fmt(r1) + ' resistors in parallel?</div>', back: '<div class="a">' + fmt(r1 / 2) + '</div><div class="note">Equal resistors in parallel: R / N.</div>' });+      else if (kind === 2) out.push({ deck: 'calc', front: '<div class="q">' + fmt(r1) + ' and ' + fmt(r2) + ' in parallel?</div>', back: '<div class="a">' + fmt(r1 * r2 / (r1 + r2)) + '</div><div class="note">Product over sum. The result is always smaller than the smaller resistor.</div>' });+      else if (kind === 3) out.push({ deck: 'calc', front: '<div class="q">Voltage divider: ' + v + ' V across ' + fmt(r1) + ' (top) and ' + fmt(r2) + ' (bottom). V<sub>out</sub> across the bottom?</div>', back: '<div class="a">' + (+(v * r2 / (r1 + r2)).toPrecision(3)) + ' V</div><div class="note">V<sub>out</sub> = V<sub>in</sub> · R₂ / (R₁ + R₂)</div>' });+      else if (kind === 4) { var iA = v / r1; out.push({ deck: 'calc', front: '<div class="q">' + v + ' V across ' + fmt(r1) + '. Current?</div>', back: '<div class="a">' + (iA >= 1e-3 ? +(iA * 1e3).toPrecision(3) + ' mA' : +(iA * 1e6).toPrecision(3) + ' µA') + '</div><div class="note">I = V / R</div>' }); }+      else { var p = v * v / r1; out.push({ deck: 'calc', front: '<div class="q">' + v + ' V across ' + fmt(r1) + '. Power dissipated? Is a 1/4 W part OK?</div>', back: '<div class="a">' + (p >= 1 ? +p.toPrecision(3) + ' W' : +(p * 1e3).toPrecision(3) + ' mW') + '</div><div class="note">P = V² / R. ' + (p <= 0.125 ? 'Yes, under half of 1/4 W.' : p <= 0.25 ? 'Marginal: within rating but over half of it.' : 'No, exceeds 1/4 W.') + '</div>' }); }+    }+    return out;+  }++  var DECKS = [+    { id: 'all', label: 'All' },+    { id: 'color', label: 'Color code' },+    { id: 'reverse', label: 'Value to bands' },+    { id: 'smd', label: 'SMD codes' },+    { id: 'formula', label: 'Formulas' },+    { id: 'calc', label: 'Calculations' }+  ];+  var ALL = [];+  function build() {+    ALL = shuffleArr(digitCards().concat(colorCards(18), reverseCards(12), smdCards(), formulaCards(), calcCards(18)));+  }++  // ---------- state ----------+  var deck = 'all', queue = [], idx = 0, flipped = false, done = 0, total = 0;+  var card = document.getElementById('card'), front = document.getElementById('front'), back = document.getElementById('back');+  var tagF = document.getElementById('tagF'), tagB = document.getElementById('tagB'), prog = document.getElementById('prog'), meter = document.getElementById('meter');+  function label(id) { return DECKS.filter(function (d) { return d.id === id; })[0].label; }++  function load() {+    queue = ALL.filter(function (c) { return deck === 'all' || c.deck === deck; });+    idx = 0; done = 0; total = queue.length; render();+  }+  function render() {+    flipped = false; card.classList.remove('flipped');+    if (!queue.length) {+      card.classList.add('done');+      front.innerHTML = '<div class="q">Deck complete. Shuffle to run it again.</div>'; back.innerHTML = '';+      tagF.textContent = label(deck); tagB.textContent = '';+    } else {+      card.classList.remove('done');+      var c = queue[idx];+      front.innerHTML = c.front; back.innerHTML = c.back;+      tagF.textContent = label(c.deck) + ' · ' + (idx + 1) + ' of ' + queue.length; tagB.textContent = tagF.textContent;+    }+    prog.textContent = done + ' of ' + total + ' marked "got it"' + (queue.length ? ', ' + queue.length + ' left in the queue' : '');+    meter.style.width = (total ? Math.round(done / total * 100) : 0) + '%';+    fit();+  }+  function flip() { if (!queue.length) return; flipped = !flipped; card.classList.toggle('flipped', flipped); }+  function next() { if (!queue.length) return; idx = (idx + 1) % queue.length; render(); }+  function prev() { if (!queue.length) return; idx = (idx - 1 + queue.length) % queue.length; render(); }+  function got() { if (!queue.length) return; queue.splice(idx, 1); done++; if (idx >= queue.length) idx = 0; render(); }+  function again() { if (queue.length < 2) { flipped = false; card.classList.remove('flipped'); return; } var c = queue.splice(idx, 1)[0]; queue.push(c); if (idx >= queue.length) idx = 0; render(); }+  function reshuffle() { build(); load(); }++  // ---------- UI wiring ----------+  var chips = document.getElementById('chips');+  DECKS.forEach(function (d) {+    var b = document.createElement('span'); b.className = 'chip' + (d.id === deck ? ' on' : ''); b.textContent = d.label;+    b.onclick = function () { deck = d.id; Array.prototype.forEach.call(chips.children, function (x) { x.classList.remove('on'); }); b.classList.add('on'); load(); };+    chips.appendChild(b);+  });+  card.onclick = flip;+  document.getElementById('flip').onclick = flip;+  document.getElementById('next').onclick = next;+  document.getElementById('prev').onclick = prev;+  document.getElementById('got').onclick = got;+  document.getElementById('again').onclick = again;+  document.getElementById('shuffle').onclick = reshuffle;+  document.addEventListener('keydown', function (e) {+    if (e.target && /input|textarea/i.test(e.target.tagName)) return;+    if (e.key === ' ') { e.preventDefault(); flip(); }+    else if (e.key === 'ArrowRight') next();+    else if (e.key === 'ArrowLeft') prev();+    else if (e.key === '1') again();+    else if (e.key === '2') got();+    else if (e.key === 's' || e.key === 'S') reshuffle();+  });++  // cheat sheet+  var cheat = document.getElementById('cheat');+  cheat.innerHTML = '<tr><th>Color</th><th>Digit</th><th>Multiplier</th><th>Tolerance</th></tr>' + COLORS.map(function (c) {+    return '<tr><td><span class="band"><i class="sw" style="background:' + c.hex + '"></i>' + c.n + '</span></td><td>' + (c.d === undefined ? '' : c.d) + '</td><td>×' + (c.m >= 1000 ? c.m.toLocaleString() : c.m) + '</td><td>' + (c.t ? '±' + c.t + '%' : '') + '</td></tr>';+  }).join('');++  // sandboxed-iframe height reporter+  function fit() { try { parent.postMessage({ type: 'readme-height', height: document.documentElement.scrollHeight }, '*'); } catch (e) {} }+  addEventListener('load', fit);+  if (window.ResizeObserver) new ResizeObserver(fit).observe(document.documentElement);++  build(); load();+})();+</script>+<script>document.querySelectorAll(".chip")[1].click();</script></body>+</html>
uninstall.sh