This commit is contained in:
Ballance 2026-08-24 14:09:36 -04:00
commit 8e27665e21
11 changed files with 2247 additions and 0 deletions

Binary file not shown.

141
ext-zone.html Normal file
View file

@ -0,0 +1,141 @@
<title>EXT Zone, Transistor & Collector Node</title>
<style>
:root{ --bg:#faf8f4;--ink:#1c1a17;--muted:#6b6459;--card:#fff;--line:#3a352e;
--red:#c0392b;--grn:#2e7d32;--slate:#5b6b7a;--amber:#c98a1a;--rule:#d8d2c7; }
@media (prefers-color-scheme:dark){:root{--bg:#17150f;--ink:#eee7d9;--muted:#a49a88;
--card:#211e17;--line:#c9c2b4;--red:#e5675a;--grn:#6bbf70;--slate:#8fa3b5;--amber:#e0b24e;--rule:#3a352b;}}
:root[data-theme=light]{--bg:#faf8f4;--ink:#1c1a17;--muted:#6b6459;--card:#fff;--line:#3a352e;
--red:#c0392b;--grn:#2e7d32;--slate:#5b6b7a;--amber:#c98a1a;--rule:#d8d2c7;}
:root[data-theme=dark]{--bg:#17150f;--ink:#eee7d9;--muted:#a49a88;--card:#211e17;--line:#c9c2b4;
--red:#e5675a;--grn:#6bbf70;--slate:#8fa3b5;--amber:#e0b24e;--rule:#3a352b;}
body{background:var(--bg);color:var(--ink);
font:15px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;margin:0;padding:24px;}
.wrap{max-width:900px;margin:0 auto;}
h1{font-size:20px;margin:0 0 2px;} .sub{color:var(--muted);margin:0 0 18px;font-size:13px;}
.card{background:var(--card);border:1px solid var(--rule);border-radius:12px;padding:16px;margin-bottom:18px;}
.scroll{overflow-x:auto;}
svg{display:block;margin:0 auto;max-width:100%;height:auto;}
text{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;fill:var(--ink);}
.lbl{font-size:13px;} .sm{font-size:11px;fill:var(--muted);} .big{font-size:14px;font-weight:bold;}
.w5{stroke:var(--red);stroke-width:3;fill:none;}
.wg{stroke:var(--line);stroke-width:3.4;fill:none;}
.wire{stroke:var(--line);stroke-width:2.2;fill:none;}
.wsig{stroke:var(--slate);stroke-width:2.4;fill:none;stroke-dasharray:6 4;}
.node{fill:var(--line);} .chip{fill:var(--card);stroke:var(--line);stroke-width:2;}
.key{display:flex;gap:18px;flex-wrap:wrap;font-size:12px;color:var(--muted);margin-top:10px;}
.key span{display:inline-flex;align-items:center;gap:6px;} .sw{width:22px;height:0;border-top:3px solid;}
ul{margin:6px 0 0;padding-left:18px;font-size:14px;} li{margin:3px 0;}
code{font-family:ui-monospace,Menlo,monospace;background:rgba(128,128,128,.12);padding:1px 5px;border-radius:4px;font-size:.92em;}
</style>
<div class="wrap">
<h1>EXT zone, the transistor & the collector node</h1>
<p class="sub">5 exterior LEDs in parallel · one PN2222 switches them all · D6</p>
<div class="card scroll">
<svg viewBox="0 0 820 470" role="img" aria-label="EXT zone: five parallel LEDs meeting at the transistor collector">
<!-- +5V rail -->
<line class="w5" x1="60" y1="45" x2="640" y2="45"/>
<text class="lbl" x="60" y="35" fill="var(--red)">+5V rail</text>
<!-- GND rail -->
<line class="wg" x1="60" y1="430" x2="760" y2="430"/>
<text class="lbl" x="60" y="452">GND rail</text>
<!-- 5 LED branches -->
<!-- each branch: vertical from +5V, LED, 220, down to collector bus at y=300 -->
<!-- collector bus -->
<line class="wire" x1="120" y1="300" x2="560" y2="300"/>
<text class="big" x="120" y="290" fill="var(--slate)">collector node</text>
<text class="sm" x="120" y="322">(where all 5 branches meet the transistor)</text>
<!-- branch generator: xs 140,240,340,440,540 -->
<!-- branch 1 -->
<g>
<line class="w5" x1="140" y1="45" x2="140" y2="80"/><circle class="node" cx="140" cy="45" r="3.2"/>
<polygon points="128,80 152,80 140,104" fill="none" stroke="var(--amber)" stroke-width="2"/>
<line x1="128" y1="104" x2="152" y2="104" stroke="var(--amber)" stroke-width="2.5"/>
<line class="wire" x1="140" y1="104" x2="140" y2="130"/>
<rect class="chip" x="122" y="130" width="36" height="46" rx="4"/><text class="sm" x="126" y="157">220</text>
<line class="wire" x1="140" y1="176" x2="140" y2="300"/><circle class="node" cx="140" cy="300" r="3.2"/>
<text class="sm" x="112" y="196">porch A</text>
</g>
<!-- branch 2 -->
<g>
<line class="w5" x1="240" y1="45" x2="240" y2="80"/><circle class="node" cx="240" cy="45" r="3.2"/>
<polygon points="228,80 252,80 240,104" fill="none" stroke="var(--amber)" stroke-width="2"/>
<line x1="228" y1="104" x2="252" y2="104" stroke="var(--amber)" stroke-width="2.5"/>
<line class="wire" x1="240" y1="104" x2="240" y2="130"/>
<rect class="chip" x="222" y="130" width="36" height="46" rx="4"/><text class="sm" x="226" y="157">220</text>
<line class="wire" x1="240" y1="176" x2="240" y2="300"/><circle class="node" cx="240" cy="300" r="3.2"/>
<text class="sm" x="212" y="196">porch B</text>
</g>
<!-- branch 3 -->
<g>
<line class="w5" x1="340" y1="45" x2="340" y2="80"/><circle class="node" cx="340" cy="45" r="3.2"/>
<polygon points="328,80 352,80 340,104" fill="none" stroke="var(--amber)" stroke-width="2"/>
<line x1="328" y1="104" x2="352" y2="104" stroke="var(--amber)" stroke-width="2.5"/>
<line class="wire" x1="340" y1="104" x2="340" y2="130"/>
<rect class="chip" x="322" y="130" width="36" height="46" rx="4"/><text class="sm" x="326" y="157">220</text>
<line class="wire" x1="340" y1="176" x2="340" y2="300"/><circle class="node" cx="340" cy="300" r="3.2"/>
<text class="sm" x="318" y="196">entry</text>
</g>
<!-- branch 4 -->
<g>
<line class="w5" x1="440" y1="45" x2="440" y2="80"/><circle class="node" cx="440" cy="45" r="3.2"/>
<polygon points="428,80 452,80 440,104" fill="none" stroke="var(--amber)" stroke-width="2"/>
<line x1="428" y1="104" x2="452" y2="104" stroke="var(--amber)" stroke-width="2.5"/>
<line class="wire" x1="440" y1="104" x2="440" y2="130"/>
<rect class="chip" x="422" y="130" width="36" height="46" rx="4"/><text class="sm" x="426" y="157">220</text>
<line class="wire" x1="440" y1="176" x2="440" y2="300"/><circle class="node" cx="440" cy="300" r="3.2"/>
<text class="sm" x="420" y="196">deck</text>
</g>
<!-- branch 5 -->
<g>
<line class="w5" x1="540" y1="45" x2="540" y2="80"/><circle class="node" cx="540" cy="45" r="3.2"/>
<polygon points="528,80 552,80 540,104" fill="none" stroke="var(--amber)" stroke-width="2"/>
<line x1="528" y1="104" x2="552" y2="104" stroke="var(--amber)" stroke-width="2.5"/>
<line class="wire" x1="540" y1="104" x2="540" y2="130"/>
<rect class="chip" x="522" y="130" width="36" height="46" rx="4"/><text class="sm" x="526" y="157">220</text>
<line class="wire" x1="540" y1="176" x2="540" y2="300"/><circle class="node" cx="540" cy="300" r="3.2"/>
<text class="sm" x="512" y="196">balcony</text>
</g>
<!-- transistor at right of collector bus -->
<line class="wire" x1="560" y1="300" x2="640" y2="300"/>
<line class="wire" x1="640" y1="300" x2="640" y2="326"/>
<circle class="chip" cx="640" cy="360" r="34"/>
<text class="lbl" x="618" y="365">Q3</text>
<text class="sm" x="600" y="410">PN2222</text>
<!-- collector top -->
<text class="sm" x="648" y="332">C (collector)</text>
<!-- emitter bottom -->
<line class="wg" x1="640" y1="394" x2="640" y2="430"/>
<circle class="node" cx="640" cy="430" r="3.2"/>
<text class="sm" x="648" y="418">E → GND</text>
<!-- base from D6 -->
<line class="wsig" x1="740" y1="360" x2="674" y2="360"/>
<text class="sm" x="648" y="352">B</text>
<rect class="chip" x="740" y="350" width="46" height="20" rx="4"/><text class="sm" x="745" y="364">1kΩ</text>
<line class="wsig" x1="786" y1="360" x2="806" y2="360"/>
<text class="sm" x="720" y="392">D6 (PWM) ──► base</text>
<text class="sm" x="60" y="65">current: +5V → each LED → its 220Ω → collector node → (Q3) → emitter → GND</text>
</svg>
<div class="key">
<span><span class="sw" style="border-color:var(--red)"></span>+5V</span>
<span><span class="sw" style="border-color:var(--line)"></span>wire / GND</span>
<span><span class="sw" style="border-color:var(--slate);border-top-style:dashed"></span>D6 signal</span>
<span><span class="sw" style="border-color:var(--amber)"></span>LED</span>
</div>
</div>
<div class="card">
<strong>The three transistor legs</strong>
<ul>
<li><code>C</code> collector, current comes <em>in</em> from the 5 LEDs (the "collector node")</li>
<li><code>B</code> base, the control leg; <code>D6</code> flips it on/off through the 1kΩ</li>
<li><code>E</code> emitter, current goes <em>out</em> to GND</li>
</ul>
<p class="sm" style="margin:8px 0 0">D6 high → base opens the valve → all 5 LEDs drain through C→E to ground → they light.
Leg order on the part (flat face toward you): <code>E · B · C</code>, left→right, collector is the right leg.</p>
</div>
</div>

331
full-wiring.html Normal file
View file

@ -0,0 +1,331 @@
<title>House Lighting, Full Wiring (transistor build)</title>
<style>
:root{ --bg:#faf8f4;--ink:#1c1a17;--muted:#6b6459;--card:#fff;--line:#3a352e;
--red:#c0392b;--grn:#2e7d32;--slate:#5b6b7a;--amber:#c98a1a;--rule:#d8d2c7; }
@media (prefers-color-scheme:dark){:root{--bg:#17150f;--ink:#eee7d9;--muted:#a49a88;
--card:#211e17;--line:#c9c2b4;--red:#e5675a;--grn:#6bbf70;--slate:#8fa3b5;--amber:#e0b24e;--rule:#3a352b;}}
:root[data-theme=light]{--bg:#faf8f4;--ink:#1c1a17;--muted:#6b6459;--card:#fff;--line:#3a352e;
--red:#c0392b;--grn:#2e7d32;--slate:#5b6b7a;--amber:#c98a1a;--rule:#d8d2c7;}
:root[data-theme=dark]{--bg:#17150f;--ink:#eee7d9;--muted:#a49a88;--card:#211e17;--line:#c9c2b4;
--red:#e5675a;--grn:#6bbf70;--slate:#8fa3b5;--amber:#e0b24e;--rule:#3a352b;}
body{background:var(--bg);color:var(--ink);
font:15px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;margin:0;padding:24px;}
.wrap{max-width:1000px;margin:0 auto;}
h1{font-size:20px;margin:0 0 2px;} .sub{color:var(--muted);margin:0 0 18px;font-size:13px;}
.card{background:var(--card);border:1px solid var(--rule);border-radius:12px;padding:16px;margin-bottom:18px;}
.scroll{overflow-x:auto;}
svg{display:block;margin:0 auto;max-width:100%;height:auto;min-width:820px;}
text{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;fill:var(--ink);}
.lbl{font-size:12.5px;} .sm{font-size:10.5px;fill:var(--muted);} .zn{font-size:13px;font-weight:bold;}
.w5{stroke:var(--red);stroke-width:3;fill:none;}
.wg{stroke:var(--line);stroke-width:3.4;fill:none;}
.wire{stroke:var(--line);stroke-width:2;fill:none;}
.wsig{stroke:var(--slate);stroke-width:2;fill:none;stroke-dasharray:5 4;}
.node{fill:var(--line);} .chip{fill:var(--card);stroke:var(--line);stroke-width:2;}
table{border-collapse:collapse;width:100%;font-size:13px;margin-top:4px;}
th,td{border:1px solid var(--rule);padding:6px 9px;text-align:left;} th{background:rgba(128,128,128,.08);}
code{font-family:ui-monospace,Menlo,monospace;background:rgba(128,128,128,.12);padding:1px 5px;border-radius:4px;font-size:.9em;}
.key{display:flex;gap:16px;flex-wrap:wrap;font-size:12px;color:var(--muted);margin-top:10px;}
.key span{display:inline-flex;align-items:center;gap:6px;} .sw{width:20px;height:0;border-top:3px solid;}
ul{margin:6px 0 0;padding-left:18px;font-size:13.5px;} li{margin:2px 0;}
</style>
<div class="wrap">
<h1>House Lighting, full wiring (transistor build)</h1>
<p class="sub">4 zones · PN2222 low-side switch per zone · Arduino Uno R3 · 5V USB · <code>townhouse_lights.ino</code></p>
<div class="card scroll">
<svg viewBox="0 0 1000 640" role="img" aria-label="Full system wiring diagram">
<!-- ===== RAILS ===== -->
<line class="w5" x1="60" y1="70" x2="980" y2="70"/>
<text class="lbl" x="300" y="62" fill="var(--red)">+5V rail</text>
<line class="wg" x1="60" y1="590" x2="980" y2="590"/>
<text class="lbl" x="300" y="608">GND rail</text>
<!-- ===== POWER INPUT (top-left) ===== -->
<rect class="chip" x="40" y="120" width="96" height="30" rx="4"/>
<text class="sm" x="48" y="139">USB bank 5V</text>
<rect class="chip" x="40" y="162" width="96" height="26" rx="4"/>
<text class="sm" x="46" y="179">USB (bench)</text>
<!-- master switch on bank +line -->
<line class="w5" x1="136" y1="132" x2="160" y2="132"/>
<circle class="node" cx="160" cy="132" r="3"/><line class="w5" x1="163" y1="130" x2="182" y2="120"/>
<circle class="node" cx="185" cy="132" r="3"/><text class="sm" x="150" y="115">master sw</text>
<line class="w5" x1="185" y1="132" x2="208" y2="132"/>
<!-- diode OR -->
<polygon points="208,124 224,132 208,140" fill="none" stroke="var(--red)" stroke-width="2"/>
<line x1="224" y1="124" x2="224" y2="140" stroke="var(--red)" stroke-width="2"/>
<line class="w5" x1="224" y1="132" x2="250" y2="132"/>
<line class="w5" x1="136" y1="175" x2="208" y2="175"/>
<polygon points="208,167 224,175 208,183" fill="none" stroke="var(--red)" stroke-width="2"/>
<line x1="224" y1="167" x2="224" y2="183" stroke="var(--red)" stroke-width="2"/>
<line class="w5" x1="224" y1="175" x2="250" y2="175"/>
<line class="w5" x1="250" y1="132" x2="250" y2="175"/>
<circle class="node" cx="250" cy="132" r="3"/>
<line class="w5" x1="250" y1="132" x2="250" y2="70"/>
<text class="sm" x="196" y="200">MBR030 diode-OR → rail</text>
<!-- GND from bank -->
<line class="wg" x1="88" y1="150" x2="88" y2="590"/>
<circle class="node" cx="88" cy="590" r="3"/>
<line class="wg" x1="88" y1="188" x2="88" y2="200"/>
<!-- ===== ARDUINO ===== -->
<rect class="chip" x="40" y="250" width="120" height="230" rx="8"/>
<text class="lbl" x="70" y="242">Arduino Uno</text>
<!-- 5V/GND to rails -->
<text class="sm" x="50" y="285">5V</text>
<line class="w5" x1="160" y1="280" x2="180" y2="280"/><line class="w5" x1="180" y1="280" x2="180" y2="70"/>
<circle class="node" cx="180" cy="70" r="3"/>
<text class="sm" x="46" y="474">GND</text>
<line class="wg" x1="100" y1="480" x2="100" y2="590"/>
<circle class="node" cx="100" cy="480" r="3"/><circle class="node" cx="100" cy="590" r="3"/>
<!-- signal pins -->
<text class="sm" x="120" y="320">D3</text><circle class="node" cx="160" cy="315" r="3"/>
<text class="sm" x="120" y="350">D5</text><circle class="node" cx="160" cy="345" r="3"/>
<text class="sm" x="120" y="380">D6</text><circle class="node" cx="160" cy="375" r="3"/>
<text class="sm" x="120" y="410">D9</text><circle class="node" cx="160" cy="405" r="3"/>
<text class="sm" x="120" y="440">D2</text><circle class="node" cx="160" cy="435" r="3"/>
<text class="sm" x="120" y="468">D4</text><circle class="node" cx="160" cy="463" r="3"/>
<!-- ===== BUTTONS: D2 scene, D4 section ===== -->
<line class="wire" x1="160" y1="435" x2="210" y2="435"/>
<rect class="chip" x="210" y="424" width="34" height="22" rx="4"/><text class="sm" x="214" y="439">BTN</text>
<line class="wg" x1="244" y1="435" x2="270" y2="435"/>
<text class="sm" x="278" y="431">scene (D2)</text>
<line class="wire" x1="160" y1="463" x2="210" y2="463"/>
<rect class="chip" x="210" y="452" width="34" height="22" rx="4"/><text class="sm" x="214" y="467">BTN</text>
<line class="wg" x1="244" y1="463" x2="270" y2="463"/>
<text class="sm" x="278" y="467">section (D4)</text>
<line class="wg" x1="270" y1="435" x2="270" y2="590"/>
<circle class="node" cx="270" cy="463" r="3"/><circle class="node" cx="270" cy="590" r="3"/>
<!-- ===== ZONE STAGES ===== -->
<!-- each: 2 LED branches (rep) + count, transistor, base from pin via 1k -->
<!-- GF cx=430 D3 y315 Q1 -->
<g>
<!-- branches -->
<line class="w5" x1="414" y1="70" x2="414" y2="96"/><circle class="node" cx="414" cy="70" r="2.5"/>
<polygon points="404,96 424,96 414,116" fill="none" stroke="var(--amber)" stroke-width="2"/>
<line x1="404" y1="116" x2="424" y2="116" stroke="var(--amber)" stroke-width="2.3"/>
<line class="wire" x1="414" y1="116" x2="414" y2="132"/>
<rect class="chip" x="398" y="132" width="32" height="34" rx="3"/><text class="sm" x="401" y="153">220</text>
<line class="wire" x1="414" y1="166" x2="414" y2="360"/>
<line class="w5" x1="446" y1="70" x2="446" y2="96"/><circle class="node" cx="446" cy="70" r="2.5"/>
<polygon points="436,96 456,96 446,116" fill="none" stroke="var(--amber)" stroke-width="2"/>
<line x1="436" y1="116" x2="456" y2="116" stroke="var(--amber)" stroke-width="2.3"/>
<line class="wire" x1="446" y1="116" x2="446" y2="132"/>
<rect class="chip" x="430" y="132" width="32" height="34" rx="3"/><text class="sm" x="433" y="153">220</text>
<line class="wire" x1="446" y1="166" x2="446" y2="360"/>
<line class="wire" x1="414" y1="360" x2="446" y2="360"/>
<text class="zn" x="404" y="210">GF · Q1</text><text class="sm" x="404" y="226">×2 LEDs</text>
<!-- transistor -->
<line class="wire" x1="430" y1="360" x2="430" y2="392"/>
<circle class="chip" cx="430" cy="422" r="28"/><text class="sm" x="418" y="426">Q1</text>
<line class="wg" x1="430" y1="450" x2="430" y2="590"/><circle class="node" cx="430" cy="590" r="2.5"/>
<text class="sm" x="438" y="470">E</text><text class="sm" x="438" y="392">C</text>
<!-- base from D3 -->
<line class="wsig" x1="160" y1="315" x2="335" y2="315"/>
<line class="wsig" x1="335" y1="315" x2="335" y2="422"/>
<rect class="chip" x="360" y="412" width="34" height="20" rx="3"/><text class="sm" x="363" y="426">1kΩ</text>
<line class="wsig" x1="335" y1="422" x2="360" y2="422"/>
<line class="wsig" x1="394" y1="422" x2="402" y2="422"/>
</g>
<!-- UP cx=600 D5 y345 Q2 -->
<g>
<line class="w5" x1="584" y1="70" x2="584" y2="96"/><circle class="node" cx="584" cy="70" r="2.5"/>
<polygon points="574,96 594,96 584,116" fill="none" stroke="var(--amber)" stroke-width="2"/>
<line x1="574" y1="116" x2="594" y2="116" stroke="var(--amber)" stroke-width="2.3"/>
<line class="wire" x1="584" y1="116" x2="584" y2="132"/>
<rect class="chip" x="568" y="132" width="32" height="34" rx="3"/><text class="sm" x="571" y="153">220</text>
<line class="wire" x1="584" y1="166" x2="584" y2="360"/>
<line class="w5" x1="616" y1="70" x2="616" y2="96"/><circle class="node" cx="616" cy="70" r="2.5"/>
<polygon points="606,96 626,96 616,116" fill="none" stroke="var(--amber)" stroke-width="2"/>
<line x1="606" y1="116" x2="626" y2="116" stroke="var(--amber)" stroke-width="2.3"/>
<line class="wire" x1="616" y1="116" x2="616" y2="132"/>
<rect class="chip" x="600" y="132" width="32" height="34" rx="3"/><text class="sm" x="603" y="153">220</text>
<line class="wire" x1="616" y1="166" x2="616" y2="360"/>
<line class="wire" x1="584" y1="360" x2="616" y2="360"/>
<text class="zn" x="574" y="210">UP · Q2</text><text class="sm" x="574" y="226">×3 LEDs</text>
<line class="wire" x1="600" y1="360" x2="600" y2="392"/>
<circle class="chip" cx="600" cy="422" r="28"/><text class="sm" x="588" y="426">Q2</text>
<line class="wg" x1="600" y1="450" x2="600" y2="590"/><circle class="node" cx="600" cy="590" r="2.5"/>
<line class="wsig" x1="160" y1="345" x2="505" y2="345"/>
<line class="wsig" x1="505" y1="345" x2="505" y2="422"/>
<rect class="chip" x="530" y="412" width="34" height="20" rx="3"/><text class="sm" x="533" y="426">1kΩ</text>
<line class="wsig" x1="505" y1="422" x2="530" y2="422"/>
<line class="wsig" x1="564" y1="422" x2="572" y2="422"/>
</g>
<!-- EXT cx=770 D6 y375 Q3 (5 LEDs, draw 2 + note) -->
<g>
<line class="w5" x1="754" y1="70" x2="754" y2="96"/><circle class="node" cx="754" cy="70" r="2.5"/>
<polygon points="744,96 764,96 754,116" fill="none" stroke="var(--amber)" stroke-width="2"/>
<line x1="744" y1="116" x2="764" y2="116" stroke="var(--amber)" stroke-width="2.3"/>
<line class="wire" x1="754" y1="116" x2="754" y2="132"/>
<rect class="chip" x="738" y="132" width="32" height="34" rx="3"/><text class="sm" x="741" y="153">220</text>
<line class="wire" x1="754" y1="166" x2="754" y2="360"/>
<line class="w5" x1="786" y1="70" x2="786" y2="96"/><circle class="node" cx="786" cy="70" r="2.5"/>
<polygon points="776,96 796,96 786,116" fill="none" stroke="var(--amber)" stroke-width="2"/>
<line x1="776" y1="116" x2="796" y2="116" stroke="var(--amber)" stroke-width="2.3"/>
<line class="wire" x1="786" y1="116" x2="786" y2="132"/>
<rect class="chip" x="770" y="132" width="32" height="34" rx="3"/><text class="sm" x="773" y="153">220</text>
<line class="wire" x1="786" y1="166" x2="786" y2="360"/>
<line class="wire" x1="754" y1="360" x2="786" y2="360"/>
<text class="zn" x="744" y="210">EXT · Q3</text><text class="sm" x="744" y="226">×5 LEDs</text>
<line class="wire" x1="770" y1="360" x2="770" y2="392"/>
<circle class="chip" cx="770" cy="422" r="28"/><text class="sm" x="758" y="426">Q3</text>
<line class="wg" x1="770" y1="450" x2="770" y2="590"/><circle class="node" cx="770" cy="590" r="2.5"/>
<line class="wsig" x1="160" y1="375" x2="675" y2="375"/>
<line class="wsig" x1="675" y1="375" x2="675" y2="422"/>
<rect class="chip" x="700" y="412" width="34" height="20" rx="3"/><text class="sm" x="703" y="426">1kΩ</text>
<line class="wsig" x1="675" y1="422" x2="700" y2="422"/>
<line class="wsig" x1="734" y1="422" x2="742" y2="422"/>
</g>
<!-- FIRE cx=930 D9 y405 Q4 (1 LED) -->
<g>
<line class="w5" x1="930" y1="70" x2="930" y2="96"/><circle class="node" cx="930" cy="70" r="2.5"/>
<polygon points="920,96 940,96 930,116" fill="none" stroke="var(--red)" stroke-width="2"/>
<line x1="920" y1="116" x2="940" y2="116" stroke="var(--red)" stroke-width="2.3"/>
<line class="wire" x1="930" y1="116" x2="930" y2="132"/>
<rect class="chip" x="914" y="132" width="32" height="34" rx="3"/><text class="sm" x="917" y="153">220</text>
<line class="wire" x1="930" y1="166" x2="930" y2="360"/>
<text class="zn" x="906" y="210">FIRE · Q4</text><text class="sm" x="912" y="226">×1 LED</text>
<text class="sm" x="906" y="242" fill="var(--red)">RED · flicker</text>
<line class="wire" x1="930" y1="360" x2="930" y2="392"/>
<circle class="chip" cx="930" cy="422" r="28"/><text class="sm" x="918" y="426">Q4</text>
<line class="wg" x1="930" y1="450" x2="930" y2="590"/><circle class="node" cx="930" cy="590" r="2.5"/>
<line class="wsig" x1="160" y1="405" x2="845" y2="405"/>
<line class="wsig" x1="845" y1="405" x2="845" y2="422"/>
<rect class="chip" x="860" y="412" width="34" height="20" rx="3"/><text class="sm" x="863" y="426">1kΩ</text>
<line class="wsig" x1="845" y1="422" x2="860" y2="422"/>
<line class="wsig" x1="894" y1="422" x2="902" y2="422"/>
</g>
</svg>
<div class="key">
<span><span class="sw" style="border-color:var(--red)"></span>+5V</span>
<span><span class="sw" style="border-color:var(--line)"></span>wire / GND</span>
<span><span class="sw" style="border-color:var(--slate);border-top-style:dashed"></span>signal (PWM → base)</span>
<span><span class="sw" style="border-color:var(--amber)"></span>LED (warm white)</span>
<span><span class="sw" style="border-color:var(--red)"></span>FIRE = red LED</span>
<span>· crossing lines with no dot = not connected</span>
</div>
</div>
<div class="card scroll">
<strong>Running the wire, shared buses, not home-runs</strong>
<p class="sm" style="margin:6px 0 12px">One <code>+5V</code> wire snakes past every fixture (shared by all zones).
Each zone has one <code>return</code> wire back to its transistor. Every LED just bridges the two nearest buses.</p>
<svg viewBox="0 0 900 330" role="img" aria-label="Bus wiring: shared +5V, per-zone returns">
<!-- +5V bus -->
<line class="w5" x1="40" y1="50" x2="860" y2="50"/>
<text class="lbl" x="40" y="42" fill="var(--red)">+5V bus, shared by ALL fixtures</text>
<!-- GF return bus (green) -->
<line x1="40" y1="210" x2="660" y2="210" stroke="var(--grn)" stroke-width="3" fill="none"/>
<text class="sm" x="666" y="214" fill="var(--grn)">GF return → Q1</text>
<!-- EXT return bus (slate) -->
<line x1="40" y1="270" x2="800" y2="270" stroke="var(--slate)" stroke-width="3" fill="none"/>
<text class="sm" x="666" y="288" fill="var(--slate)">EXT return → Q3</text>
<!-- board hint -->
<text class="sm" x="40" y="305">(returns run back to the driver board)</text>
<!-- fixture template: EXT at 150,450,750 ; GF at 300,600 -->
<!-- EXT fixture 150 -->
<g>
<circle class="node" cx="150" cy="50" r="3.2" fill="var(--red)"/>
<line class="wire" x1="150" y1="50" x2="150" y2="76"/>
<polygon points="140,76 160,76 150,96" fill="none" stroke="var(--amber)" stroke-width="2"/>
<line x1="140" y1="96" x2="160" y2="96" stroke="var(--amber)" stroke-width="2.3"/>
<line class="wire" x1="150" y1="96" x2="150" y2="112"/>
<rect class="chip" x="134" y="112" width="32" height="30" rx="3"/><text class="sm" x="137" y="131">220</text>
<line class="wire" x1="150" y1="142" x2="150" y2="270"/>
<circle class="node" cx="150" cy="270" r="3.2" fill="var(--slate)"/>
<text class="sm" x="128" y="164">porch A</text>
</g>
<!-- GF fixture 300 -->
<g>
<circle class="node" cx="300" cy="50" r="3.2" fill="var(--red)"/>
<line class="wire" x1="300" y1="50" x2="300" y2="76"/>
<polygon points="290,76 310,76 300,96" fill="none" stroke="var(--amber)" stroke-width="2"/>
<line x1="290" y1="96" x2="310" y2="96" stroke="var(--amber)" stroke-width="2.3"/>
<line class="wire" x1="300" y1="96" x2="300" y2="112"/>
<rect class="chip" x="284" y="112" width="32" height="30" rx="3"/><text class="sm" x="287" y="131">220</text>
<line class="wire" x1="300" y1="142" x2="300" y2="210"/>
<circle class="node" cx="300" cy="210" r="3.2" fill="var(--grn)"/>
<text class="sm" x="280" y="164">GF living</text>
</g>
<!-- EXT fixture 450 (crosses GF bus, no dot) -->
<g>
<circle class="node" cx="450" cy="50" r="3.2" fill="var(--red)"/>
<line class="wire" x1="450" y1="50" x2="450" y2="76"/>
<polygon points="440,76 460,76 450,96" fill="none" stroke="var(--amber)" stroke-width="2"/>
<line x1="440" y1="96" x2="460" y2="96" stroke="var(--amber)" stroke-width="2.3"/>
<line class="wire" x1="450" y1="96" x2="450" y2="112"/>
<rect class="chip" x="434" y="112" width="32" height="30" rx="3"/><text class="sm" x="437" y="131">220</text>
<line class="wire" x1="450" y1="142" x2="450" y2="270"/>
<circle class="node" cx="450" cy="270" r="3.2" fill="var(--slate)"/>
<text class="sm" x="428" y="164">entry</text>
<text class="sm" x="458" y="205" fill="var(--muted)">← no dot: crosses</text>
<text class="sm" x="458" y="218" fill="var(--muted)">GF bus, not joined</text>
</g>
<!-- GF fixture 600 -->
<g>
<circle class="node" cx="600" cy="50" r="3.2" fill="var(--red)"/>
<line class="wire" x1="600" y1="50" x2="600" y2="76"/>
<polygon points="590,76 610,76 600,96" fill="none" stroke="var(--amber)" stroke-width="2"/>
<line x1="590" y1="96" x2="610" y2="96" stroke="var(--amber)" stroke-width="2.3"/>
<line class="wire" x1="600" y1="96" x2="600" y2="112"/>
<rect class="chip" x="584" y="112" width="32" height="30" rx="3"/><text class="sm" x="587" y="131">220</text>
<line class="wire" x1="600" y1="142" x2="600" y2="210"/>
<circle class="node" cx="600" cy="210" r="3.2" fill="var(--grn)"/>
<text class="sm" x="580" y="164">GF kitchen</text>
</g>
<!-- EXT fixture 750 -->
<g>
<circle class="node" cx="750" cy="50" r="3.2" fill="var(--red)"/>
<line class="wire" x1="750" y1="50" x2="750" y2="76"/>
<polygon points="740,76 760,76 750,96" fill="none" stroke="var(--amber)" stroke-width="2"/>
<line x1="740" y1="96" x2="760" y2="96" stroke="var(--amber)" stroke-width="2.3"/>
<line class="wire" x1="750" y1="96" x2="750" y2="112"/>
<rect class="chip" x="734" y="112" width="32" height="30" rx="3"/><text class="sm" x="737" y="131">220</text>
<line class="wire" x1="750" y1="142" x2="750" y2="270"/>
<circle class="node" cx="750" cy="270" r="3.2" fill="var(--slate)"/>
<text class="sm" x="726" y="164">porch B</text>
</g>
</svg>
<div class="key">
<span><span class="sw" style="border-color:var(--red)"></span>+5V bus (shared)</span>
<span><span class="sw" style="border-color:var(--grn)"></span>GF return</span>
<span><span class="sw" style="border-color:var(--slate)"></span>EXT return</span>
<span>· solid dot = tap/join · line crossing with no dot = not connected</span>
</div>
<ul>
<li><strong>Daisy-chain, don't home-run:</strong> tap the passing +5V and zone-return buses at each fixture, don't run separate pairs all the way back to the board.</li>
<li><strong>One +5V for the whole house</strong> + <strong>one return per zone</strong> (4 zones → 4 returns; 6 → 6). That's the total wire count out of the board.</li>
<li><strong>Different zones near each other</strong> share the +5V bus but must keep <em>separate</em> return wires, never let two zone returns touch, or they switch together.</li>
<li>Put each <strong>220Ω at the LED</strong> (heat-shrink it) so the buses stay clean two-conductor runs. Color-code: red = +5V, a distinct color per return.</li>
</ul>
</div>
<div class="card">
<table>
<tr><th>Zone</th><th>Pin → 1kΩ → base</th><th>Transistor</th><th>LEDs (each +5V→LED→220Ω→collector)</th></tr>
<tr><td>GF_INT</td><td><code>D3</code></td><td>Q1 (PN2222)</td><td>2, living + kitchen ceilings</td></tr>
<tr><td>UP_INT</td><td><code>D5</code></td><td>Q2</td><td>3, 2 bedroom ceilings, attic</td></tr>
<tr><td>EXT</td><td><code>D6</code></td><td>Q3</td><td>5, porch A/B, entry, deck, balcony</td></tr>
<tr><td>FIRE</td><td><code>D9</code></td><td>Q4</td><td>1, hearth · <b style="color:var(--red)">RED LED</b> (flickers)</td></tr>
<tr><td>scene button</td><td><code>D2</code> → button → GND</td><td>, </td><td>cycles scenes / wakes</td></tr>
<tr><td>section button</td><td><code>D4</code> → button → GND</td><td>, </td><td>spotlight one zone: GF→UP→EXT→FIRE→off</td></tr>
</table>
</div>
<div class="card">
<strong>Build & wiring rules</strong>
<ul>
<li>Every zone's transistor: <code>E</code>→GND rail, <code>C</code>→that zone's LED bundle, base←pin through 1kΩ. Legs (flat face toward you): <code>E · B · C</code>.</li>
<li>Every LED: long leg (+) → <code>+5V</code>, short leg () → its own 220Ω → the zone's collector. One resistor per LED.</li>
<li>Add more LEDs to a zone by hanging more of these branches in parallel on the same collector.</li>
<li><strong>FIRE zone uses a RED LED</strong>; all other zones warm-white/white. (Color is hardware only, the sketch just sets brightness.)</li>
<li><strong>Two buttons</strong>, each to GND (internal pull-ups, no resistor): <code>D2</code> = scene cycle, <code>D4</code> = section spotlight (one zone at a time). Either wakes from idle.</li>
<li><strong>Power:</strong> USB bank → master switch → diode-OR → +5V rail. Bench-test on computer USB alone. Only ONE 5V source live at a time (the diode-OR makes that safe if both are ever connected).</li>
<li>Common ground everywhere: bank , Arduino GND, all emitters share the one GND rail.</li>
</ul>
</div>
</div>

368
gru-wiring.html Normal file
View file

@ -0,0 +1,368 @@
<title>House Lighting, Gru & the Minions (interactive)</title>
<style>
:root{ --bg:#141019; --ink:#f3eeff; --muted:#a99fc4; --rule:#3a3350;
--card:#1c1728; --red:#ff4436; --amber:#ffc14d; --white:#fff6e6; --slate:#9aa6c8;
--cyan:#7fe0ff; --grn:#48c78e; --yellow:#f7d33e; --yellow2:#caa62a;
--denim:#2f5b8c; --denim2:#1f3f63; --skin:#d7b89a; }
*{box-sizing:border-box}
body{margin:0;background:radial-gradient(1200px 600px at 50% -10%,#241b3a,#120e1c 70%);
color:var(--ink);font:15px/1.55 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;padding:22px;}
.wrap{max-width:1100px;margin:0 auto;}
h1{font-size:22px;margin:0 0 2px;letter-spacing:.2px;}
.sub{color:var(--muted);font-size:13px;margin:0 0 16px;}
.card{background:var(--card);border:1px solid var(--rule);border-radius:14px;padding:16px;margin-bottom:18px;}
.scroll{overflow-x:auto;}
svg{display:block;margin:0 auto;max-width:100%;height:auto;min-width:940px;}
text{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;fill:var(--ink);}
.lbl{font-size:12.5px;} .sm{font-size:10.5px;fill:var(--muted);} .tag{font-size:11px;font-weight:bold;}
.wire{stroke:#b8b0d0;stroke-width:2;fill:none;}
.node{fill:#b8b0d0;}
table{border-collapse:collapse;width:100%;font-size:13px;margin-top:6px;}
th,td{border:1px solid var(--rule);padding:7px 10px;text-align:left;}
th{background:rgba(255,255,255,.05);}
code{font-family:ui-monospace,Menlo,monospace;background:rgba(255,255,255,.08);padding:1px 5px;border-radius:4px;font-size:.9em;}
.key{display:flex;gap:16px;flex-wrap:wrap;font-size:12px;color:var(--muted);margin-top:10px;}
.cmds{display:flex;gap:10px;flex-wrap:wrap;margin-top:2px;}
.cmds .grp{display:flex;gap:10px;flex-wrap:wrap;}
button{font:600 13.5px/1 inherit;color:#1a1205;background:var(--amber);border:0;
padding:11px 15px;border-radius:10px;cursor:pointer;transition:.12s;}
button.zone{background:transparent;color:var(--ink);border:1px solid var(--rule);}
button.zone.on{background:#2c2410;color:var(--amber);border-color:#5a4a1e;}
button.zone.on::before{content:"● ";color:var(--grn);}
button.zone::before{content:"○ ";color:var(--muted);}
button:active{transform:translateY(1px);}
.spacer{flex:1}
</style>
<div class="wrap">
<h1> House Lighting, Gru gives the orders</h1>
<p class="sub">Click a command. Gru shouts it, the right minion (a ULN2803A channel) yanks its zone to ground, and the lights come on. Same wiring as the build.</p>
<!-- ============ reusable characters ============ -->
<svg width="0" height="0" style="position:absolute">
<defs>
<!-- shared minion body pieces via nested reuse would need more markup; each variant is self-contained -->
<!-- A: one eye, spiky hair -->
<symbol id="minionA" viewBox="0 0 60 150">
<path d="M12 70 L6 20" stroke="var(--yellow2)" stroke-width="5" fill="none"/>
<path d="M48 70 L54 20" stroke="var(--yellow2)" stroke-width="5" fill="none"/>
<circle cx="6" cy="18" r="5" fill="var(--yellow)" stroke="var(--yellow2)" stroke-width="1.5"/>
<circle cx="54" cy="18" r="5" fill="var(--yellow)" stroke="var(--yellow2)" stroke-width="1.5"/>
<rect x="8" y="22" width="44" height="108" rx="22" fill="var(--yellow)" stroke="var(--yellow2)" stroke-width="2"/>
<path d="M24 22 l-2 -8 M30 21 l0 -9 M36 22 l2 -8" stroke="#2a2416" stroke-width="1.6" fill="none"/>
<rect x="6" y="44" width="48" height="13" fill="#7d828c"/>
<rect x="6" y="44" width="48" height="13" fill="none" stroke="#5a5f68" stroke-width="1"/>
<circle cx="30" cy="50.5" r="11" fill="#cfd3da" stroke="#63687040" stroke-width="3"/>
<circle cx="30" cy="50.5" r="7" fill="#fff"/>
<circle cx="31" cy="50.5" r="3.2" fill="#3a2b1a"/>
<path d="M22 72 q8 7 16 0" stroke="#7a5b2a" stroke-width="1.6" fill="none"/>
<path d="M8 98 h44 v10 a22 22 0 0 1 -44 0 z" fill="var(--denim)"/>
<rect x="23" y="86" width="14" height="14" fill="var(--denim)"/>
<path d="M24 86 l-4 -12 M36 86 l4 -12" stroke="var(--denim)" stroke-width="3" fill="none"/>
<rect x="25" y="100" width="10" height="9" fill="var(--denim2)" stroke="#16304d" stroke-width="1"/>
<text x="27.5" y="107.5" font-size="7" fill="#cfe0f5" font-family="monospace">G</text>
<rect x="14" y="128" width="14" height="12" rx="3" fill="#2a2a33" stroke="#9a9ab0" stroke-width="1.3"/>
<rect x="32" y="128" width="14" height="12" rx="3" fill="#2a2a33" stroke="#9a9ab0" stroke-width="1.3"/>
</symbol>
<!-- B: two eyes, bald -->
<symbol id="minionB" viewBox="0 0 60 150">
<path d="M12 70 L6 20" stroke="var(--yellow2)" stroke-width="5" fill="none"/>
<path d="M48 70 L54 20" stroke="var(--yellow2)" stroke-width="5" fill="none"/>
<circle cx="6" cy="18" r="5" fill="var(--yellow)" stroke="var(--yellow2)" stroke-width="1.5"/>
<circle cx="54" cy="18" r="5" fill="var(--yellow)" stroke="var(--yellow2)" stroke-width="1.5"/>
<rect x="8" y="22" width="44" height="108" rx="22" fill="var(--yellow)" stroke="var(--yellow2)" stroke-width="2"/>
<rect x="6" y="44" width="48" height="13" fill="#7d828c"/>
<rect x="6" y="44" width="48" height="13" fill="none" stroke="#5a5f68" stroke-width="1"/>
<line x1="30" y1="46" x2="30" y2="55" stroke="#5a5f68" stroke-width="1.4"/>
<circle cx="21" cy="50.5" r="8.5" fill="#cfd3da" stroke="#63687040" stroke-width="2.5"/>
<circle cx="39" cy="50.5" r="8.5" fill="#cfd3da" stroke="#63687040" stroke-width="2.5"/>
<circle cx="21" cy="50.5" r="5.2" fill="#fff"/><circle cx="39" cy="50.5" r="5.2" fill="#fff"/>
<circle cx="22" cy="50.5" r="2.4" fill="#3a2b1a"/><circle cx="40" cy="50.5" r="2.4" fill="#3a2b1a"/>
<path d="M22 72 q8 6 16 0" stroke="#7a5b2a" stroke-width="1.6" fill="none"/>
<path d="M8 98 h44 v10 a22 22 0 0 1 -44 0 z" fill="var(--denim)"/>
<rect x="23" y="86" width="14" height="14" fill="var(--denim)"/>
<path d="M24 86 l-4 -12 M36 86 l4 -12" stroke="var(--denim)" stroke-width="3" fill="none"/>
<rect x="25" y="100" width="10" height="9" fill="var(--denim2)" stroke="#16304d" stroke-width="1"/>
<text x="27.5" y="107.5" font-size="7" fill="#cfe0f5" font-family="monospace">G</text>
<rect x="14" y="128" width="14" height="12" rx="3" fill="#2a2a33" stroke="#9a9ab0" stroke-width="1.3"/>
<rect x="32" y="128" width="14" height="12" rx="3" fill="#2a2a33" stroke="#9a9ab0" stroke-width="1.3"/>
</symbol>
<!-- C: two eyes, side tuft of hair -->
<symbol id="minionC" viewBox="0 0 60 150">
<path d="M12 70 L6 20" stroke="var(--yellow2)" stroke-width="5" fill="none"/>
<path d="M48 70 L54 20" stroke="var(--yellow2)" stroke-width="5" fill="none"/>
<circle cx="6" cy="18" r="5" fill="var(--yellow)" stroke="var(--yellow2)" stroke-width="1.5"/>
<circle cx="54" cy="18" r="5" fill="var(--yellow)" stroke="var(--yellow2)" stroke-width="1.5"/>
<rect x="8" y="22" width="44" height="108" rx="22" fill="var(--yellow)" stroke="var(--yellow2)" stroke-width="2"/>
<path d="M20 23 c 1 -7 7 -9 12 -6 M26 22 c 1 -6 6 -7 10 -4" stroke="#2a2416" stroke-width="1.5" fill="none"/>
<rect x="6" y="44" width="48" height="13" fill="#7d828c"/>
<rect x="6" y="44" width="48" height="13" fill="none" stroke="#5a5f68" stroke-width="1"/>
<line x1="30" y1="46" x2="30" y2="55" stroke="#5a5f68" stroke-width="1.4"/>
<circle cx="21" cy="50.5" r="8.5" fill="#cfd3da" stroke="#63687040" stroke-width="2.5"/>
<circle cx="39" cy="50.5" r="8.5" fill="#cfd3da" stroke="#63687040" stroke-width="2.5"/>
<circle cx="21" cy="50.5" r="5.2" fill="#fff"/><circle cx="39" cy="50.5" r="5.2" fill="#fff"/>
<circle cx="20" cy="50.5" r="2.4" fill="#3a2b1a"/><circle cx="38" cy="50.5" r="2.4" fill="#3a2b1a"/>
<path d="M22 73 q8 5 16 0" stroke="#7a5b2a" stroke-width="1.6" fill="none"/>
<path d="M8 98 h44 v10 a22 22 0 0 1 -44 0 z" fill="var(--denim)"/>
<rect x="23" y="86" width="14" height="14" fill="var(--denim)"/>
<path d="M24 86 l-4 -12 M36 86 l4 -12" stroke="var(--denim)" stroke-width="3" fill="none"/>
<rect x="25" y="100" width="10" height="9" fill="var(--denim2)" stroke="#16304d" stroke-width="1"/>
<text x="27.5" y="107.5" font-size="7" fill="#cfe0f5" font-family="monospace">G</text>
<rect x="14" y="128" width="14" height="12" rx="3" fill="#2a2a33" stroke="#9a9ab0" stroke-width="1.3"/>
<rect x="32" y="128" width="14" height="12" rx="3" fill="#2a2a33" stroke="#9a9ab0" stroke-width="1.3"/>
</symbol>
<!-- D: one eye, bald, wide grin -->
<symbol id="minionD" viewBox="0 0 60 150">
<path d="M12 70 L6 20" stroke="var(--yellow2)" stroke-width="5" fill="none"/>
<path d="M48 70 L54 20" stroke="var(--yellow2)" stroke-width="5" fill="none"/>
<circle cx="6" cy="18" r="5" fill="var(--yellow)" stroke="var(--yellow2)" stroke-width="1.5"/>
<circle cx="54" cy="18" r="5" fill="var(--yellow)" stroke="var(--yellow2)" stroke-width="1.5"/>
<rect x="8" y="22" width="44" height="108" rx="22" fill="var(--yellow)" stroke="var(--yellow2)" stroke-width="2"/>
<rect x="6" y="44" width="48" height="13" fill="#7d828c"/>
<rect x="6" y="44" width="48" height="13" fill="none" stroke="#5a5f68" stroke-width="1"/>
<circle cx="30" cy="50.5" r="11" fill="#cfd3da" stroke="#63687040" stroke-width="3"/>
<circle cx="30" cy="50.5" r="7" fill="#fff"/>
<circle cx="29" cy="50.5" r="3.2" fill="#3a2b1a"/>
<path d="M20 71 q10 10 20 0" stroke="#7a5b2a" stroke-width="1.8" fill="none"/>
<path d="M8 98 h44 v10 a22 22 0 0 1 -44 0 z" fill="var(--denim)"/>
<rect x="23" y="86" width="14" height="14" fill="var(--denim)"/>
<path d="M24 86 l-4 -12 M36 86 l4 -12" stroke="var(--denim)" stroke-width="3" fill="none"/>
<rect x="25" y="100" width="10" height="9" fill="var(--denim2)" stroke="#16304d" stroke-width="1"/>
<text x="27.5" y="107.5" font-size="7" fill="#cfe0f5" font-family="monospace">G</text>
<rect x="14" y="128" width="14" height="12" rx="3" fill="#2a2a33" stroke="#9a9ab0" stroke-width="1.3"/>
<rect x="32" y="128" width="14" height="12" rx="3" fill="#2a2a33" stroke="#9a9ab0" stroke-width="1.3"/>
</symbol>
<symbol id="gru" viewBox="0 0 130 210">
<path d="M42 92 Q39 98 34 122 L12 205 L118 205 L96 122 Q91 98 88 92 Z" fill="#26282e" stroke="#141518" stroke-width="2"/>
<rect x="36" y="107" width="58" height="18" rx="9" fill="#31333b" stroke="#141518" stroke-width="1.5" transform="rotate(23 65 118)"/>
<rect x="36" y="107" width="58" height="18" rx="9" fill="#3a3d46" stroke="#141518" stroke-width="1.5" transform="rotate(-23 65 118)"/>
<circle cx="91" cy="108" r="6.5" fill="#d9bb9d"/>
<circle cx="39" cy="108" r="6.5" fill="#d9bb9d"/>
<path d="M39 72 Q65 87 91 72 L93 93 Q65 106 37 93 Z" fill="#8f949c" stroke="#585d66" stroke-width="1.5"/>
<path d="M38 78 Q65 92 92 78 M37 85 Q65 99 93 85 M38 91 Q65 104 92 91" stroke="#2f3238" stroke-width="2.6" fill="none"/>
<path d="M80 93 l11 30 l-14 -3 l-1 -25 z" fill="#82878f" stroke="#585d66" stroke-width="1"/>
<path d="M78 101 l12 3 M77 110 l13 3 M77 118 l12 2" stroke="#2f3238" stroke-width="2.4"/>
<ellipse cx="64" cy="45" rx="29" ry="31" fill="#d9bb9d"/>
<ellipse cx="64" cy="30" rx="24" ry="16" fill="#e0c4a8"/>
<circle cx="35" cy="49" r="5" fill="#d9bb9d"/><circle cx="93" cy="49" r="5" fill="#d3b494"/>
<path d="M61 42 Q58 54 61 60 Q66 64 72 59 Q74 51 69 43 Z" fill="#d0ae8f" stroke="#b78f6e" stroke-width="0.8"/>
<path d="M62 59 Q66 62 71 58" stroke="#ad8459" stroke-width="1.1" fill="none"/>
<circle cx="64" cy="59" r="0.9" fill="#a67f57"/><circle cx="69" cy="58" r="0.9" fill="#a67f57"/>
<path d="M47 33 Q55 30 63 35 M82 37 Q75 33 68 36" stroke="#4a3b2a" stroke-width="2.6" fill="none" stroke-linecap="round"/>
<ellipse cx="57" cy="43" rx="5" ry="6.2" fill="#fff" stroke="#3a3a3a" stroke-width="1"/>
<ellipse cx="71" cy="43" rx="5" ry="6.2" fill="#fff" stroke="#3a3a3a" stroke-width="1"/>
<circle cx="58" cy="44" r="2.5" fill="#221"/><circle cx="71" cy="44" r="2.5" fill="#221"/>
<path d="M53 65 Q64 61 75 66" stroke="#7a5b48" stroke-width="2" fill="none"/>
</symbol>
</defs>
</svg>
<!-- ============ command buttons ============ -->
<div class="card">
<div class="cmds">
<button class="zone" data-cmd="all">All lights</button>
<span class="spacer"></span>
<div class="grp">
<button class="zone" data-cmd="gf">Ground floor</button>
<button class="zone" data-cmd="up">Upstairs</button>
<button class="zone" data-cmd="ext">Exterior lights</button>
<button class="zone" data-cmd="fire">Fireplace</button>
</div>
</div>
</div>
<!-- ============ main scene ============ -->
<div class="card scroll">
<svg viewBox="0 0 1180 940" role="img" aria-label="Gru commands the minions to light the house">
<defs>
<marker id="arw" markerWidth="9" markerHeight="9" refX="6" refY="3" orient="auto">
<path d="M0,0 L6,3 L0,6 z" fill="currentColor"/>
</marker>
<filter id="soft" x="-60%" y="-60%" width="220%" height="220%"><feGaussianBlur stdDeviation="9"/></filter>
<linearGradient id="sky" x1="0" y1="0" x2="0" y2="1">
<stop offset="0" stop-color="#33406a"/>
<stop offset="1" stop-color="#1a2138"/>
</linearGradient>
</defs>
<!-- scene backdrop for contrast -->
<rect x="0" y="0" width="1180" height="940" rx="12" fill="url(#sky)"/>
<!-- ===== 4 ZONE COLUMNS ; centers 240 500 760 1020 ===== -->
<!-- GF -->
<g>
<rect x="202" y="96" width="76" height="84" rx="6" fill="#241d33" stroke="var(--rule)"/>
<circle class="led" data-zone="gf" cx="224" cy="130" r="8" fill="var(--white)"/>
<circle class="led" data-zone="gf" cx="256" cy="130" r="8" fill="var(--white)"/>
<text class="sm" x="210" y="170">GF · ×2 white</text>
<rect x="226" y="186" width="28" height="18" rx="3" fill="#2a2340" stroke="var(--rule)"/><text class="sm" x="229" y="199">220</text>
<line class="wire" x1="240" y1="204" x2="240" y2="300"/>
<text class="sm" x="248" y="256">OUT1 · pin18</text>
<ellipse class="glow" data-zone="gf" cx="240" cy="366" rx="34" ry="67" fill="var(--white)" filter="url(#soft)" opacity="0"/>
<use href="#minionA" x="213" y="300" width="54" height="135"/>
<rect id="pill-gf" x="184" y="450" width="112" height="22" rx="11" fill="#241d33" stroke="var(--rule)"/>
<text id="pilltxt-gf" x="240" y="465" font-size="10.5" text-anchor="middle" fill="var(--muted)">ground floor · off</text>
</g>
<!-- UP -->
<g>
<rect x="454" y="96" width="92" height="84" rx="6" fill="#241d33" stroke="var(--rule)"/>
<circle class="led" data-zone="up" cx="474" cy="130" r="7" fill="var(--white)"/>
<circle class="led" data-zone="up" cx="500" cy="130" r="7" fill="var(--white)"/>
<circle class="led" data-zone="up" cx="526" cy="130" r="7" fill="var(--white)"/>
<text class="sm" x="462" y="170">UP · ×3 white</text>
<rect x="486" y="186" width="28" height="18" rx="3" fill="#2a2340" stroke="var(--rule)"/><text class="sm" x="489" y="199">220</text>
<line class="wire" x1="500" y1="204" x2="500" y2="300"/>
<text class="sm" x="508" y="256">OUT2 · pin17</text>
<ellipse class="glow" data-zone="up" cx="500" cy="366" rx="34" ry="67" fill="var(--white)" filter="url(#soft)" opacity="0"/>
<use href="#minionB" x="473" y="300" width="54" height="135"/>
<rect id="pill-up" x="446" y="450" width="108" height="22" rx="11" fill="#241d33" stroke="var(--rule)"/>
<text id="pilltxt-up" x="500" y="465" font-size="10.5" text-anchor="middle" fill="var(--muted)">upstairs · off</text>
</g>
<!-- EXT -->
<g>
<rect x="708" y="96" width="104" height="84" rx="6" fill="#241d33" stroke="var(--rule)"/>
<circle class="led" data-zone="ext" cx="726" cy="122" r="6" fill="var(--white)"/>
<circle class="led" data-zone="ext" cx="746" cy="122" r="6" fill="var(--white)"/>
<circle class="led" data-zone="ext" cx="766" cy="122" r="6" fill="var(--white)"/>
<circle class="led" data-zone="ext" cx="736" cy="146" r="6" fill="var(--white)"/>
<circle class="led" data-zone="ext" cx="756" cy="146" r="6" fill="var(--white)"/>
<text class="sm" x="716" y="172">EXT · ×5 white</text>
<rect x="746" y="186" width="28" height="18" rx="3" fill="#2a2340" stroke="var(--rule)"/><text class="sm" x="749" y="199">220</text>
<line class="wire" x1="760" y1="204" x2="760" y2="300"/>
<text class="sm" x="768" y="256">OUT3 · pin16</text>
<ellipse class="glow" data-zone="ext" cx="760" cy="366" rx="34" ry="67" fill="var(--white)" filter="url(#soft)" opacity="0"/>
<use href="#minionC" x="733" y="300" width="54" height="135"/>
<rect id="pill-ext" x="686" y="450" width="148" height="22" rx="11" fill="#241d33" stroke="var(--rule)"/>
<text id="pilltxt-ext" x="760" y="465" font-size="10.5" text-anchor="middle" fill="var(--muted)">exterior lights · off</text>
</g>
<!-- FIRE -->
<g>
<rect x="984" y="96" width="72" height="84" rx="6" fill="#2a1720" stroke="#5a2530"/>
<circle class="led" data-zone="fire" cx="1020" cy="130" r="9" fill="var(--red)"/>
<text class="sm" x="990" y="172" fill="var(--red)">FIRE · ×1 RED</text>
<rect x="1006" y="186" width="28" height="18" rx="3" fill="#2a2340" stroke="var(--rule)"/><text class="sm" x="1009" y="199">220</text>
<line class="wire" x1="1020" y1="204" x2="1020" y2="300"/>
<text class="sm" x="1028" y="256">OUT4 · pin15</text>
<ellipse class="glow" data-zone="fire" cx="1020" cy="366" rx="34" ry="67" fill="var(--red)" filter="url(#soft)" opacity="0"/>
<use href="#minionD" x="993" y="300" width="54" height="135"/>
<path id="torch" d="M1046 330 q7 -14 0 -26 q12 9 5 26 z" fill="var(--red)" filter="drop-shadow(0 0 6px var(--red))" opacity="0"/>
<rect id="pill-fire" x="948" y="450" width="144" height="22" rx="11" fill="#2a1720" stroke="var(--rule)"/>
<text id="pilltxt-fire" x="1020" y="465" font-size="10.5" text-anchor="middle" fill="var(--muted)">fireplace · off</text>
</g>
<!-- ===== GRU below, shouting a command up each wire ===== -->
<use href="#gru" x="543" y="633" width="175" height="283"/>
<text class="lbl" x="452" y="770">GRU</text>
<text class="sm" x="428" y="786">= Arduino · the boss</text>
<text class="sm" x="452" y="810">shouts PWM on</text>
<text class="sm" x="452" y="824">D3 · D5 · D6 · D9</text>
<!-- command origin ABOVE Gru's head; wires fan up, never crossing his face -->
<line x1="630" y1="652" x2="630" y2="646" stroke="var(--slate)" stroke-width="2.2"/>
<circle cx="630" cy="644" r="4" fill="var(--slate)"/>
<line class="cmdwire" id="wire-gf" x1="630" y1="644" x2="240" y2="426" marker-end="url(#arw)"/>
<line class="cmdwire" id="wire-up" x1="630" y1="644" x2="500" y2="426" marker-end="url(#arw)"/>
<line class="cmdwire" id="wire-ext" x1="630" y1="644" x2="760" y2="426" marker-end="url(#arw)"/>
<line class="cmdwire" id="wire-fire" x1="630" y1="644" x2="1020" y2="426" marker-end="url(#arw)"/>
<text class="tag" x="418" y="544" fill="var(--slate)">D3→IN1</text>
<text class="tag" x="556" y="552" fill="var(--slate)">D5→IN2</text>
<text class="tag" x="690" y="552" fill="var(--slate)">D6→IN3</text>
<text class="tag" x="838" y="544" fill="var(--slate)">D9→IN4</text>
<!-- Gru speech bubble (dynamic) -->
<g>
<rect x="726" y="676" width="210" height="60" rx="12" fill="#241d33" stroke="var(--amber)"/>
<path d="M726 712 l-16 -6 l14 -12 z" fill="#241d33" stroke="var(--amber)" stroke-width="1"/>
<text x="831" y="700" font-size="13" font-weight="bold" text-anchor="middle" fill="var(--amber)">MINIONS!</text>
<text id="speech" x="831" y="720" font-size="12" text-anchor="middle" fill="var(--ink)">Await orders…</text>
</g>
</svg>
<div class="key">
<span><span style="color:#b8b0d0"></span> zone wire (LED → OUT)</span>
<span><span style="color:var(--cyan)">▬→</span> active order · <span style="color:var(--slate)">▬ ▬</span> idle</span>
<span>· each minion sinks its zone to ground (ULN pin 9), see the pin map below</span>
</div>
</div>
<!-- ============ real pin map ============ -->
<div class="card">
<strong> The actual pin map</strong>
<table>
<tr><th>Zone</th><th>Gru says (Arduino)</th><th>Minion ear (ULN in)</th><th>Minion hand (ULN out)</th><th>Lights</th></tr>
<tr><td>GF_INT</td><td><code>D3</code></td><td>IN1 · pin 1</td><td>OUT1 · pin 18</td><td>2 white</td></tr>
<tr><td>UP_INT</td><td><code>D5</code></td><td>IN2 · pin 2</td><td>OUT2 · pin 17</td><td>3 white</td></tr>
<tr><td>EXT</td><td><code>D6</code></td><td>IN3 · pin 3</td><td>OUT3 · pin 16</td><td>5 white</td></tr>
<tr><td>FIRE</td><td><code>D9</code></td><td>IN4 · pin 4</td><td>OUT4 · pin 15</td><td>1 <b style="color:var(--red)">red</b></td></tr>
</table>
<p class="sm" style="margin:8px 0 0">No 1kΩ base resistors (built into the ULN). Each LED: <code>+5V → LED → 220Ω → OUTx</code>. Same sketch, same scenes.</p>
</div>
</div>
<script>
const ZONES = ['gf','up','ext','fire'];
const NAME = {gf:'the ground floor', up:'the upstairs', ext:'the exterior lights', fire:'the fireplace'};
const state = {gf:false, up:false, ext:false, fire:false};
let fireTick = 0;
const $ = s => document.querySelector(s);
const leds = z => document.querySelectorAll(`.led[data-zone="${z}"]`);
const glow = z => document.querySelector(`.glow[data-zone="${z}"]`);
function paintZone(z){
const on = state[z];
const isFire = z==='fire';
// fireplace flickers; others steady
let t = on ? 1 : 0;
if (on && isFire) t = 0.55 + 0.45*Math.abs(Math.sin(fireTick*0.9)) * (0.6+0.4*Math.random());
const rgb = isFire ? '255,70,50' : '255,248,236';
leds(z).forEach(el=>{
el.style.opacity = on ? (0.35 + 0.65*t).toFixed(2) : '0.12';
el.style.filter = on ? `drop-shadow(0 0 ${(4+8*t).toFixed(1)}px rgba(${rgb},${(0.9*t).toFixed(2)}))` : 'none';
});
glow(z).style.opacity = on ? (isFire ? 0.5*t : 0.42).toFixed(2) : '0';
// command wire
const w = $(`#wire-${z}`);
w.setAttribute('stroke', on ? 'var(--cyan)' : 'var(--slate)');
w.setAttribute('stroke-width', on ? '3' : '2.2');
w.setAttribute('stroke-dasharray', on ? '0' : '6 4');
w.style.color = on ? '#7fe0ff' : '#9aa6c8'; // arrowhead uses currentColor
w.style.opacity = on ? '1' : '0.45';
// pill
const pill = $(`#pill-${z}`), txt = $(`#pilltxt-${z}`);
const label = NAME[z].replace('the ','');
if (on){ pill.setAttribute('fill', isFire?'#2a1720':'#153a2a'); pill.setAttribute('stroke', isFire?'var(--red)':'var(--grn)');
txt.setAttribute('fill', isFire?'var(--red)':'#7ff0b0'); txt.textContent = `${label} · ON`; }
else { pill.setAttribute('fill','#241d33'); pill.setAttribute('stroke','var(--rule)');
txt.setAttribute('fill','var(--muted)'); txt.textContent = `${label} · off`; }
if (isFire) $('#torch').style.opacity = on ? t.toFixed(2) : '0';
}
function render(){ ZONES.forEach(paintZone); syncButtons(); }
function syncButtons(){
document.querySelectorAll('button.zone').forEach(b=>{
const z = b.dataset.cmd;
b.classList.toggle('on', z==='all' ? ZONES.every(k=>state[k]) : state[z]);
});
}
function say(msg){ $('#speech').textContent = msg; }
document.querySelectorAll('button').forEach(btn=>{
btn.onclick = () => {
const c = btn.dataset.cmd;
if (c==='all'){ const allOn = ZONES.every(z=>state[z]); ZONES.forEach(z=>state[z]=!allOn);
say(allOn ? 'Lights out!' : 'Light the whole house!'); }
else { state[c] = !state[c]; say(state[c] ? `Light ${NAME[c]}!` : `Turn off ${NAME[c]}!`); }
render();
};
});
// fireplace flicker loop
setInterval(()=>{ if(state.fire){ fireTick++; paintZone('fire'); } }, 90);
render();
</script>

246
presentation.html Normal file
View file

@ -0,0 +1,246 @@
<title>Watt a House! Class Presentation</title>
<style>
:root{ --bg:#fef9ee; --ink:#23262f; --muted:#6b6f7d; --card:#ffffff;
--yellow:#f7d33e; --yellow2:#d9b62f; --blue:#2f5b8c; --red:#e5463a;
--accent:#f6a723; --grn:#2f9e57; --rule:#e7e0d0; }
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--ink);
font:18px/1.5 "Trebuchet MS","Segoe UI",system-ui,sans-serif;overflow:hidden;}
.deck{height:100vh;display:flex;flex-direction:column;}
.stage{flex:1;display:flex;align-items:center;justify-content:center;padding:24px;overflow:hidden;}
.slide{display:none;width:100%;max-width:900px;text-align:center;}
.slide.active{display:block;animation:fade .3s ease;}
@keyframes fade{from{opacity:0;transform:translateY(8px)}to{opacity:1}}
h1{font-size:clamp(30px,6vw,58px);margin:.1em 0;line-height:1.05;}
h2{font-size:clamp(24px,5vw,44px);margin:.1em 0 .3em;}
p.big{font-size:clamp(19px,2.6vw,28px);color:var(--ink);margin:.4em auto;max-width:20em;}
.kicker{display:inline-block;background:var(--yellow);color:#3a2c00;font-weight:bold;
padding:6px 16px;border-radius:999px;font-size:16px;letter-spacing:.5px;margin-bottom:8px;}
ul.pts{list-style:none;padding:0;margin:14px auto;max-width:18em;text-align:left;}
ul.pts li{background:var(--card);border:2px solid var(--rule);border-radius:14px;
padding:12px 16px;margin:10px 0;font-size:clamp(17px,2.3vw,24px);display:flex;gap:12px;align-items:center;}
ol.steps{list-style:none;counter-reset:s;padding:0;margin:16px auto;max-width:20em;text-align:left;}
ol.steps li{counter-increment:s;background:var(--card);border:2px solid var(--rule);border-radius:14px;
padding:14px 16px 14px 58px;margin:12px 0;position:relative;font-size:clamp(17px,2.4vw,24px);}
ol.steps li::before{content:counter(s);position:absolute;left:12px;top:50%;transform:translateY(-50%);
width:32px;height:32px;background:var(--accent);color:#fff;border-radius:50%;
display:flex;align-items:center;justify-content:center;font-weight:bold;}
.art{margin:10px auto;}
svg.fig{display:block;margin:0 auto;height:clamp(160px,30vh,280px);width:auto;}
.demo{background:#fff7e6;border:3px dashed var(--accent);border-radius:20px;padding:22px;max-width:22em;margin:14px auto;}
.demo .file{font-family:ui-monospace,Menlo,monospace;background:#fdeecb;padding:2px 8px;border-radius:6px;}
.bar{display:flex;align-items:center;gap:14px;padding:10px 18px;border-top:2px solid var(--rule);background:#fffdf6;}
.note{flex:1;font-size:15px;color:#4a4030;background:#fff6dc;border:1px solid #f0dfa8;border-radius:10px;
padding:8px 14px;min-height:38px;}
.note b{color:#8a5a00;}
.note.hidden{visibility:hidden;}
.count{font-family:ui-monospace,Menlo,monospace;color:var(--muted);font-size:14px;min-width:56px;text-align:center;}
button{font:bold 16px inherit;border:0;border-radius:12px;padding:12px 20px;cursor:pointer;
background:var(--blue);color:#fff;}
button.ghost{background:#fff;color:var(--ink);border:2px solid var(--rule);}
button:active{transform:translateY(1px);}
.hint{color:var(--muted);font-size:13px;margin-top:16px;}
.row{display:flex;gap:18px;justify-content:center;flex-wrap:wrap;align-items:flex-end;margin-top:8px;}
.tagname{font-size:14px;color:var(--muted);margin-top:4px;}
</style>
<!-- ===== characters ===== -->
<svg width="0" height="0" style="position:absolute"><defs>
<symbol id="minion" viewBox="0 0 60 150">
<path d="M12 66 L6 18" stroke="var(--yellow2)" stroke-width="5"/><path d="M48 66 L54 18" stroke="var(--yellow2)" stroke-width="5"/>
<circle cx="6" cy="16" r="5" fill="var(--yellow)" stroke="var(--yellow2)" stroke-width="1.5"/>
<circle cx="54" cy="16" r="5" fill="var(--yellow)" stroke="var(--yellow2)" stroke-width="1.5"/>
<rect x="8" y="20" width="44" height="110" rx="22" fill="var(--yellow)" stroke="var(--yellow2)" stroke-width="2"/>
<path d="M24 20 l-2 -8 M30 19 l0 -9 M36 20 l2 -8" stroke="#2a2416" stroke-width="1.8" fill="none"/>
<rect x="6" y="42" width="48" height="13" fill="#8b9099"/><rect x="6" y="42" width="48" height="13" fill="none" stroke="#5a5f68"/>
<circle cx="30" cy="48.5" r="11" fill="#dfe3ea" stroke="#63687055" stroke-width="3"/>
<circle cx="30" cy="48.5" r="7" fill="#fff"/><circle cx="31" cy="48.5" r="3.2" fill="#3a2b1a"/>
<path d="M22 70 q8 7 16 0" stroke="#7a5b2a" stroke-width="1.6" fill="none"/>
<path d="M8 96 h44 v12 a22 22 0 0 1 -44 0 z" fill="var(--blue)"/>
<rect x="23" y="84" width="14" height="14" fill="var(--blue)"/>
<path d="M24 84 l-4 -12 M36 84 l4 -12" stroke="var(--blue)" stroke-width="3"/>
<rect x="14" y="128" width="14" height="12" rx="3" fill="#2a2a33"/><rect x="32" y="128" width="14" height="12" rx="3" fill="#2a2a33"/>
</symbol>
<symbol id="minion2" viewBox="0 0 60 150">
<path d="M12 66 L6 18" stroke="var(--yellow2)" stroke-width="5"/><path d="M48 66 L54 18" stroke="var(--yellow2)" stroke-width="5"/>
<circle cx="6" cy="16" r="5" fill="var(--yellow)" stroke="var(--yellow2)" stroke-width="1.5"/>
<circle cx="54" cy="16" r="5" fill="var(--yellow)" stroke="var(--yellow2)" stroke-width="1.5"/>
<rect x="8" y="20" width="44" height="110" rx="22" fill="var(--yellow)" stroke="var(--yellow2)" stroke-width="2"/>
<rect x="6" y="42" width="48" height="13" fill="#8b9099"/><rect x="6" y="42" width="48" height="13" fill="none" stroke="#5a5f68"/>
<line x1="30" y1="44" x2="30" y2="53" stroke="#5a5f68" stroke-width="1.4"/>
<circle cx="21" cy="48.5" r="8.5" fill="#dfe3ea" stroke="#63687055" stroke-width="2.5"/>
<circle cx="39" cy="48.5" r="8.5" fill="#dfe3ea" stroke="#63687055" stroke-width="2.5"/>
<circle cx="21" cy="48.5" r="5" fill="#fff"/><circle cx="39" cy="48.5" r="5" fill="#fff"/>
<circle cx="22" cy="48.5" r="2.3" fill="#3a2b1a"/><circle cx="40" cy="48.5" r="2.3" fill="#3a2b1a"/>
<path d="M22 70 q8 6 16 0" stroke="#7a5b2a" stroke-width="1.6" fill="none"/>
<path d="M8 96 h44 v12 a22 22 0 0 1 -44 0 z" fill="var(--blue)"/>
<rect x="23" y="84" width="14" height="14" fill="var(--blue)"/>
<path d="M24 84 l-4 -12 M36 84 l4 -12" stroke="var(--blue)" stroke-width="3"/>
<rect x="14" y="128" width="14" height="12" rx="3" fill="#2a2a33"/><rect x="32" y="128" width="14" height="12" rx="3" fill="#2a2a33"/>
</symbol>
<symbol id="gru" viewBox="0 0 130 210">
<path d="M42 92 Q39 98 34 122 L12 205 L118 205 L96 122 Q91 98 88 92 Z" fill="#3a3f4a" stroke="#242830" stroke-width="2"/>
<rect x="36" y="107" width="58" height="18" rx="9" fill="#31333b" transform="rotate(23 65 118)"/>
<rect x="36" y="107" width="58" height="18" rx="9" fill="#43464f" transform="rotate(-23 65 118)"/>
<circle cx="91" cy="108" r="6.5" fill="#d9bb9d"/><circle cx="39" cy="108" r="6.5" fill="#d9bb9d"/>
<path d="M39 72 Q65 87 91 72 L93 93 Q65 106 37 93 Z" fill="#9298a1" stroke="#585d66" stroke-width="1.5"/>
<path d="M38 78 Q65 92 92 78 M37 85 Q65 99 93 85 M38 91 Q65 104 92 91" stroke="#33363c" stroke-width="2.6" fill="none"/>
<path d="M80 93 l11 30 l-14 -3 l-1 -25 z" fill="#82878f"/>
<ellipse cx="64" cy="45" rx="29" ry="31" fill="#d9bb9d"/><ellipse cx="64" cy="30" rx="24" ry="16" fill="#e0c4a8"/>
<circle cx="35" cy="49" r="5" fill="#d9bb9d"/><circle cx="93" cy="49" r="5" fill="#d3b494"/>
<path d="M61 42 Q58 54 61 60 Q66 64 72 59 Q74 51 69 43 Z" fill="#d0ae8f"/>
<path d="M47 33 Q55 30 63 35 M82 37 Q75 33 68 36" stroke="#4a3b2a" stroke-width="2.6" fill="none" stroke-linecap="round"/>
<ellipse cx="57" cy="43" rx="5" ry="6.2" fill="#fff" stroke="#3a3a3a"/><ellipse cx="71" cy="43" rx="5" ry="6.2" fill="#fff" stroke="#3a3a3a"/>
<circle cx="58" cy="44" r="2.5" fill="#221"/><circle cx="71" cy="44" r="2.5" fill="#221"/>
<path d="M53 65 Q64 61 75 66" stroke="#7a5b48" stroke-width="2" fill="none"/>
</symbol>
<symbol id="house" viewBox="0 0 200 180">
<polygon points="100,20 186,92 14,92" fill="#c0553e"/>
<rect x="150" y="40" width="18" height="30" fill="#9a4432"/>
<rect x="30" y="92" width="140" height="80" fill="#f2c879" stroke="#c79a4a" stroke-width="2"/>
<rect x="86" y="128" width="28" height="44" rx="2" fill="#7a5230"/>
<circle cx="108" cy="150" r="2.5" fill="#ffd76a"/>
<rect class="win" x="44" y="106" width="26" height="26" rx="2" fill="#fff2c2" stroke="#c79a4a"/>
<rect class="win" x="130" y="106" width="26" height="26" rx="2" fill="#fff2c2" stroke="#c79a4a"/>
<rect class="win" x="44" y="140" width="26" height="24" rx="2" fill="#fff2c2" stroke="#c79a4a"/>
<rect class="win" x="130" y="140" width="26" height="24" rx="2" fill="#fff2c2" stroke="#c79a4a"/>
</symbol>
</defs></svg>
<div class="deck">
<div class="stage">
<!-- 1 -->
<section class="slide active" data-note="Hi everyone! My name is Sebastian. My project is called Watt a House, because a 'watt' is how we measure electricity! I'm going to show you my light-up house, and how I made it work with a little help from Gru and the Minions.">
<span class="kicker">MY PROJECT</span>
<h1>Watt a House!</h1>
<p class="big">How I made a tiny house turn its lights on and off, with help from <b>Gru</b> and the <b>Minions</b>!</p>
<svg class="fig" viewBox="0 0 200 180"><use href="#house"/></svg>
<p class="hint">By Sebastian Ballance · Third Year, Lower Elementary</p>
</section>
<!-- 2 -->
<section class="slide" data-note="This is a house, but it's special. The rooms REALLY light up! I can turn on the living room, the bedrooms, the porch outside, and even a fireplace.">
<h2>What I built </h2>
<p class="big">A house where I can turn on the lights!</p>
<ul class="pts">
<li> living room &amp; kitchen</li>
<li> bedrooms upstairs</li>
<li> porch &amp; outside lights</li>
<li> a fireplace that flickers</li>
</ul>
</section>
<!-- 3 -->
<section class="slide" data-note="Here's the tricky part. There are LOTS of tiny lights. Something has to tell them all when to turn on and off. So I needed a boss to give orders, and helpers to do the work, just like Gru and the Minions!">
<h2>The tricky part </h2>
<p class="big">How do you control <b>SO many</b> little lights at once?</p>
<p class="big">I needed a <b>boss</b> to give orders… and <b>helpers</b> to do the heavy work.</p>
</section>
<!-- 4 -->
<section class="slide" data-note="Meet the boss! This little computer is the brain of my house. I call him Gru. He decides what to do and gives the orders, but he is too weak to power all the lights by himself.">
<h2>Meet the boss: <span style="color:var(--blue)">GRU</span></h2>
<svg class="fig" viewBox="0 0 130 210"><use href="#gru"/></svg>
<ul class="pts">
<li> Gru is the <b>brain</b> (a tiny computer)</li>
<li> He gives the <b>orders</b></li>
<li> But he's too weak to do the heavy work himself!</li>
</ul>
</section>
<!-- 5 -->
<section class="slide" data-note="Meet the workers, the Minions! They live inside a little black chip. Each minion has ONE job: turn on one part of the house. When Gru gives an order, the right minion does the work.">
<h2>Meet the workers: the <span style="color:var(--yellow2)">Minions</span> </h2>
<div class="row art">
<div><svg class="fig" style="height:150px" viewBox="0 0 60 150"><use href="#minion"/></svg><div class="tagname">ground floor</div></div>
<div><svg class="fig" style="height:150px" viewBox="0 0 60 150"><use href="#minion2"/></svg><div class="tagname">upstairs</div></div>
<div><svg class="fig" style="height:150px" viewBox="0 0 60 150"><use href="#minion"/></svg><div class="tagname">outside</div></div>
<div><svg class="fig" style="height:150px" viewBox="0 0 60 150"><use href="#minion2"/></svg><div class="tagname">fireplace</div></div>
</div>
<p class="big">Each minion turns on <b>one part</b> of the house.</p>
</section>
<!-- 6 -->
<section class="slide" data-note="Here's how it works. Gru shouts an order, like 'turn on the outside lights!' The minion for the outside hears it and flips its switch. And the lights come on! Each minion listens for its own order.">
<h2>How it works </h2>
<ol class="steps">
<li>Gru shouts: <b>“Turn on the outside lights!”</b></li>
<li>That minion flips its switch </li>
<li>The lights glow! </li>
</ol>
</section>
<!-- 7 -->
<section class="slide" data-note="Now let me show you for real! (Open the Minions page.) Watch, when I click 'Fireplace,' Gru says it, the minion lights up, and the fireplace turns red and flickers like real fire. Let me try 'All lights' too!">
<h2>Let's try it! </h2>
<div class="demo">
<p class="big" style="margin-top:0">Open the <span class="file">Minions</span> page and click a button!</p>
<p style="margin:.4em 0 0">Try <b>“Exterior lights”</b> and <b>“Fireplace”</b> </p>
</div>
<p class="hint">(Grown-up: open <b>gru-wiring.html</b> for the live demo)</p>
</section>
<!-- 8 -->
<section class="slide" data-note="Here are the parts inside my house. The brain is the boss. The minion chip is the helpers. The LEDs are the little lights. Resistors keep the lights safe. A battery gives the power, and wires connect everything.">
<h2>What's inside </h2>
<ul class="pts">
<li> <b>Brain</b>, the boss (Gru)</li>
<li> <b>Chip</b>, the minions (helpers)</li>
<li> <b>LEDs</b>, the little lights</li>
<li> <b>Resistors</b>, keep the lights safe</li>
<li> <b>Battery</b>, the power</li>
<li> <b>Wires</b>, connect it all</li>
</ul>
</section>
<!-- 9 -->
<section class="slide" data-note="Four cool things I learned. One: electricity flows in a loop, like a race track, it has to go all the way around. Two: an LED is a tiny light that only works one way, so if you put it in backwards it stays dark! Three: a transistor is a tiny switch, and there are BILLIONS inside one chip, each smaller than a hair! Four: a resistor is like a seatbelt for the light, so it doesn't get too much power and burn out.">
<h2>4 cool things I learned</h2>
<ul class="pts">
<li>Electricity flows in a <b>loop</b>, like a race track</li>
<li>An <b>LED</b> is a tiny light that only works one way, backwards it stays dark!</li>
<li>A <b>transistor</b> is a tiny switch, a chip has <b>billions</b>, each smaller than a hair!</li>
<li>A <b>resistor</b> is a seatbelt for the light so it won't burn out</li>
</ul>
</section>
<!-- 10 -->
<section class="slide" data-note="And that's my light-up house! Thank you for watching. Does anyone have any questions?">
<span class="kicker"> THE END </span>
<h1>Thanks for watching!</h1>
<p class="big">Any questions? </p>
<svg class="fig" viewBox="0 0 60 150" style="height:200px"><use href="#minion"/></svg>
</section>
</div>
<div class="bar">
<button class="ghost" onclick="go(-1)">◀ Back</button>
<div class="note" id="note"></div>
<div class="count" id="count">1 / 10</div>
<button onclick="toggleNote()" class="ghost" title="Show/hide what to say">Notes</button>
<button onclick="go(1)">Next ▶</button>
</div>
</div>
<script>
const slides = [...document.querySelectorAll('.slide')];
const note = document.getElementById('note');
const count = document.getElementById('count');
let i = 0, showNote = true;
function render(){
slides.forEach((s,n)=>s.classList.toggle('active', n===i));
note.textContent = 'Say: ' + slides[i].dataset.note;
note.classList.toggle('hidden', !showNote);
count.textContent = (i+1) + ' / ' + slides.length;
}
function go(d){ i = Math.max(0, Math.min(slides.length-1, i+d)); render(); }
function toggleNote(){ showNote = !showNote; render(); }
document.onkeydown = e => {
if(e.key==='ArrowRight'||e.key===' '){ e.preventDefault(); go(1); }
else if(e.key==='ArrowLeft'){ go(-1); }
else if(e.key.toLowerCase()==='n'){ toggleNote(); }
};
render();
</script>

108
report.html Normal file
View file

@ -0,0 +1,108 @@
<title>Watt a House! Report</title>
<style>
:root{ --ink:#23262f; --muted:#6b6f7d; --yellow:#f7d33e; --yellow2:#d9b62f;
--blue:#2f5b8c; --red:#e5463a; --accent:#f6a723; --rule:#e2dcce; --paper:#fffdf7; }
*{box-sizing:border-box}
body{margin:0;background:#efe9db;color:var(--ink);
font:16px/1.6 "Trebuchet MS","Segoe UI",system-ui,sans-serif;padding:24px;}
.page{max-width:760px;margin:0 auto;background:var(--paper);border:1px solid var(--rule);
border-radius:14px;padding:40px 46px;box-shadow:0 6px 24px rgba(0,0,0,.08);}
header{text-align:center;border-bottom:3px solid var(--yellow);padding-bottom:14px;margin-bottom:18px;}
h1{font-size:32px;margin:.1em 0;}
.by{color:var(--muted);font-size:15px;}
h2{font-size:21px;color:var(--blue);margin:22px 0 6px;}
p{margin:8px 0;}
.lead{font-size:17px;}
.float{float:right;width:150px;margin:0 0 8px 18px;}
.float svg{width:100%;height:auto;}
.cap{font-size:12px;color:var(--muted);text-align:center;margin-top:2px;}
.cards{display:flex;gap:12px;flex-wrap:wrap;margin:10px 0;}
.cards div{flex:1 1 40%;background:#fff8e8;border:1px solid #f0e2b8;border-radius:10px;padding:8px 12px;font-size:15px;}
.learned{background:#f2f8f2;border:1px solid #cfe6d3;border-radius:12px;padding:6px 18px;margin-top:8px;}
.quote{background:#fff4dd;border-left:5px solid var(--accent);padding:10px 16px;border-radius:6px;font-style:italic;margin:12px 0;}
b.g{color:var(--blue);} b.m{color:var(--yellow2);}
footer{margin-top:24px;border-top:2px solid var(--rule);padding-top:12px;color:var(--muted);font-size:14px;text-align:center;}
@media print{ body{background:#fff;padding:0;} .page{box-shadow:none;border:0;border-radius:0;max-width:none;} }
</style>
<svg width="0" height="0" style="position:absolute"><defs>
<symbol id="minion" viewBox="0 0 60 150">
<path d="M12 66 L6 18" stroke="var(--yellow2)" stroke-width="5"/><path d="M48 66 L54 18" stroke="var(--yellow2)" stroke-width="5"/>
<circle cx="6" cy="16" r="5" fill="var(--yellow)" stroke="var(--yellow2)" stroke-width="1.5"/><circle cx="54" cy="16" r="5" fill="var(--yellow)" stroke="var(--yellow2)" stroke-width="1.5"/>
<rect x="8" y="20" width="44" height="110" rx="22" fill="var(--yellow)" stroke="var(--yellow2)" stroke-width="2"/>
<path d="M24 20 l-2 -8 M30 19 l0 -9 M36 20 l2 -8" stroke="#2a2416" stroke-width="1.8" fill="none"/>
<rect x="6" y="42" width="48" height="13" fill="#8b9099"/><rect x="6" y="42" width="48" height="13" fill="none" stroke="#5a5f68"/>
<circle cx="30" cy="48.5" r="11" fill="#dfe3ea" stroke="#63687055" stroke-width="3"/><circle cx="30" cy="48.5" r="7" fill="#fff"/><circle cx="31" cy="48.5" r="3.2" fill="#3a2b1a"/>
<path d="M22 70 q8 7 16 0" stroke="#7a5b2a" stroke-width="1.6" fill="none"/>
<path d="M8 96 h44 v12 a22 22 0 0 1 -44 0 z" fill="var(--blue)"/><rect x="23" y="84" width="14" height="14" fill="var(--blue)"/><path d="M24 84 l-4 -12 M36 84 l4 -12" stroke="var(--blue)" stroke-width="3"/>
<rect x="14" y="128" width="14" height="12" rx="3" fill="#2a2a33"/><rect x="32" y="128" width="14" height="12" rx="3" fill="#2a2a33"/>
</symbol>
<symbol id="gru" viewBox="0 0 130 210">
<path d="M42 92 Q39 98 34 122 L12 205 L118 205 L96 122 Q91 98 88 92 Z" fill="#3a3f4a" stroke="#242830" stroke-width="2"/>
<rect x="36" y="107" width="58" height="18" rx="9" fill="#31333b" transform="rotate(23 65 118)"/><rect x="36" y="107" width="58" height="18" rx="9" fill="#43464f" transform="rotate(-23 65 118)"/>
<circle cx="91" cy="108" r="6.5" fill="#d9bb9d"/><circle cx="39" cy="108" r="6.5" fill="#d9bb9d"/>
<path d="M39 72 Q65 87 91 72 L93 93 Q65 106 37 93 Z" fill="#9298a1" stroke="#585d66" stroke-width="1.5"/>
<path d="M38 78 Q65 92 92 78 M37 85 Q65 99 93 85 M38 91 Q65 104 92 91" stroke="#33363c" stroke-width="2.6" fill="none"/>
<path d="M80 93 l11 30 l-14 -3 l-1 -25 z" fill="#82878f"/>
<ellipse cx="64" cy="45" rx="29" ry="31" fill="#d9bb9d"/><ellipse cx="64" cy="30" rx="24" ry="16" fill="#e0c4a8"/>
<circle cx="35" cy="49" r="5" fill="#d9bb9d"/><circle cx="93" cy="49" r="5" fill="#d3b494"/>
<path d="M61 42 Q58 54 61 60 Q66 64 72 59 Q74 51 69 43 Z" fill="#d0ae8f"/>
<path d="M47 33 Q55 30 63 35 M82 37 Q75 33 68 36" stroke="#4a3b2a" stroke-width="2.6" fill="none" stroke-linecap="round"/>
<ellipse cx="57" cy="43" rx="5" ry="6.2" fill="#fff" stroke="#3a3a3a"/><ellipse cx="71" cy="43" rx="5" ry="6.2" fill="#fff" stroke="#3a3a3a"/>
<circle cx="58" cy="44" r="2.5" fill="#221"/><circle cx="71" cy="44" r="2.5" fill="#221"/>
<path d="M53 65 Q64 61 75 66" stroke="#7a5b48" stroke-width="2" fill="none"/>
</symbol>
</defs></svg>
<div class="page">
<header>
<h1>Watt a House!</h1>
<div class="by">By Sebastian Ballance &nbsp;·&nbsp; Third Year, Lower Elementary &nbsp;·&nbsp; Science Project</div>
</header>
<p class="lead">I built a house where the rooms really light up! I can turn on the living room, the bedrooms, the porch outside, and even a fireplace that flickers like real fire. I can turn them on one at a time, or all at once.</p>
<h2>The problem</h2>
<div class="float">
<svg viewBox="0 0 130 210"><use href="#gru"/></svg>
<div class="cap">Gru = the brain</div>
</div>
<p>My house has lots of tiny lights. Something has to tell them all when to turn on and off. So I used a <b>boss</b> to give the orders and <b>helpers</b> to do the heavy work. To make it easy to understand, I think about them like <b class="g">Gru</b> and the <b class="m">Minions</b> from the movie!</p>
<h2>Gru is the boss</h2>
<p>The brain of my house is a tiny computer called an <b>Arduino</b>. I call it <b class="g">Gru</b>. Gru is smart and gives all the orders, like <i>“turn on the outside lights!”</i> But Gru is too weak to power all the lights by himself. He needs helpers.</p>
<h2>The Minions do the work</h2>
<div class="float">
<svg viewBox="0 0 60 150" style="width:80px;display:block;margin:0 auto"><use href="#minion"/></svg>
<div class="cap">A minion = one switch</div>
</div>
<p>The helpers live inside a little black chip (its real name is a <b>ULN2803A</b>). I think of them as <b class="m">minions</b>. Each minion has one job: turn on one part of the house. When Gru shouts an order, the right minion flips its switch and lets the electricity through. That makes the lights glow!</p>
<div class="quote">Gru shouts the order, the minion flips the switch, the lights turn on!</div>
<h2>What's inside</h2>
<div class="cards">
<div><b>Brain (Arduino)</b>, the boss</div>
<div><b>Chip</b>, the minions</div>
<div><b>LEDs</b>, the little lights</div>
<div><b>Resistors</b>, keep lights safe</div>
<div><b>Battery</b>, the power</div>
<div><b>Wires</b>, connect everything</div>
</div>
<h2>What I would like to teach you</h2>
<div class="learned">
<p><b>Electricity flows in a loop</b>, like a race track. It has to go all the way around to work.</p>
<p>An <b>LED</b> is a tiny light. It only works one way, so if you put it in backwards it stays dark! LED is short for <b>Light Emitting Diode</b>.</p>
<p>A <b>transistor</b> is a tiny switch. There are <b>billions</b> of them inside one chip, and each one is smaller than a human hair!</p>
<p>A <b>resistor</b> is like a seatbelt for a light. It stops the light from getting too much power and burning out.</p>
</div>
<h2>The best part</h2>
<p>My favorite part is the <b>fireplace</b>. It uses a red light that flickers, so it looks like a real fire in the house. When I press the button, Gru tells the fireplace minion to turn it on!</p>
<footer>
Thank you for reading about my light-up house!
</footer>
</div>

224
simulator.html Normal file
View file

@ -0,0 +1,224 @@
<title>House Lighting, Simulator</title>
<style>
:root{ --warm:#f3efe6; --warmcore:#ffffff; --fire:#ff3d2e; --firecore:#ff6a4d;
--panel:#141821; --panel2:#1b2130;
--ink:#e8eaf0; --muted:#8b93a6; --rule:#2a3142; --accent:#ffb765; }
*{box-sizing:border-box}
body{margin:0;background:#0a0c12;color:var(--ink);
font:15px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;padding:20px;}
.wrap{max-width:940px;margin:0 auto;}
h1{font-size:19px;margin:0 0 2px;} .sub{color:var(--muted);font-size:13px;margin:0 0 16px;}
.grid{display:grid;grid-template-columns:1.3fr 1fr;gap:18px;align-items:start;}
@media(max-width:760px){.grid{grid-template-columns:1fr;}}
.stage{background:linear-gradient(#0e1430 0%,#141a3a 45%,#20264a 100%);
border:1px solid var(--rule);border-radius:14px;overflow:hidden;position:relative;}
svg{display:block;width:100%;height:auto;}
.panel{background:var(--panel);border:1px solid var(--rule);border-radius:14px;padding:16px;}
.scene-name{font-size:22px;font-weight:700;letter-spacing:.3px;}
.scene-sub{color:var(--muted);font-size:12px;margin-bottom:14px;}
.row{display:flex;align-items:center;gap:10px;margin:9px 0;font-size:13px;}
.tag{font-family:ui-monospace,Menlo,monospace;font-size:11px;color:var(--muted);width:96px;flex:none;}
.bar{flex:1;height:10px;background:var(--panel2);border-radius:6px;overflow:hidden;}
.fill{height:100%;width:0;background:linear-gradient(90deg,#7a4a12,var(--warm));transition:width .06s linear;}
.val{font-family:ui-monospace,Menlo,monospace;font-size:12px;width:34px;text-align:right;color:var(--ink);}
.btns{display:flex;gap:10px;margin-top:16px;flex-wrap:wrap;}
button{font:600 14px/1 inherit;color:#1a1205;background:var(--accent);border:0;
padding:11px 16px;border-radius:10px;cursor:pointer;}
button.ghost{background:transparent;color:var(--ink);border:1px solid var(--rule);}
button:active{transform:translateY(1px);}
.idle{display:flex;align-items:center;gap:10px;margin-top:16px;font-size:12px;color:var(--muted);}
.idle input{flex:1;}
.idlebar{height:4px;background:var(--panel2);border-radius:3px;margin-top:6px;overflow:hidden;}
.idlefill{height:100%;background:var(--muted);width:100%;}
.banner{margin-top:12px;padding:8px 12px;border-radius:8px;background:#2a1f10;color:var(--accent);
font-size:12.5px;display:none;}
.legend{margin-top:14px;font-size:11.5px;color:var(--muted);line-height:1.7;}
.legend b{color:var(--ink);font-weight:600;}
.hint{color:var(--muted);font-size:11.5px;margin-top:10px;}
</style>
<div class="wrap">
<h1>House Lighting, live simulator</h1>
<p class="sub">Runs the same logic as <code style="color:var(--muted)">townhouse_lights.ino</code>: scenes, PWM brightness, fireplace flicker, idle auto-off, boot self-check.</p>
<div class="grid">
<div class="stage">
<svg viewBox="0 0 360 380" role="img" aria-label="House with switchable lights">
<!-- moon -->
<circle cx="312" cy="42" r="16" fill="#e7ecff" opacity=".85"/>
<circle cx="306" cy="38" r="16" fill="#141a3a" opacity=".6"/>
<!-- ground -->
<rect x="0" y="338" width="360" height="42" fill="#0b1022"/>
<!-- house body -->
<rect x="70" y="150" width="220" height="190" fill="#242b3d"/>
<!-- roof -->
<polygon points="58,152 180,86 302,152" fill="#1c2233"/>
<!-- attic dormer -->
<polygon points="150,120 180,100 210,120" fill="#222a3c"/>
<rect x="164" y="118" width="32" height="26" fill="#2a3247"/>
<!-- chimney -->
<rect x="234" y="96" width="22" height="40" fill="#1a2030"/>
<!-- ==== EXTERIOR lights (data-zone=ext) ==== -->
<!-- porch lamp left of door -->
<circle class="light" data-zone="ext" cx="150" cy="286" r="7" fill="var(--warmcore)"/>
<!-- entry door glow -->
<rect class="light" data-zone="ext" x="166" y="290" width="28" height="50" rx="2" fill="var(--warm)"/>
<!-- porch lamp right -->
<circle class="light" data-zone="ext" cx="210" cy="286" r="7" fill="var(--warmcore)"/>
<!-- deck / side light -->
<circle class="light" data-zone="ext" cx="286" cy="300" r="6" fill="var(--warmcore)"/>
<!-- balcony light (upper) -->
<circle class="light" data-zone="ext" cx="96" cy="214" r="6" fill="var(--warmcore)"/>
<!-- ==== GROUND FLOOR interior (data-zone=gf) ==== -->
<rect class="light" data-zone="gf" x="92" y="270" width="40" height="40" rx="3" fill="var(--warm)"/>
<rect class="light" data-zone="gf" x="228" y="270" width="40" height="40" rx="3" fill="var(--warm)"/>
<!-- ==== UPSTAIRS interior (data-zone=up) ==== -->
<rect class="light" data-zone="up" x="96" y="176" width="38" height="40" rx="3" fill="var(--warm)"/>
<rect class="light" data-zone="up" x="226" y="176" width="38" height="40" rx="3" fill="var(--warm)"/>
<rect class="light" data-zone="up" x="166" y="120" width="28" height="24" rx="2" fill="var(--warm)"/>
<!-- ==== FIREPLACE (data-zone=fire) ==== -->
<rect class="light" data-zone="fire" x="168" y="312" width="24" height="26" rx="2" fill="var(--firecore)"/>
<circle class="light" data-zone="fire" cx="245" cy="96" r="9" fill="var(--fire)"/>
<!-- window frames (static, drawn over glow faintly) -->
<g stroke="#0e1322" stroke-width="2" opacity=".5" fill="none">
<line x1="112" y1="270" x2="112" y2="310"/><line x1="248" y1="270" x2="248" y2="310"/>
<line x1="115" y1="176" x2="115" y2="216"/><line x1="245" y1="176" x2="245" y2="216"/>
</g>
</svg>
</div>
<div class="panel">
<div class="scene-name" id="sceneName">Evening</div>
<div class="scene-sub" id="sceneSub">scene 1 of 4 · press the button to cycle</div>
<div class="row"><span class="tag">GF_INT · D3</span><div class="bar"><div class="fill" id="f_gf"></div></div><span class="val" id="v_gf">0</span></div>
<div class="row"><span class="tag">UP_INT · D5</span><div class="bar"><div class="fill" id="f_up"></div></div><span class="val" id="v_up">0</span></div>
<div class="row"><span class="tag">EXT · D6</span><div class="bar"><div class="fill" id="f_ext"></div></div><span class="val" id="v_ext">0</span></div>
<div class="row"><span class="tag">FIRE · D9</span><div class="bar"><div class="fill" id="f_fire"></div></div><span class="val" id="v_fire">0</span></div>
<div class="btns">
<button id="btnScene">⏻ Scene button (D2), next scene</button>
<button class="ghost" id="btnSect">◐ Section button (D4), spotlight next zone</button>
<button class="ghost" id="btnBoot">▶ Reset (boot self-check)</button>
</div>
<div class="idle">
<span>idle&nbsp;off</span>
<input type="range" id="idleSlider" min="5" max="60" value="20">
<span id="idleLbl" style="width:70px;text-align:right">20 s</span>
</div>
<div class="idlebar"><div class="idlefill" id="idleFill"></div></div>
<div class="banner" id="banner">💤 Idle, faded dark. Press the button to wake.</div>
<div class="legend">
<b>Scenes:</b> Evening → All&nbsp;On → Night → Off<br>
<b>Fireplace</b> flickers <code>55 + random(0,130)</code> each frame when its scene has fire on.<br>
<b>Idle:</b> slider stands in for the firmware's real <code>20&nbsp;min</code> auto-off.
</div>
<div class="hint">Tip: press <b>Space</b> to cycle scenes.</div>
</div>
</div>
</div>
<script>
// ---- scene table (mirrors townhouse_lights.ino) ----
const scenes = [
{name:'Evening', sub:'cozy, fire lit', gf:60, up:40, ext:140, fire:true},
{name:'All On', sub:'everything up', gf:90, up:90, ext:120, fire:true},
{name:'Night', sub:'porch + embers', gf:0, up:0, ext:30, fire:true},
{name:'Off', sub:'dark', gf:0, up:0, ext:0, fire:false},
];
let idx = 0;
let lastActive = performance.now();
let idleMs = 20000;
let booting = false;
let bootVals = null;
// section spotlight, mirrors BTN_SECT / applySpotlight() in townhouse_lights.ino
let mode = 'scene'; // 'scene' | 'section'
let sectIdx = 0; // 0=GF 1=UP 2=EXT 3=FIRE 4=all off
const MAN = {gf:90, up:90, ext:120}; // spotlight brightness, matches the .ino
const SECT_LBL = ['GF only','UP only','EXT only','FIRE only','all off'];
const $ = id => document.getElementById(id);
const idleSlider = $('idleSlider');
idleSlider.oninput = () => { idleMs = idleSlider.value*1000; $('idleLbl').textContent = idleSlider.value+' s'; };
function cycle(){ mode='scene'; idx = (idx+1) % scenes.length; lastActive = performance.now(); }
$('btnScene').onclick = cycle;
document.onkeydown = e => { if(e.code==='Space'){ e.preventDefault(); cycle(); } };
// section button: spotlight one zone at a time, then all off (matches D4 in firmware)
$('btnSect').onclick = () => { mode='section'; sectIdx = (sectIdx+1) % 5; lastActive = performance.now(); };
// boot self-check: pulse each zone in turn, then resume
$('btnBoot').onclick = () => {
if (booting) return;
booting = true; idx = 0; lastActive = performance.now();
const seq = ['gf','up','ext','fire'];
let i = 0;
const step = () => {
if (i >= seq.length){ booting = false; bootVals = null; return; }
bootVals = {gf:0,up:0,ext:0,fire:0}; bootVals[seq[i]] = 120;
i++; setTimeout(step, 220);
};
step();
};
// ---- render one zone's glow ----
function paint(zone, v){
// perceptual curve: a dim LED reads brighter than its raw duty cycle (e.g. Night porch at 30/255)
const t = Math.pow(Math.max(0, Math.min(1, v/255)), 0.55);
const glow = zone==='fire' ? '255,70,50' : '255,248,236'; // fire = red, rest = white
document.querySelectorAll(`[data-zone="${zone}"]`).forEach(el=>{
el.style.opacity = (0.05 + 0.95*t).toFixed(3);
el.style.filter = t>0.02
? `drop-shadow(0 0 ${(3+18*t).toFixed(1)}px rgba(${glow},${(0.85*t).toFixed(2)}))`
: 'none';
});
}
function bar(id,v){ $('f_'+id).style.width = (v/255*100)+'%'; $('v_'+id).textContent = Math.round(v); }
// ---- main loop ~33 Hz ----
function loop(){
let gf,up,ext,fireOn,fireV;
const idle = !booting && (performance.now()-lastActive > idleMs);
if (booting && bootVals){
({gf,up,ext} = bootVals); fireV = bootVals.fire; fireOn = bootVals.fire>0;
$('sceneName').textContent = 'Self-check…'; $('sceneSub').textContent = 'pulsing each zone in turn';
$('banner').style.display='none';
} else if (mode==='section'){
gf = idle?0:(sectIdx===0 ? MAN.gf : 0);
up = idle?0:(sectIdx===1 ? MAN.up : 0);
ext = idle?0:(sectIdx===2 ? MAN.ext : 0);
fireOn = !idle && sectIdx===3;
fireV = fireOn ? (55 + Math.floor(Math.random()*130)) : 0;
$('sceneName').textContent = idle ? 'Off (idle)' : 'Spotlight';
$('sceneSub').textContent = idle ? 'auto-faded dark' : SECT_LBL[sectIdx];
$('banner').style.display = idle ? 'block':'none';
} else {
const s = scenes[idx];
gf = idle?0:s.gf; up = idle?0:s.up; ext = idle?0:s.ext;
fireOn = idle?false:s.fire;
fireV = fireOn ? (55 + Math.floor(Math.random()*130)) : 0;
$('sceneName').textContent = idle ? 'Off (idle)' : s.name;
$('sceneSub').textContent = idle ? 'auto-faded dark' : `scene ${idx+1} of 4 · ${s.sub}`;
$('banner').style.display = idle ? 'block':'none';
}
paint('gf',gf); paint('up',up); paint('ext',ext); paint('fire',fireV);
bar('gf',gf); bar('up',up); bar('ext',ext); bar('fire',fireV);
// idle countdown bar
const remain = booting ? 1 : Math.max(0, 1-(performance.now()-lastActive)/idleMs);
$('idleFill').style.width = (remain*100)+'%';
requestAnimationFrame(loop);
}
loop();
</script>

View file

@ -0,0 +1,88 @@
// Townhouse dollhouse lighting, Arduino Uno R3, discrete zone outputs (no addressable data line).
// Each zone = one PWM pin -> 1k -> PN2222 base; transistor sinks that zone's LEDs to ground.
// Each LED has its own ~200-220 ohm series resistor: +5V -> LED -> R -> transistor collector.
// FIRE zone uses a RED LED; all other zones warm-white/white. (Color is hardware only, no code change.)
// No library needed.
#define PIN_GF 3 // ground-floor interior (living + kitchen ceilings) -> Q1 base via 1k
#define PIN_UP 5 // upstairs interior (bedrooms + attic) -> Q2 base via 1k
#define PIN_EXT 6 // exterior (porch, entry, deck, balcony) -> Q3 base via 1k
#define PIN_FIRE 9 // fireplace / hearth (red) -> Q4 base via 1k
#define BTN_PIN 2 // momentary button to GND: cycles scenes / wakes
#define BTN_SECT 4 // momentary button to GND: spotlight one zone at a time (GF->UP->EXT->FIRE->off)
#define IDLE_OFF_MS (20UL * 60UL * 1000UL) // cordless: fade dark after 20 min idle
// Per-zone brightness 0-255. Dollhouse rooms read best DIM, this is your knob
// (or raise the LED series resistors to knock brightness back in hardware).
uint8_t gGF, gUP, gEXT;
bool fireOn;
// ---- Scenes ---------------------------------------------------------------
void sceneEvening(){ gGF = 60; gUP = 40; gEXT = 140; fireOn = true; } // cozy, fire lit
void sceneAllOn() { gGF = 90; gUP = 90; gEXT = 120; fireOn = true; }
void sceneNight() { gGF = 0; gUP = 0; gEXT = 30; fireOn = true; } // porch + embers
void sceneOff() { gGF = 0; gUP = 0; gEXT = 0; fireOn = false; }
typedef void (*Scene)();
Scene scenes[] = {sceneEvening, sceneAllOn, sceneNight, sceneOff};
const uint8_t N_SCENES = sizeof(scenes) / sizeof(scenes[0]);
uint8_t sceneIdx = 0;
unsigned long lastActive = 0;
// ---- Section spotlight ----------------------------------------------------
// BTN_SECT lights exactly ONE zone at a time, then all off, then repeats.
uint8_t sectIdx = 0; // 0=GF 1=UP 2=EXT 3=FIRE 4=all off
const uint8_t N_SECT = 5;
void applySpotlight(uint8_t i){
gGF = (i == 0) ? 90 : 0;
gUP = (i == 1) ? 90 : 0;
gEXT = (i == 2) ? 120 : 0;
fireOn = (i == 3);
}
void setup() {
pinMode(PIN_GF, OUTPUT); pinMode(PIN_UP, OUTPUT);
pinMode(PIN_EXT, OUTPUT); pinMode(PIN_FIRE, OUTPUT);
pinMode(BTN_PIN, INPUT_PULLUP);
pinMode(BTN_SECT, INPUT_PULLUP);
// Power-on self-check: pulse each output in turn, so a dead zone shows itself immediately.
const uint8_t pins[] = {PIN_GF, PIN_UP, PIN_EXT, PIN_FIRE};
for (uint8_t i = 0; i < 4; i++) { analogWrite(pins[i], 120); delay(220); analogWrite(pins[i], 0); }
scenes[sceneIdx]();
lastActive = millis();
}
void loop() {
// Button: cycle scene + reset idle timer.
static bool prev = HIGH;
bool now = digitalRead(BTN_PIN);
if (prev == HIGH && now == LOW) {
sceneIdx = (sceneIdx + 1) % N_SCENES;
scenes[sceneIdx]();
lastActive = millis();
delay(30); // debounce
}
prev = now;
// Section button: spotlight one zone at a time (GF -> UP -> EXT -> FIRE -> off).
static bool prevS = HIGH;
bool nowS = digitalRead(BTN_SECT);
if (prevS == HIGH && nowS == LOW) {
sectIdx = (sectIdx + 1) % N_SECT;
applySpotlight(sectIdx);
lastActive = millis();
delay(30); // debounce
}
prevS = nowS;
// Cordless battery saver.
if (millis() - lastActive > IDLE_OFF_MS) sceneOff();
analogWrite(PIN_GF, gGF);
analogWrite(PIN_UP, gUP);
analogWrite(PIN_EXT, gEXT);
// Fireplace: amber-ish flicker around a low base when on.
analogWrite(PIN_FIRE, fireOn ? (55 + random(0, 130)) : 0);
delay(30); // ~33 Hz, smooth flicker, snappy button
}

153
transistor-stage0.html Normal file
View file

@ -0,0 +1,153 @@
<title>Transistor Stage 0, One Zone</title>
<style>
:root{
--bg:#faf8f4; --ink:#1c1a17; --muted:#6b6459; --card:#fff;
--line:#3a352e; --red:#c0392b; --grn:#2e7d32; --slate:#5b6b7a;
--amber:#c98a1a; --rule:#d8d2c7;
}
@media (prefers-color-scheme:dark){
:root{ --bg:#17150f; --ink:#eee7d9; --muted:#a49a88; --card:#211e17;
--line:#c9c2b4; --red:#e5675a; --grn:#6bbf70; --slate:#8fa3b5;
--amber:#e0b24e; --rule:#3a352b; }
}
:root[data-theme=light]{ --bg:#faf8f4;--ink:#1c1a17;--muted:#6b6459;--card:#fff;
--line:#3a352e;--red:#c0392b;--grn:#2e7d32;--slate:#5b6b7a;--amber:#c98a1a;--rule:#d8d2c7; }
:root[data-theme=dark]{ --bg:#17150f;--ink:#eee7d9;--muted:#a49a88;--card:#211e17;
--line:#c9c2b4;--red:#e5675a;--grn:#6bbf70;--slate:#8fa3b5;--amber:#e0b24e;--rule:#3a352b; }
body{background:var(--bg);color:var(--ink);
font:15px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
margin:0;padding:24px;}
.wrap{max-width:860px;margin:0 auto;}
h1{font-size:20px;margin:0 0 2px;}
.sub{color:var(--muted);margin:0 0 18px;font-size:13px;}
.card{background:var(--card);border:1px solid var(--rule);border-radius:12px;
padding:16px;margin-bottom:18px;}
.scroll{overflow-x:auto;}
svg{display:block;margin:0 auto;max-width:100%;height:auto;}
text{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;fill:var(--ink);}
.lbl{font-size:13px;} .sm{font-size:11px;fill:var(--muted);}
.wire{stroke:var(--line);stroke-width:2.2;fill:none;}
.w5{stroke:var(--red);stroke-width:3;fill:none;}
.wg{stroke:var(--line);stroke-width:3;fill:none;}
.wsig{stroke:var(--slate);stroke-width:2.2;fill:none;stroke-dasharray:6 4;}
.node{fill:var(--line);}
.box{fill:none;stroke:var(--line);stroke-width:2;}
.chip{fill:var(--card);stroke:var(--line);stroke-width:2;}
table{border-collapse:collapse;width:100%;font-size:13px;margin-top:4px;}
th,td{border:1px solid var(--rule);padding:6px 10px;text-align:left;}
th{background:rgba(128,128,128,.08);}
code{font-family:ui-monospace,Menlo,monospace;background:rgba(128,128,128,.12);
padding:1px 5px;border-radius:4px;font-size:.92em;}
.key{display:flex;gap:18px;flex-wrap:wrap;font-size:12px;color:var(--muted);margin-top:8px;}
.key span{display:inline-flex;align-items:center;gap:6px;}
.sw{width:22px;height:0;border-top:3px solid;}
</style>
<div class="wrap">
<h1>Transistor Stage 0, one zone (GF / D3)</h1>
<p class="sub">PN2222 low-side switch · clone ×4 for the other pins · Arduino Uno R3</p>
<div class="card scroll">
<svg viewBox="0 0 780 440" role="img" aria-label="One-zone transistor LED driver schematic">
<!-- +5V rail -->
<line class="w5" x1="150" y1="40" x2="720" y2="40"/>
<text class="lbl" x="150" y="30" fill="var(--red)">+5V rail</text>
<!-- GND rail -->
<line class="wg" x1="150" y1="400" x2="720" y2="400"/>
<text class="lbl" x="150" y="422">GND rail</text>
<!-- Arduino block -->
<rect class="box" x="30" y="120" width="90" height="200" rx="8"/>
<text class="lbl" x="52" y="112">Uno</text>
<!-- pins -->
<text class="lbl" x="46" y="150">5V</text>
<line class="w5" x1="120" y1="145" x2="150" y2="145"/>
<line class="w5" x1="150" y1="145" x2="150" y2="40"/>
<circle class="node" cx="150" cy="40" r="3.5"/>
<text class="lbl" x="46" y="205">D3</text>
<line class="wsig" x1="120" y1="200" x2="300" y2="200"/>
<text class="lbl" x="46" y="265">D2</text>
<line class="wire" x1="120" y1="260" x2="600" y2="260"/>
<text class="lbl" x="40" y="315">GND</text>
<line class="wg" x1="120" y1="310" x2="150" y2="310"/>
<line class="wg" x1="150" y1="310" x2="150" y2="400"/>
<circle class="node" cx="150" cy="400" r="3.5"/>
<!-- 1k base resistor along D3 line -->
<rect class="chip" x="300" y="190" width="60" height="20" rx="4"/>
<text class="sm" x="308" y="204">1kΩ</text>
<line class="wsig" x1="360" y1="200" x2="470" y2="200"/>
<!-- PN2222 -->
<circle class="chip" cx="510" cy="200" r="34"/>
<text class="lbl" x="486" y="205">Q1</text>
<text class="sm" x="470" y="250">PN2222</text>
<!-- base lead -->
<line class="wire" x1="470" y1="200" x2="476" y2="200"/>
<text class="sm" x="452" y="188">B</text>
<!-- collector up -->
<line class="wire" x1="510" y1="166" x2="510" y2="120"/>
<text class="sm" x="518" y="150">C</text>
<!-- emitter down to GND -->
<line class="wg" x1="510" y1="234" x2="510" y2="400"/>
<text class="sm" x="518" y="255">E → GND</text>
<circle class="node" cx="510" cy="400" r="3.5"/>
<!-- LED + 220 from +5V down to collector -->
<!-- from +5V rail down -->
<line class="w5" x1="620" y1="40" x2="620" y2="70"/>
<circle class="node" cx="620" cy="40" r="3.5"/>
<!-- LED symbol (triangle + bar) -->
<polygon points="606,70 634,70 620,96" fill="none" stroke="var(--amber)" stroke-width="2"/>
<line x1="606" y1="96" x2="634" y2="96" stroke="var(--amber)" stroke-width="2.5"/>
<text class="sm" x="640" y="86" fill="var(--amber)">LED</text>
<text class="sm" x="640" y="99">warm white</text>
<text class="sm" x="560" y="66">anode +</text>
<line class="wire" x1="620" y1="96" x2="620" y2="112"/>
<!-- 220 resistor -->
<rect class="chip" x="590" y="112" width="60" height="20" rx="4"/>
<text class="sm" x="596" y="126">220Ω</text>
<!-- down to collector node -->
<line class="wire" x1="620" y1="132" x2="620" y2="120"/>
<line class="wire" x1="620" y1="120" x2="510" y2="120"/>
<circle class="node" cx="510" cy="120" r="3.5"/>
<!-- button on D2 to GND -->
<line class="wire" x1="600" y1="260" x2="600" y2="300"/>
<rect class="box" x="580" y="300" width="40" height="26" rx="4"/>
<text class="sm" x="588" y="317">BTN</text>
<line class="wg" x1="600" y1="326" x2="600" y2="400"/>
<circle class="node" cx="600" cy="400" r="3.5"/>
<text class="sm" x="628" y="285">D2 → button → GND</text>
<!-- current path note -->
<text class="sm" x="150" y="60">current: +5V → LED → 220Ω → collector → (Q1) → emitter → GND</text>
</svg>
<div class="key">
<span><span class="sw" style="border-color:var(--red)"></span>+5V</span>
<span><span class="sw" style="border-color:var(--line)"></span>GND / wire</span>
<span><span class="sw" style="border-color:var(--slate);border-top-style:dashed"></span>signal (PWM)</span>
<span><span class="sw" style="border-color:var(--amber)"></span>LED</span>
</div>
</div>
<div class="card">
<strong>Then clone the transistor block ×4</strong>, same wiring, just change the Arduino pin:
<table>
<tr><th>Zone</th><th>Arduino pin → 1kΩ → base</th><th>Fixtures</th></tr>
<tr><td>GF_INT</td><td><code>D3</code></td><td>living + kitchen ceilings</td></tr>
<tr><td>UP_INT</td><td><code>D5</code></td><td>bedrooms + attic</td></tr>
<tr><td>EXT</td><td><code>D6</code></td><td>porch, entry, deck, balcony</td></tr>
<tr><td>FIRE</td><td><code>D9</code></td><td>hearth (flicker)</td></tr>
</table>
<p class="sm" style="margin:10px 0 0">Each zone shares the same <code>+5V</code> and <code>GND</code> rails.
Add more LEDs to a zone by putting each one (anode→+5V, cathode→220Ω→collector) in parallel on that transistor.</p>
</div>
<div class="card">
<strong>PN2222 leg order</strong>, flat face toward you, legs down: <code>E · B · C</code> (left→right).
If nothing lights, swap E↔C, that's the usual culprit and it's harmless.
</div>
</div>

316
wiring-reference.html Normal file
View file

@ -0,0 +1,316 @@
<title>House Lighting, Wiring Reference</title>
<style>
* { box-sizing:border-box; -webkit-print-color-adjust:exact; print-color-adjust:exact; }
@page { size:Letter; margin:14mm; }
:root {
--paper:#fff; --ink:#1C1B18; --muted:#6E6A62; --line:#DED8CC; --line-strong:#B9B2A3;
--slate:#2F5D74; --accent:#E39A2C; --panel:#F6F3EC;
--z-ext:#3763A0; --z-fire:#C4402A; --z-gf:#B9741C; --z-up:#2E7D6B;
--pos:#C4402A; --gnd:#1C1B18;
}
body {
background:var(--paper); color:var(--ink); margin:0;
font-family:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
font-size:12px; line-height:1.5;
}
.mono { font-family:ui-monospace,"SF Mono",Menlo,Consolas,monospace; }
.page { padding:0 0 8mm; }
.page + .page { break-before:page; padding-top:2mm; }
/* ---- Title block ---- */
.titleblock { border:1.5px solid var(--ink); border-radius:3px; overflow:hidden; display:grid; grid-template-columns:1.7fr 1fr; }
.tb-main { padding:14px 18px; border-right:1px solid var(--line-strong); }
.tb-eyebrow { font-family:ui-monospace,monospace; font-size:10px; letter-spacing:.18em; text-transform:uppercase; color:var(--accent); margin:0 0 4px; }
h1 { font-size:23px; line-height:1.08; margin:0; text-wrap:balance; letter-spacing:-.01em; }
.tb-sub { color:var(--muted); font-size:12px; margin:6px 0 0; }
.tb-meta { display:grid; grid-template-columns:1fr 1fr; }
.tb-cell { padding:7px 12px; border-bottom:1px solid var(--line); }
.tb-cell:nth-child(odd) { border-right:1px solid var(--line); }
.tb-cell:nth-last-child(-n+2) { border-bottom:none; }
.tb-cell .k { font-family:ui-monospace,monospace; font-size:8.5px; letter-spacing:.1em; text-transform:uppercase; color:var(--muted); }
.tb-cell .v { font-size:12px; font-weight:600; margin-top:1px; }
section { margin-top:15px; break-inside:avoid; }
.sec-head { display:flex; align-items:baseline; gap:10px; margin:0 0 10px; }
.sec-head h2 { font-size:14px; margin:0; }
.sec-head .num { font-family:ui-monospace,monospace; font-size:11px; color:var(--paper); background:var(--ink); border-radius:3px; padding:1px 7px; font-weight:700; }
.sec-head .hint { color:var(--muted); font-size:11px; margin-left:auto; }
.diagram { background:var(--panel); border:1px solid var(--line-strong); border-radius:6px; padding:12px 14px; }
.diagram svg { display:block; width:100%; height:auto; }
.caption { color:var(--muted); font-size:10.5px; margin:7px 2px 0; font-family:ui-monospace,monospace; }
.grid2 { display:grid; grid-template-columns:1fr 1fr; gap:20px; align-items:start; }
table { width:100%; border-collapse:collapse; font-size:11.5px; }
th { text-align:left; font-family:ui-monospace,monospace; font-size:8.5px; letter-spacing:.09em; text-transform:uppercase; color:var(--muted); font-weight:700; padding:0 7px 6px; border-bottom:1.5px solid var(--line-strong); }
td { padding:6px 7px; border-bottom:1px solid var(--line); vertical-align:top; }
td.c { font-family:ui-monospace,monospace; }
tbody tr:last-child td { border-bottom:none; }
.pic { font-family:ui-monospace,monospace; font-size:10.5px; color:var(--muted); white-space:nowrap; }
.chip { display:inline-flex; align-items:center; gap:5px; font-family:ui-monospace,monospace; font-size:10px; font-weight:700; white-space:nowrap; }
.chip::before { content:""; width:9px; height:9px; border-radius:2px; background:var(--c); flex:none; }
.z-ext{--c:var(--z-ext);} .z-fire{--c:var(--z-fire);} .z-gf{--c:var(--z-gf);} .z-up{--c:var(--z-up);}
.steps { list-style:none; margin:0; padding:0; }
.steps li { display:grid; grid-template-columns:auto 1fr; gap:10px; padding:6px 0; border-bottom:1px solid var(--line); break-inside:avoid; }
.steps li:last-child { border-bottom:none; }
.box { width:14px; height:14px; border:1.5px solid var(--line-strong); border-radius:3px; margin-top:2px; }
.steps .pic { display:block; margin-bottom:1px; }
.steps .what { font-size:11.5px; }
.crit { color:var(--z-fire); font-weight:700; font-family:ui-monospace,monospace; font-size:9px; letter-spacing:.07em; text-transform:uppercase; }
.bom { columns:2; column-gap:22px; font-size:11.5px; }
.bom .item { break-inside:avoid; display:grid; grid-template-columns:auto 1fr auto; gap:8px; align-items:baseline; padding:5px 0; border-bottom:1px solid var(--line); }
.bom .box { margin-top:3px; }
.bom .qty { font-family:ui-monospace,monospace; font-size:10px; color:var(--muted); white-space:nowrap; }
.bom .have { opacity:.5; }
.bom .have .name { text-decoration:line-through; }
.callout { background:var(--panel); border:1px solid var(--line-strong); border-left:3px solid var(--accent); border-radius:5px; padding:11px 13px; margin-top:14px; font-size:11.5px; break-inside:avoid; }
.callout b { font-family:ui-monospace,monospace; font-size:10px; letter-spacing:.04em; }
.scenes { display:flex; flex-wrap:wrap; gap:6px; margin-top:7px; }
.scenes span { font-family:ui-monospace,monospace; font-size:10.5px; border:1px solid var(--line-strong); border-radius:20px; padding:2px 9px; }
.scenes .arrow { border:none; color:var(--muted); padding:2px 0; }
footer { margin-top:16px; padding-top:9px; border-top:1px solid var(--line); display:flex; justify-content:space-between; color:var(--muted); font-size:10px; font-family:ui-monospace,monospace; }
</style>
<!-- ============================= PAGE 1 ============================= -->
<div class="page">
<div class="titleblock">
<div class="tb-main">
<p class="tb-eyebrow">Bench Reference · Rev B · discrete-driver</p>
<h1>House, Lighting Wiring Reference</h1>
<p class="tb-sub">4 switched zones · plain warm-white LEDs · ULN2803A low-side driver · cordless 5V.</p>
</div>
<div class="tb-meta">
<div class="tb-cell"><div class="k">Controller</div><div class="v">Arduino Nano</div></div>
<div class="tb-cell"><div class="k">Driver</div><div class="v">ULN2803A · 8-ch</div></div>
<div class="tb-cell"><div class="k">Power</div><div class="v">USB bank · 5V</div></div>
<div class="tb-cell"><div class="k">Outputs</div><div class="v mono">D3 D5 D6 D9 · PWM</div></div>
<div class="tb-cell"><div class="k">Sketch</div><div class="v mono">townhouse_lights.ino</div></div>
<div class="tb-cell"><div class="k">Series R</div><div class="v mono">220Ω / LED</div></div>
</div>
</div>
<section>
<div class="sec-head"><span class="num">1</span><h2>System schematic</h2><span class="hint">Nano drives ULN inputs; ULN sinks each zone to ground</span></div>
<div class="diagram">
<svg viewBox="0 0 900 300" role="img" aria-label="System schematic: USB power bank through master switch to 5V rail, Arduino Nano PWM pins into ULN2803A inputs, ULN outputs sinking each of four LED zones">
<!-- rails -->
<line x1="60" y1="46" x2="880" y2="46" stroke="var(--pos)" stroke-width="3"/>
<text x="60" y="38" font-size="11" fill="var(--pos)" font-family="ui-monospace,monospace" font-weight="700">+5V</text>
<line x1="60" y1="270" x2="880" y2="270" stroke="var(--gnd)" stroke-width="3"/>
<text x="60" y="288" font-size="11" fill="var(--gnd)" font-family="ui-monospace,monospace" font-weight="700">GND</text>
<!-- power bank + master switch -->
<rect x="60" y="92" width="104" height="58" rx="5" fill="#fff" stroke="var(--line-strong)" stroke-width="1.5"/>
<text x="112" y="116" text-anchor="middle" font-size="12" font-weight="700" fill="var(--ink)" font-family="ui-monospace,monospace">USB bank</text>
<text x="112" y="133" text-anchor="middle" font-size="9.5" fill="var(--muted)">5V · always-on</text>
<line x1="112" y1="150" x2="112" y2="270" stroke="var(--gnd)" stroke-width="3"/>
<!-- switch up to +5V rail -->
<line x1="112" y1="92" x2="112" y2="78" stroke="var(--pos)" stroke-width="3"/>
<circle cx="112" cy="74" r="4" fill="var(--pos)"/>
<line x1="115" y1="71" x2="133" y2="60" stroke="var(--pos)" stroke-width="3"/>
<circle cx="137" cy="58" r="4" fill="var(--pos)"/>
<line x1="137" y1="54" x2="137" y2="46" stroke="var(--pos)" stroke-width="3"/>
<text x="150" y="78" font-size="9.5" fill="var(--muted)" font-family="ui-monospace,monospace">master sw</text>
<!-- Nano -->
<rect x="250" y="86" width="150" height="128" rx="6" fill="#fff" stroke="var(--ink)" stroke-width="1.5"/>
<text x="325" y="112" text-anchor="middle" font-size="13" font-weight="700" fill="var(--ink)" font-family="ui-monospace,monospace">Arduino Nano</text>
<g font-family="ui-monospace,monospace" font-size="10" fill="var(--muted)">
<text x="264" y="140">5V</text><text x="264" y="196">GND</text>
<text x="386" y="140" text-anchor="end">D3</text>
<text x="386" y="158" text-anchor="end">D5</text>
<text x="386" y="176" text-anchor="end">D6</text>
<text x="386" y="194" text-anchor="end">D9</text>
</g>
<!-- power to nano -->
<line x1="112" y1="46" x2="250" y2="46" stroke="var(--pos)" stroke-width="3"/>
<line x1="240" y1="46" x2="240" y2="134" stroke="var(--pos)" stroke-width="2.5"/><line x1="240" y1="134" x2="252" y2="134" stroke="var(--pos)" stroke-width="2.5"/>
<circle cx="252" cy="134" r="2.5" fill="var(--pos)"/>
<line x1="252" y1="192" x2="238" y2="192" stroke="var(--gnd)" stroke-width="2.5"/><line x1="238" y1="192" x2="238" y2="270" stroke="var(--gnd)" stroke-width="2.5"/>
<circle cx="252" cy="192" r="2.5" fill="var(--gnd)"/>
<!-- button on ... show near nano bottom -->
<text x="325" y="236" text-anchor="middle" font-size="9.5" fill="var(--muted)" font-family="ui-monospace,monospace">button: D2 → GND (scene / wake)</text>
<!-- ULN2803 -->
<rect x="470" y="86" width="150" height="128" rx="6" fill="#fff" stroke="var(--ink)" stroke-width="1.5"/>
<text x="545" y="112" text-anchor="middle" font-size="13" font-weight="700" fill="var(--ink)" font-family="ui-monospace,monospace">ULN2803A</text>
<g font-family="ui-monospace,monospace" font-size="10" fill="var(--muted)">
<text x="484" y="140">IN1</text><text x="484" y="158">IN2</text><text x="484" y="176">IN3</text><text x="484" y="194">IN4</text>
<text x="606" y="140" text-anchor="end">O1</text><text x="606" y="158" text-anchor="end">O2</text><text x="606" y="176" text-anchor="end">O3</text><text x="606" y="194" text-anchor="end">O4</text>
</g>
<!-- nano D3/5/6/9 -> ULN IN1-4 (slate signal) -->
<g stroke="var(--slate)" stroke-width="2">
<line x1="400" y1="134" x2="470" y2="134"/>
<line x1="400" y1="152" x2="470" y2="152"/>
<line x1="400" y1="170" x2="470" y2="170"/>
<line x1="400" y1="188" x2="470" y2="188"/>
</g>
<!-- ULN GND pin9 -->
<line x1="545" y1="214" x2="545" y2="270" stroke="var(--gnd)" stroke-width="2.5"/>
<text x="551" y="230" font-size="9" fill="var(--muted)" font-family="ui-monospace,monospace">GND (pin 9)</text>
<!-- Zone outputs -->
<g font-family="ui-monospace,monospace" font-size="10">
<!-- each: line from ULN out to a zone tag box, LED glyph fed from +5V rail -->
<!-- Z GF -->
<line x1="620" y1="134" x2="700" y2="134" stroke="var(--z-gf)" stroke-width="2.5"/>
<rect x="700" y="122" width="150" height="24" rx="4" fill="#fff" stroke="var(--z-gf)" stroke-width="1.5"/>
<text x="712" y="138" fill="var(--ink)" font-weight="700">GF_INT</text><text x="843" y="138" text-anchor="end" fill="var(--muted)">2 LED</text>
<!-- Z UP -->
<line x1="620" y1="152" x2="700" y2="152" stroke="var(--z-up)" stroke-width="2.5"/>
<rect x="700" y="150" width="150" height="24" rx="4" fill="#fff" stroke="var(--z-up)" stroke-width="1.5"/>
<text x="712" y="166" fill="var(--ink)" font-weight="700">UP_INT</text><text x="843" y="166" text-anchor="end" fill="var(--muted)">3 LED</text>
<!-- Z EXT -->
<line x1="620" y1="170" x2="700" y2="178" stroke="var(--z-ext)" stroke-width="2.5"/>
<rect x="700" y="178" width="150" height="24" rx="4" fill="#fff" stroke="var(--z-ext)" stroke-width="1.5"/>
<text x="712" y="194" fill="var(--ink)" font-weight="700">EXT</text><text x="843" y="194" text-anchor="end" fill="var(--muted)">5 LED</text>
<!-- Z FIRE -->
<line x1="620" y1="188" x2="700" y2="206" stroke="var(--z-fire)" stroke-width="2.5"/>
<rect x="700" y="206" width="150" height="24" rx="4" fill="#fff" stroke="var(--z-fire)" stroke-width="1.5"/>
<text x="712" y="222" fill="var(--ink)" font-weight="700">FIRE</text><text x="843" y="222" text-anchor="end" fill="var(--muted)">1 LED</text>
</g>
<text x="775" y="252" text-anchor="middle" font-size="9.5" fill="var(--muted)" font-family="ui-monospace,monospace">each zone = 2-wire loop (+5V / return), see detail ▶</text>
</svg>
</div>
<p class="caption">Signal (slate) = Nano PWM → ULN input. +5V red, GND black. The ULN pulls each zone's return to ground on command; the LED current never touches an Arduino pin.</p>
</section>
<section>
<div class="sec-head"><span class="num">2</span><h2>Zone loop detail, how LEDs attach</h2><span class="hint">Repeat per zone · add LEDs anywhere on the loop</span></div>
<div class="grid2">
<div class="diagram">
<svg viewBox="0 0 420 220" role="img" aria-label="One zone loop: LEDs in parallel between the 5V rail and a ULN output, each LED with its own series resistor">
<line x1="20" y1="34" x2="400" y2="34" stroke="var(--pos)" stroke-width="3"/>
<text x="20" y="26" font-size="10" fill="var(--pos)" font-family="ui-monospace,monospace" font-weight="700">+5V</text>
<!-- three LEDs -->
<g font-family="ui-monospace,monospace" font-size="9">
<!-- LED template at x=90,190,290 -->
<!-- LED 1 -->
<line x1="90" y1="34" x2="90" y2="66" stroke="var(--pos)" stroke-width="2"/>
<polygon points="80,66 100,66 90,84" fill="var(--z-gf)"/><line x1="80" y1="84" x2="100" y2="84" stroke="var(--z-gf)" stroke-width="2.5"/>
<line x1="90" y1="84" x2="90" y2="104" stroke="var(--ink)" stroke-width="2"/>
<rect x="78" y="104" width="24" height="12" rx="2" fill="#fff" stroke="var(--ink)" stroke-width="1.3"/><text x="90" y="113" text-anchor="middle" fill="var(--ink)">220Ω</text>
<line x1="90" y1="116" x2="90" y2="170" stroke="var(--ink)" stroke-width="2"/>
<!-- LED 2 -->
<line x1="200" y1="34" x2="200" y2="66" stroke="var(--pos)" stroke-width="2"/>
<polygon points="190,66 210,66 200,84" fill="var(--z-gf)"/><line x1="190" y1="84" x2="210" y2="84" stroke="var(--z-gf)" stroke-width="2.5"/>
<line x1="200" y1="84" x2="200" y2="104" stroke="var(--ink)" stroke-width="2"/>
<rect x="188" y="104" width="24" height="12" rx="2" fill="#fff" stroke="var(--ink)" stroke-width="1.3"/><text x="200" y="113" text-anchor="middle" fill="var(--ink)">220Ω</text>
<line x1="200" y1="116" x2="200" y2="170" stroke="var(--ink)" stroke-width="2"/>
<!-- LED 3 -->
<line x1="310" y1="34" x2="310" y2="66" stroke="var(--pos)" stroke-width="2"/>
<polygon points="300,66 320,66 310,84" fill="var(--z-gf)"/><line x1="300" y1="84" x2="320" y2="84" stroke="var(--z-gf)" stroke-width="2.5"/>
<line x1="310" y1="84" x2="310" y2="104" stroke="var(--ink)" stroke-width="2"/>
<rect x="298" y="104" width="24" height="12" rx="2" fill="#fff" stroke="var(--ink)" stroke-width="1.3"/><text x="310" y="113" text-anchor="middle" fill="var(--ink)">220Ω</text>
<line x1="310" y1="116" x2="310" y2="170" stroke="var(--ink)" stroke-width="2"/>
</g>
<!-- return bus to ULN out -->
<line x1="90" y1="170" x2="360" y2="170" stroke="var(--ink)" stroke-width="3"/>
<line x1="360" y1="170" x2="360" y2="196" stroke="var(--ink)" stroke-width="3"/>
<rect x="300" y="196" width="100" height="18" rx="3" fill="#fff" stroke="var(--z-gf)" stroke-width="1.3"/>
<text x="350" y="209" text-anchor="middle" font-size="9.5" fill="var(--ink)" font-family="ui-monospace,monospace">ULN OUTx</text>
</svg>
</div>
<div>
<p style="margin-top:0">Every fixture in a zone shares two wires: <b>+5V</b> and the zone's <b>return</b> to its ULN output. Wire an LED like this and drop it anywhere on the loop, no order, no polarity chain to keep straight beyond each LED's own <b class="mono">+</b> (anode) toward 5V.</p>
<ul style="margin:8px 0 0; padding-left:18px;">
<li><b>Anode (+, longer leg)</b> → +5V rail</li>
<li><b>Cathode (, flat side)</b> → 220Ω → zone return</li>
<li>One resistor <b>per LED</b>, keeps brightness even if one fails</li>
</ul>
<div class="callout"><b>BRIGHTNESS KNOB</b>, start at 220Ω. Too dim? drop toward 150Ω. Too bright? the sketch's per-zone level also trims it in software. Dollhouse rooms read best low.</div>
</div>
</div>
</section>
</div>
<!-- ============================= PAGE 2 ============================= -->
<div class="page">
<section style="margin-top:0">
<div class="sec-head"><span class="num">3</span><h2>Output map</h2></div>
<table>
<thead><tr><th>Zone</th><th>Arduino</th><th>ULN in</th><th>ULN out (pin)</th><th>Fixtures</th><th>Control</th></tr></thead>
<tbody>
<tr><td><span class="chip z-gf">GF_INT</span></td><td class="c">D3 · PWM</td><td class="c">IN1</td><td class="c">OUT1 · pin18</td><td>living + kitchen ceilings</td><td>dim</td></tr>
<tr><td><span class="chip z-up">UP_INT</span></td><td class="c">D5 · PWM</td><td class="c">IN2</td><td class="c">OUT2 · pin17</td><td>2× bedroom ceiling, attic</td><td>dim</td></tr>
<tr><td><span class="chip z-ext">EXT</span></td><td class="c">D6 · PWM</td><td class="c">IN3</td><td class="c">OUT3 · pin16</td><td>porch A/B, entry, deck, balcony</td><td>dim</td></tr>
<tr><td><span class="chip z-fire">FIRE</span></td><td class="c">D9 · PWM</td><td class="c">IN4</td><td class="c">OUT4 · pin15</td><td>hearth</td><td>flicker</td></tr>
</tbody>
</table>
<p class="caption">ULN2803A: GND = pin 9. COM (pin 10) unused for LEDs. Inputs IN18 = pins 18; outputs OUT18 = pins 1811.</p>
</section>
<div class="grid2" style="margin-top:15px">
<section style="margin-top:0">
<div class="sec-head"><span class="num">4</span><h2>Fixture schedule</h2></div>
<table>
<thead><tr><th>Fixture</th><th>Zone</th><th>Install at</th></tr></thead>
<tbody>
<tr><td>Porch light A</td><td><span class="chip z-ext">EXT</span></td><td class="pic">Pic 89</td></tr>
<tr><td>Porch light B</td><td><span class="chip z-ext">EXT</span></td><td class="pic">Pic 89</td></tr>
<tr><td>Front-door entry</td><td><span class="chip z-ext">EXT</span></td><td class="pic">Pic 89</td></tr>
<tr><td>Side deck / wing</td><td><span class="chip z-ext">EXT</span></td><td class="pic">Pic 89</td></tr>
<tr><td>Fireplace / hearth</td><td><span class="chip z-fire">FIRE</span></td><td class="pic">Pic 10</td></tr>
<tr><td>GF living ceiling</td><td><span class="chip z-gf">GF_INT</span></td><td class="pic">Pic 11 ✦</td></tr>
<tr><td>GF kitchen ceiling</td><td><span class="chip z-gf">GF_INT</span></td><td class="pic">Pic 11 ✦</td></tr>
<tr><td>Balcony wall light</td><td><span class="chip z-ext">EXT</span></td><td class="pic">Pic 1213</td></tr>
<tr><td>2F bedroom ceiling</td><td><span class="chip z-up">UP_INT</span></td><td class="pic">Pic 14 ✦</td></tr>
<tr><td>2F bedroom ceiling</td><td><span class="chip z-up">UP_INT</span></td><td class="pic">Pic 14 ✦</td></tr>
<tr><td>Attic ceiling</td><td><span class="chip z-up">UP_INT</span></td><td class="pic">Pic 1617</td></tr>
<tr><td>Spare, eave / yard</td><td><span class="chip">, </span></td><td class="pic">any</td></tr>
</tbody>
</table>
<div class="callout">
<b>SCENES</b>, button on D2 cycles; auto-fades dark after 20 min idle.
<div class="scenes"><span>Evening</span><span class="arrow"></span><span>All&nbsp;On</span><span class="arrow"></span><span>Night</span><span class="arrow"></span><span>Off</span></div>
</div>
</section>
<section style="margin-top:0">
<div class="sec-head"><span class="num">5</span><h2>Build-order checklist</h2></div>
<ul class="steps">
<li><span class="box"></span><span><span class="pic">Pic 5, base closing</span><span class="what">Mount Nano + ULN driver board + power bank + master switch in the crawlspace. Run a 2-wire loop (+5V + return) for each zone up into the house.</span></span></li>
<li><span class="box"></span><span><span class="pic">Pic 89, GF walls</span><span class="what">Wire the 4 <b class="mono">EXT</b> fixtures (porch A/B, entry, deck) onto the EXT loop through pre-drilled holes.</span></span></li>
<li><span class="box"></span><span><span class="pic">Pic 10, chimney base</span><span class="what">Drop the <b class="mono">FIRE</b> hearth LED into the chimney.</span></span></li>
<li><span class="box"></span><span><span class="pic">Pic 11, GF ceiling</span><span class="what"><span class="crit">✦ wire before glue</span> Glue the 2 <b class="mono">GF_INT</b> LEDs to the panel <em>underside</em>, route to a corner, then set the floor.</span></span></li>
<li><span class="box"></span><span><span class="pic">Pic 1213, 2F walls</span><span class="what">Wire the <b class="mono">EXT</b> balcony light.</span></span></li>
<li><span class="box"></span><span><span class="pic">Pic 14, 2F ceiling</span><span class="what"><span class="crit">✦ wire before glue</span> Glue the 2 <b class="mono">UP_INT</b> bedroom LEDs to the panel <em>underside</em> before it goes down.</span></span></li>
<li><span class="box"></span><span><span class="pic">Pic 1617, roof</span><span class="what">Fix the <b class="mono">UP_INT</b> attic LED to a rafter before closing the roof; dormers double as light wells.</span></span></li>
<li><span class="box"></span><span><span class="pic">Finish</span><span class="what">Route the power-bank charge port to a hidden opening (rear wall / chimney base). Leave a base access hatch.</span></span></li>
</ul>
</section>
</div>
<section>
<div class="sec-head"><span class="num">6</span><h2>Bill of materials</h2><span class="hint">Arduino + LEDs already on hand (struck through)</span></div>
<div class="bom">
<div class="item have"><span class="box"></span><span class="name">Arduino Nano</span><span class="qty">×1</span></div>
<div class="item have"><span class="box"></span><span class="name">Warm-white LEDs</span><span class="qty">×12</span></div>
<div class="item"><span class="box"></span><span class="name">ULN2803A driver (+ DIP socket)</span><span class="qty">×1</span></div>
<div class="item"><span class="box"></span><span class="name">220Ω resistors (150Ω to brighten)</span><span class="qty">×14</span></div>
<div class="item"><span class="box"></span><span class="name">Momentary pushbutton</span><span class="qty">×1</span></div>
<div class="item"><span class="box"></span><span class="name">Slide switch (master, in 5V line)</span><span class="qty">×1</span></div>
<div class="item"><span class="box"></span><span class="name">USB power bank · always-on mode</span><span class="qty">×1</span></div>
<div class="item"><span class="box"></span><span class="name">USB-A pigtail / breakout</span><span class="qty">×1</span></div>
<div class="item"><span class="box"></span><span class="name">Hookup wire 2630 AWG (R/B/sig)</span><span class="qty">~10m</span></div>
<div class="item"><span class="box"></span><span class="name">Perfboard for driver board</span><span class="qty">×1</span></div>
<div class="item"><span class="box"></span><span class="name">Hot glue + sticks</span><span class="qty">, </span></div>
<div class="item"><span class="box"></span><span class="name">Heat-shrink / Kapton tape</span><span class="qty">, </span></div>
<div class="item"><span class="box"></span><span class="name">1000µF cap across 5V (optional)</span><span class="qty">×1</span></div>
<div class="item"><span class="box"></span><span class="name">Drill bits 11.5mm</span><span class="qty">, </span></div>
</div>
<p class="caption">Tools: soldering iron + solder, wire strippers, flush cutters, multimeter (verify each zone before gluing it in).</p>
</section>
<footer>
<span>Toys4play Townhouse · 3mm ply · ~1:12 · Rev B</span>
<span>✦ = can't undo once glued · zones: GF_INT · UP_INT · EXT · FIRE</span>
</footer>
</div>

272
wiring-sheet.html Normal file
View file

@ -0,0 +1,272 @@
<title>House Lighting, Wiring Sheet</title>
<style>
:root {
--paper:#FCFBF8; --ink:#1C1B18; --muted:#6E6A62; --line:#DED8CC; --line-strong:#C4BDAE;
--slate:#2F5D74; --accent:#E39A2C;
--z-ext:#3763A0; --z-fire:#C4402A; --z-gf:#B9741C; --z-up:#2E7D6B;
--panel:#F5F2EA; --shadow:0 1px 0 rgba(0,0,0,.03);
}
@media (prefers-color-scheme: dark) {
:root {
--paper:#181915; --ink:#ECEAE2; --muted:#9C978A; --line:#33352E; --line-strong:#454737;
--slate:#7FB2C7; --accent:#F0AE45;
--z-ext:#6EA0DE; --z-fire:#E77257; --z-gf:#E0A14E; --z-up:#5FB8A2;
--panel:#20211B; --shadow:none;
}
}
:root[data-theme="light"] {
--paper:#FCFBF8; --ink:#1C1B18; --muted:#6E6A62; --line:#DED8CC; --line-strong:#C4BDAE;
--slate:#2F5D74; --accent:#E39A2C;
--z-ext:#3763A0; --z-fire:#C4402A; --z-gf:#B9741C; --z-up:#2E7D6B;
--panel:#F5F2EA; --shadow:0 1px 0 rgba(0,0,0,.03);
}
:root[data-theme="dark"] {
--paper:#181915; --ink:#ECEAE2; --muted:#9C978A; --line:#33352E; --line-strong:#454737;
--slate:#7FB2C7; --accent:#F0AE45;
--z-ext:#6EA0DE; --z-fire:#E77257; --z-gf:#E0A14E; --z-up:#5FB8A2;
--panel:#20211B; --shadow:none;
}
* { box-sizing:border-box; }
body {
background:var(--paper); color:var(--ink);
font-family:system-ui,-apple-system,"Segoe UI",Roboto,sans-serif;
line-height:1.5; margin:0; padding:32px 24px;
-webkit-font-smoothing:antialiased;
}
.sheet { max-width:1040px; margin:0 auto; }
.mono { font-family:ui-monospace,"SF Mono",Menlo,Consolas,monospace; }
/* ---- Title block ---- */
.titleblock {
border:1.5px solid var(--ink); border-radius:3px; overflow:hidden;
display:grid; grid-template-columns:1.6fr 1fr;
}
.tb-main { padding:16px 20px; border-right:1px solid var(--line-strong); }
.tb-eyebrow {
font-family:ui-monospace,monospace; font-size:11px; letter-spacing:.18em;
text-transform:uppercase; color:var(--accent); margin:0 0 4px;
}
h1 { font-size:26px; line-height:1.1; margin:0; text-wrap:balance; letter-spacing:-.01em; }
.tb-sub { color:var(--muted); font-size:13px; margin:6px 0 0; }
.tb-meta { display:grid; grid-template-columns:1fr 1fr; }
.tb-cell { padding:9px 14px; border-bottom:1px solid var(--line); }
.tb-cell:nth-child(odd) { border-right:1px solid var(--line); }
.tb-cell:nth-last-child(-n+2) { border-bottom:none; }
.tb-cell .k { font-family:ui-monospace,monospace; font-size:9.5px; letter-spacing:.12em; text-transform:uppercase; color:var(--muted); }
.tb-cell .v { font-size:13px; font-weight:600; margin-top:1px; }
/* ---- Section scaffolding ---- */
section { margin-top:26px; }
.sec-head { display:flex; align-items:baseline; gap:12px; margin:0 0 12px; }
.sec-head h2 { font-size:15px; margin:0; letter-spacing:.01em; }
.sec-head .num {
font-family:ui-monospace,monospace; font-size:12px; color:var(--paper);
background:var(--ink); border-radius:3px; padding:1px 7px; font-weight:600;
}
.sec-head .hint { color:var(--muted); font-size:12px; margin-left:auto; }
/* ---- Diagram ---- */
.diagram { background:var(--panel); border:1px solid var(--line-strong); border-radius:6px; padding:14px; overflow-x:auto; }
.diagram svg { display:block; width:100%; min-width:640px; height:auto; }
/* ---- Two-column body ---- */
.cols { display:grid; grid-template-columns:1.15fr .85fr; gap:26px; align-items:start; }
/* ---- Schedule table ---- */
table { width:100%; border-collapse:collapse; font-size:12.5px; }
th { text-align:left; font-family:ui-monospace,monospace; font-size:9.5px; letter-spacing:.1em; text-transform:uppercase; color:var(--muted); font-weight:600; padding:0 8px 7px; border-bottom:1.5px solid var(--line-strong); }
td { padding:7px 8px; border-bottom:1px solid var(--line); vertical-align:top; }
td.idx { font-family:ui-monospace,monospace; font-weight:700; color:var(--ink); width:1%; }
tbody tr:last-child td { border-bottom:none; }
.pic { font-family:ui-monospace,monospace; font-size:11px; color:var(--muted); white-space:nowrap; }
.chip { display:inline-flex; align-items:center; gap:5px; font-family:ui-monospace,monospace; font-size:10.5px; font-weight:600; white-space:nowrap; }
.chip::before { content:""; width:9px; height:9px; border-radius:2px; background:var(--c); flex:none; }
.z-ext{--c:var(--z-ext);} .z-fire{--c:var(--z-fire);} .z-gf{--c:var(--z-gf);} .z-up{--c:var(--z-up);}
/* ---- Checklist / callouts ---- */
.steps { list-style:none; margin:0; padding:0; display:flex; flex-direction:column; gap:2px; }
.steps li { display:grid; grid-template-columns:auto 1fr; gap:11px; padding:9px 0; border-bottom:1px solid var(--line); }
.steps li:last-child { border-bottom:none; }
.box { width:15px; height:15px; border:1.5px solid var(--line-strong); border-radius:3px; margin-top:2px; }
.steps .pic { display:block; margin-bottom:1px; }
.steps .what { font-size:12.5px; }
.steps .crit { color:var(--z-fire); font-weight:700; font-family:ui-monospace,monospace; font-size:10px; letter-spacing:.08em; text-transform:uppercase; }
.callout { background:var(--panel); border:1px solid var(--line-strong); border-left:3px solid var(--accent); border-radius:5px; padding:12px 14px; margin-top:16px; font-size:12.5px; }
.callout b { font-family:ui-monospace,monospace; font-size:11px; letter-spacing:.04em; }
.scenes { display:flex; flex-wrap:wrap; gap:6px; margin-top:8px; }
.scenes span { font-family:ui-monospace,monospace; font-size:11px; border:1px solid var(--line-strong); border-radius:20px; padding:2px 10px; }
.scenes .arrow { border:none; color:var(--muted); padding:2px 0; }
footer { margin-top:28px; padding-top:12px; border-top:1px solid var(--line); display:flex; justify-content:space-between; color:var(--muted); font-size:11px; font-family:ui-monospace,monospace; }
.theme-toggle { position:fixed; top:14px; right:14px; font-family:ui-monospace,monospace; font-size:11px; background:var(--panel); color:var(--ink); border:1px solid var(--line-strong); border-radius:5px; padding:5px 10px; cursor:pointer; }
.theme-toggle:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
@media (max-width:720px) { .titleblock,.cols{grid-template-columns:1fr;} .tb-main{border-right:none;border-bottom:1px solid var(--line-strong);} }
@media print {
:root { --paper:#fff; --ink:#000; --panel:#fff; --line:#ccc; --line-strong:#999; }
body { padding:0; }
.theme-toggle { display:none; }
section, .titleblock, .diagram, .cols { break-inside:avoid; }
.steps li, tr { break-inside:avoid; }
}
</style>
<button class="theme-toggle" onclick="document.documentElement.dataset.theme = document.documentElement.dataset.theme==='dark'?'light':'dark'">◐ theme</button>
<div class="sheet">
<div class="titleblock">
<div class="tb-main">
<p class="tb-eyebrow">Bench Reference · keep near the glue</p>
<h1>House, Lighting Wiring Sheet</h1>
<p class="tb-sub">12 addressable pixels · one data chain · cordless. Solder each pixel at the build step its panel goes on.</p>
</div>
<div class="tb-meta">
<div class="tb-cell"><div class="k">Controller</div><div class="v">Arduino Nano</div></div>
<div class="tb-cell"><div class="k">Fixtures</div><div class="v">12× SK6812 RGBW·WW</div></div>
<div class="tb-cell"><div class="k">Power</div><div class="v">USB power bank · 5V</div></div>
<div class="tb-cell"><div class="k">Data pin</div><div class="v mono">D6 · 470Ω series</div></div>
<div class="tb-cell"><div class="k">Sketch</div><div class="v mono">townhouse_lights.ino</div></div>
<div class="tb-cell"><div class="k">Rev</div><div class="v">A · cordless</div></div>
</div>
</div>
<section>
<div class="sec-head"><span class="num">1</span><h2>Power &amp; controller wiring</h2><span class="hint">DATA flows one way, arrows point away from the Nano</span></div>
<div class="diagram">
<svg viewBox="0 0 900 250" role="img" aria-label="Wiring schematic from USB power bank through master switch to Arduino Nano and the SK6812 pixel chain">
<defs>
<marker id="ar" markerWidth="8" markerHeight="8" refX="6" refY="3" orient="auto"><path d="M0,0 L6,3 L0,6 Z" fill="var(--slate)"/></marker>
</defs>
<!-- rails legend -->
<g font-family="ui-monospace,monospace" font-size="11">
<line x1="620" y1="24" x2="648" y2="24" stroke="var(--z-fire)" stroke-width="3"/><text x="654" y="28" fill="var(--muted)">+5V</text>
<line x1="700" y1="24" x2="728" y2="24" stroke="var(--ink)" stroke-width="3"/><text x="734" y="28" fill="var(--muted)">GND</text>
<line x1="784" y1="24" x2="812" y2="24" stroke="var(--slate)" stroke-width="2.5"/><text x="818" y="28" fill="var(--muted)">DATA</text>
</g>
<!-- Power bank -->
<rect x="12" y="70" width="120" height="66" rx="5" fill="var(--panel)" stroke="var(--line-strong)" stroke-width="1.5"/>
<text x="72" y="98" text-anchor="middle" font-size="13" font-weight="700" fill="var(--ink)" font-family="ui-monospace,monospace">USB bank</text>
<text x="72" y="116" text-anchor="middle" font-size="10.5" fill="var(--muted)">5V · always-on</text>
<!-- master switch -->
<line x1="132" y1="90" x2="180" y2="90" stroke="var(--z-fire)" stroke-width="3"/>
<circle cx="184" cy="90" r="4" fill="var(--z-fire)"/><line x1="188" y1="88" x2="206" y2="78" stroke="var(--z-fire)" stroke-width="3"/><circle cx="210" cy="76" r="4" fill="var(--z-fire)"/>
<text x="197" y="112" text-anchor="middle" font-size="10" fill="var(--muted)" font-family="ui-monospace,monospace">master sw</text>
<line x1="214" y1="80" x2="250" y2="90" stroke="var(--z-fire)" stroke-width="3"/>
<line x1="72" y1="136" x2="72" y2="170" stroke="var(--ink)" stroke-width="3"/>
<line x1="72" y1="170" x2="250" y2="170" stroke="var(--ink)" stroke-width="3"/>
<!-- Nano -->
<rect x="250" y="66" width="150" height="118" rx="6" fill="var(--panel)" stroke="var(--ink)" stroke-width="1.5"/>
<text x="325" y="92" text-anchor="middle" font-size="14" font-weight="700" fill="var(--ink)" font-family="ui-monospace,monospace">Arduino Nano</text>
<g font-family="ui-monospace,monospace" font-size="11" fill="var(--muted)">
<text x="266" y="118">5V</text><text x="266" y="140">GND</text>
<text x="384" y="118" text-anchor="end">D6</text><text x="384" y="140" text-anchor="end">D2</text>
</g>
<circle cx="252" cy="114" r="3" fill="var(--z-fire)"/><circle cx="252" cy="136" r="3" fill="var(--ink)"/>
<circle cx="398" cy="114" r="3" fill="var(--slate)"/><circle cx="398" cy="136" r="3" fill="var(--ink)"/>
<!-- 5V/GND into nano -->
<line x1="250" y1="90" x2="252" y2="90" stroke="var(--z-fire)" stroke-width="3"/><line x1="240" y1="90" x2="252" y2="114" stroke="var(--z-fire)" stroke-width="3"/>
<line x1="250" y1="170" x2="252" y2="136" stroke="var(--ink)" stroke-width="3"/>
<!-- button on D2 -->
<line x1="398" y1="136" x2="430" y2="136" stroke="var(--ink)" stroke-width="2"/>
<rect x="430" y="128" width="30" height="16" rx="3" fill="none" stroke="var(--ink)" stroke-width="1.5"/>
<line x1="460" y1="136" x2="470" y2="136" stroke="var(--ink)" stroke-width="2"/><line x1="470" y1="130" x2="470" y2="142" stroke="var(--ink)" stroke-width="2"/>
<text x="445" y="164" text-anchor="middle" font-size="10" fill="var(--muted)" font-family="ui-monospace,monospace">scene / wake</text>
<!-- 470 ohm on data -->
<line x1="398" y1="114" x2="440" y2="114" stroke="var(--slate)" stroke-width="2.5"/>
<rect x="440" y="107" width="34" height="14" rx="2" fill="var(--panel)" stroke="var(--slate)" stroke-width="1.5"/>
<text x="457" y="118" text-anchor="middle" font-size="9" fill="var(--slate)" font-family="ui-monospace,monospace">470Ω</text>
<line x1="474" y1="114" x2="540" y2="114" stroke="var(--slate)" stroke-width="2.5" marker-end="url(#ar)"/>
<!-- 5V + GND rails out to chain -->
<line x1="240" y1="90" x2="240" y2="210" stroke="var(--z-fire)" stroke-width="3"/><line x1="240" y1="210" x2="880" y2="210" stroke="var(--z-fire)" stroke-width="3"/>
<line x1="228" y1="170" x2="228" y2="228" stroke="var(--ink)" stroke-width="3"/><line x1="228" y1="228" x2="880" y2="228" stroke="var(--ink)" stroke-width="3"/>
<!-- 1000uF cap at chain head -->
<line x1="512" y1="210" x2="512" y2="219" stroke="var(--z-fire)" stroke-width="2.5"/>
<line x1="504" y1="219" x2="520" y2="219" stroke="var(--z-fire)" stroke-width="2.5"/>
<line x1="504" y1="223" x2="520" y2="223" stroke="var(--ink)" stroke-width="2.5"/>
<line x1="512" y1="223" x2="512" y2="228" stroke="var(--ink)" stroke-width="2.5"/>
<text x="512" y="245" text-anchor="middle" font-size="9.5" fill="var(--muted)" font-family="ui-monospace,monospace">1000µF</text>
<!-- pixel chain -->
<g font-family="ui-monospace,monospace">
<rect x="548" y="96" width="46" height="40" rx="4" fill="var(--panel)" stroke="var(--z-ext)" stroke-width="1.5"/>
<text x="571" y="121" text-anchor="middle" font-size="14" font-weight="700" fill="var(--ink)">P0</text>
<line x1="571" y1="136" x2="571" y2="210" stroke="var(--z-fire)" stroke-width="2"/>
<line x1="560" y1="136" x2="560" y2="228" stroke="var(--ink)" stroke-width="2"/>
<line x1="594" y1="114" x2="618" y2="114" stroke="var(--slate)" stroke-width="2.5" marker-end="url(#ar)"/>
<rect x="626" y="96" width="46" height="40" rx="4" fill="var(--panel)" stroke="var(--z-ext)" stroke-width="1.5"/>
<text x="649" y="121" text-anchor="middle" font-size="14" font-weight="700" fill="var(--ink)">P1</text>
<line x1="649" y1="136" x2="649" y2="210" stroke="var(--z-fire)" stroke-width="2"/>
<line x1="638" y1="136" x2="638" y2="228" stroke="var(--ink)" stroke-width="2"/>
<line x1="672" y1="114" x2="696" y2="114" stroke="var(--slate)" stroke-width="2.5" marker-end="url(#ar)"/>
<text x="726" y="120" font-size="20" fill="var(--muted)">· · ·</text>
<line x1="756" y1="114" x2="780" y2="114" stroke="var(--slate)" stroke-width="2.5" marker-end="url(#ar)"/>
<rect x="788" y="96" width="54" height="40" rx="4" fill="var(--panel)" stroke="var(--z-up)" stroke-width="1.5"/>
<text x="815" y="121" text-anchor="middle" font-size="13" font-weight="700" fill="var(--ink)">P11</text>
<line x1="815" y1="136" x2="815" y2="210" stroke="var(--z-fire)" stroke-width="2"/>
<line x1="804" y1="136" x2="804" y2="228" stroke="var(--ink)" stroke-width="2"/>
</g>
</svg>
</div>
</section>
<div class="cols">
<section>
<div class="sec-head"><span class="num">2</span><h2>Fixture schedule</h2></div>
<table>
<thead><tr><th>Px</th><th>Fixture</th><th>Zone</th><th>Install at</th></tr></thead>
<tbody>
<tr><td class="idx">0</td><td>Porch light A</td><td><span class="chip z-ext">EXT</span></td><td class="pic">Pic 89</td></tr>
<tr><td class="idx">1</td><td>Porch light B</td><td><span class="chip z-ext">EXT</span></td><td class="pic">Pic 89</td></tr>
<tr><td class="idx">2</td><td>Front-door entry</td><td><span class="chip z-ext">EXT</span></td><td class="pic">Pic 89</td></tr>
<tr><td class="idx">3</td><td>Side deck / wing</td><td><span class="chip z-ext">EXT</span></td><td class="pic">Pic 89</td></tr>
<tr><td class="idx">4</td><td>Fireplace / hearth</td><td><span class="chip z-fire">FIRE</span></td><td class="pic">Pic 10</td></tr>
<tr><td class="idx">5</td><td>GF living ceiling</td><td><span class="chip z-gf">GF_INT</span></td><td class="pic">Pic 11 ✦</td></tr>
<tr><td class="idx">6</td><td>GF kitchen ceiling</td><td><span class="chip z-gf">GF_INT</span></td><td class="pic">Pic 11 ✦</td></tr>
<tr><td class="idx">7</td><td>Balcony wall light</td><td><span class="chip z-ext">EXT</span></td><td class="pic">Pic 1213</td></tr>
<tr><td class="idx">8</td><td>2F bedroom ceiling</td><td><span class="chip z-up">UP_INT</span></td><td class="pic">Pic 14 ✦</td></tr>
<tr><td class="idx">9</td><td>2F bedroom ceiling</td><td><span class="chip z-up">UP_INT</span></td><td class="pic">Pic 14 ✦</td></tr>
<tr><td class="idx">10</td><td>Attic ceiling</td><td><span class="chip z-up">UP_INT</span></td><td class="pic">Pic 1617</td></tr>
<tr><td class="idx">11</td><td>Spare, eave / yard</td><td><span class="chip">, </span></td><td class="pic">any</td></tr>
</tbody>
</table>
<div class="callout">
<b>SCENES</b>, button on D2 cycles; auto-fades dark after 20 min idle.
<div class="scenes"><span>Evening</span><span class="arrow"></span><span>All&nbsp;On</span><span class="arrow"></span><span>Night</span><span class="arrow"></span><span>Off</span></div>
</div>
</section>
<section>
<div class="sec-head"><span class="num">3</span><h2>Build-order checklist</h2></div>
<ul class="steps">
<li><span class="box"></span><span><span class="pic">Pic 5, base closing</span><span class="what">Mount Nano, power bank, master switch, 470Ω + 1000µF in the crawlspace. Leave the 3-wire chain head + risers poking up.</span></span></li>
<li><span class="box"></span><span><span class="pic">Pic 89, GF walls</span><span class="what">Solder <b class="mono">P0P3</b> (porch, entry, deck) through pre-drilled holes as walls seat.</span></span></li>
<li><span class="box"></span><span><span class="pic">Pic 10, chimney base</span><span class="what">Drop <b class="mono">P4</b> flicker into the hearth.</span></span></li>
<li><span class="box"></span><span><span class="pic">Pic 11, GF ceiling</span><span class="what"><span class="crit">✦ wire before glue</span> Glue <b class="mono">P5P6</b> to the panel <em>underside</em>, route to a corner, then set the floor.</span></span></li>
<li><span class="box"></span><span><span class="pic">Pic 1213, 2F walls</span><span class="what">Solder <b class="mono">P7</b> balcony light.</span></span></li>
<li><span class="box"></span><span><span class="pic">Pic 14, 2F ceiling</span><span class="what"><span class="crit">✦ wire before glue</span> Glue <b class="mono">P8P9</b> to the panel <em>underside</em> before it goes down.</span></span></li>
<li><span class="box"></span><span><span class="pic">Pic 1617, roof</span><span class="what">Fix <b class="mono">P10</b> to a rafter before closing the roof; dormers double as light wells.</span></span></li>
<li><span class="box"></span><span><span class="pic">Finish</span><span class="what">Route the power-bank charge port to a hidden opening (rear wall or chimney base). Leave a base hatch.</span></span></li>
</ul>
</section>
</div>
<footer>
<span>Toys4play Townhouse · 3mm ply · ~1:12</span>
<span>Zones: EXT · FIRE · GF_INT · UP_INT · ✦ = can't undo once glued</span>
</footer>
</div>