This page documents TubeGuru's architecture, data sources, feed card design, and AI roadmap.
TubeGuru blends live surf cameras with a rigorously separated data stack: raw observations and models → normalized series → derived metrics (energy, difficulty) → UI. Energy is a physics measure; difficulty is a surfability index; sources remain transparent.
[SENSORS + MODELS]
├─ IFREMER MARC (model) — hs_m, tp_s, dir_deg
├─ Allosurf (buoy) — hs_m, tp_s, dir_deg
├─ Surf-Report (forecast)
└─ Open-Meteo (fallback)
│ normalization
▼
/api/obs → model | buoy | blended series (+ quality)
│
/api/energy → physics energy (kJ = 0.49 × H² × T × 60) + window
│
/lib/difficulty.ts → index(height, period, wind, energy floor) → Flat/Beginner/Intermediate/Advanced/Expert
│
UI
• CamCard (pill, swell/wind, flow)
• EnergyModal (evolution + compare)
• Advanced page /spot/[id]/advanced (energy, compare, tables, forecast, wind, tide)┌───────────────────────────────────────────────────────────────┐ │ 🎥 Live stream (external iframe) │ └───────────────────────────────────────────────────────────────┘ ┌──────────────┬───────────────────────────────────────────────┐ │ Location │ Spot name, region, source icon │ ├──────────────┼───────────────────────────────────────────────┤ │ Swell/Wind │ "1.8 m / 8.5 s", "12 kts W" │ │ │ source: /api/obs (IFREMER, Allosurf, Blended) │ ├──────────────┼───────────────────────────────────────────────┤ │ Energy Pill │ "⚡ 230 kJ · 620 kJ window" + Level band │ │ │ source: /api/energy + /lib/difficulty │ │ │ levels: Flat / Beginner / Intermediate / │ │ │ Advanced / Expert │ ├──────────────┼───────────────────────────────────────────────┤ │ Meta │ Flow index, source tag, confidence │ ├──────────────┼───────────────────────────────────────────────┤ │ Actions │ Open Stream • Advanced • Ask Flow (AI) │ └──────────────┴───────────────────────────────────────────────┘
1) Oceanic (houle, marées, SST) • IFREMER / MARC (ERDDAP) — model swell height/period/direction • Allosurf — buoy observations (ground truth) • Surf-Report — human-readable forecasts • Open-Meteo Marine — global fallback (swell partitions + combined wave) • Tides — SHOM (FR), NOAA (US), others (IHO) 2) Atmospheric (wind, pressure) • GFS / ECMWF / AROME via aggregators (Windy/Windguru) for wind fields 3) Geographical/topo • Bathymetry (SHOM, NOAA, GEBCO), coastal orientation (shapefiles/DEM) • Used for exposure weighting & stance hints
Design principles: separation of concerns, graceful degradation, source transparency.
POST /api/obs
{ "items":[{ "id":"carcavelos","lat":38.678,"lon":-9.335,"aspect_deg":270 }], "hours":24 }
→ {
"ok": true,
"results":[
{ "id":"carcavelos",
"model": { "times":[...], "hs_m":[...], "tp_s":[...], "dir_deg":[...], "source":"ifremer", "quality":0.9 },
"buoy": { ... "source":"allosurf", "quality":0.95 },
"blended": { ... "source":"blended", "quality":0.93 }
}
]
}POST /api/energy
{ "items":[{ "id":"carcavelos","lat":38.678,"lon":-9.335,"aspect_deg":270 }], "hours":3, "wantSeries": true }
→ {
"ok": true,
"results":[
{ "id":"carcavelos",
"energy": { "kj": 420, "windowKj": 1150, "source":"calc" },
"series": { "times":[...], "kj":[...], "source":"calc" }
}
]
}index = f(Hs, Tp, wind_penalty) with energy floors: if Hs < 0.35 m OR Tp < 6 s OR Energy < 80 kJ → Flat bands: Flat | Beginner | Intermediate | Advanced | Expert
User ↔ Flow Chat UI
│
├─ RAG: spot history (obs + energy series)
├─ Tools: /api/obs, /api/energy, /api/forecast, tides, sunrise
└─ Policies: beginner/goofy filters, daylight windows, ETA constraints