Skip to content

Bird song journal scene (BirdWeather) - #327

Open
mariusandra wants to merge 13 commits into
mainfrom
bird-song-journal
Open

Bird song journal scene (BirdWeather)#327
mariusandra wants to merge 13 commits into
mainfrom
bird-song-journal

Conversation

@mariusandra

Copy link
Copy Markdown
Collaborator

Summary

A fork of #262 that sources its birds from BirdWeather instead of iNaturalist: a sibling sample scene under repo/scenes/samples/Bird song journal, so the two can ship side by side. #262 draws birds somebody photographed nearby; this one draws birds that BirdWeather's listening stations actually heard.

Stacked on bird-field-journal-scene with main merged in, so the diff below also carries #262's commits. Once #262 merges this reduces to the new scene alone. The frameosVersion export stamping #262 added has since landed on main independently, so that conflict is resolved in main's favour.

The BirdWeather side

Their public API is GraphQL (POST /graphql, no auth for reads), so the app sends one query per poll:

  • topSpecies — the species roster with detection counts over the window. Species carries imageUrl plus imageCredit/imageLicense, which is what the plate is drawn from and what the stored attribution records.
  • an aliased detections — the newest local detection per species, for the "last 19:40 at PUC-23115" half of the caption, plus the totals shown while the collection is still filling.

Species.latestDetections looks like the obvious source for that second part and is not used: it is global, so a Belgian bounding box gets told about a station in the UK. Verified against the live API.

Either a latitude/longitude/radius box or explicit station IDs select what to listen to. Stations win when both are set, because BirdWeather intersects them. Species heard fewer than minDetections times in the window are skipped — BirdNET guesses at the edge of its confidence produce one-off species that aren't worth a plate.

The plate style now asks for the bird mid-song with a small hand-drawn sonogram in the margin, which is what the preview shows.

Test plan

  • nim c -r src/frameos/tests/test_bird_song_journal_scene.nim — passes. Mock BirdWeather serves two well-heard species plus one below the detection floor and one with no reference photo; asserts only the usable two are logged, one plate drawn + verified per render, HTML credits stored as plain attribution, pollMinutes keeping later renders off the network, the collection cycling, and a configured station ID replacing the bounding box in the query.
  • Offline render with empty state (the gallery-card case) draws the paper placeholder with no network calls and no errors.
  • backend: pytest app/api/tests/test_repositories.py — 19 passed, with the new template asserted in the samples repository.
  • The preview image is a real 480x800 interpreter render of the scene, its Great Tit plate generated from BirdWeather's licensed reference photo and passed through the pipeline's own verification step.

Notes

  • Visual snapshots are left to CI, which regenerates and commits them for same-repo PRs.
  • test_repo_scenes_esp32.nim does not compile on main right now (availableRenderBytesOverride undeclared), so the new scene could not be checked through it. Pre-existing and untouched here.
  • Generating the preview surfaced something worth knowing: the Responses API image_generation tool returns HTTP 520 for the local OpenAI key across models, while plain Responses calls and /v1/images/edits both work. The shipped app still uses the Responses tool exactly as Bird field journal scene #262 does; the preview was generated through the Images API instead. Might be worth checking whether that's account-specific before either scene is relied on.

🤖 Generated with Claude Code

mariusandra and others added 13 commits July 15, 2026 09:12
Split out of #259. Platform work for JavaScript repo apps:

- JS app runtime: HTTP requests (bounded fetch with headers and
  binary responses), asset management, streams, and gated settings
  access for repo code apps
- JS transpiler: template interpolations and comparisons no longer
  eat object literals; native/JS transpiler parity test

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Split out of #259; stacked on the JS app runtime extensions it uses.

- repo/apps/code/birdJournal: iNaturalist sightings become
  OpenAI-generated field-journal plates
- Sample scene under repo/scenes/samples/Bird field journal
- End-to-end mock-server scene test (test_bird_journal_scene.nim)
- Regenerated frontend/src/generated/repoApps.ts and the add-scene /
  apps-drawer visual snapshots for the new app and sample scene

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
# Conflicts:
#	backend/app/api/templates.py
#	e2e/frontend-visual/snapshots/chromium/visual.spec.ts/frame-scenes--add-scene--dark--full.png
#	e2e/frontend-visual/snapshots/chromium/visual.spec.ts/frame-scenes--add-scene--dark--mid.png
#	e2e/frontend-visual/snapshots/chromium/visual.spec.ts/frame-scenes--add-scene--dark--mobile.png
#	e2e/frontend-visual/snapshots/chromium/visual.spec.ts/frame-scenes--add-scene--light--full.png
#	e2e/frontend-visual/snapshots/chromium/visual.spec.ts/frame-scenes--add-scene--light--mid.png
#	e2e/frontend-visual/snapshots/chromium/visual.spec.ts/frame-scenes--add-scene--light--mobile.png
A sibling of the Bird field journal that sources its birds from what
BirdWeather's listening stations actually heard rather than from what
somebody photographed.

The BirdWeather public API is GraphQL, so the app posts a single query
per poll: topSpecies for the roster and window counts, plus an aliased
detections field for the newest local detection per species. Species
carry a licensed reference photo, which is what the plate is drawn from.
Species.latestDetections is deliberately unused — it is global, so it
reports stations on other continents for a local bounding box.

Either a latitude/longitude/radius box or explicit station IDs select
what to listen to; stations win, because passing both intersects them.
Species heard fewer than minDetections times are skipped, since BirdNET
guesses at the edge of its confidence produce one-off species.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A real 480x800 render of the scene through the interpreter, with a Great
Tit plate drawn from BirdWeather's licensed reference photo and live
detection numbers from the Brussels box the placeholder coordinates
describe. Like the other sample previews it is a PNG under a .jpg name.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant