Metabolism: rule program, song-driven life, tribe VMs; M2.7 design (strains & allegiances, living wells)

This commit is contained in:
Dejvino
2026-10-28 10:07:05 +01:00
parent 16f4b4a805
commit f939351689
28 changed files with 3199 additions and 601 deletions
+28 -1
View File
@@ -24,7 +24,7 @@ function load(name) {
/** Run `seconds` of the world for song `name` with a seed. Returns world. */
function grow(name, seed, seconds = 20) {
const song = load(name);
const run = new Run(song, { fps: 30, seed, width: 240, height: 135 });
const run = new Run(song, { fps: 30, seed, width: 240, height: 135, field: 64, genesis: 0 });
for (let f = 0; f < Math.floor(seconds * 30); f++) {
run.world.step();
run.camera.update(f);
@@ -78,4 +78,31 @@ test('three songs grow fingerprints further apart than seeds of one song', () =>
const a2 = fingerprint(grow('drone', 99).world);
const within = divergence(a, a2);
assert.ok(cross > within * 2, `cross ${cross} !> 2×within ${within}`);
});
test('genesis pre-simulates generations so frame 0 is already an ecosystem', () => {
const song = load('drone');
const withGenesis = new Run(song, { fps: 30, seed: 12345, width: 240, height: 135, field: 64 });
const without = new Run(song, { fps: 30, seed: 12345, width: 240, height: 135, field: 64, genesis: 0 });
assert.ok(withGenesis.world.genesisFrames > 0, 'song should demand a genesis epoch');
// The world at frame 0 is more evolved (generations already lived)…
assert.ok(withGenesis.world.count > without.world.count * 1.1,
`genesis world should be more populated (${withGenesis.world.count} vs ${without.world.count})`);
// …and the ground already carries history, where a fresh plate has none.
assert.ok(withGenesis.world.sampleTrailMass() > 0.0001,
`genesis world should already hold ink (${withGenesis.world.sampleTrailMass()})`);
assert.equal(withGenesis.world.history.alive[0], 0, 'genesis must not record into the film');
assert.equal(withGenesis.world.frame, -1, 'the film starts at frame 0');
});
test('genesis is deterministic and song-scaled', () => {
const a = new Run(load('drone'), { fps: 30, seed: 12345, width: 240, height: 135, field: 64 });
const b = new Run(load('drone'), { fps: 30, seed: 12345, width: 240, height: 135, field: 64 });
assert.equal(a.world.genesisFrames, b.world.genesisFrames);
assert.deepEqual(Array.from(a.world.pop[0]), Array.from(b.world.pop[0]));
const runner = new Run(load('runner'), { fps: 30, seed: 12345, width: 240, height: 135, field: 64 });
assert.notEqual(a.world.genesisFrames, runner.world.genesisFrames,
'the genesis amount should depend on the song');
});