Skip to content

Lineage, world files, trails, sweeps and a dark theme - #5

Merged
mahim37 merged 11 commits into
mainfrom
lineage-trails-sweep
Sep 20, 2026
Merged

mahim37 merged 11 commits into
mainfrom
lineage-trails-sweep

Conversation

@mahim37

@mahim37 mahim37 commented Sep 6, 2026

Copy link
Copy Markdown
Owner

Stacked on #4. The world gets a memory of who begat whom, files that move worlds and birds between the browser and the CLI, a sweep subcommand for tuning, and the frontend gets the family view, trails, a dark theme, pinch zoom and lint tooling. The golden checksum is unchanged: nothing in the simulation's arithmetic moved.

Core

  • Lineage: one record per bird ever born (parent, generation, birth and death ticks, cause, chicks), compacted every 4096 ticks to the records reachable from living birds. Answers ancestors, chicks, living descendants and "relatives" (birds sharing a grandparent). It never touches the RNG and is not hashed. Snapshots carry it, so the crates are 0.2.0 and older snapshots are rejected by the version check instead of misread.

CLI

  • run --resume / verify --resume start from a snapshot file; verify --resume world --ticks 0 prints the checksum the app showed when the file was saved.
  • sweep --set field=v1,v2 --set other=a,b --seeds N --ticks T --out sweep.csv: cartesian product across seeds in parallel, one CSV row per run (final and second-half means, minima, immigration, extinction ticks, field of view, checksum). Fields are set by dotted path on the config JSON, so a misspelt one is an error.

wasm facade

  • Sim owns the selection: it records the selected bird's trail every tick and flags its relatives in every frame. New: select, selected, family, refreshRelatives, introduce (release a bird from a saved genome). Frame layout: header 5, 10 floats per bird (speed fraction, kin flag), trail after the patches; protocol.ts mirrors it.

Browser

  • Family block in the inspector: ancestors back to a founder with lifespan, chicks and fate; living chicks as chips; living descendants; relatives count. Relatives get a halo on the map, the followed bird leaves a fading trail (toggle, T), and resting birds hold their wings level. The selected bird's wedge outline no longer spans the map when it crosses the torus edge.
  • Save world / Open (and drag-and-drop) for .world files; drop a saved genome to release that bird.
  • Dark theme (system / light / dark, remembered, no flash before first paint). Canvas and chart colours are read back from the CSS variables. Dark series colours were checked for colour-vision separation and 3:1 contrast on the dark surface.
  • Pinch to zoom on touch screens; trackpad pinch gets a sensible factor.
  • ESLint (type-aware) and Prettier, both in CI. The stylesheet and index.html are hand-laid-out and excluded from Prettier.

Docs

  • README with a screenshot, a recording and the family panel under .github/media/; the web README lists the new modules and file formats.

Performance, looked at and left alone. A native profile puts about three quarters of a tick in the two sensing queries. A cell-ordered, batch-filtered grid was tried: bit-identical, but no faster (8.4 vs 8.3 ms/tick at ~4k birds), so it was dropped. The remaining levers (sensing cadence, SIMD, cheaper angle wrapping) all change bits or need nightly.

Checks

  • cargo test --workspace, fmt, clippy (native and wasm32), golden checksum 1065c218b08af910.
  • pnpm build, lint, format:check, test (27 tests, wasm loaded in Node).
  • Screenshots and the recording were captured from vite preview in headless Brave (SwiftShader), light and dark.

Action needed at merge time. As with #4, the Vercel project's Root Directory must be changed from www to the repository root, or the Vercel check keeps failing.

Living birds only carry their parent's id, and the parent is usually
long dead by the time anyone asks. `Lineage` keeps one record per bird
ever born (parent, species, generation, birth and death ticks, cause of
death, chick count) and answers the questions the inspector needs: the
chain of ancestors, the chicks, and how many living birds descend from
a bird. `relatives` picks the living birds that share a grandparent,
which is what the map highlights.

The log is compacted every 4096 ticks to the records still reachable
from a living bird, so memory follows the population rather than the
age of the world. It never touches the RNG and is not part of the
checksum, so the golden value is unchanged.

