---
---
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Google tag (gtag.js) — production host only -->
<script>
  (function() {
    if (location.hostname !== 'taprun.dev') return;
    var s = document.createElement('script');
    s.async = true;
    s.src = 'https://www.googletagmanager.com/gtag/js?id=G-RH14PQ10QK';
    document.head.appendChild(s);
    window.dataLayer = window.dataLayer || [];
    window.gtag = function(){ dataLayer.push(arguments); };
    gtag('js', new Date());
    gtag('config', 'G-RH14PQ10QK');
  })();
</script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>The Taprun Library — Taprun</title>
<meta name="description" content="Reference edition of every compiled browser program in the Taprun Library. Each entry is a named, reproducible data extraction with a live doctor verdict.">
<link rel="canonical" href="https://taprun.dev/taps/">
<meta property="og:title" content="The Taprun Library — Taprun">
<meta property="og:description" content="Compiled browser programs as W3C Annotations. Each entry has a named site, stable args, and a live doctor verdict.">
<meta property="og:url" content="https://taprun.dev/taps/">
<meta property="og:type" content="website">
<meta property="og:image" content="https://taprun.dev/social-preview.png">
{% include head-common.html %}
<link href="https://fonts.googleapis.com/css2?family=Fraunces:ital,opsz,wght,SOFT@0,9..144,300..900,0..100;1,9..144,300..900,0..100&display=swap" rel="stylesheet">

{% assign tap_pages = site.pages | where_exp: "p", "p.layout == 'tap'" | sort: "site_name" %}
{% assign sites = tap_pages | map: "site_name" | uniq %}
{% assign healthy_count = tap_pages | where: "doctor_verdict", "healthy" | size %}

<script type="application/ld+json">
{
  "@context": ["http://www.w3.org/ns/anno.jsonld", "https://taprun.dev/ns/tap-v1"],
  "@type": "AnnotationCollection",
  "id": "https://taprun.dev/taps/",
  "label": "Taprun Library",
  "total": {{ tap_pages.size }},
  "items": [
    {% for tap in tap_pages %}"https://taprun.dev{{ tap.url }}"{% unless forloop.last %},{% endunless %}{% endfor %}
  ]
}
</script>

<style>
:root {
  --bg-deep: #F4EDDE;
  --bg-surface: #EDE4CE;
  --bg-card: #E7DCBE;
  --indigo: #1C2D5A;
  --indigo-light: #384E80;
  --gold: #A67A2E;
  --gold-dim: #7A5A22;
  --red: #7E2B1C;
  --red-dark: #5A1C10;
  --green: #3D5E3B;
  --text: #14110C;
  --text-dim: #3B332A;
  --text-muted: #7A6F60;
  --paper: #FAF5EB;
  --font-heading: 'Fraunces', 'Hoefler Text', Georgia, serif;
  --font-body: 'Fraunces', 'Hoefler Text', Georgia, serif;
  --font-mono: 'JetBrains Mono', 'SF Mono', monospace;
}
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  font-family: var(--font-body);
  background: var(--bg-deep);
  color: var(--text);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Grain overlay — matches homepage */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  opacity: 0.025;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ===== Masthead strip (breadcrumb bar) ===== */
.masthead-strip {
  border-bottom: 1px solid rgba(20, 17, 12, 0.18);
  padding: 14px 0;
  position: relative;
  z-index: 2;
}
.masthead-strip .row {
  max-width: 1080px;
  margin: 0 auto;
  padding: 0 32px;
  display: grid;
  grid-template-columns: max-content 1fr max-content;
  gap: 24px;
  align-items: baseline;
  font-family: var(--font-mono);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  color: var(--text-muted);
}
.masthead-strip a { color: var(--text-dim); text-decoration: none; transition: color 0.2s; }
.masthead-strip a:hover { color: var(--red); }
.masthead-strip .brand {
  font-family: var(--font-heading);
  font-style: italic;
  font-weight: 700;
  font-size: 16px;
  letter-spacing: -0.01em;
  color: var(--text);
  text-transform: none;
}
.masthead-strip .center {
  justify-self: center;
  text-align: center;
  font-size: 10px;
}
.masthead-strip .ornament-dot { color: var(--gold); margin: 0 10px; }

