Marcusmalarkus

Smart HR Fan

Unnamed
smart_hr_fan_blog.html29.7 KiB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Building a Smart Fan with AI — A Real-World Project</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400;0,700;1,400&family=DM+Mono:wght@400;500&family=DM+Sans:wght@300;400;500&display=swap" rel="stylesheet">
<style>
  *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

  :root {
    --ink: #1a1916;
    --ink-mid: #4a4843;
    --ink-soft: #8a8780;
    --paper: #f5f2eb;
    --paper-dark: #ede9df;
    --accent: #c8401a;
    --accent-soft: #f0d4cb;
    --teal: #1a6b5a;
    --teal-soft: #c8e8e0;
    --code-bg: #2a2825;
    --code-text: #e8d5a8;
    --rule: rgba(26,25,22,0.12);
  }

  html { scroll-behavior: smooth; }

  body {
    font-family: 'DM Sans', sans-serif;
    background: var(--paper);
    color: var(--ink);
    font-size: 17px;
    line-height: 1.75;
    -webkit-font-smoothing: antialiased;
  }

  /* ── MASTHEAD ───────────────────────────── */
  .masthead {
    border-bottom: 1px solid var(--rule);
    padding: 1.25rem 2rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
    position: sticky;
    top: 0;
    background: var(--paper);
    z-index: 100;
  }
  .masthead-title {
    font-family: 'DM Mono', monospace;
    font-size: 12px;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ink-soft);
  }
  .masthead-tag {
    font-family: 'DM Mono', monospace;
    font-size: 11px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    background: var(--accent-soft);
    color: var(--accent);
    padding: 4px 12px;
    border-radius: 2px;
  }

  /* ── HERO ───────────────────────────────── */
  .hero {
    max-width: 820px;
    margin: 0 auto;
    padding: 5rem 2rem 4rem;
    border-bottom: 1px solid var(--rule);
  }
  .hero-kicker {
    font-family: 'DM Mono', monospace;
    font-size: 11px;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--accent);
    margin-bottom: 1.5rem;
  }
  .hero h1 {
    font-family: 'Playfair Display', serif;
    font-size: clamp(2.2rem, 5vw, 3.6rem);
    line-height: 1.15;
    font-weight: 700;
    letter-spacing: -0.02em;
    margin-bottom: 1.75rem;
    color: var(--ink);
  }
  .hero h1 em {
    font-style: italic;
    color: var(--accent);
  }
  .hero-dek {
    font-size: 1.2rem;
    line-height: 1.65;
    color: var(--ink-mid);
    font-weight: 300;
    max-width: 640px;
    margin-bottom: 2.5rem;
  }
  .hero-meta {
    display: flex;
    gap: 2rem;
    flex-wrap: wrap;
    border-top: 1px solid var(--rule);
    padding-top: 1.5rem;
  }
  .hero-meta-item {
    display: flex;
    flex-direction: column;
    gap: 3px;
  }
  .hero-meta-label {
    font-family: 'DM Mono', monospace;
    font-size: 10px;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--ink-soft);
  }
  .hero-meta-value {
    font-size: 14px;
    font-weight: 500;
    color: var(--ink);
  }

  /* ── LAYOUT ────────────────────────────── */
  .content-wrap {
    max-width: 820px;
    margin: 0 auto;
    padding: 0 2rem;
  }

  /* ── SECTIONS ──────────────────────────── */
  .section {
    padding: 3.5rem 0;
    border-bottom: 1px solid var(--rule);
  }
  .section:last-child { border-bottom: none; }

  .section-label {
    font-family: 'DM Mono', monospace;
    font-size: 10px;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--ink-soft);
    margin-bottom: 1.25rem;
    display: flex;
    align-items: center;
    gap: 10px;
  }
  .section-label::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--rule);
    max-width: 60px;
  }

  h2 {
    font-family: 'Playfair Display', serif;
    font-size: 1.85rem;
    font-weight: 700;
    line-height: 1.25;
    letter-spacing: -0.01em;
    margin-bottom: 1.25rem;
    color: var(--ink);
  }

  h3 {
    font-family: 'DM Sans', sans-serif;
    font-size: 1.05rem;
    font-weight: 500;
    letter-spacing: 0.01em;
    margin: 2rem 0 0.75rem;
    color: var(--ink);
  }

  p { margin-bottom: 1.25rem; color: var(--ink-mid); }
  p:last-child { margin-bottom: 0; }

  strong { color: var(--ink); font-weight: 500; }

  /* ── PULL QUOTE ────────────────────────── */
  .pull-quote {
    border-left: 3px solid var(--accent);
    padding: 1rem 0 1rem 1.75rem;
    margin: 2.5rem 0;
  }
  .pull-quote p {
    font-family: 'Playfair Display', serif;
    font-size: 1.3rem;
    font-style: italic;
    line-height: 1.5;
    color: var(--ink);
    margin: 0;
  }

  /* ── TOOL COMPARISON TABLE ─────────────── */
  .tool-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1px;
    background: var(--rule);
    border: 1px solid var(--rule);
    border-radius: 4px;
    overflow: hidden;
    margin: 2rem 0;
  }
  .tool-card {
    background: var(--paper);
    padding: 1.5rem 1.25rem;
  }
  .tool-card-header {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin-bottom: 1rem;
  }
  .tool-icon {
    width: 32px;
    height: 32px;
    border-radius: 6px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: 'DM Mono', monospace;
    font-size: 12px;
    font-weight: 500;
    flex-shrink: 0;
  }
  .tool-icon.chat { background: var(--teal-soft); color: var(--teal); }
  .tool-icon.code { background: var(--code-bg); color: var(--code-text); }
  .tool-icon.cowork { background: var(--accent-soft); color: var(--accent); }
  .tool-name {
    font-size: 14px;
    font-weight: 500;
    color: var(--ink);
    line-height: 1.3;
  }
  .tool-role {
    font-size: 12px;
    color: var(--ink-soft);
  }
  .tool-tasks {
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 6px;
  }
  .tool-tasks li {
    font-size: 13px;
    color: var(--ink-mid);
    padding-left: 14px;
    position: relative;
    line-height: 1.45;
  }
  .tool-tasks li::before {
    content: '→';
    position: absolute;
    left: 0;
    color: var(--ink-soft);
    font-size: 11px;
    top: 1px;
  }

  /* ── PARTS TABLE ───────────────────────── */
  .parts-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 14px;
    margin: 1.5rem 0;
  }
  .parts-table th {
    font-family: 'DM Mono', monospace;
    font-size: 10px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-soft);
    padding: 8px 12px;
    text-align: left;
    border-bottom: 1px solid var(--rule);
  }
  .parts-table td {
    padding: 10px 12px;
    border-bottom: 1px solid var(--rule);
    color: var(--ink-mid);
    vertical-align: top;
  }
  .parts-table tr:last-child td { border-bottom: none; }
  .parts-table td:first-child { font-weight: 500; color: var(--ink); }
  .parts-table td.price {
    font-family: 'DM Mono', monospace;
    font-size: 13px;
    color: var(--teal);
    white-space: nowrap;
  }
  .parts-table tr.total td {
    border-top: 2px solid var(--ink);
    font-weight: 500;
    color: var(--ink);
  }

  /* ── AGENT REVIEW BOX ──────────────────── */
  .review-box {
    background: var(--paper-dark);
    border: 1px solid var(--rule);
    border-radius: 4px;
    padding: 1.75rem;
    margin: 2rem 0;
  }
  .review-box-title {
    font-family: 'DM Mono', monospace;
    font-size: 10px;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--ink-soft);
    margin-bottom: 1rem;
  }
  .review-findings {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }
  .review-finding {
    display: flex;
    gap: 10px;
    align-items: flex-start;
    font-size: 14px;
  }
  .finding-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
    margin-top: 5px;
  }
  .dot-ok { background: var(--teal); }
  .dot-warn { background: #c8941a; }
  .dot-fix { background: var(--accent); }
  .finding-text { color: var(--ink-mid); line-height: 1.5; }
  .finding-text strong { color: var(--ink); }

  /* ── CODE SNIPPET ──────────────────────── */
  .code-block {
    background: var(--code-bg);
    border-radius: 4px;
    padding: 1.25rem 1.5rem;
    margin: 1.5rem 0;
    overflow-x: auto;
  }
  .code-block pre {
    font-family: 'DM Mono', monospace;
    font-size: 12.5px;
    line-height: 1.7;
    color: var(--code-text);
    white-space: pre;
  }
  .code-label {
    font-family: 'DM Mono', monospace;
    font-size: 10px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--ink-soft);
    margin-bottom: 0.5rem;
  }

  /* ── NEXT STEPS ────────────────────────── */
  .next-steps {
    display: flex;
    flex-direction: column;
    gap: 1px;
    background: var(--rule);
    border: 1px solid var(--rule);
    border-radius: 4px;
    overflow: hidden;
    margin: 2rem 0;
  }
  .next-step {
    background: var(--paper);
    padding: 1.25rem 1.5rem;
    display: grid;
    grid-template-columns: 2rem 1fr;
    gap: 1rem;
    align-items: start;
  }
  .step-num {
    font-family: 'DM Mono', monospace;
    font-size: 11px;
    color: var(--ink-soft);
    padding-top: 2px;
  }
  .step-body {}
  .step-title {
    font-size: 14px;
    font-weight: 500;
    color: var(--ink);
    margin-bottom: 3px;
  }
  .step-desc {
    font-size: 13px;
    color: var(--ink-mid);
    line-height: 1.5;
  }
  .step-tool {
    display: inline-block;
    font-family: 'DM Mono', monospace;
    font-size: 10px;
    letter-spacing: 0.1em;
    padding: 2px 8px;
    border-radius: 2px;
    margin-top: 6px;
  }
  .step-tool.chat { background: var(--teal-soft); color: var(--teal); }
  .step-tool.code { background: #3a3830; color: var(--code-text); }
  .step-tool.cowork { background: var(--accent-soft); color: var(--accent); }
  .step-tool.hw { background: var(--paper-dark); color: var(--ink-soft); border: 1px solid var(--rule); }

  /* ── INSIGHT CALLOUT ───────────────────── */
  .insight {
    display: grid;
    grid-template-columns: 3px 1fr;
    gap: 1.25rem;
    margin: 2rem 0;
  }
  .insight-bar { background: var(--teal); border-radius: 2px; }
  .insight-body {
    background: var(--teal-soft);
    padding: 1.25rem 1.5rem;
    border-radius: 0 4px 4px 0;
  }
  .insight-label {
    font-family: 'DM Mono', monospace;
    font-size: 10px;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--teal);
    margin-bottom: 0.5rem;
  }
  .insight-body p {
    font-size: 14px;
    color: #1a4a3a;
    margin: 0;
    line-height: 1.6;
  }

  /* ── FOOTER ────────────────────────────── */
  .footer {
    margin-top: 4rem;
    padding: 2rem;
    border-top: 1px solid var(--rule);
    text-align: center;
  }
  .footer p {
    font-family: 'DM Mono', monospace;
    font-size: 11px;
    letter-spacing: 0.12em;
    color: var(--ink-soft);
    text-transform: uppercase;
  }

  /* ── RESPONSIVE ────────────────────────── */
  @media (max-width: 640px) {
    .tool-grid { grid-template-columns: 1fr; }
    .hero { padding: 3rem 1.25rem 2.5rem; }
    .section { padding: 2.5rem 0; }
    .content-wrap { padding: 0 1.25rem; }
    .masthead { padding: 1rem 1.25rem; }
  }
