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 savanah-saves daily mirror · /tmp/savanah/backups.jsonl

      Player saves + Discord identity store rsynced from ~/.local/share/godot/app_userdata/Savanah/ into the private majicmaj/savanah-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 ~/savanah-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.

      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.