A live, hand-illustrated collage of the birds outside your window — named by ear. A standalone Belkins build of BirdNET-Pi (CC-BY-NC-SA-4.0).
3
stars
3,262
commits
Python
primary language
Sep 9, 2026
updated
A live, hand-illustrated collage of the birds outside your window — named by ear.
A single $17 USB microphone in your window turns the birds outside into a living collage. Belkins BirdNET listens through the mic, lets Cornell's BirdNET name every passing call, and blooms each species onto the screen as a hand-painted kachō-e illustration — sized by how often it's been heard and repainted within seconds of each new detection.
500 bundled illustrations across 250 species, a Gemini pipeline to restyle them for your region, an optional e-ink frame for your wall — and one read-only SQLite file at the heart of it all.
Belkins BirdNET is a standalone build of BirdNET-Pi; the live-collage concept is inspired by AvianVisitors. Kudos, license, and full Cornell attribution are below.
The Living Gallery — a dark nocturne theme (with a light day theme), where every detected bird is spotlit. Collage · Index · Stats · Atlas.
A handful of the 500 bundled kachō-e illustrations — every species ships in a perched and a flight pose.
From a microphone in the window to a hand-painted bird on the wall — every arrow is real data flow.
flowchart LR
classDef cap fill:#fde68a,stroke:#d97706,color:#3f2d00;
classDef det fill:#bfdbfe,stroke:#2563eb,color:#0b2447;
classDef sto fill:#c7f9e5,stroke:#0d9488,color:#06372b;
classDef ill fill:#fbcfe8,stroke:#db2777,color:#4a0d2b;
classDef disp fill:#ddd6fe,stroke:#7c3aed,color:#2a1259;
classDef fwd fill:#fecaca,stroke:#dc2626,color:#4c0519;
classDef frm fill:#fed7aa,stroke:#ea580c,color:#451a03;
subgraph LISTEN [" Listen "]
mic["USB lavalier mic"]:::cap
rec["BirdNET-Pi recorder"]:::cap
end
subgraph IDENT [" Identify "]
model["BirdNET 6K v2.4<br/>6,522 labels"]:::det
ana["birdnet_analysis.py"]:::det
end
subgraph CORE [" Store + Read API "]
db[("birds.db<br/>SQLite")]:::sto
media["By_Date<br/>mp3 + spectrogram"]:::sto
api["birdnet-api.php"]:::sto
cut["cutout.php<br/>image resolver"]:::sto
end
subgraph ART [" Illustrate (optional) "]
gemini["Gemini 2.5<br/>Flash Image"]:::ill
pregen["pregen.py"]:::ill
cutpy["cutout.py<br/>BiRefNet matte"]:::ill
illus["500 illustrations<br/>250 species"]:::ill
end
subgraph SHOW [" Show "]
ui["Collage UI<br/>apt.js"]:::disp
web["web/ React shell"]:::disp
cast["birdcast<br/>SSE :8090"]:::disp
caddy["Caddy + PHP-FPM<br/>birdnet.local"]:::disp
end
subgraph WALL [" Wall frame "]
bw["BirdWeather<br/>GraphQL"]:::frm
shoot["shoot.py"]:::frm
disp["display.py"]:::frm
inky["Inky 13.3in<br/>e-ink Spectra-6"]:::frm
end
subgraph OUT [" Forward "]
cf["Cloudflare Tunnel"]:::fwd
ha["Home Assistant"]:::fwd
mqtt["MQTT bridge"]:::fwd
end
mic --> rec -->|"WAV segment"| ana
model --> ana
ana -->|"detection row"| db
ana -->|"clip + png"| media
ana -. "emit_detected" .-> cast
db --> api
db --> cast
media --> api
illus --> cut
gemini --> pregen --> cutpy --> illus
api --> ui
cut --> ui
api --> web
cast -. "bird.detected, under 3s" .-> web
ui --> caddy
web --> caddy
caddy --> cf
api --> ha
api --> mqtt
ui -->|"1200x1600 shot"| shoot
bw --> shoot
shoot --> disp --> inky
| 500 bundled illustrations | 250 species (perched + flight) | 6,522 BirdNET model labels | under 3s detection → screen |
| 158 photo-cutout fallbacks | 3 off-LAN forwarding recipes | 13.3" Spectra-6 e-ink panel | ~$70 mic + Pi build cost |
| Qty | Description | Price | Link | Notes |
|---|---|---|---|---|
| 1 | Raspberry Pi (4B / 5 / Zero 2 W) | ~$35–80 | Amazon | RPi0W2 note |
| 1 | Micro SD card (≥32 GB) | ~$10 | Amazon | |
| 1 | USB lavalier microphone | $16.95 | Amazon | |
| 1 | Pi power supply | ~$10 | — |
Optional: a Gemini API key to restyle illustrations, and an eBird API key to filter species by region.
Use Raspberry Pi Imager → Raspberry Pi OS Lite (64-bit). In the customisation dialog set a username, WiFi SSID + password, hostname birdnet, and enable SSH with password auth. Plug the USB mic into the Pi, place the capsule in a window, and boot.
Assumes passwordless sudo (the Raspberry Pi OS Lite default).
ssh <your-username>@birdnet.local
curl -s https://raw.githubusercontent.com/Belkins/belkins-birdnet/main/newinstaller.sh | bash
Clones this repo, installs BirdNET-Pi, and symlinks the Belkins BirdNET overlay into the Caddy web root. Takes 20–40 minutes and reboots when done.
http://birdnet.local/http://birdnet.local/index.phpThe repo ships with 500 bundled illustrations. To restyle them or generate a set for your own region:
pip install -r ~/BirdNET-Pi/avian/scripts/requirements.txt
export GEMINI_API_KEY='your-key' # image generation requires billing enabled
# generate on a cream ground → cut the ground off → rebuild the collage masks
python3 ~/BirdNET-Pi/avian/scripts/pregen.py --labels ~/BirdNET-Pi/model/labels.txt --force
python3 ~/BirdNET-Pi/avian/scripts/cutout.py
python3 ~/BirdNET-Pi/avian/scripts/build_masks.py
Filter to your region with --ebird-region US-CA (needs EBIRD_API_KEY). The full pipeline, prompt, reference images, and per-species tuning live in avian/scripts/README.md; the style lives in prompt.template.md.
New work in this build: a stdlib Server-Sent-Events spine so detections paint the instant BirdNET writes them.
avian/realtime/birdcast.py — POST /emit in, GET /events out, ~500-event replay ring buffer, reads birds.db read-only.web/ — a Vite + React + TypeScript collage shell that seeds from the snapshot API, subscribes to the SSE stream, and paints in each new bird (Canvas2D fade + scale, no re-pack). Runs with no backend at all via npm run dev:mock.# on the Pi — additive, idempotent, non-destructive. Brings up the SSE spine +
# the React collage at /collage (and the auto-gen watcher below, if its env is set).
bash deploy-christina.sh
deploy-realtime.sh is the spine-only subset if you don't want the collage yet.
The collage ships 250 illustrated species. When BirdNET hears one that isn't bundled, the auto-gen watcher generates its kachō-e illustration on the fly and paints it in — no human in the loop.
detection → forwarder (Pi) ──HTTPS──▶ birdgen (Railway) ──▶ Gemini + cream-key cutout
│
collage ◀── cutout.php 302 ◀── /asset/<slug>.png ◀───────┘ (frontend retries → paints)
services/birdgen/ — a small FastAPI service that deploys to Railway: a Bearer-auth POST /detected webhook, a single-flight queue, pregen.gen_one + the cream-key cutout, an SQLite-lease dedup state machine (queued → generating → done/dead), and GET /asset/<slug>.png off a persistent volume. The Gemini key lives only here — never on the Pi.avian/realtime/forwarder.py — a Pi-side daemon that subscribes to the birdcast SSE, drops bundled / low-confidence (<0.70) detections, and forwards genuinely-new species to Railway (plus a reconcile sweep every 6 h that heals anything the live stream missed). Holds only a rotatable webhook secret.avian/api/cutout.php — with AV_RAILWAY_ASSET_BASE set, a long-tail miss 302-redirects to the Railway asset (unset → unchanged behavior).avian/realtime/railway_liveness.py — a 6-hourly systemd timer that pushes a phone alert (ntfy) if the Railway service ever goes dark.avian/api/regen.php — the repaint gesture: anyone on the LAN can ask the museum to repaint a plate from the bird dossier (repaint ↺). The old plate stays on the wall until its replacement passes every QA gate (never-worse, atomic swap, previous plate archived to _prev/); presses are cooled down per species (15 min) and globally, spend is fenced by a $6/month manual sub-budget inside the $20 ledger, and the endpoint stays dark until armed with pool-env credentials (AV_RAILWAY_API_BASE + AV_REGEN_SECRET in the php-fpm pool — the secret never reaches a browser). The popup's control budget is constitutional: see docs/POPUP-BUDGET.md.# deploy the generator (needs a Railway account + a billing-enabled Gemini key)
cd services/birdgen
railway up
railway volume add -m /data/assets
railway variables set GEMINI_API_KEY=… WATCHER_WEBHOOK_SECRET=…
railway domain
# then on the Pi, wire it (same secret + the Railway URL):
CHRISTINA_RAILWAY_BASE=https://<svc>.up.railway.app \
CHRISTINA_WEBHOOK_SECRET=<secret> bash deploy-christina.sh
Cost: ~$0.04 per genuinely-new species, on-demand. Generation requires a billing-enabled Gemini key; the worker is single-flight, deduped, and degrades gracefully — if Railway is down the collage keeps running, just without new art.
Three independent recipes in avian/forwarding/:
An optional e-ink frame mirrors the last 24h of birds onto a panel by your window — in the nocturne or day theme. Build it from frame/. It can run off your own BirdNET mic, or standalone from BirdWeather for any ZIP code with no mic at all.
Left running on a wall screen, or printed to the 13.3" Spectra-6 e-ink frame — same composition, six inks, day or night.
avian/ # everything Belkins BirdNET adds to BirdNET-Pi
├── frontend/ # static HTML/JS/CSS for the collage
├── assets/ # bundled kachō-e illustrations + photo-cutout fallbacks
├── api/ # PHP shims served by BirdNET-Pi's PHP-FPM (cutout.php 302)
├── scripts/ # generate → cutout (creamkey) → masks pipeline + prompt
├── realtime/ # birdcast SSE spine + forwarder + liveness monitor
└── forwarding/ # optional HA / MQTT / Cloudflare configs
web/ # next-gen React + TS collage shell (live SSE)
services/birdgen/ # Railway: on-demand kachō-e generator (Gemini + cream-key)
frame/ # optional e-ink wall display
deploy-christina.sh # one-shot full-stack deploy on the Pi (spine + collage + watcher)
Everything outside avian/, web/, services/, and frame/ is upstream BirdNET-Pi.
Belkins BirdNET stands on the work of others:
CC-BY-NC-SA-4.0, inherited from BirdNET-Pi. Non-commercial use only. See the BirdNET-Pi README for full Cornell attribution.
BirdNET-Lite and the BirdNET model are © the K. Lisa Yang Center for Conservation Bioacoustics, Cornell Lab of Ornithology. BirdNET-Pi is © Patrick McGuire. Belkins BirdNET is a derivative work distributed under the same CC-BY-NC-SA-4.0 terms — see
LICENSE.
Fork · Watch · Open an issue
Made by Belkins · inspired by AvianVisitors · built on the shoulders of BirdNET-Pi and the Cornell Lab of Ornithology.
(top 30 of 57)
Python
27.1%
TypeScript
21.1%
PHP
19.6%
JavaScript
15.5%
Shell
7.8%
CSS
6.9%
HTML
1.9%
A live, hand-illustrated collage of the birds outside your window — named by ear. A standalone Belkins build of BirdNET-Pi (CC-BY-NC-SA-4.0).
3
stars
3,262
commits
Python
primary language
Sep 9, 2026
updated
A live, hand-illustrated collage of the birds outside your window — named by ear.
A single $17 USB microphone in your window turns the birds outside into a living collage. Belkins BirdNET listens through the mic, lets Cornell's BirdNET name every passing call, and blooms each species onto the screen as a hand-painted kachō-e illustration — sized by how often it's been heard and repainted within seconds of each new detection.
500 bundled illustrations across 250 species, a Gemini pipeline to restyle them for your region, an optional e-ink frame for your wall — and one read-only SQLite file at the heart of it all.
Belkins BirdNET is a standalone build of BirdNET-Pi; the live-collage concept is inspired by AvianVisitors. Kudos, license, and full Cornell attribution are below.
The Living Gallery — a dark nocturne theme (with a light day theme), where every detected bird is spotlit. Collage · Index · Stats · Atlas.
A handful of the 500 bundled kachō-e illustrations — every species ships in a perched and a flight pose.
From a microphone in the window to a hand-painted bird on the wall — every arrow is real data flow.
flowchart LR
classDef cap fill:#fde68a,stroke:#d97706,color:#3f2d00;
classDef det fill:#bfdbfe,stroke:#2563eb,color:#0b2447;
classDef sto fill:#c7f9e5,stroke:#0d9488,color:#06372b;
classDef ill fill:#fbcfe8,stroke:#db2777,color:#4a0d2b;
classDef disp fill:#ddd6fe,stroke:#7c3aed,color:#2a1259;
classDef fwd fill:#fecaca,stroke:#dc2626,color:#4c0519;
classDef frm fill:#fed7aa,stroke:#ea580c,color:#451a03;
subgraph LISTEN [" Listen "]
mic["USB lavalier mic"]:::cap
rec["BirdNET-Pi recorder"]:::cap
end
subgraph IDENT [" Identify "]
model["BirdNET 6K v2.4<br/>6,522 labels"]:::det
ana["birdnet_analysis.py"]:::det
end
subgraph CORE [" Store + Read API "]
db[("birds.db<br/>SQLite")]:::sto
media["By_Date<br/>mp3 + spectrogram"]:::sto
api["birdnet-api.php"]:::sto
cut["cutout.php<br/>image resolver"]:::sto
end
subgraph ART [" Illustrate (optional) "]
gemini["Gemini 2.5<br/>Flash Image"]:::ill
pregen["pregen.py"]:::ill
cutpy["cutout.py<br/>BiRefNet matte"]:::ill
illus["500 illustrations<br/>250 species"]:::ill
end
subgraph SHOW [" Show "]
ui["Collage UI<br/>apt.js"]:::disp
web["web/ React shell"]:::disp
cast["birdcast<br/>SSE :8090"]:::disp
caddy["Caddy + PHP-FPM<br/>birdnet.local"]:::disp
end
subgraph WALL [" Wall frame "]
bw["BirdWeather<br/>GraphQL"]:::frm
shoot["shoot.py"]:::frm
disp["display.py"]:::frm
inky["Inky 13.3in<br/>e-ink Spectra-6"]:::frm
end
subgraph OUT [" Forward "]
cf["Cloudflare Tunnel"]:::fwd
ha["Home Assistant"]:::fwd
mqtt["MQTT bridge"]:::fwd
end
mic --> rec -->|"WAV segment"| ana
model --> ana
ana -->|"detection row"| db
ana -->|"clip + png"| media
ana -. "emit_detected" .-> cast
db --> api
db --> cast
media --> api
illus --> cut
gemini --> pregen --> cutpy --> illus
api --> ui
cut --> ui
api --> web
cast -. "bird.detected, under 3s" .-> web
ui --> caddy
web --> caddy
caddy --> cf
api --> ha
api --> mqtt
ui -->|"1200x1600 shot"| shoot
bw --> shoot
shoot --> disp --> inky
| 500 bundled illustrations | 250 species (perched + flight) | 6,522 BirdNET model labels | under 3s detection → screen |
| 158 photo-cutout fallbacks | 3 off-LAN forwarding recipes | 13.3" Spectra-6 e-ink panel | ~$70 mic + Pi build cost |
| Qty | Description | Price | Link | Notes |
|---|---|---|---|---|
| 1 | Raspberry Pi (4B / 5 / Zero 2 W) | ~$35–80 | Amazon | RPi0W2 note |
| 1 | Micro SD card (≥32 GB) | ~$10 | Amazon | |
| 1 | USB lavalier microphone | $16.95 | Amazon | |
| 1 | Pi power supply | ~$10 | — |
Optional: a Gemini API key to restyle illustrations, and an eBird API key to filter species by region.
Use Raspberry Pi Imager → Raspberry Pi OS Lite (64-bit). In the customisation dialog set a username, WiFi SSID + password, hostname birdnet, and enable SSH with password auth. Plug the USB mic into the Pi, place the capsule in a window, and boot.
Assumes passwordless sudo (the Raspberry Pi OS Lite default).
ssh <your-username>@birdnet.local
curl -s https://raw.githubusercontent.com/Belkins/belkins-birdnet/main/newinstaller.sh | bash
Clones this repo, installs BirdNET-Pi, and symlinks the Belkins BirdNET overlay into the Caddy web root. Takes 20–40 minutes and reboots when done.
http://birdnet.local/http://birdnet.local/index.phpThe repo ships with 500 bundled illustrations. To restyle them or generate a set for your own region:
pip install -r ~/BirdNET-Pi/avian/scripts/requirements.txt
export GEMINI_API_KEY='your-key' # image generation requires billing enabled
# generate on a cream ground → cut the ground off → rebuild the collage masks
python3 ~/BirdNET-Pi/avian/scripts/pregen.py --labels ~/BirdNET-Pi/model/labels.txt --force
python3 ~/BirdNET-Pi/avian/scripts/cutout.py
python3 ~/BirdNET-Pi/avian/scripts/build_masks.py
Filter to your region with --ebird-region US-CA (needs EBIRD_API_KEY). The full pipeline, prompt, reference images, and per-species tuning live in avian/scripts/README.md; the style lives in prompt.template.md.
New work in this build: a stdlib Server-Sent-Events spine so detections paint the instant BirdNET writes them.
avian/realtime/birdcast.py — POST /emit in, GET /events out, ~500-event replay ring buffer, reads birds.db read-only.web/ — a Vite + React + TypeScript collage shell that seeds from the snapshot API, subscribes to the SSE stream, and paints in each new bird (Canvas2D fade + scale, no re-pack). Runs with no backend at all via npm run dev:mock.# on the Pi — additive, idempotent, non-destructive. Brings up the SSE spine +
# the React collage at /collage (and the auto-gen watcher below, if its env is set).
bash deploy-christina.sh
deploy-realtime.sh is the spine-only subset if you don't want the collage yet.
The collage ships 250 illustrated species. When BirdNET hears one that isn't bundled, the auto-gen watcher generates its kachō-e illustration on the fly and paints it in — no human in the loop.
detection → forwarder (Pi) ──HTTPS──▶ birdgen (Railway) ──▶ Gemini + cream-key cutout
│
collage ◀── cutout.php 302 ◀── /asset/<slug>.png ◀───────┘ (frontend retries → paints)
services/birdgen/ — a small FastAPI service that deploys to Railway: a Bearer-auth POST /detected webhook, a single-flight queue, pregen.gen_one + the cream-key cutout, an SQLite-lease dedup state machine (queued → generating → done/dead), and GET /asset/<slug>.png off a persistent volume. The Gemini key lives only here — never on the Pi.avian/realtime/forwarder.py — a Pi-side daemon that subscribes to the birdcast SSE, drops bundled / low-confidence (<0.70) detections, and forwards genuinely-new species to Railway (plus a reconcile sweep every 6 h that heals anything the live stream missed). Holds only a rotatable webhook secret.avian/api/cutout.php — with AV_RAILWAY_ASSET_BASE set, a long-tail miss 302-redirects to the Railway asset (unset → unchanged behavior).avian/realtime/railway_liveness.py — a 6-hourly systemd timer that pushes a phone alert (ntfy) if the Railway service ever goes dark.avian/api/regen.php — the repaint gesture: anyone on the LAN can ask the museum to repaint a plate from the bird dossier (repaint ↺). The old plate stays on the wall until its replacement passes every QA gate (never-worse, atomic swap, previous plate archived to _prev/); presses are cooled down per species (15 min) and globally, spend is fenced by a $6/month manual sub-budget inside the $20 ledger, and the endpoint stays dark until armed with pool-env credentials (AV_RAILWAY_API_BASE + AV_REGEN_SECRET in the php-fpm pool — the secret never reaches a browser). The popup's control budget is constitutional: see docs/POPUP-BUDGET.md.# deploy the generator (needs a Railway account + a billing-enabled Gemini key)
cd services/birdgen
railway up
railway volume add -m /data/assets
railway variables set GEMINI_API_KEY=… WATCHER_WEBHOOK_SECRET=…
railway domain
# then on the Pi, wire it (same secret + the Railway URL):
CHRISTINA_RAILWAY_BASE=https://<svc>.up.railway.app \
CHRISTINA_WEBHOOK_SECRET=<secret> bash deploy-christina.sh
Cost: ~$0.04 per genuinely-new species, on-demand. Generation requires a billing-enabled Gemini key; the worker is single-flight, deduped, and degrades gracefully — if Railway is down the collage keeps running, just without new art.
Three independent recipes in avian/forwarding/:
An optional e-ink frame mirrors the last 24h of birds onto a panel by your window — in the nocturne or day theme. Build it from frame/. It can run off your own BirdNET mic, or standalone from BirdWeather for any ZIP code with no mic at all.
Left running on a wall screen, or printed to the 13.3" Spectra-6 e-ink frame — same composition, six inks, day or night.
avian/ # everything Belkins BirdNET adds to BirdNET-Pi
├── frontend/ # static HTML/JS/CSS for the collage
├── assets/ # bundled kachō-e illustrations + photo-cutout fallbacks
├── api/ # PHP shims served by BirdNET-Pi's PHP-FPM (cutout.php 302)
├── scripts/ # generate → cutout (creamkey) → masks pipeline + prompt
├── realtime/ # birdcast SSE spine + forwarder + liveness monitor
└── forwarding/ # optional HA / MQTT / Cloudflare configs
web/ # next-gen React + TS collage shell (live SSE)
services/birdgen/ # Railway: on-demand kachō-e generator (Gemini + cream-key)
frame/ # optional e-ink wall display
deploy-christina.sh # one-shot full-stack deploy on the Pi (spine + collage + watcher)
Everything outside avian/, web/, services/, and frame/ is upstream BirdNET-Pi.
Belkins BirdNET stands on the work of others:
CC-BY-NC-SA-4.0, inherited from BirdNET-Pi. Non-commercial use only. See the BirdNET-Pi README for full Cornell attribution.
BirdNET-Lite and the BirdNET model are © the K. Lisa Yang Center for Conservation Bioacoustics, Cornell Lab of Ornithology. BirdNET-Pi is © Patrick McGuire. Belkins BirdNET is a derivative work distributed under the same CC-BY-NC-SA-4.0 terms — see
LICENSE.
Fork · Watch · Open an issue
Made by Belkins · inspired by AvianVisitors · built on the shoulders of BirdNET-Pi and the Cornell Lab of Ornithology.
(top 30 of 57)
Python
27.1%
TypeScript
21.1%
PHP
19.6%
JavaScript
15.5%
Shell
7.8%
CSS
6.9%
HTML
1.9%