/* ===== Hero masthead ===== */
.masthead {
  max-width: 1080px;
  margin: 0 auto;
  padding: 96px 32px 56px;
  text-align: center;
  border-bottom: 2px solid var(--text);
  position: relative;
}
.masthead .kicker {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 32px;
}
.masthead .kicker::before,
.masthead .kicker::after {
  content: '—';
  color: var(--gold);
  margin: 0 14px;
}
.masthead h1 {
  font-family: var(--font-heading);
  font-weight: 300;
  font-style: italic;
  font-size: clamp(62px, 10vw, 140px);
  line-height: 0.9;
  letter-spacing: -0.045em;
  color: var(--text);
  margin-bottom: 28px;
  font-variation-settings: "SOFT" 100, "opsz" 144;
}
.masthead h1 .article {
  display: block;
  font-family: var(--font-mono);
  font-style: normal;
  font-weight: 400;
  font-size: 13px;
  letter-spacing: 0.4em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: 10px;
}
.masthead h1 em {
  font-style: italic;
  color: var(--red);
  font-weight: 400;
}
.masthead .dek {
  font-family: var(--font-heading);
  font-style: italic;
  font-weight: 300;
  font-size: 21px;
  color: var(--text-dim);
  max-width: 640px;
  margin: 0 auto 40px;
  line-height: 1.45;
  font-variation-settings: "SOFT" 100;
}
.masthead .dek code {
  font-family: var(--font-mono);
  font-size: 15px;
  font-style: normal;
  color: var(--indigo);
  background: rgba(28, 45, 90, 0.08);
  padding: 1px 6px;
}
.masthead .dek a {
  color: var(--indigo);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  transition: color 0.2s;
}
.masthead .dek a:hover { color: var(--red); }

.masthead .stats {
  display: inline-flex;
  gap: 0;
  border: 1px solid var(--text);
}
.masthead .stats > span {
  padding: 18px 36px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  border-right: 1px solid var(--text);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.masthead .stats > span:last-child { border-right: none; }
.masthead .stats .num {
  font-family: var(--font-heading);
  font-weight: 600;
  font-style: italic;
  font-size: 32px;
  letter-spacing: -0.02em;
  color: var(--text);
  line-height: 1;
  font-variation-settings: "SOFT" 100;
}

/* Ornament under masthead */
.ornament {
  text-align: center;
  color: var(--gold);
  margin: 36px 0 56px;
  font-family: var(--font-heading);
  font-size: 18px;
  letter-spacing: 0.8em;
}

/* ===== Catalog ===== */
.catalog {
  max-width: 1080px;
  margin: 0 auto;
  padding: 0 32px;
}

.site-block { margin-bottom: 72px; }

.site-head {
  display: grid;
  grid-template-columns: max-content 1fr max-content;
  align-items: baseline;
  gap: 28px;
  margin-bottom: 20px;
  padding-bottom: 14px;
  border-bottom: 1px solid var(--text);
}
.site-head .site-name {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 22px;
  letter-spacing: -0.01em;
  color: var(--text);
}
.site-head .site-name::before {
  content: '§ ';
  color: var(--gold);
  font-family: var(--font-heading);
  font-weight: 400;
  font-style: italic;
  margin-right: 2px;
}
.site-head .rule {
  height: 1px;
  background: rgba(20, 17, 12, 0.2);
  align-self: center;
  margin-top: 2px;
}
.site-head .count {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--text-muted);
  letter-spacing: 0.22em;
  text-transform: uppercase;
}

/* Entry rows */
.tap-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) max-content minmax(190px, max-content);
  grid-column-gap: 32px;
  padding: 22px 4px;
  border-bottom: 1px solid rgba(20, 17, 12, 0.08);
  transition: background 0.25s;
  align-items: start;
}
.tap-row:hover {
  background: rgba(28, 45, 90, 0.035);
}
.tap-row:last-child { border-bottom: none; }