</style>
</head>
<body>

<nav class="masthead">
  <span class="masthead-title">AI in the Real World</span>
  <span class="masthead-tag">Project log</span>
</nav>

<header class="hero content-wrap">
  <p class="hero-kicker">From conversation to circuit board</p>
  <h1>Building a <em>smart fan</em> with nothing but a chat window and an idea</h1>
  <p class="hero-dek">A triathlete wanted a fan that responds to their heart rate. What followed was a real-world demonstration of how AI tools — used together — can take a complete non-developer from concept to deployable code, sourced parts, and a build guide, without a single Google search.</p>
  <div class="hero-meta">
    <div class="hero-meta-item">
      <span class="hero-meta-label">Project type</span>
      <span class="hero-meta-value">DIY electronics build</span>
    </div>
    <div class="hero-meta-item">
      <span class="hero-meta-label">Tools used</span>
      <span class="hero-meta-value">Claude.ai · Claude Code · Cowork</span>
    </div>
    <div class="hero-meta-item">
      <span class="hero-meta-label">Location</span>
      <span class="hero-meta-value">Toronto, Canada</span>
    </div>
    <div class="hero-meta-item">
      <span class="hero-meta-label">Status</span>
      <span class="hero-meta-value">Parts sourced — ready to build</span>
    </div>
  </div>
