Your Ecological Address (YEA) — System Specification
Your Ecological Address (YEA) — System Specification
A Multi-Source Ecological Profiling Engine for Any Location on Earth
Document ID: CNL-TN-2026-025 Version: 2.0 Date: February 22, 2026 Author: Michael P. Hamilton, Ph.D.
AI Assistance Disclosure: This specification was developed with assistance from Claude (Anthropic, Opus 4.6). The AI contributed to system documentation, API reference compilation, and manuscript drafting based on the author's working codebase and architectural decisions. The author takes full responsibility for the content, accuracy, and conclusions.
Abstract
Your Ecological Address (YEA) is a web application that transforms geographic coordinates into comprehensive ecological profiles by querying 15+ geospatial and biodiversity APIs in parallel. Given any latitude and longitude on Earth, the system returns a structured ecological identity spanning terrain morphometry, bedrock geology and stratigraphy, climate classification, multi-decadal climate history, water balance and evapotranspiration, ecoregion taxonomy, land cover characterization, vegetation community classification, conservation-listed species, multi-taxon biodiversity inventories, seasonal phenology, recent avian field observations, and acoustic bird detections. Place context enrichment via Mapbox POI lookup and Wikipedia geosearch provides narrative grounding for named ecological features. An AI narrative system using Anthropic's Claude Haiku generates interpretive prose from three personas — Naturalist, Scientist, and Teacher — with anti-hallucination constraints that restrict all claims to the data profile.
The interface is organized as a field guide with four thematic panels — Identity, Physical Place, Ecological Setting, and Living Systems — plus a Field Notebook panel for AI-generated narratives. Each panel contains cards that display snapshot summaries and expand to full detail via drawer interaction. A modular JavaScript frontend (ten modules on the FG namespace) communicates with a PHP backend using parallel API fetching (curl_multi) and MySQL caching with source-appropriate TTL values organized by temporal ecology: permanent for geological data, weekly for species inventories, six-hour for bird activity, and fifteen-minute for weather conditions.
A privacy-respecting analytics system tracks usage patterns without IP logging or cookies, and an administrative dashboard provides API health monitoring, cache management, and a MapBox globe visualization of all queried locations worldwide. The cache coordinate resolution of three decimal places (~111 m) was chosen to match the coarsest common spatial resolution of the underlying data sources.
YEA serves as a standalone ecological reference tool at yea.earth, a metadata engine for the SCOPE panoramic photograph database, and a prototype component of the Macroscope integrated environmental observatory platform.
1. Introduction
1.1 Purpose and Concept
YEA computes an "ecological address" for any point on Earth. Where a postal address locates a person within a human administrative framework, an ecological address locates them within the planet's natural organization: what biogeographic realm, what biome, what ecoregion, what climate zone, what bedrock geology, what terrain, what vegetation community, what species assemblage. The tool answers the question: what would a naturalist tell you about this place?
The application accepts input via map click (Mapbox GL JS satellite imagery), place name search (dual iNaturalist and Mapbox Geocoding), direct coordinate entry, or browser geolocation. A single backend call orchestrates parallel queries to all data sources, returning a consolidated JSON response that the frontend renders as thematic panels with expandable data cards.
1.2 Context
YEA is a component of the Macroscope project at the Canemah Nature Laboratory. It is standalone — with its own header, footer, navigation, and CSS. The application is the homepage of yea.earth. A key secondary use is populating ecological metadata for 400+ panoramic photographs in the SCOPE database.
1.3 Design Philosophy
Six principles guide the system:
- Naturalist interpretation over raw data. Data is contextualized, not just displayed. AI narratives interpret ecological relationships.
- Senior-friendly accessibility. 26px Georgia serif base font, high contrast warm parchment palette, large tap targets — informed by user feedback.
- Progressive disclosure. Snapshot cards (compact summary) expand to full detail via drawer interaction.
- Graceful degradation. US-only sources (EPA, NLCD, LANDFIRE) are skipped for international coordinates; global alternatives (RESOLVE, Esri Sentinel-2, Macrostrat) are always available.
- Data richness over implementation complexity. Multiple APIs unified into a coherent ecological narrative through straightforward parallel fetching and parsing.
- Silo independence. Each data card owns its own API sources. Cross-silo ecological interpretation is delegated to the narrative LLM layer, not embedded in the data pipeline.
2. Architecture
2.1 Deployment
| Property | Value |
|---|---|
| Server | Galatea — Mac Mini M4 Pro, 1Gb fiber (production) |
| Web server | Apache 2 (WebMon managed) |
| Backend | PHP 8.3+, mysqli (no PDO) |
| Database | MySQL 8.4+ (managed via phpMyAdmin) |
| Frontend | Vanilla JavaScript (FG namespace), Mapbox GL JS 3.3.0 |
| DEM processing | ImageMagick CLI (convert) |
| Narrative AI | Anthropic Claude Haiku 4.5 (server-side) |
| URL | https://yea.earth → https://canemah.org/projects/ecoADDRESS/ |
| Project root | ecoADDRESS/ (under Apache document root) |
2.2 File Structure
ecoADDRESS/
├── index.php — Page shell: search bar, map, results container
├── address_api.php — Backend orchestrator: validation, caching, API coordination, JSON response
├── narrative_api.php — On-demand AI narrative generation (Anthropic Claude Haiku)
├── about.php — About page
├── contact.php — Contact page
├── sources.php — Data sources page (public-facing)
├── css/
│ ├── fieldguide.css — Base styles: typography, color palette, shared patterns
│ ├── layout.css — Page layout: hero, nav, search, map, controls
│ ├── panels.css — Panel and card system: headers, bodies, status dots
│ ├── drawers.css — Drawer expansion, info modals, lightbox overlay
│ ├── species.css — Species lists, taxon groups, thumbnails, photo backfill
│ └── responsive.css — Breakpoints at 850px and 500px
├── js/
│ ├── fg-config.js — Module 1: FG namespace, Mapbox setup, DOM refs, constants, card info
│ ├── fg-analytics.js — Module 2: Privacy-respecting session tracking, event logging
│ ├── fg-icons.js — Module 3: Lucide SVG icon library (inline generation)
│ ├── fg-helpers.js — Module 4: Shared utilities (escaping, formatting, radius labels)
│ ├── fg-species.js — Module 5: Species list rendering, taxon groups, photo backfill
│ ├── fg-snapshots.js — Module 6: Snapshot summaries for all cards (compact one-line views)
│ ├── fg-drawers.js — Module 7: Drawer content builders for all card types
│ ├── fg-search.js — Module 8: Dual place search (iNaturalist + Mapbox Geocoding)
│ ├── fg-map.js — Module 9: Map interaction, API calls, coordinate handling
│ └── fg-init.js — Module 10: Master renderer, panel builders, event handlers, auto-init
├── lib/
│ ├── sources.php — URL builders, parallel fetch engine (curl_multi), GraphQL client
│ ├── parsers.php — Parser coordinator: loads sub-parsers, provides parseAll()
│ ├── database.php — MySQL caching, query logging, event logging, narrative cache
│ ├── place_context.php — Mapbox POI + Wikipedia geosearch enrichment
│ └── parsers/
│ ├── terrain.php — parseTerrain(), compassLabel()
│ ├── geology.php — parseMacrostrat()
│ ├── climate.php — parseKoppen(), parseClimateArchive()
│ ├── geography.php — parseReverseGeo(), parseEcoregion(), parseResolveEcoregion()
│ ├── landcover.php — parseNlcd(), parseEsriLulc(), parseLandfireEvt()
│ ├── landfire_evt_lookup.php — LANDFIRE EVT code-to-name table (1,068 entries)
│ ├── weather.php — parseWuNearby(), formatWuCurrent(), parseOpenMeteo()
│ ├── biodiversity.php — parseInatTotal(), parseInatTaxon()
│ ├── birds.php — parseEbirdRecent(), parseEbirdNotable(),
│ │ parseBirdWeatherSpecies(), parseBirdWeatherStations()
│ └── conservation.php — parseConservation()
├── includes/
│ ├── header.php — Shared HTML head, hero banner, site navigation
│ └── footer.php — Shared footer, external links
├── admin/ — Administrative dashboard (password-protected)
│ ├── index.php — Dashboard home: API health, cache stats, recent queries
│ ├── analytics.php — Usage analytics: sessions, devices, engagement, referrers
│ ├── globe.php — MapBox globe visualization of all queried locations
│ ├── globe_data.php — GeoJSON endpoint for globe (aggregated by coordinate)
│ ├── events_api.php — POST handler for frontend usage events
│ └── includes/
│ └── header.php — Admin navigation
├── img/ — Favicons, hero banner, author photo, logo
├── deprecated/ — Earlier experimental versions (address.js, cards.js, classic.php)
└── docs/ — Documentation, SQL schema, workplans
2.3 Credential Files (Outside Webroot)
/Library/WebServer/secure/credentials/ecoaddress/
ai-config.php — Defines WU_API_KEY, MAPBOX_TOKEN, EBIRD_API_KEY,
OPEN_METEO_API_KEY, ANTHROPIC_API_KEY
ecoaddress.php — Database credentials: $db_host, $db_name, $db_user, $db_pass
2.4 Request Flow
The primary lookup lifecycle:
- User clicks map, searches a place name, enters coordinates, or uses browser geolocation.
fg-map.jscallsGET address_api.php?lat={lat}&lon={lon}&sid={session_id}.- The orchestrator validates input and determines CONUS membership (US bounding box check).
- Mapbox tile coordinates are computed for zoom level 14.
- MySQL cache is checked for existing responses (
cacheGetAll). - URLs are built only for uncached sources (
buildUrlsinsources.php). - All uncached sources are fetched in parallel via
curl_multi(fetchAllinsources.php). - New responses are cached (
cacheSetAll). - All responses are parsed (
parseAllinparsers.php). - Sequential Weather Underground station iteration finds an active personal weather station (PWS) within five miles. PWS temperature is validated against Open-Meteo baseline (±10°F divergence rejection).
- Dynamic radius widening runs for iNaturalist (1 → 5 → 10 → 20 km if fewer than five species).
- Conservation status queries run at the final iNaturalist radius.
- Dynamic radius widening runs for eBird (same cascade).
- Dynamic radius widening runs for BirdWeather (same cascade, GraphQL POST with bounding box).
- BirdWeather station metadata is fetched via the
Species.stationsnested field. - LANDFIRE vegetation type is fetched with 30m grid-snapped coordinates (standalone curl, CONUS only).
- Open-Meteo Historical archive is queried for 1991–2025 climate + water balance (cached permanently; skipped if cache hit). Single request with 6 variables feeds both Climate History and Water Balance cards.
- iNaturalist seasonal queries (month-filtered) run for all nine taxa with radius widening.
- Place context enrichment: Mapbox POI reverse lookup + Wikipedia geosearch + ecoregion Wikipedia fallback.
- POI name promotion: if within 200m of a named ecological place (park, reserve, trail), promote to primary identity.
- Query is logged with timing, per-source status, user agent, referer, and session ID.
- Consolidated JSON is returned to the frontend.
fg-init.jsrenders field guide panels. Async bird photo backfill begins for species missing thumbnails.- Analytics module sends session_start event and tracks subsequent interactions.
3. Data Sources
YEA integrates 15+ external data sources spanning terrain, geology, climate, climate history, water balance, ecoregion classification, land cover, vegetation community, weather, biodiversity, conservation status, phenology, avian monitoring, and place context. Each source is described below.
3.1 Source Summary
| # | Source | Data | Scope | Resolution | Cache TTL |
|---|---|---|---|---|---|
| 1 | Mapbox Terrain-RGB DEM [1] | Elevation, slope, aspect | Global | ~9.5 m (zoom 14) | Permanent |
| 2 | Macrostrat [21] | Bedrock geology, lithology, formation, age | Global | Vector polygon | Permanent |
| 3 | Köppen Climate API [5] | Climate zone + description | Global | ~28 km | 90 days |
| 4 | Mapbox Reverse Geocoding [1] | Place name, county, state | Global | Point | Permanent |
| 5 | RESOLVE Ecoregions 2017 [6] | Realm, biome, ecoregion | Global | Vector polygon | Permanent |
| 6 | Esri Sentinel-2 10m LULC [7] | 9-class land cover | Global | 10 m | Permanent |
| 7 | EPA Omernik Ecoregions [8,9] | Levels I–IV | US only | 1:250K | Permanent |
| 8 | MRLC NLCD 2021 [10] | 20-class land cover | CONUS | 30 m | Permanent |
| 9 | LANDFIRE LF2024 EVT [22] | Vegetation community (1,068 NatureServe ecological systems) | CONUS | 30 m | Permanent |
| 10 | Weather Underground [12] | PWS current conditions | Global | Point | 15 min |
| 11 | Open-Meteo Pro [13] | Modeled weather baseline | Global | Reanalysis grid | 15 min |
| 12 | iNaturalist [2] | Species counts (9 taxa) | Global | Point + radius | 7 days |
| 13 | iNaturalist Conservation [2] | Threatened/IUCN-listed species | Global | Point + radius | 7 days |
| 14 | eBird API 2.0 [3,14] | Recent + notable observations | Global | Point + radius | 6 hours |
| 15 | BirdWeather [15,16] | Acoustic detections + stations | Global (station-dependent) | Bounding box | 6 hours |
| 16 | Open-Meteo Historical Pro [17,18,20] | 1991–2025 climate normals + water balance (6 variables) | Global | 9–25 km | Permanent |
| 17 | iNaturalist Seasonal [2] | Month-filtered species counts (9 taxa, 3-month window) | Global | Point + radius | 7 days |
| 18 | Mapbox Search Box [1] | Nearby POIs (parks, reserves, landmarks) | Global | Point + radius | Permanent |
| 19 | Wikipedia Geosearch [23] | Geotagged articles with summaries | Global | Point + radius | Permanent |
Removed sources: USDA FIA Forest Atlas (GeoPlatform identify endpoint returns HTTP 400 since Kubernetes migration, February 2026; vegetation type coverage now provided by LANDFIRE EVT at 30m).
3.2 API Endpoints
3.2.1 Mapbox Terrain-RGB DEM [1]
https://api.mapbox.com/v4/mapbox.terrain-rgb/{z}/{tx}/{ty}.pngraw?access_token={token}
Returns a raw PNG tile encoding elevation in the RGB channels. Elevation is decoded as: −10000.0 + ((R × 256 × 256 + G × 256 + B) × 0.1), yielding 0.1 m precision. Slope and aspect are computed from a 3×3 pixel neighborhood gradient using ImageMagick CLI to write a temporary PNG, crop a 3×3 region via convert -depth 8 -crop, and parse the text output (~100–200 ms overhead, no PHP extension dependencies). Requires MAPBOX_TOKEN.
3.2.2 Macrostrat Geologic Map [21]
https://macrostrat.org/api/v2/geologic_units/map?lat={lat}&lng={lon}&response=long
Returns bedrock geology at multiple map scales. The parser selects the most detailed unit (richest description, narrowest age range) and returns: formation name, lithology (major and minor rock types), stratigraphic name, geologic age (top/bottom in Ma), period, best interval, map color, and source reference. No API key required. CC-BY 4.0 license. Global coverage from 225+ integrated geological survey maps.
3.2.3 Köppen Climate API [5]
http://climateapi.scottpinkelman.com/api/v1/location/{lat}/{lon}
Returns the Köppen-Geiger climate zone code and description. No API key required.
3.2.4 Mapbox Reverse Geocoding [1]
https://api.mapbox.com/geocoding/v5/mapbox.places/{lon},{lat}.json
?access_token={token}&types=place,region,district,locality
Returns place name, county, and state. Requires MAPBOX_TOKEN.
3.2.5 RESOLVE Ecoregions 2017 [6]
https://data-gis.unep-wcmc.org/server/rest/services/
Bio-geographicalRegions/Resolve_Ecoregions/MapServer/identify
?geometry={lon},{lat}&geometryType=esriGeometryPoint&sr=4326
&layers=all:0&tolerance=0
&mapExtent={bbox ± 0.01°}&imageDisplay=800,600,96
&returnGeometry=false&f=json
Returns realm, biome, ecoregion name, Nature Needs Half category. No API key required. The tight bounding box (± 0.01°) is critical for accuracy at ecotone boundaries.
3.2.6 Esri Sentinel-2 10m LULC [7]
https://ic.imagery1.arcgis.com/arcgis/rest/services/
Sentinel2_10m_LandCover/ImageServer/identify
?geometry={"x":{x_merc},"y":{y_merc},"spatialReference":{"wkid":3857}}
&geometryType=esriGeometryPoint&returnGeometry=false
&returnCatalogItems=false&f=json
Requires Web Mercator projection. Nine land cover classes: Water (1), Trees (2), Flooded Vegetation (4), Crops (5), Built Area (7), Bare Ground (8), Snow/Ice (9), Clouds (10), Rangeland (11). No API key required.
3.2.7 EPA Omernik Ecoregions [8,9]
https://geodata.epa.gov/arcgis/rest/services/
ORD/USEPA_Ecoregions_Level_III_and_IV/MapServer/identify
?geometry={lon},{lat}&geometryType=esriGeometryPoint&sr=4326
&layers=all:7&tolerance=0
&mapExtent={bbox ± 0.01°}&imageDisplay=800,600,96
&returnGeometry=false&f=json
US only. Layer 7 = Level IV polygons, which return all four Omernik levels in a single query. The tight bounding box (± 0.01°) replaces the default global map extent, which caused incorrect polygon returns at mountain ecotone boundaries. No API key required.
3.2.8 MRLC NLCD 2021 [10]
https://www.mrlc.gov/geoserver/mrlc_display/
NLCD_2021_Land_Cover_L48/ows
?service=WMS&version=1.1.1&request=GetFeatureInfo
&layers=NLCD_2021_Land_Cover_L48
&query_layers=NLCD_2021_Land_Cover_L48
&info_format=application/json&x=50&y=50&width=101&height=101
&srs=EPSG:4326&bbox={bbox ± 0.005°}
CONUS only. Twenty land cover classes at 30 m resolution. No API key required.
3.2.9 LANDFIRE LF2024 Existing Vegetation Type [22]
https://lfps.usgs.gov/arcgis/rest/services/Landfire_LF230/
US_230EVT/ImageServer/identify
?geometry={"x":{lon},"y":{lat},"spatialReference":{"wkid":4326}}
&geometryType=esriGeometryPoint&returnGeometry=false&f=json
CONUS only. 30 m resolution. Requires User-Agent header. Returns a numeric EVT code (e.g., 7039) that maps to one of 1,068 NatureServe ecological system classifications via a generated PHP lookup table. Each entry provides: ecological system name, lifeform (tree/shrub/herbaceous), physiognomy, group name, order, class, and subclass. Standalone curl call with 30m grid-snapped coordinates (not part of the parallel fetchAll batch) to ensure consistent pixel selection regardless of GPS jitter.
Grid-snapping math: Coordinates are snapped to the center of the nearest 30m LANDFIRE pixel before the API call. lat_step = 30.0 / 111111.0 (~0.00027°); lon_step adjusted by cos(latitude) for meridian convergence. This ensures that GPS jitter within a single pixel always resolves to the same query coordinate and cache key.
3.2.10 Weather Underground [12]
Nearby stations:
https://api.weather.com/v3/location/near
?geocode={lat},{lon}&product=pws&format=json&apiKey={key}
Current conditions (sequential, per station):
https://api.weather.com/v2/pws/observations/current
?stationId={id}&format=json&units=e&apiKey={key}
Requires WU_API_KEY. The orchestrator iterates through up to five nearest stations, querying each sequentially until one reports non-null temperature. PWS data is validated against the Open-Meteo baseline; temperature divergence exceeding ±10°F triggers station rejection.
3.2.11 Open-Meteo Pro [13]
https://customer-api.open-meteo.com/v1/forecast
?latitude={lat}&longitude={lon}
¤t=temperature_2m,relative_humidity_2m,wind_speed_10m,
wind_direction_10m,surface_pressure
&temperature_unit=fahrenheit&wind_speed_unit=mph
&apikey={key}
Global modeled weather baseline. Always queried regardless of PWS availability. Requires OPEN_METEO_API_KEY (commercial Pro API subscription).
3.2.12 iNaturalist [2]
https://api.inaturalist.org/v1/observations/species_counts
?lat={lat}&lng={lon}&radius={km}&per_page={n}
[&iconic_taxa={taxon}]
Nine taxon groups are queried independently: Plantae, Fungi, Aves, Mammalia, Reptilia, Amphibia, Insecta, Arachnida, Mollusca. Plants return per_page=20; all others return per_page=10. A total species count query (no taxon filter) is also made. No API key required.
3.2.13 iNaturalist Conservation [2]
https://api.inaturalist.org/v1/observations/species_counts
?lat={lat}&lng={lon}&radius={km}&threatened=true&per_page=100
Two queries at the final biodiversity radius: (1) threatened=true&per_page=0 for total count of all conservation-listed species (NatureServe + IUCN + state listings), and (2) threatened=true&per_page=100 for full details. Species are grouped by conservation severity: Critically Endangered, Endangered, Vulnerable, Near Threatened, NatureServe Imperiled.
3.2.14 eBird API 2.0 [3,14]
Recent observations (30 days):
https://api.ebird.org/v2/data/obs/geo/recent
?lat={lat}&lng={lon}&dist={km}&back=30&sort=species&key={key}
Notable/rare species (14 days):
https://api.ebird.org/v2/data/obs/geo/recent/notable
?lat={lat}&lng={lon}&dist={km}&back=14&key={key}
Requires EBIRD_API_KEY.
3.2.15 BirdWeather GraphQL [15,16]
POST to https://app.birdweather.com/graphql. No API key required.
Species detections (7 days):
{
topSpecies(
ne: {lat: NE_LAT, lon: NE_LON},
sw: {lat: SW_LAT, lon: SW_LON},
period: {count: 7, unit: "day"},
limit: 20
) {
species {
id commonName scientificName thumbnailUrl imageUrl
ebirdCode ebirdUrl birdweatherUrl wikipediaSummary color
}
count
breakdown { almostCertain veryLikely uncertain unlikely }
}
}
Station metadata (via Species.stations nested field):
The root stations GraphQL query returns HTTP 500 (broken server-side). Station metadata is recovered via the Species.stations nested field, which uses a different resolver. The system queries topSpecies(limit:3) with nested stations to discover PUC devices in the bounding box, then deduplicates by station ID.
Note: BirdWeather InputLocation uses {lat, lon} (not {lat, lng}).
3.2.16 Open-Meteo Historical Pro — Climate Archive [17,18,20]
Unified daily aggregates, 1991–2025 (6 variables):
https://customer-archive-api.open-meteo.com/v1/archive
?latitude={lat}&longitude={lon}
&start_date=1991-01-01&end_date=2025-12-31
&daily=temperature_2m_max,temperature_2m_min,temperature_2m_mean,
precipitation_sum,sunshine_duration,
et0_fao_evapotranspiration
&temperature_unit=fahrenheit&wind_speed_unit=mph
&precipitation_unit=inch&timezone=auto
&apikey={key}
A single request with 6 variables feeds both the Climate History card and the Water Balance card, replacing the original three separate requests (48% API cost reduction). Returns ~12,400 daily records processed server-side into monthly summary statistics via a single-pass parser with dual accumulators:
- Baseline (1991–2020): 30-year climate normals per month — temperature (mean, high, low), precipitation totals, sunshine hours.
- Trend (2010–2024): Delta comparison against baseline — warming, drying, wetter, longer frost-free season.
- Water balance: Monthly precipitation minus ET₀ (FAO Penman-Monteith reference evapotranspiration). Surplus months (recharge) and deficit months (drought stress).
- Growing degree days: Cumulative from mean temperature using 5°C base.
The "Best Match" model is used by default, seamlessly blending ECMWF IFS (9 km, 2017–present) with ERA5 and ERA5-Land for the earlier record. Requires OPEN_METEO_API_KEY. Results cached permanently — historical normals do not change.
Dropped from v1.1: wind_speed_10m_max (grid-modeled wind is ecologically meaningless), daylight_duration (pure astronomy, computed from latitude), separate ERA5-Land soil temperature/moisture queries (soil variables were found to add complexity without proportionate ecological insight at the screen-display level).
3.2.17 iNaturalist Seasonal (Month-Filtered) [2]
https://api.inaturalist.org/v1/observations/species_counts
?lat={lat}&lng={lon}&radius={km}&per_page={n}
&month={prev},{current},{next}
[&iconic_taxa={taxon}]
Same endpoint as the Biodiversity card (3.2.12) but with the month= parameter added. The month parameter accepts comma-separated month numbers (1–12) and returns observations from those months across all years in the database, collapsing interannual variation onto a 12-month calendar.
The three-month window (current month ± 1) captures species active in the current season, early and late seasonal transitions, and shoulder-season species. Month wrapping is handled in PHP: for January, the query becomes month=12,1,2; for December, month=11,12,1.
3.2.18 Place Context: Mapbox POI + Wikipedia [1,23]
Mapbox Search Box reverse:
https://api.mapbox.com/search/searchbox/v1/reverse
?longitude={lon}&latitude={lat}&access_token={token}
&types=poi&limit=5&language=en
Wikipedia geosearch:
https://en.wikipedia.org/w/api.php
?action=query&list=geosearch&gscoord={lat}|{lon}
&gsradius=2000&gslimit=5&format=json
Wikipedia extracts (for articles found by geosearch):
https://en.wikipedia.org/w/api.php
?action=query&prop=extracts&exintro&explaintext
&pageids={ids}&format=json
Place context enrichment provides narrative grounding. POIs within 200m of ecological categories (parks, reserves, natural areas, trails, campgrounds) can be promoted to primary place identity. Wikipedia articles provide contextual summaries for the narrative AI prompt. A tiered fallback system queries: (1) nearby POIs, (2) nearby Wikipedia articles, (3) Wikipedia article for the RESOLVE ecoregion name.
3.3 Coordinate Transformations
Web Mercator (EPSG:3857) is required by the Esri LULC endpoint:
$x_merc = $lon * 20037508.34 / 180;
$y_merc = log(tan(M_PI / 4 + deg2rad($lat) / 2)) * 20037508.34 / M_PI;
CONUS detection for conditional US-only source queries:
$is_conus = ($lat >= 24.0 && $lat <= 50.0 && $lon >= -125.0 && $lon <= -66.0);
4. Dynamic Radius Widening
All biodiversity sources (iNaturalist, eBird, BirdWeather) use the same progressive widening pattern:
- Initial query at 1 km radius.
- If species count is below the threshold (fewer than five species, or three for seasonal), widen progressively: 5 → 10 → 20 km.
- Accept the first radius meeting the threshold, or accept the maximum (20 km) result.
- BirdWeather uses a bounding box computed from
radius_km / 111.1latitude offset rather than a true radius parameter.
Each widened query is a fresh fetchAll() or fetchBirdWeather() call. Conservation status queries run after biodiversity widening completes, using the final iNaturalist radius. The widening cascades run sequentially after the initial parallel fetch completes. The final radius used is recorded in the JSON response for display in the UI.
5. Weather Validation
Personal weather stations (PWS) from Weather Underground can report erroneous data. YEA implements a validation strategy:
- Open-Meteo is always queried as a global modeled baseline.
- WU stations are accepted only within five miles of the query point.
- The orchestrator iterates sequentially through up to five nearest WU stations until one reports non-null temperature.
- The PWS temperature is compared against the Open-Meteo baseline. If divergence exceeds ±10°F, the station is rejected as malfunctioning.
- On rejection or absence of any valid PWS, modeled Open-Meteo data is used as fallback and tagged as "modeled" in the UI.
6. Database Schema
Database: ecological_address
6.1 lookup_cache
Stores raw API responses keyed by rounded coordinates and source identifier.
CREATE TABLE lookup_cache (
id int UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
coord_key varchar(24) NOT NULL,
source varchar(32) NOT NULL,
response MEDIUMTEXT NOT NULL,
created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uk_coord_source (coord_key, source),
KEY idx_created (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
Coordinate key format: Lat and lon rounded to three decimal places (~111 m precision), e.g., "45.357,-122.607". This resolution was chosen to match the ecological resolution of the data sources — the finest actual data source is 10m (Esri Sentinel-2 LULC) and the majority are 30m or coarser, while radius-searched biodiversity APIs query in circles measured in kilometers. Two points within ~111m will share a single cache entry, improving cache hit rates without losing meaningful ecological variation.
6.2 lookup_log
Records every query with timing, per-source cache status, and privacy-respecting session metadata.
CREATE TABLE lookup_log (
id int UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
coord_key varchar(24) NOT NULL,
lat decimal(8,4) NOT NULL,
lon decimal(9,4) NOT NULL,
place_name varchar(128) DEFAULT NULL,
duration_ms int UNSIGNED NOT NULL,
source_status JSON NOT NULL,
user_agent varchar(512) DEFAULT NULL,
referer varchar(512) DEFAULT NULL,
session_id char(12) DEFAULT NULL,
created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_coord (coord_key),
KEY idx_created (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
6.3 narrative_cache
Stores LLM-generated narratives keyed by coordinate and data hash. Multiple narrative tiers (teaser, naturalist, scientist, teacher) accumulate in a single JSON object per coordinate+hash. The data hash is an MD5 of the parsed ecological data excluding weather and eBird (which change too frequently); if the underlying data changes, the hash changes and fresh narratives are generated.
CREATE TABLE narrative_cache (
id int UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
coord_key varchar(24) NOT NULL,
data_hash char(32) NOT NULL,
narratives MEDIUMTEXT NOT NULL,
provider varchar(16) NOT NULL,
model varchar(64) NOT NULL,
created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uk_coord_hash (coord_key, data_hash),
KEY idx_created (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
6.4 usage_events
Frontend interaction tracking for analytics. No IP logging, no cookies, no persistent identifiers.
CREATE TABLE usage_events (
id int UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
session_id char(12) NOT NULL,
event_type varchar(32) NOT NULL,
event_data JSON DEFAULT NULL,
created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
KEY idx_session (session_id),
KEY idx_type (event_type),
KEY idx_created (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
6.5 Cache TTL Strategy
Cache expiration is organized by the temporal behavior of each data source:
| Temporal Class | TTL | Sources |
|---|---|---|
| Geological (permanent) | 365 days | terrain, macrostrat, ecoregion, resolve_eco, nlcd, esri_lulc, landfire_evt, reverse_geo, place_context |
| Climate (static dataset) | 90 days | koppen |
| Climate normals (permanent) | 365 days | climate_history, water_balance |
| Seasonal accumulation | 7 days | all inat* sources, all season* sources, inat_threatened, inat_conservation |
| Daily activity | 6 hours | ebird_recent, ebird_notable, bw_species |
| Real-time | 15 minutes | wu_nearby, open_meteo |
| Narrative | 30 days | narrative_cache (keyed by data hash — invalidated when source data changes) |
7. Frontend Architecture
7.1 Panel Structure
The interface is organized as a field guide with five thematic panels. Each panel (except Identity and Field Notebook) contains expandable data cards.
| Panel | Subtitle | Cards |
|---|---|---|
| Identity | The identity of this place | Place name, coordinates, ecological address summary |
| Physical Place | The abiotic foundation | Terrain, Geology, Climate, Current Conditions, Climate History, Water Balance |
| Ecological Setting | Biogeographic context | Ecoregion & Biome, Land Cover, Vegetation Type, Conservation Status |
| Living Systems | What lives here | Biodiversity, Seasonality, Recent Bird Activity, Acoustic Detections |
| Field Notebook | Ecological interpretation | AI-generated narratives from three personas |
Panel ordering rationale: The environmental story flows from permanent identity (place, geology, climate zone) through temporal context (climate history, ecoregion, land cover, conditions, water balance) to biological inventory (biodiversity, seasonality, birds, acoustics), culminating in synthesized interpretation (narratives). This mirrors the way a naturalist orients: geology first, climate second, biology third.
7.2 Card States
Each card has three visual states:
- Placeholder — displayed before any search. Shows category title and explanatory text.
- Snapshot — compact data summary after search. One-line key data value plus source attribution and status indicator (green dot = data received, red dot = error).
- Drawer — full detail view on card click. Card expands below the snapshot with all fields, species lists, charts, and interactive elements.
An info button (ℹ) on each card opens a modal explaining the data source, what it shows, and its ecological interpretation. Info content is defined in FG.CARD_INFO in fg-config.js.
7.3 JavaScript Module Architecture
Ten modules load in dependency order on the FG namespace (all 'use strict'):
| Load Order | Module | Responsibility |
|---|---|---|
| 1 | fg-config.js |
Namespace creation, Mapbox setup, DOM refs, constants, card info definitions, placeholder text, progress messages, CARD_SOURCE_MAP |
| 2 | fg-analytics.js |
Session ID generation (12-char random, tab-scoped), FG.track(event, data), sendBeacon/fetch transport |
| 3 | fg-icons.js |
Lucide SVG icon library — FG.icon(name) returns inline SVG markup |
| 4 | fg-helpers.js |
Shared utilities: FG.esc(), FG.formatNum(), radius labels, taxon display helpers |
| 5 | fg-species.js |
Species list rendering, taxon group headers with representative thumbnails, photo backfill via iNaturalist taxa autocomplete API |
| 6 | fg-snapshots.js |
Snapshot summary builders for all 14 card types |
| 7 | fg-drawers.js |
Drawer content builders for all card types, including species lightbox, eBird sections, BirdWeather sections, climate charts, geology details |
| 8 | fg-search.js |
Dual place search merging iNaturalist Places (reserves, parks, field stations) with Mapbox Geocoding (addresses, cities, POIs), tagged by source |
| 9 | fg-map.js |
Map click handler, coordinate input, geolocation, API fetch orchestration, analytics event emission |
| 10 | fg-init.js |
Master renderer, panel builders, placeholder rendering, card click handlers, info modal, persona narrative handlers |
7.4 Field Notebook — AI Narrative System
The Field Notebook panel provides AI-generated ecological narratives from three personas:
| Persona | Voice | Target Audience | Length |
|---|---|---|---|
| Naturalist | Story-driven, sensory, interpretive prose | General public, curious visitors | 150–200 words |
| Scientist | Technical, precise, research-oriented with Markdown formatting | Graduate students, researchers | 200–300 words |
| Teacher | Wonder-driven, age-appropriate, ends with activity prompt | Classrooms, field trips, young learners | 150–200 words |
Additionally, a teaser narrative (50 words maximum, 2 sentences) is generated automatically for the Identity panel, providing a brief data-driven synthesis without requiring the user to click into the Field Notebook.
Anti-hallucination architecture: Every narrative prompt includes the complete ecological data profile as the sole source of truth, with explicit instructions: "Every factual claim must come directly from the data profile below. Do NOT draw on outside knowledge about named places, water bodies, landmarks, or history not in the data." Absent data categories are explicitly flagged so the model does not infer missing information.
Urban-context awareness: The prompt system detects developed/urban land cover and instructs the narrative to interpret the location as urban or suburban ecology — managed landscapes, edge habitats, species navigating human-built environments — rather than describing it as wild.
Model: Anthropic Claude Haiku 4.5 (claude-haiku-4-5-20251001) for all four tiers. Teaser uses 150 max tokens; Naturalist and Teacher use 400; Scientist uses 600. Temperature 0.6.
Caching: Narratives are cached by coordinate + MD5 hash of the ecological data (excluding weather and eBird). Multiple tiers accumulate in a single JSON object. If the underlying data changes (e.g., new species observed, cache refresh), the hash changes and fresh narratives are generated on next request.
8. Analytics System
8.1 Design Principles
The analytics system is privacy-respecting by design: no IP addresses are logged, no cookies are set, and no persistent user identifiers exist. Session identity is a 12-character random alphanumeric string generated client-side in a JavaScript variable that dies when the browser tab closes. Sessions cannot be linked to individuals or across visits.
8.2 Tier 1 — Enriched Lookup Log (Server-Side)
Every API lookup records: coordinates, place name, response time, per-source cache status (hit/cached/error), user agent string, HTTP referer, and session ID. This enables device detection (mobile vs desktop, browser identification) and referrer analysis without any client-side tracking beyond the session parameter.
8.3 Tier 2 — Frontend Event Tracking
The fg-analytics.js module tracks seven event types via POST to events_api.php:
| Event | Payload | Trigger |
|---|---|---|
session_start |
viewport dimensions, touch capability, language | Page load |
lookup |
lat, lon, place name, method (map/search/coords/geolocate) | API call |
map_click |
lat, lon | Map click |
search_select |
query string, source (inat/mapbox) | Search selection |
geolocate |
lat, lon | Geolocation button |
drawer_open |
card ID | Card expansion |
narrative_request |
persona (naturalist/scientist/teacher) | Persona click |
Transport uses navigator.sendBeacon when available, falling back to fetch with keepalive: true.
8.4 Administrative Dashboard
Password-protected admin interface at /admin/ providing:
- Dashboard: API health summary, cache statistics, recent queries with timing
- Analytics: 14-day session overview, daily activity trends, entry method breakdown, card engagement, narrative persona usage, device/browser distribution, referrer analysis, recent session browser
- Globe: MapBox globe visualization with satellite-streets basemap, showing all queried locations as GPU-rendered circle layers. Time filter (7d/30d/90d/All). Sidebar with sortable location list. Click-to-fly interaction. Geographically accurate circle size (~111m diameter at street-level zoom matching the cache coordinate resolution).
9. UI Design Specifications
9.1 Color Palette
The "warm parchment" palette uses earth tones:
| Element | Hex |
|---|---|
| Page background | #f5f0e8 |
| Primary text | #2c2416 |
| Card background | #fffdf7 |
| Card border | #c4b99a |
| Accent / buttons | #5c7a3a (forest green) |
| Section headers | #5c7a3a (uppercase) |
| Secondary text | #5a4e3a, #7a6e56 |
| Muted text | #9a8e76, #b0a690 |
| Card hover border | #7a8c5a |
9.2 Typography
| Property | Value |
|---|---|
| Font family | Georgia, 'Times New Roman', serif |
| Base font size | 26 px (bumped for senior accessibility) |
| Mobile base | 24 px |
| Line height | 1.7 |
| Coordinate display | 'SF Mono', 'Fira Code', Consolas, monospace |
| Card titles | 1.1 rem, bold, uppercase, letter-spacing 0.04 em |
9.3 Map Configuration
Mapbox GL JS 3.3.0 with satellite-streets-v12 style. Default center: Canemah [−122.6068, 45.3573], zoom 10. Red marker (#e74c3c). Navigation control top-right. Dual place search merges iNaturalist Places with Mapbox Geocoding, tagging results by source.
9.4 Responsive Breakpoints
| Breakpoint | Behavior |
|---|---|
| > 850 px | Full desktop layout, side-by-side elements where applicable |
| 500–850 px | Tablet — single column, reduced padding |
| < 500 px | Mobile — stacked layout, 24px base font, touch-optimized tap targets |
10. Key Technical Decisions
| Decision | Rationale |
|---|---|
| Mapbox DEM over Open-Meteo elevation | 0.1 m precision vs 90 m. Slope and aspect require fine resolution from 3×3 neighborhood. |
| ImageMagick CLI over PHP GD | No GD/Imagick extensions on Galatea. convert handles DEM pixel extraction reliably. |
| EPA tight bounding box (± 0.01°) | Default global map extent caused wrong polygon returns at mountain ecotone boundaries. |
| Macrostrat for geology | Global coverage from 225+ integrated maps, CC-BY license, rich metadata. No API key required. |
| LANDFIRE EVT replacing USDA FIA | 30m NatureServe ecological system classifications vs 250m forest type groups. FIA endpoint broken since Feb 2026. |
| LANDFIRE 30m grid-snapping | GPS jitter across devices can place same location in different 30m pixels. Snap to pixel center ensures cache consistency. |
| 3-decimal coordinate rounding (~111 m) | Matches ecological resolution of data sources. Coarsest common resolution is 10m (Esri LULC), most sources are 30m+, and biodiversity APIs search in km-scale radii. Two points within ~111m return identical data from all sources. |
| Unified climate archive (6 vars) | Single request for both Climate History and Water Balance cards. 48% API cost reduction vs three separate requests. |
| Open-Meteo Pro API | Commercial subscription enables higher rate limits and priority access for production use. |
| Dual place search (iNat + Mapbox) | iNaturalist Places finds ecological sites (reserves, parks). Mapbox finds human places (addresses, cities). |
| Sequential WU station iteration | Many PWS stations go offline or report null. Loop until finding one with valid temperature. |
| Open-Meteo as PWS validator | ±10°F divergence threshold catches malfunctioning stations. |
BirdWeather Species.stations path |
Root stations query returns HTTP 500. Nested field uses different resolver and works reliably. |
| Async bird photo backfill | eBird returns no photos; BirdWeather sometimes lacks thumbnails. iNat taxa autocomplete provides photos. Batched in groups of three to avoid rate limiting. |
| iNat conservation over IUCN API | iNaturalist already embeds conservation status. Pragmatic over complex. |
| Separate Climate History and Water Balance cards | Silo independence. Different ecological questions (atmosphere vs below-ground water budget). |
iNat month= for Seasonality |
Collapses interannual variation onto 12-month calendar. Solves episodic observation problem. |
| Claude Haiku 4.5 for narratives | Cost-effective at scale; data-rich prompts produce high-quality prose even from smaller models. |
| Anti-hallucination prompt architecture | Repeated constraints: "the data is your only source of truth." Explicitly flags absent data categories. |
| POI name promotion with category filtering | Only ecological places (parks, reserves, trails) promoted; schools, businesses, historic buildings blocked. |
| Tab-scoped session ID (no cookies) | Privacy-respecting analytics. Session dies with tab. Cannot link across visits or to individuals. |
sendBeacon for analytics |
Reliable delivery even on page unload. Fallback to fetch with keepalive. |
| GPU-rendered circle layers for globe | MapBox circle layers render on GPU. Handles 10,000+ points without lag. Zero DOM overhead. |
| Globe circles at true geographic scale | circle-pitch-alignment: 'map' renders ~111m footprint at street zoom, honest about data resolution. |
| mysqli over PDO | Project convention for all Macroscope PHP code. |
| Vanilla JS, no frameworks | No React/Vue build step. Editable in BBEdit. Simplicity over scaffolding. |
11. Verified Test Sites
| Site | Lat | Lon | Key Characteristics |
|---|---|---|---|
| Canemah (home) | 45.357 | −122.607 | Bluff, 23.8° slope, E-facing. Willamette Valley. Urban-edge habitat. |
| Bellingham, WA | 48.75 | −122.48 | Puget Lowland. 1,285 species. Tests WU station iteration. |
| Blue Oak Ranch, CA | 37.382 | −121.738 | Central CA Foothills. 574 m. Rough coords can hit Open Water. |
| James/Idyllwild, CA | 33.746 | −116.715 | Southern CA Mountains. Tests tight bbox for ecoregion accuracy. |
12. Limitations
YEA depends on the availability and accuracy of 15+ external APIs, each with its own coverage gaps, rate limits, and potential for change. US-specific sources (EPA, NLCD, LANDFIRE) are unavailable internationally; the global alternatives (RESOLVE, Esri Sentinel-2) are coarser. Weather Underground PWS coverage is uneven, especially outside urban areas. iNaturalist observation density varies dramatically by region — heavily observed areas (Pacific Northwest, California) return rich species lists, while remote or under-observed areas may require maximum radius widening and still return sparse data. BirdWeather coverage depends entirely on PUC station deployment, which is concentrated in North America and Western Europe. The Köppen Climate API is a third-party service with no SLA. The BirdWeather GraphQL API has known instabilities (the root stations query returns HTTP 500).
Open-Meteo Historical API responses for the unified 35-year query (1991–2025, 6 variables) are large (~12,400 daily records); server-side computation of monthly summaries adds processing time to first-visit requests, but permanent caching ensures subsequent lookups are instant. The fetchClimateArchive function implements retry logic (up to 2 attempts with 2-second pause) to handle intermittent timeouts.
LANDFIRE vegetation data covers CONUS only. Locations outside the contiguous US show "CONUS only" for vegetation type. Macrostrat geology has global coverage but resolution varies by region depending on available source maps.
The iNaturalist month= parameter for seasonal filtering depends on adequate multi-year observation history at the location; recently documented or under-observed areas may have insufficient seasonal data to distinguish phenological patterns. The 3-decimal coordinate rounding (~111m) means that two users standing 120 meters apart will receive different ecological profiles; users closer than ~111m will share the same cached result.
Narrative generation depends on the Anthropic API and incurs per-token costs. The anti-hallucination constraints are effective but not infallible — the prompt instructs the model not to fabricate, but LLMs can occasionally introduce plausible-sounding details not present in the source data. The teaser narrative (50-word limit) occasionally exceeds the word count target.
13. Planned Enhancements
13.1 Biodiversity API Expansion
GBIF for historical records and deeper temporal coverage. Map of Life for predicted species ranges. IUCN Red List API for authoritative global conservation status.
13.2 Sensor Integration Layers
Custom API layers for Macroscope sensors, ecoSPLAT 360° panoramas, and small aerial drone imagery. The globe visualization infrastructure already supports multiple GeoJSON layers that could serve as spatial indices for these data types.
13.3 Organelle Convergence Architecture
Integration with the broader Macroscope platform as described in Hamilton (2026), "Organelle Convergence Architecture." Shared spatiotemporal index, event bus, and STRATA synthesis layer connecting YEA, MEO, ecoSPLAT, and Macroscope Nexus. See CNL-FN-2026-026 for architectural details.
13.4 Additional Enhancements
- Climate projection data to 2050 for forward-looking ecological context
- "Deep Dive" narratives using Sonnet for integrated media content
- Species lightbox modals with comprehensive external resource links
- "Guide" introduction page for new visitors
- "Data Sources, Organizations & Sponsors" recognition page
- Batch mode for classroom use
- PDF/image export of ecological address profile
14. Development Conventions
14.1 Code Standards
- Simplicity over cleverness — readable, maintainable, 200 lines or fewer per file.
- Minimal changes — never reimplement from scratch without permission.
- Style consistency — match existing code patterns.
- Scope discipline — never make unrelated changes.
- No filename prefixes (new, improved, updated_).
- Complete files ready for BBEdit, never snippets.
- File headers in comments: path, filename, change description.
- Wait for "proceed" after each delivery.
14.2 Module Pattern
PHP uses separate files organized into lib/ (sources, parsers, database, place_context) and lib/parsers/ (domain sub-parsers), with the orchestrator in address_api.php. JavaScript uses the FG namespace pattern — fg-config.js creates window.FG = {}, and subsequent modules attach functions and state to FG. IIFEs are used in modules that need private scope. CSS is split across six files by concern: base typography (fieldguide.css), page layout (layout.css), panel/card system (panels.css), drawer expansion (drawers.css), species display (species.css), and responsive breakpoints (responsive.css).
14.3 Error Handling
API failures return null — the orchestrator never crashes. The frontend shows "No data" for null sections, never blank cards. curl_multi treats non-2xx/3xx responses as null. Database connection failures return null or empty arrays without halting execution. The LANDFIRE standalone curl call has an 18-second timeout to accommodate intermittent USGS server slowness. The climate archive fetch implements retry logic with 2-second pauses.
14.4 Naming Conventions
| Context | Convention | Examples |
|---|---|---|
| PHP functions | camelCase | parseKoppen, fetchClimateArchive, buildInatUrls |
| JS functions | camelCase | renderFieldGuide, fetchAddress, buildBirdPhotoLookup |
| JS namespace | FG.* |
FG.track, FG.esc, FG.icon, FG.currentData |
| CSS classes | kebab-case | fg-panel, card-drawer, species-thumb, taxon-group-header |
| Database columns | snake_case | coord_key, source_status, created_at, session_id |
| API response keys | snake_case | com_name, sci_name, detection_count |
| Source keys | snake_case | inat_plantae, ebird_recent, bw_species, climate_history, water_balance, landfire_evt, macrostrat |
References
[1] Mapbox (2026). "Mapbox GL JS, Terrain-RGB v1, Geocoding v5, Search Box v1." https://docs.mapbox.com/ (accessed February 22, 2026).
[2] iNaturalist (2026). "iNaturalist: A Community for Naturalists." https://www.inaturalist.org (accessed February 22, 2026).
[3] Sullivan, B. L., Wood, C. L., Iliff, M. J., Bonney, R. E., Fink, D., & Kelling, S. (2009). "eBird: A Citizen-Based Bird Observation Network in the Biological Sciences." Biological Conservation, 142(10), 2282–2292.
[4] Hamilton, M. P. (2026). "Canemah Nature Laboratory." https://canemah.org (accessed February 22, 2026).
[5] Peel, M. C., Finlayson, B. L., & McMahon, T. A. (2007). "Updated World Map of the Köppen-Geiger Climate Classification." Hydrology and Earth System Sciences, 11, 1633–1644. https://doi.org/10.5194/hess-11-1633-2007
[6] Dinerstein, E., Olson, D., Joshi, A., et al. (2017). "An Ecoregion-Based Approach to Protecting Half the Terrestrial Realm." BioScience, 67(6), 534–545. https://doi.org/10.1093/biosci/bix014
[7] Karra, K., Kontgis, C., Statman-Weil, Z., et al. (2021). "Global Land Use / Land Cover with Sentinel-2 and Deep Learning." 2021 IEEE IGARSS, 4704–4707. https://doi.org/10.1109/IGARSS47720.2021.9553499
[8] Omernik, J. M. (1987). "Ecoregions of the Conterminous United States." Annals of the Association of American Geographers, 77(1), 118–125.
[9] Omernik, J. M. & Griffith, G. E. (2014). "Ecoregions of the Conterminous United States: Evolution of a Hierarchical Spatial Framework." Environmental Management, 54(6), 1249–1266. https://doi.org/10.1007/s00267-014-0364-1
[10] Dewitz, J. (2023). "National Land Cover Database (NLCD) 2021 Products." U.S. Geological Survey data release. https://doi.org/10.5066/P9JZ7AO3
[12] The Weather Company (2026). "Weather Underground API." https://www.wunderground.com/member/api-keys (accessed February 22, 2026).
[13] Open-Meteo (2026). "Open-Meteo Weather API (Pro)." https://open-meteo.com (accessed February 22, 2026).
[14] Sullivan, B. L., Aycrigg, J. L., Barry, J. H., et al. (2014). "The eBird Enterprise: An Integrated Approach to Development and Application of Citizen Science." Biological Conservation, 169, 31–40. https://doi.org/10.1016/j.biocon.2013.11.003
[15] Scribe Labs (2026). "BirdWeather: A Living Library of Bird Vocalizations." https://www.birdweather.com (accessed February 22, 2026).
[16] Kahl, S., Wood, C. M., Eibl, M., & Klinck, H. (2021). "BirdNET: A Deep Learning Solution for Avian Diversity Monitoring." Ecological Informatics, 61, 101236. https://doi.org/10.1016/j.ecoinf.2021.101236
[17] Zippenfenig, P. (2023). "Open-Meteo.com Weather API." Zenodo. https://doi.org/10.5281/ZENODO.7970649
[18] Hersbach, H., Bell, B., Berrisford, P., et al. (2023). "ERA5 Hourly Data on Single Levels from 1940 to Present." ECMWF, Copernicus Climate Change Service. https://doi.org/10.24381/cds.adbb2d47
[20] Open-Meteo (2026). "Historical Weather API." https://open-meteo.com/en/docs/historical-weather-api (accessed February 22, 2026).
[21] Peters, S. E., Husson, J. M., & Czaplewski, J. (2018). "Macrostrat: A Platform for Geological Data Integration and Deep-Time Earth Crust Research." Geochemistry, Geophysics, Geosystems, 19(4), 1393–1409. https://doi.org/10.1029/2018GC007467
[22] LANDFIRE (2024). "LANDFIRE LF2024 Existing Vegetation Type (EVT)." U.S. Department of Agriculture and U.S. Department of the Interior. https://landfire.gov (accessed February 22, 2026).
[23] Wikipedia (2026). "MediaWiki API: Geosearch." https://www.mediawiki.org/wiki/API:Geosearch (accessed February 22, 2026).
Document History
| Version | Date | Changes |
|---|---|---|
| 0.1 | 2026-02-19 | Initial draft from project study session |
| 1.0 | 2026-02-19 | CNL style guide compliance; formal references; abstract; AI disclosure |
| 1.1 | 2026-02-19 | Three new cards: Climate History, Soils & Water Balance, Seasonality. Open-Meteo Historical API endpoints. iNaturalist month-filtered seasonal queries. Silo independence principle. ecoSPLAT integration pathway. Security sanitization. References [17–20] added. |
| 2.0 | 2026-02-22 | Complete rewrite reflecting field guide architecture. New: modular JS frontend (10 modules on FG namespace), 6 CSS files, PHP sub-parser architecture, LANDFIRE LF2024 EVT (replacing USDA FIA), Macrostrat geology, conservation status card, place context enrichment (Mapbox POI + Wikipedia), narrative AI system (4 tiers via Anthropic Claude Haiku), admin dashboard with analytics and globe visualization, privacy-respecting session tracking, unified climate archive (6 vars, 48% API cost reduction), 3-decimal coordinate rounding (~111m ecological resolution), POI name promotion, updated file structure, updated database schema (usage_events table, enriched lookup_log). Removed USDA FIA (broken endpoint). Updated all references. |
Cite This Document
BibTeX
Permanent URL: https://canemah.org/archive/document.php?id=CNL-TN-2026-025