.tap-name-col {
  display: flex;
  flex-direction: column;
  gap: 7px;
  min-width: 0;
}
.tap-row a.tap-name {
  font-family: var(--font-mono);
  font-weight: 600;
  font-size: 17px;
  color: var(--indigo);
  text-decoration: none;
  letter-spacing: -0.005em;
  position: relative;
  display: inline-block;
  width: max-content;
  max-width: 100%;
}
.tap-row a.tap-name::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 1px;
  background: var(--indigo);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.3s cubic-bezier(0.65, 0, 0.35, 1);
}
.tap-row a.tap-name:hover {
  color: var(--red);
}
.tap-row a.tap-name:hover::after {
  background: var(--red);
  transform: scaleX(1);
}
.tap-row .desc {
  font-family: var(--font-heading);
  font-style: italic;
  font-weight: 300;
  font-size: 15.5px;
  color: var(--text-dim);
  max-width: 560px;
  line-height: 1.45;
  font-variation-settings: "SOFT" 100;
}

.layer-stamp {
  font-family: var(--font-heading);
  font-weight: 600;
  font-style: italic;
  font-size: 13px;
  padding: 2px 11px;
  align-self: start;
  margin-top: 2px;
  letter-spacing: 0.02em;
  font-variation-settings: "SOFT" 100;
}
.layer-stamp.is-read { color: var(--green); border: 1px solid var(--green); }
.layer-stamp.is-write { color: var(--red-dark); border: 1px solid var(--red-dark); }

.doctor-chip {
  align-self: start;
  margin-top: 4px;
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  display: flex;
  align-items: center;
  gap: 9px;
  white-space: nowrap;
}
.doctor-chip .dot {
  width: 7px;
  height: 7px;
  border-radius: 100px;
  display: inline-block;
  flex-shrink: 0;
}
.doctor-chip.healthy { color: var(--green); }
.doctor-chip.healthy .dot { background: var(--green); box-shadow: 0 0 0 3px rgba(61, 94, 59, 0.12); }
.doctor-chip.stale { color: var(--gold-dim); }
.doctor-chip.stale .dot { background: var(--gold); box-shadow: 0 0 0 3px rgba(166, 122, 46, 0.15); }
.doctor-chip.broken { color: var(--red); }
.doctor-chip.broken .dot { background: var(--red); box-shadow: 0 0 0 3px rgba(126, 43, 28, 0.15); }
.doctor-chip.none { color: var(--text-muted); }
.doctor-chip.none .dot {
  background: transparent;
  border: 1px solid var(--text-muted);
}
.doctor-chip .check {
  color: var(--text-muted);
  font-size: 10px;
  letter-spacing: 0.05em;
  font-weight: 400;
  text-transform: none;
  font-style: italic;
  font-family: var(--font-heading);
}

/* End-of-document ornament */
.end-ornament {
  text-align: center;
  margin: 96px 0 28px;
}
.end-ornament .rule {
  display: inline-block;
  width: 96px;
  height: 1px;
  background: var(--gold);
  vertical-align: middle;
  margin: 0 22px;
}
.end-ornament span.glyph {
  font-family: var(--font-heading);
  color: var(--gold);
  font-size: 18px;
  font-style: italic;
  vertical-align: middle;
}

