<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Cradicle Explorer</title>
    <link href="/css/bootstrap/bootstrap.min.css" rel="stylesheet">
    <style>
      .form-control-dark::placeholder {
          color: #aaa;
          opacity: 1;
      }
    </style>
    <link rel="stylesheet" href="/assets/fontawesome/css/all.min.css">
    <link rel="icon" type="image/png" href="/favicon.png">


                <link href="/css/dashboard.css" rel="stylesheet">
                </head>
                <body>
                <header class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0 shadow">
                  <a class="navbar-brand col-md-3 col-lg-2 me-0 px-3 fs-6" href="/">Cradicle Explorer</a>
                  <button class="navbar-toggler position-absolute d-md-none collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#sidebarMenu" aria-controls="sidebarMenu" aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                  </button>
                  <form method="get" action="/cgi-bin/main" style="width:100%;"><input class="form-control form-control-dark w-100 rounded-0 border-0" type="text" name="q" placeholder="Search repos" aria-label="Search"></form>
                  <div class="navbar-nav flex-row">
                    <div class="nav-item text-nowrap">
                      <a class="nav-link px-3 active" href="/cgi-bin/repo?id=zWb3dBVsx5VB669xjjcvKmV8de72">PodCrawl</a>
                    </div>
                  </div>
                </header>
                <div class="container-fluid">
                  <div class="row">
                    <nav id="sidebarMenu" class="col-md-3 col-lg-2 d-md-block bg-dark sidebar collapse">
                      <div class="position-sticky pt-3 sidebar-sticky">
                        <ul class="nav flex-column">
                          <li class="nav-item">
                            <a class="nav-link active" href="/cgi-bin/repo?id=zWb3dBVsx5VB669xjjcvKmV8de72">
                              <i class="align-text-bottom fa-solid fa-info"></i>
                              Info
                            </a>
                          </li>
                          <li class="nav-item">
                            <a class="nav-link" href="/cgi-bin/repo?id=zWb3dBVsx5VB669xjjcvKmV8de72&issue=list">
                              <i class="align-text-bottom fa-solid fa-layer-group"></i>
                              Issues
                            </a>
                          </li>
                          <li class="nav-item">
                            <a class="nav-link" href="/cgi-bin/repo?id=zWb3dBVsx5VB669xjjcvKmV8de72&patch=list">
                              <i class="align-text-bottom fa-solid fa-vest-patches"></i>
                              Patches
                            </a>
                          </li>
                          <li class="nav-item">
                            <a class="nav-link" href="/cgi-bin/repo?id=zWb3dBVsx5VB669xjjcvKmV8de72&wallet=list">
                              <i class="align-text-bottom fa-solid fa-wallet"></i>
                              Wallets
                            </a>
                          </li>
                          <li class="nav-item">
                            <a class="nav-link" href="/cgi-bin/repo?id=zWb3dBVsx5VB669xjjcvKmV8de72&source=.">
                              <i class="align-text-bottom fa-solid fa-code"></i>
                              Source
                            </a>
                          </li>
                        <h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted text-uppercase">
                          <span></span>
                        </h6>
                        <ul class="nav flex-column mb-2">
                        
                        </ul>
                      </div>
                    </nav>
                <main class="col-md-9 ms-sm-auto col-lg-10">
                  <div class="container px-1 py-3">
        

    <div class="list-group">
    <div class="list-group-item">
    <div style="font-size:1.3rem;">PodCrawl</div>
    <div class="repo-item">Podcast crawling and transcription digital spirit</div>
    <div>rad:zWb3dBVsx5VB669xjjcvKmV8de72</div>
    </div>
    <div class="list-group-item">
    <div>Visibility</div>
    <div class="repo-item">public</div>
    </div>
    <div class="list-group-item">
    <div>Delegates</div><div class="repo-item">did:key:z6MksAEMTumQbRK1dvFqt7Xt5YHMRPsmhhS2jfhxzbsDUWX5</div><div class="repo-item">did:key:z6MkksxzdRLbceEq9FPq1XRDWYWQgSrXC1DZrpTruSnrvHfq</div>
    </div>
    <div class="list-group-item">
    <div>Default branch</div>
    <div><span class="repo-item">main &#8594 ca9820248b72b52aa48ff6cfa89a7c666a9b1cbe</span> (Wed Feb 18 10:58:35 2026)</div>
    </div>
    <div class="list-group-item">
    <div>Threshold</div>
    <div class="repo-item">1</div>
    </div>
    </div>
    
        <div class="list-group mt-3">
        <div class="list-group-item">
        <div class="mb-2" style="font-weight:bold;"><i class="fa-solid fa-book"></i> README.md</div>
        <pre style="margin:0; font-size:0.85rem; overflow-x:auto; color:#fafafa;"># PodCrawl