</header>

<main>

  <!-- THE IDEA -->
  <div class="content-wrap">
  <section class="section">
    <p class="section-label">01 — The idea</p>
    <h2>It started with a simple question</h2>
    <p>The premise was straightforward: build a fan that automatically adjusts its speed based on heart rate. Work harder, get more cooling. Rest, and it quiets down. A genuinely useful training tool — responsive, automatic, and personal.</p>
    <p>The person asking had some Arduino tinkering experience and a Garmin chest strap they'd been using for years. They didn't know what it transmitted. They didn't have a parts list. They didn't have a circuit. They had an idea and a chat window.</p>

    <div class="pull-quote">
      <p>"I want this to be a fun project where we source the parts, get a little bit of code, and put it together. It must be safe, especially if there are any electrical components."</p>
    </div>

    <p>That single constraint — safety — shaped every decision that followed. It's a good example of how stating your requirements upfront changes the entire design space. No mains voltage. No AC control. All decisions pushed toward low-voltage DC electronics that a first-time builder could safely assemble.</p>
  </section>
  </div>

  <!-- THE DISCOVERY PROCESS -->
  <div class="content-wrap">
  <section class="section">
    <p class="section-label">02 — Discovery</p>
    <h2>The real value was in the questions</h2>
    <p>Before any parts were selected, the conversation surface four constraints that fundamentally shaped the build: experience level, use case, heart rate source, and priorities. These weren't checkbox questions — each answer cascaded into real decisions.</p>
    <p>The most consequential discovery: the user's existing Garmin chest strap — model HRM-SS — turned out to be <strong>ANT+ only</strong>, with no Bluetooth at all. A newer Garmin HRM would have been a natural upgrade choice, but research revealed the HRM Pro Plus had recently been discontinued. The recommendation landed on a <strong>Polar H10</strong> instead — better battery life (400 hours), superior open-water swimming performance for a triathlete, and no dependency on the Garmin ecosystem.</p>

    <div class="insight">
      <div class="insight-bar"></div>
      <div class="insight-body">
        <p class="insight-label">Key design decision</p>
        <p>Keeping the fan on 12V DC from a sealed wall adapter — never touching mains voltage — eliminated the most significant safety risk of the entire build. All control logic runs at 3.3V or 5V. The motor controller acts as the isolation layer between these worlds.</p>
      </div>
    </div>

    <p>The fan choice evolved through several iterations: a 120mm Noctua, then two 120mm fans in parallel, then the realisation that a single <strong>200mm Noctua NF-A20</strong> gives 86 CFM of wide, quiet airflow — better for full-body cooling from a training distance — at nearly the same price.</p>
  </section>
  </div>

  <!-- THE PARTS REVIEW -->
  <div class="content-wrap">
  <section class="section">
    <p class="section-label">03 — The review</p>
    <h2>An AI reviewing its own recommendations</h2>
    <p>One of the more interesting moments in the project was when the conversation shifted to a review mode — delegating the parts list to three parallel "agents" with different remits: parts accuracy, pricing and sourcing, and safety. This isn't a feature of the tool so much as a prompting technique, but the effect was genuinely useful.</p>

    <div class="review-box">
      <p class="review-box-title">What the review found</p>
      <div class="review-findings">
        <div class="review-finding">
          <div class="finding-dot dot-fix"></div>
          <p class="finding-text"><strong>L298N replaced with IRLZ44N MOSFET.</strong> The L298N is a bidirectional H-bridge for reversible motors — entirely wrong for a brushless 4-pin PWM fan. A single N-channel MOSFET does the job natively, costs ~$2, and is 3.3V logic compatible — solving the Arduino voltage issue simultaneously.</p>
        </div>
        <div class="review-finding">
          <div class="finding-dot dot-warn"></div>
          <p class="finding-text"><strong>25kHz PWM frequency flagged.</strong> Arduino's default <code>analogWrite()</code> runs at ~730Hz. The Noctua NF-A20 expects 25kHz per Intel's 4-pin fan spec. At wrong frequencies the fan may not respond to speed changes. This needs a SAMD21 timer register fix — flagged for Claude Code to solve.</p>
        </div>
        <div class="review-finding">
          <div class="finding-dot dot-ok"></div>
          <p class="finding-text"><strong>Power supply confirmed safe.</strong> The NF-A20 draws only 80mA at 12V. The 2A wall adapter provides 25x headroom. No thermal management concerns.</p>
        </div>
        <div class="review-finding">
          <div class="finding-dot dot-ok"></div>
          <p class="finding-text"><strong>Toronto sourcing confirmed.</strong> All components available within a 10-minute walk: MEC Queen St W (Polar H10), Canada Computers College St (Noctua fan + Arduino), College Home Hardware basement (MOSFET, diode, resistors).</p>
        </div>
      </div>
    </div>

    <p>The net result: a parts list that's technically sounder and ~$8 cheaper than the original, with a safety improvement built in. This kind of adversarial self-review — deliberately asking "what's wrong with this?" — is underused as a prompting pattern.</p>
  </section>
  </div>

  <!-- THE PARTS LIST -->
  <div class="content-wrap">
  <section class="section">
    <p class="section-label">04 — Final parts</p>
    <h2>The full build, locked in</h2>
    <p>After the review, the parts list settled at nine components, all available in Toronto or via Amazon.ca with 1–2 day delivery.</p>

    <table class="parts-table">
      <thead>
        <tr>
          <th>Component</th>
          <th>Part</th>
          <th>Est. (CAD)</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Heart rate strap</td>
          <td>Polar H10 (M-XXL)</td>
          <td class="price">$130–160</td>
        </tr>
        <tr>
          <td>Microcontroller</td>
          <td>Arduino Nano 33 IoT</td>
          <td class="price">~$39</td>
        </tr>
        <tr>
          <td>Fan</td>
          <td>Noctua NF-A20 PWM (200mm)</td>
          <td class="price">~$52</td>
        </tr>
        <tr>
          <td>Motor switch</td>
          <td>IRLZ44N N-channel MOSFET</td>
          <td class="price">~$2</td>
        </tr>
        <tr>
          <td>Protection</td>
          <td>1N4007 diode + 10kΩ resistor</td>
          <td class="price">~$1</td>
        </tr>
        <tr>
          <td>Power supply</td>
          <td>12V 2A DC wall adapter</td>
          <td class="price">~$14</td>
        </tr>
        <tr>
          <td>Enclosure</td>
          <td>Hammond 1591 ABS box</td>
          <td class="price">~$12</td>
        </tr>
        <tr>
          <td>Soldering iron</td>
          <td>Pinecil V2 kit</td>
          <td class="price">~$45</td>
        </tr>
        <tr>
          <td>Misc</td>
          <td>Wires, heat shrink, barrel jack</td>
          <td class="price">~$14</td>
        </tr>
        <tr class="total">
          <td colspan="2">Total</td>
          <td class="price">~$319–335</td>
        </tr>
      </tbody>
    </table>
  </section>
  </div>

  <!-- THE CODE -->
  <div class="content-wrap">
  <section class="section">
    <p class="section-label">05 — The code</p>
    <h2>From BPM to fan speed in ~100 lines</h2>
    <p>The sketch connects to the Polar H10 over BLE, subscribes to heart rate notifications, parses the BPM from the raw packet, and maps it to a PWM duty cycle. The fan curves are configurable at the top of the file — three constants you change to tune the feel of the system.</p>

    <p class="code-label">Heart rate → PWM mapping (core logic)</p>
    <div class="code-block"><pre>// User-configurable: adjust these for your fitness level