.end-note {
  text-align: center;
  font-family: var(--font-heading);
  font-style: italic;
  font-weight: 300;
  font-size: 15px;
  color: var(--text-muted);
  margin: 0 auto 88px;
  max-width: 580px;
  line-height: 1.55;
  font-variation-settings: "SOFT" 100;
}
.end-note code {
  font-family: var(--font-mono);
  font-style: normal;
  color: var(--indigo);
  font-size: 12px;
  background: rgba(28, 45, 90, 0.08);
  padding: 1px 5px;
}
.end-note a {
  color: var(--indigo);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.end-note a:hover { color: var(--red); }

.empty-state {
  text-align: center;
  padding: 80px 0;
  font-family: var(--font-heading);
  font-style: italic;
  font-weight: 300;
  font-size: 19px;
  color: var(--text-muted);
}

/* Editor's-desk CTA — reference-edition voice, single block */
.catalog-cta {
  text-align: center;
  margin: 80px auto 24px;
  max-width: 620px;
  padding: 0 24px;
}
.catalog-cta .cta-rule {
  width: 64px;
  height: 1px;
  background: var(--gold);
  margin: 0 auto 28px;
}
.catalog-cta .cta-kicker {
  font-family: var(--font-heading);
  font-style: italic;
  font-weight: 400;
  font-size: 13px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--gold-dim);
  margin-bottom: 12px;
}
.catalog-cta .cta-headline {
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: 28px;
  line-height: 1.25;
  color: var(--indigo);
  margin-bottom: 14px;
  font-variation-settings: "SOFT" 50;
}
.catalog-cta .cta-body {
  font-family: var(--font-heading);
  font-weight: 300;
  font-size: 16px;
  line-height: 1.6;
  color: var(--text-dim);
  margin-bottom: 24px;
  font-variation-settings: "SOFT" 100;
}
.catalog-cta .cta-button {
  display: inline-block;
  font-family: var(--font-heading);
  font-style: italic;
  font-weight: 500;
  font-size: 16px;
  color: var(--paper);
  background: var(--indigo);
  padding: 12px 28px;
  text-decoration: none;
  border: 1px solid var(--indigo);
  transition: background 0.15s ease;
}
.catalog-cta .cta-button:hover {
  background: var(--indigo-light);
}
.catalog-cta .cta-fallback {
  font-family: var(--font-heading);
  font-style: italic;
  font-weight: 300;
  font-size: 13px;
  color: var(--text-muted);
  margin-top: 16px;
}
.catalog-cta .cta-fallback a {
  color: var(--indigo);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.catalog-cta .cta-fallback a:hover { color: var(--red); }

/* Scroll reveal */
.reveal { opacity: 0; transform: translateY(16px); transition: opacity 0.7s ease, transform 0.7s ease; }
.reveal.visible { opacity: 1; transform: translateY(0); }

@media (max-width: 720px) {
  .masthead { padding: 64px 20px 44px; }
  .masthead .stats { flex-direction: column; width: 100%; }
  .masthead .stats > span { border-right: none; border-bottom: 1px solid var(--text); padding: 14px 24px; }
  .masthead .stats > span:last-child { border-bottom: none; }
  .catalog { padding: 0 20px; }
  .site-head { grid-template-columns: 1fr; gap: 6px; }
  .site-head .rule { display: none; }
  .site-head .count { text-align: left; }
  .tap-row { grid-template-columns: 1fr; gap: 10px; padding: 20px 0; }
  .layer-stamp, .doctor-chip { align-self: start; margin-top: 0; }
  .masthead-strip .row { grid-template-columns: 1fr max-content; padding: 0 20px; }
  .masthead-strip .center { display: none; }
  .ornament { margin: 28px 0 40px; }
  .end-ornament { margin-top: 64px; }
  .end-ornament .rule { width: 48px; margin: 0 12px; }
}
</style>
</head>
<body>

<header class="masthead-strip">
  <div class="row">
    <a href="/" class="brand">Taprun</a>
    <span class="center">Reference Edition<span class="ornament-dot">◆</span>Taprun Library<span class="ornament-dot">◆</span>Compiled Catalog</span>
    <a href="https://github.com/LeonTing1010/tap-skills" rel="noopener">source&nbsp;↗</a>
  </div>
</header>

<div class="masthead">
  <div class="kicker">Volume 1 · MMXXVI · A Reference Edition</div>
  <h1>
    <span class="article">The</span>
    Taprun <em>Library</em>
  </h1>
  <p class="dek">Each entry is a compiled browser program — one-time AI authoring via <code>taprun forge</code>, then deterministic execution at $0 per run. Source lives in <a href="https://github.com/LeonTing1010/tap-skills">tap-skills</a>; every entry here is also a machine-readable <a href="/ns/tap-v1/">W3C&nbsp;Annotation</a>.</p>
  <div class="stats">
    <span><span class="num">{{ tap_pages.size }}</span>Entries</span>
    <span><span class="num">{{ sites.size }}</span>Sites</span>
    <span><span class="num">{{ healthy_count }}</span>Healthy</span>
  </div>
</div>

<div class="ornament">◆&nbsp;&nbsp;◆&nbsp;&nbsp;◆</div>

<main class="catalog">
{% if tap_pages.size == 0 %}
  <div class="empty-state">Showcase in progress — check back as entries graduate from <code>tap-skills</code>.</div>
{% endif %}

{% for s in sites %}
  {% assign site_taps = tap_pages | where: "site_name", s | sort: "tap_name" %}
  <section class="site-block reveal">
    <header class="site-head">
      <div class="site-name">{{ s }}</div>
      <div class="rule"></div>
      <div class="count">{{ site_taps.size }} entr{% if site_taps.size == 1 %}y{% else %}ies{% endif %}</div>
    </header>

    {% for tap in site_taps %}
    <article class="tap-row">
      <div class="tap-name-col">
        <a class="tap-name" href="{{ tap.url }}">{{ tap.tap_name }}</a>
        {% if tap.description %}<div class="desc">{{ tap.description }}</div>{% endif %}
      </div>
      {% assign t_intent = tap.intent | default: "read" %}
      <div class="layer-stamp is-{{ t_intent }}" title="{% if t_intent == 'write' %}Performs side effects — publishes, posts, or modifies data.{% else %}Read-only — safe to run.{% endif %}">{% if t_intent == "write" %}write{% else %}read-only{% endif %}</div>
      {% if tap.doctor_verdict == "healthy" %}
        <div class="doctor-chip healthy"><span class="dot"></span>Healthy{% if tap.doctor_checked %}<span class="check">· {{ tap.doctor_checked }}</span>{% endif %}</div>
      {% elsif tap.doctor_verdict == "stale" %}
        <div class="doctor-chip stale"><span class="dot"></span>Stale{% if tap.doctor_checked %}<span class="check">· {{ tap.doctor_checked }}</span>{% endif %}</div>
      {% elsif tap.doctor_verdict == "broken" %}
        <div class="doctor-chip broken"><span class="dot"></span>Broken{% if tap.doctor_checked %}<span class="check">· {{ tap.doctor_checked }}</span>{% endif %}</div>
      {% else %}
        <div class="doctor-chip none"><span class="dot"></span>Unchecked</div>
      {% endif %}
    </article>
    {% endfor %}
  </section>
{% endfor %}

<aside class="catalog-cta reveal">
  <div class="cta-rule"></div>
  <div class="cta-kicker">Editor's Desk</div>
  <h2 class="cta-headline">Need one of these in production?</h2>
  <p class="cta-body">Every entry in this catalog runs locally with your own browser session. If you're building agents and want help wiring a specific source — or one that isn't here yet — book a fifteen-minute call.</p>
  <a class="cta-button" href="https://cal.com/data-d-b6kqb5/15min?utm_source=taprun.dev&utm_medium=taps_catalog&utm_campaign=cta_15min">Book 15 min →</a>
  <p class="cta-fallback">or write <a href="mailto:hello@taprun.dev?subject=Taprun%20catalog%20%E2%80%94%20question%20from%20%2Ftaps%2F">hello@taprun.dev</a></p>
</aside>

<div class="end-ornament">
  <span class="rule"></span>
  <span class="glyph">◈</span>
  <span class="rule"></span>
</div>
<p class="end-note">Fetch any tap's <code>.jsonld</code> sibling for programmatic consumption. Each entry embeds the same annotation inline as <code>&lt;script type="application/ld+json"&gt;</code>.</p>
</main>

<script>
  const observer = new IntersectionObserver((entries) => {
    entries.forEach(e => { if (e.isIntersecting) e.target.classList.add('visible'); });
  }, { threshold: 0.05, rootMargin: '0px 0px -40px 0px' });
  document.querySelectorAll('.reveal').forEach(el => observer.observe(el));
</script>

</body>
</html>