Snapshots now carry the log, which changes their layout; the crates
move to 0.2.0 so older snapshots are rejected by the version check
instead of misread.
`run --resume` and `verify --resume` start from a snapshot file instead
of a seed, so a world saved in the browser can be continued headless,
and `verify --resume world --ticks 0` prints the checksum the app
showed when it was saved.

`sweep` runs the cartesian product of `--set field=v1,v2,...` across
seeds in parallel and writes one CSV row per run: final and
second-half mean populations, minima, immigration counts, extinction
ticks, mean field of view and checksum. Fields are set on the config
JSON by dotted path, so a misspelt name is an error rather than a
silently unchanged run.
`Sim` now remembers which bird is selected. While one is selected it
records that bird's position every tick into a trail and flags its
relatives in every packed frame, so the page only has to say when the
selection changes. New methods: `select`, `selected`, `family`,
`refreshRelatives` and `introduce` (release a bird from a saved genome
file).

The frame grows a fifth header float (trail length) and two floats per
bird (speed as a fraction of top speed, and the kin flag), and carries
the trail after the patches.

The worker follows the facade: it forwards selection, sends the family
and relative count about once a second alongside the frame, restores
worlds from bytes, exports them, and releases genomes. The protocol,
client, type mirrors and the Node test of the wasm are updated with it.
The inspector gains a Family block: ancestors back to a founder (older
generations collapsed into a count) with how long each lived, how many
chicks it had and how it died; living chicks as clickable chips; living
descendants; and how many relatives the map is highlighting. Living
ancestors and chicks select on click.

The renderer draws a soft halo under every relative of the selected
bird and the selected bird's trail as fading dots, one per tick, with a
toggle and the T key. A bird that is not moving now holds its wings
level instead of flapping on the spot. The wedge outline is wrapped
relative to the bird, so an outline crossing the torus edge no longer
draws a line across the map.
"Save world" downloads the running world as a .world file, the same
bytes `rustywings run --resume` reads. "Open", or dropping the file on
the map, restores it; a bad file leaves the running world alone and
says why. Dropping a saved genome .json, or "Release a saved genome" in
the empty inspector, adds that bird to the world and selects it.
System, light and dark, chosen in the settings and remembered. The
effective theme lands on <html data-theme> before first paint; the CSS
switches its variables, and the canvas field, the selection and trail
ink and the chart colours are read back from those variables so nothing
is defined twice. The dark series colours are steps of the same three
hues, chosen to keep colour-vision separation and 3:1 contrast on the
dark surface.
Two pointers on the map zoom about their midpoint while the midpoint
pans; one still drags and taps. Trackpad pinches, which arrive as
ctrl+wheel with small deltas, get a larger zoom factor.
Type-aware ESLint (typescript-eslint's recommendedTypeChecked plus
consistent type imports, exhaustive switches, eqeqeq and no stray
console output) and Prettier at 140 columns. Both run in CI after the
wasm build so the generated declarations are available. The stylesheet
and index.html are excluded from Prettier: one rule per line reads
better than its expansion.

The findings were small: a few unnecessary casts, a promise handed to
an event handler, and a redundant union member.
A screenshot of the app, a recording of following a bird (trail, field
of view, relatives' halos) and the family panel, captured from the built
site. The README describes the browser features, the world and genome
files, `--resume` and `sweep`; the web README lists the new modules and
the file formats.
@vercel

vercel Bot commented Sep 6, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
rusty-wings Error Error Sep 20, 2026 8:25am UTC

`libs/` and `www/` were the tutorial-derived crates and webpack site the
project started from. Everything deployed now lives in `crates/` and
`web/`, so the workspace is just `crates/*`, and CI formats, lints and
tests the whole workspace instead of naming the crates one by one.

The Vercel project must point its Root Directory at the repository root
before this merges: the old site's directory no longer exists.
@mahim37 mahim37 mentioned this pull request Sep 6, 2026
@mahim37
mahim37 changed the base branch from web-app to main September 20, 2026 08:26
@mahim37
mahim37 merged commit 5b90d4d into main Sep 20, 2026
7 of 8 checks passed

This branch had an error being deployed

1 failed deployment
Preview — 1fac08cc Deployed Sep 20, 2026 by vercel[bot]
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