Savanah / health

Window →

Funnel web visit → game session · current window

Stage funnel

page_load · engine_ready · menu_shown · play_click are client beacons (counted once per page visit); connect · spawn come from the server log. A cliff between engine_ready and menu_shown means the web client booted but never reached the menu — i.e. a boot hang.

Stage-to-stage drop-off

StageCount % of top% of prev

By country

CountryLoads EngineMenu Play

Daily trend page loads vs spawns per day

Overview headline KPIs · Δ vs first half of window

Activity what + when filtered players play

Favorite animals (one per UUID)

Cause of player death (filtered)

Hour-of-day played (run starts, local time)

Run-length distribution

Buckets: <30s · 30s–2m · 2–5m · 5–15m · 15m–1h · >1h.

Geography where filtered players live

Player heatmap

Top countries

    Choropleth shaded by player count (UUID-keyed). World + NA views colour by country (ipinfo ISO2); US view colours by state (ipinfo region). Side list mirrors the same data — top 12 entries, scope-aware. Filter pills above honour the heatmap.

    Network latency + transport for filtered players

    Network (filtered)

    Network ping over time (filtered)

    Pools every [ping-stat] sample across all filtered players, binned into ~24 buckets over the visible span. Solid line = median; shaded band = p25–p95; dashed line = bin tail (max single sample).

    Avg-ping distribution (per UUID)

    Buckets: <30 · 30–60 · 60–100 · 100–200 · 200–500 · >500 ms.

    Players sortable table · click a row to inspect runs

    Players (UUID-keyed; click row for runs)

    One row per UUID. Ping cell shows recent [ping-stat] samples (10 s cadence per peer) as a sparkline + p95; activity cell shows per-run survival as a bar sparkline + total play. Hover a sparkline for sample count + peak. Sort by clicking a column header; click a row to open per-run details on the right.

    Toggle columns
    Density
    ● Rank Level Name UUID Current run Location Net Client OS Ping Activity Deaths Animals Favorite First seen Last seen

    World map (live)

    Live snapshot from the latest [map-state] dump (10 s cadence, server-side). Water + trees are static; entities + groups update on each refresh. Hover for a quick tooltip. Drag the canvas to pan (the world wraps on a torus, so panning past an edge brings the other side into view); scroll-wheel zooms toward the cursor; Shift+drag aggregates stats for a box; click an entity to pin its full stats. Press Esc to clear · recenter resets pan + zoom.

    Layers | | Time live

    Group sizes

    Groups by species

    Active groups

    Derived from the latest [map-state] dump. Solo bots are excluded — count shown in summary cards.

    Actor Filters age distribution, pop over time (humans = event-driven series), deaths/kills rates. Pred-prey ratios + warnings stay AI-only — players aren't part of the food web.

    Population over time

    AI series sourced from [bots] census line per snapshot. Player series is event-driven from spawn/death/disconnect [server] peer lines, plotted as a step line. Long windows downsample server-side to ~400 buckets (avg per bucket) so the chart stays responsive.

    Age distribution by species

    Buckets by growth fraction (size − baby) ÷ (adult − baby): cub < 33 %, juvenile 33–67 %, adult ≥ 67 %, alpha = is_alpha flag (size ≈ adult × 1.5). Aggregated across the latest [map-state] dump of every selected deploy.

    Deaths per game-day

    Warnings

      Chat log

      Global text chat from every connected player. Searched server-side against message + sender (case-insensitive, indexed). Cheat commands (/wisdomof* family) are filtered before they reach the log. Cross-deploy by default — narrow with the date range / deploy picker.

      Pride-hunt funnel (Lion only)

      rallies → spots → challenges → kills. Conversion ratio per stage in cards above.

      Predator × prey — kills by species (stacked)

      x-axis = prey species. Stacked colour = predator. Replaces the per-predator triplet + the predator-totals bar — column heights = matrix row totals; segment heights = matrix cell values.

      Killer → victim matrix (combat only)

      Hero of the matrix sub-tab. Row totals = deaths by species (replaces the standalone bar); column totals = predator kills (replaces the predator-kills bar on Summary).

      Species death × phase (day vs night)

      Cause of death × species (stacked)

      Victim avg state at death

      Avg growth & size at event

      Strength ranking

      Alpha-vs-alpha win differential. Score = wins − losses against other alphas; bot-only kills don't count.

      Player-killing prowess

      Net result against human players (player kills − player deaths). Negative means humans dominate this alpha; positive = the alpha is hunting players successfully.

      Kills vs deaths

      Total kills + total deaths across all opponents.

      Alphas — full board

      Score = kills − 2 × deaths. Alphas respawn at dawn with fresh names; same name across deploys = same character. Click a row to highlight their events below.

      Alpha vs alpha — rivalries

      Newest first. Loser respawns at the next in-game dawn.

      Player challenges

      Every time a human player traded blows with an alpha and one side fell.

      Snapshot perf live perf log series

      Avg packet size (B)

      Total bytes / snapshot-tick

      Food + corpses

      Players-online line moved to World › Ecosystem — pop-series there shows humans + bots stacked, richer than the line that lived here.

      Netstat windows [netstat] dumps every 30 s · A/B via deploy picker

      Sourced from [netstat] blocks (auto-emit every 30 s + on the /netstat chat command). Multi-deploy is the A/B view here — pick Phase-0 + Phase-1 deploys in the header to see before/after side-by-side. All ratios are SUM/SUM to dodge Simpson's-paradox traps when player counts differ between deploys.

      Snapshot pipeline health

      Per-packet bytes avg/max vs the 1100 B SCTP single-datagram cap. Twin axis: byte_cap_sat % (encoder bailed because next entity wouldn't fit). Encode-µs avg/max → cards above.

      FX filter savings — out-of-view blocks by kind, per window

      Stacked bars per window. High = good. Each unit is a cosmetic FX RPC the Phase 1 _peers_in_view_of filter blocked from going to a peer outside view radius — bytes / packets that did not fly. Counter is pre-filter (all peers); the filter cuts before the wire. recv_eat_anim dominates because grazing fires fastest.

      FX regression detector — actual bytes that flew, per kind

      actual_sent = bytes − oov_bytes per kind per window. This is the real regression signal: should scale linearly with peer count and average actor density. Spike without proportional player climb = filter regression (someone added a bare .rpc() at a new FX site and missed the _peers_in_view_of wrapper).

      Per-kind aggregate (selected window)

      Per-peer bufferedAmount peak — heatmap

      Cells: peak bytes queued in the WebRTC SCTP send buffer per peer per window. ≥ 1 KB = noticeable; ≥ 16 KB = backpressure threshold; ≥ 64 KB = client falling badly behind. Each row is one peer (labelled by latest spawn name); each column one window.

      Ping median vs byte_cap_sat %

      Each point = one (window × peer ping_stat). Cluster in the upper-right = saturation correlates with felt latency; flat = saturation harmless.

      Ping median vs FX out-of-view count

      Bursts of OOV FX bytes correlated with latency spikes confirms the "guard saves felt latency" thesis.

      Saves backup savannah-saves daily mirror · /tmp/savanah/backups.jsonl

      Player saves + Discord identity store rsynced from ~/.local/share/godot/app_userdata/Savanah/ into the private majicmaj/savannah-saves repo by savanah-backup.timer (03:17 UTC daily, append-forever). Status badges: pushed = new commit, no_changes = idempotent no-op, skipped = lock held / source missing, error = backup failed (check journal).

      Repo size over time

      repo_bytes = du -sb ~/savannah-saves/.git at each run; tracks cumulative history size. working_bytes = full checkout incl. saves+identity.

      Recent runs

      Newest first. Failed rows show the failing command + exit code in msg; on prod, full stderr is in journalctl --user -u savanah-backup.

      Nightly benchmarks connect · FPS · ping · bandwidth · frame-time · downloads

      Connect time (ms)

      Total dial → first-snapshot latency per run. Client runs only.

      Client FPS (p50)

      Median in-game frames/s. Client runs only.

      WebSocket ping (p50 / p95, ms)

      Snapshot bandwidth (bytes/s)

      Server frame-time (p95, µs)

      Box-server bench only.

      Latest download sizes (MB)

      Latest box run's per-platform build sizes.

      Recent runs

      Species base stats — baby / adult / alpha

      Derived from scripts/sim/constants.gd. No per-peer entropy applied (spawned animals roll ±10% on speed / damage / HP / size); alpha row reflects deterministic AI_ALPHA_STAT_MULT = 1.5. DPS = Q-attack damage ÷ ATTACK_COOLDOWN. Click any column header to sort.

      Time to adult — eating strategies

      Baby → adult arc per species, simulated against three eating strategies. Numbers derived live from scripts/sim/constants.gd + net.gd (BITE_GROWTH_FRACTION, GROWTH_SECONDS, Well Fed buff hooks). Each cycle includes the WF lockout (60 s, hunger frozen) and the on-expire −25% hunger drop.

      How the strategies differ

      • Ideal — refill the moment Well Fed expires, so the +1% growth bonus fires every cycle. Optimal but assumes infinite food + zero travel time.
      • Plan — wait for hunger to drain back to 25% before re-feeding. Gives one WF trigger per long cycle; passive growth + WF bonus carry the rest.
      • Worst — only top up halfway (0 → 50 %) so Well Fed never fires. Bites still grow you; passive baseline runs in parallel. Slowest pure-eating arc, but still beats no-eating (5 h passive floor).

      Skill-tree perks — per species

      One shared 4-branch skill tree (Offense / Survival / Mobility / Hybrid). At each growth milestone you're offered a rarity-rolled pick; T1 perks unlock at spawn, T2/T3 need a prior pick in the same branch. A few perks are gated by species — below, each animal shows only the perks it can actually be offered. Flat fields stack additively; multiplicative fields chain. Derived live from scripts/sim/constants.gd PERKS + the skill_tree.gd gating rules.

      Pickup berries + buffs

      Spinning cubes scattered on land. E to eat. Re-eating extends timer instead of stacking magnitude. Synthetic buffs (Well Fed, Alpha Slayer) listed at bottom — not spawned in the world.

      POI bias — which item kinds spawn where

      Each item kind has a preferred POI biome (ITEM_BIOME_PREF in scripts/sim/constants.gd). On every spawn the engine rolls ITEM_POI_SPAWN_BIAS chance to place the drop inside a matching named POI; failing that, ITEM_GRASS_SPAWN_BIAS for grass-tuft jitter; otherwise uniform anywhere. POI bias is positional only — it does not change the per-tier rarity roll or the global ITEM_CAP.

      Leaderboard rank — percentile placement

      The big gem on the leaderboard's Rank board is a relative placement: the active player pool is sliced top-down across Bronze→Diamond. Recomputed every fetch — moving up the board can move your gem. Inactive players (last seen outside the active window) drop to Unranked so they can't permanently block higher tiers.

      Rules

      Mirrors tools/dashboard/ranks.py::assign_percentile_tiers. Worked examples in the table above show how the slice rounds at small N — N=100 gives clean 1/4/5/15/25/50; smaller pools collapse via the floor rule.

      Player levels

      The small Lvl chip on the leaderboard is your career level — earned from quality runs, not raw playtime. A run "qualifies" for a level when its survival time meets that level's minimum (scaled by the species multiplier below — fragile species need shorter runs, well-protected species need longer). Promote to a level once you have enough qualifying runs. Levels are absolute and never drop; they don't depend on what other players are doing. Mirrors scripts/sim/ranks.gd on the game side.

      Per-species duration multiplier

      Applied to the per-level minimum-run-survival threshold. Lion is the baseline (1.00×). Greater than 1 = harder to qualify on that species; less than 1 = easier. Tunable in scripts/sim/constants.gd::RANK_SPECIES_DURATION_MULT — adjust there and any subsequent level refresh on the game server picks up the new value.

      Cheats & debug commands

      Type these in the in-game chat box. Cheat commands work only on a local server you host with cheats enabled — tick Enable cheats in the Host Local Server dialog, or toggle at runtime with /cheats on / /cheats off (bare /cheats flips it; /cheats list prints the catalog in-chat). They are permanently locked on the public online server. Client debug toggles are local-only visual aids and work anywhere. Mirrors _handle_local_chat_command in scripts/net/net.gd.