Podcast network graph visualization. Paste an RSS feed URL onto a black canvas and watch the host-guest conversation network grow in real-time as AI extracts guests from episode titles.

## What It Does

PodCrawl takes a podcast RSS feed and builds a force-directed graph of the conversation network: host at center, guests as nodes, episodes as edges. When running inside InterBrain (Obsidian), it uses the AI inference bridge to extract guest names mapped to specific episodes. When running standalone in a browser, it parses RSS and shows the host node (guest extraction requires the AI bridge).

This is the foundation for recursive podcast network crawling: podcast → guest graph → guest podcasts → their guest graphs → exponential outward growth.

## Graph Visualization

Full-screen HTML5 Canvas with force-directed layout on a black background.

### Nodes
White-bordered black circles with name text below. Host node gets a thicker border and stronger center gravity.

### Edges — Two View Modes

**Global view**: Single undirected blue edge per person pair. Thickness hints at shared episode count.

**Edge detail view** (click any blue edge): Zooms in and unfolds the edge into individual red directed curves (host→guest) in a vesica piscis pattern — one curve per episode, with episode titles along each curve.

### Vesica Piscis Layout
- 1 episode: straight line
- 2 episodes: symmetric curves above/below (the vesica shape)
- 3+ episodes: evenly distributed within the vesica envelope
- All curves are quadratic Bezier with control points offset along the perpendicular at the midpoint

### Co-guest Detection
When multiple guests appear on the same episode (shared episode indices), they automatically get undirected edges between each other.

## Interaction

- **Paste URL** onto the black canvas to start crawling
- **Drag and drop** a URL also works
- **Type** to open a URL input field
- **Mouse wheel** to zoom (toward cursor)
- **Click and drag** to pan
- **Click a blue edge** to zoom into edge detail (vesica piscis view)
- **Click background** in edge detail to return to global view

## Data Model

AI returns `{ &quot;Guest Name&quot;: [0, 3, 7], &quot;Another Guest&quot;: [2, 3] }` — mapping guest names to episode indices (0-based). This enables the graph to know exactly which episodes connect which people.

## Design System

| Element | Value |
|---------|-------|
| Background | `#000000` |
| Blue (aggregate edges) | `#00A2FF` |
| Red (episode edges) | `#FF644E` |
| Nodes | White border `#FFFFFF`, black fill |
| Font | `&#x27;TeX Gyre Termes&#x27;, Georgia, serif` |

## Architecture

Single `index.html`, zero build step, ~500 lines. Canvas 2D rendering with force-directed layout (N-body repulsion + edge springs + center gravity). The graph grows incrementally as AI batches return — nodes animate in (radius 0→full over 300ms), edges fade in (200ms), force simulation redistributes on each addition.

## AI Bridge Protocol

Same postMessage protocol as before — see InterBrain&#x27;s inference service. The only change is the AI prompt now requests a `{ guest: [indices] }` map instead of a flat `string[]` array. Falls back gracefully to flat arrays from older bridge implementations.

## Streaming Growth Flow

```
Paste RSS URL onto black canvas
  → fetch + parse RSS
  → host node appears at center, HUD shows &quot;247 episodes&quot;
  → batch 50 titles to AI with prompt requesting { guest: [indices] } format
  → first batch returns → guest nodes animate in, blue edges form
  → next batch → more nodes appear, force sim redistributes
  → all batches done → graph settles, camera fits to graph
```
</pre>
        </div>
        </div>

</div>
</main>
</div>
</div>


</body>
</html>