const int HR_MIN      = 60;   // BPM → fan starts
const int HR_MAX      = 160;  // BPM → full speed
const int FAN_MIN_PWM = 60;   // minimum PWM when fan is on

int bpmToPWM(int bpm) {
  if (bpm &lt;= HR_MIN) return 0;              // fan off at rest
  if (bpm &gt;= HR_MAX) return 255;            // full blast at max effort
  float ratio = (float)(bpm - HR_MIN)
              / (float)(HR_MAX - HR_MIN);
  return (int)(FAN_MIN_PWM + ratio * (255 - FAN_MIN_PWM));
}</pre></div>

    <p>One known issue was identified during generation and flagged explicitly for the next phase: <code>analogWrite()</code> on the SAMD21 defaults to ~730Hz. The Noctua fan expects 25kHz. This requires configuring a hardware timer directly — something that needs a compiler to validate. That's the handoff point to Claude Code.</p>

    <div class="insight">
      <div class="insight-bar"></div>
      <div class="insight-body">
        <p class="insight-label">Honest self-assessment</p>
        <p>The code produced here is architecturally correct and will likely work — but "likely" isn't good enough when you're about to solder. The 25kHz fix requires running a compiler against the actual SAMD21 board package. That's why the project hands off to Claude Code rather than shipping as-is.</p>
      </div>
    </div>
  </section>
  </div>

  <!-- THE TOOL ECOSYSTEM -->
  <div class="content-wrap">
  <section class="section">
    <p class="section-label">06 — The tools</p>
    <h2>Three tools, one project, no overlap</h2>
    <p>One of the more instructive aspects of this project is how naturally the three Anthropic tools divide the work — not by design, but because they're genuinely optimised for different things.</p>

    <div class="tool-grid">
      <div class="tool-card">
        <div class="tool-card-header">
          <div class="tool-icon chat">AI</div>
          <div>
            <div class="tool-name">Claude.ai</div>
            <div class="tool-role">The thinking partner</div>
          </div>
        </div>
        <ul class="tool-tasks">
          <li>Discovery conversations and tradeoff analysis</li>
          <li>Parts research and comparison</li>
          <li>Wiring diagrams and visual mockups</li>
          <li>Toronto store sourcing</li>
          <li>Code generation (first draft)</li>
          <li>This blog post</li>
        </ul>
      </div>
      <div class="tool-card">
        <div class="tool-card-header">
          <div class="tool-icon code">&gt;_</div>
          <div>
            <div class="tool-name">Claude Code</div>
            <div class="tool-role">The builder</div>
          </div>
        </div>
        <ul class="tool-tasks">
          <li>Fix 25kHz PWM timer (SAMD21)</li>
          <li>Compile against arduino:samd core</li>
          <li>Install ArduinoBLE library</li>
          <li>Run serial monitor, debug BLE</li>
          <li>Produce final flashable .ino</li>
        </ul>
      </div>
      <div class="tool-card">
        <div class="tool-card-header">
          <div class="tool-icon cowork">CW</div>
          <div>
            <div class="tool-name">Cowork</div>
            <div class="tool-role">The organiser</div>
          </div>
        </div>
        <ul class="tool-tasks">
          <li>Assemble project files into a folder</li>
          <li>Generate a printed build guide PDF</li>
          <li>Organise receipts after purchase</li>
          <li>Create a parts checklist document</li>
        </ul>
      </div>
    </div>

    <p>The key insight is that these tools share no live memory between them — but they share a <strong>filesystem</strong>. The handoff brief produced in this conversation is a markdown file. Claude Code reads it as context on session start. Cowork reads the same folder to produce the build guide. The tools are connected not by software, but by files.</p>
  </section>
  </div>

  <!-- NEXT STEPS -->
  <div class="content-wrap">
  <section class="section">
    <p class="section-label">07 — What's next</p>
    <h2>The build is three steps away</h2>
    <p>The project is at a clean handoff point. Everything that can be done in a conversation has been done. What remains is physical and executable.</p>

    <div class="next-steps">
      <div class="next-step">
        <span class="step-num">01</span>
        <div class="step-body">
          <div class="step-title">Buy the parts</div>
          <div class="step-desc">One afternoon: MEC Queen St W for the Polar H10, Canada Computers College St for the Noctua fan and Arduino, College Home Hardware basement for the MOSFET and small components.</div>
          <span class="step-tool hw">In person</span>
        </div>
      </div>
      <div class="next-step">
        <span class="step-num">02</span>
        <div class="step-body">
          <div class="step-title">Fix and compile the code</div>
          <div class="step-desc">Open Claude Code, paste the handoff brief, and let it fix the 25kHz PWM timer configuration on the SAMD21, compile cleanly against the arduino:samd core, and produce a verified final .ino file ready to flash.</div>
          <span class="step-tool code">Claude Code</span>
        </div>
      </div>
      <div class="next-step">
        <span class="step-num">03</span>
        <div class="step-body">
          <div class="step-title">Solder, assemble, test</div>
          <div class="step-desc">Wire the MOSFET circuit, mount components in the Hammond enclosure, flash the firmware, pair the Polar H10, and verify the fan responds to heart rate. The wiring is three connections and two passive components.</div>
          <span class="step-tool hw">Hardware</span>
        </div>
      </div>
      <div class="next-step">
        <span class="step-num">04</span>
        <div class="step-body">
          <div class="step-title">Produce the build guide</div>
          <div class="step-desc">Point Cowork at the project folder. Ask it to assemble the diagrams, parts list, wiring notes, and final code into a single printable PDF — a reference to keep with the hardware.</div>
          <span class="step-tool cowork">Cowork</span>
        </div>
      </div>
      <div class="next-step">
        <span class="step-num">05</span>
        <div class="step-body">
          <div class="step-title">Tune the HR curve</div>
          <div class="step-desc">After first use — adjust HR_MIN, HR_MAX, and FAN_MIN_PWM to match actual training zones. A triathlete's functional zones are different from the defaults. One re-flash, no rewiring needed.</div>
          <span class="step-tool code">Claude Code</span>
        </div>
      </div>
    </div>
  </section>
  </div>

  <!-- THE BIGGER POINT -->
  <div class="content-wrap">
  <section class="section">
    <p class="section-label">08 — The bigger point</p>
    <h2>What this project actually demonstrates</h2>
    <p>The smart fan is a useful object. But it's not the point. The point is what the process reveals about how AI tools are becoming genuinely useful for real-world projects — not because they're magic, but because they're good at specific things when used deliberately.</p>

    <h3>AI as a thinking partner, not an answer machine</h3>
    <p>The most valuable moments in this conversation weren't when Claude produced outputs — they were when it asked questions. Clarifying experience level, use case, heart rate source, and priorities before making a single recommendation. The quality of the output is entirely dependent on the quality of the framing. This is as true for AI as it is for any expert you'd consult.</p>

    <h3>The honest acknowledgement of limits</h3>
    <p>The conversation explicitly flagged what it couldn't do well: compile code, test PWM frequencies against real hardware, verify BLE pairing behaviour. Rather than papering over this, it produced a handoff brief — structured context designed to be read by a different tool better suited to those tasks. That kind of honest scope awareness is what makes an AI tool trustworthy.</p>

    <h3>The file as the universal handoff</h3>
    <p>None of these tools share live memory. Claude.ai, Claude Code, and Cowork each start fresh. But they all read files. The workflow that emerged — conversation produces files, files carry context to the next tool — is a pattern that generalises far beyond this project. Any complex undertaking benefits from the same discipline: document decisions as you make them, and those documents become the connective tissue between tools, sessions, and people.</p>

    <div class="pull-quote">
      <p>The fan will work. But the more transferable skill is learning to use AI as a disciplined collaborator — one that asks before it answers, flags what it doesn't know, and produces handoffs rather than false finality.</p>
    </div>
  </section>
  </div>

</main>

<footer class="footer">
  <p>Smart HR Fan Project · Toronto · March 2026 · Built with Claude</p>
</footer>

</body>
</html>