Skip to content

tripitakit/Lenies

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

383 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Lenies — Digital Evolution Sandbox

Lenies is a Phoenix LiveView application that runs a small artificial world where digital organisms — Lenies — live, eat, reproduce, mutate, fight, die, and gradually evolve under selection pressure. Each Lenie is a BEAM process animated by its own tiny program (its codeome), and the whole population shares a single 256×256 toroidal grid full of regenerating resources, decaying detritus, and the occasional cosmic-ray-style mutation.

The point isn't to ship a finished simulation — it's to give you a window into one. You can watch the population drift in real time, click into any species to disassemble its code, freeze the world, edit a codeome by drag-and-drop, and spawn your own creatures into the soup to see whether they thrive, get eaten, or quietly starve.

📘 Want to write your own codeomes? Start with the Lenies Programming Manual — a chapter-by-chapter guide that takes you from your first six-opcode walker to a tuned self-replicator.


Table of contents


What Lenies looks like

Open the dashboard and you'll see a dark sci-fi console with the world map filling the full body height on the left — a square canvas pulsing with coloured pixels, each one a live Lenie coloured by its species. The right column stacks two rows: at the top a sparkline of recent population history with a table beneath listing every active species sorted by population; at the bottom a control panel for pausing, sterilising, spawning seeds, plus a live tuning section for every knob in the simulation.

You can scroll-zoom and click-drag-pan on the map; double-click any Lenie cell and the codeome editor opens with that species pre-loaded. Hovering a Lenie cell switches the cursor to a hand pointer as a hint that the cell is editable. Clicking a species row in the table opens the inspector to its right — a disassembly of the codeome with population and average generation — and dims every other species on the map so the selected one stands out.


Quick start

Requirements: Erlang/OTP 26+, Elixir 1.18+ (1.19 known to work).

mix deps.get
mix compile
iex -S mix phx.server

Open http://localhost:4000. The simulation starts immediately with a hand-tuned replicator seeding the population.


How it works, in three paragraphs

The world is a 2D grid that wraps at every edge (so a Lenie walking north long enough comes back from the south). Each cell holds either nothing, a pile of resource, detritus, or one Lenie. Radiation drips new resource into cells every tick, concentrated on a handful of permanent hotspots and sprinkled uniformly elsewhere; detritus decays over time and is also edible. Energy is conserved: it enters the system only through radiation, leaves only when Lenies starve, and is passed around through eating, fighting, and reproduction.

A Lenie is a BEAM process whose only state is a stack-based virtual machine and an energy counter. Its program — the codeome — is a sequence of opcodes drawn from a small whitelist. The same sequence is both the genome (copied with errors into children during replication) and the running code (executed in batches by an interpreter). Lenies die when their energy hits zero; species emerge as clusters of identical or near-identical codeomes, identified by a stable hash. The Programming Manual covers all of this from the ground up.

Selection falls out of these mechanics without any explicit fitness function. Codeomes that waste energy, fail to forage, or crash on common mutations die out; codeomes that replicate cleanly and tolerate copy errors slowly spread. Predators (Lenies whose codeomes invoke :attack) appear, and herbivores evolve defences. There's no winner — just a small ecosystem you can poke at.


Touring the dashboard

On the world map (left, full-height):

  • Scroll zooms in and out, anchored on the cursor so the cell under the mouse stays put across the zoom.
  • Click and drag pans the view (only meaningful once zoomed past 1×; at 1× the whole grid is on screen).
  • Single click on a cell recenters the view there.
  • Double click on a cell with a Lenie opens the codeome editor for that species (cursor turns into a pointer over occupied cells to hint at this). Empty cells are a no-op.
  • Three checkboxes under the map toggle the Lenies / Resources / Detritus layers independently.

On the right column, top row:

  • The sparkline tracks the population of the top species over the last few minutes; one coloured line per species in the current top 10.
  • The table beneath lists every active species (full count, scrolls vertically when there are many). Click a row to open the species inspector and highlight that species on the map — every other species is dimmed to 30 % alpha.

On the right column, bottom row:

  • Pause / Resume stops and restarts the environmental tick. The world freezes; the canvas stops updating.
  • Sterilize kills every Lenie and resets the world to an empty grid. A confirm button appears to prevent accidents.
  • + New Seed opens the codeome editor with an empty buffer.
  • Manage toggles the list of user-saved seeds so you can delete them.
  • Spawn picks a seed from the dropdown (built-in or user-saved) and drops N copies into random free cells with a chosen starting energy.
  • Snapshot saves and reloads the entire world state from disk.
  • Under that, the Tuning Live section exposes runtime sliders for every world parameter — radiation, eat amount, copy-error rates, attack damage, the BG-mutation rate per 1000 ticks, and more. Changes apply immediately to all live Lenies.

The species inspector (slides in when you click a row) shows the species' colour swatch, the codeome disassembled into coloured opcode blocks (one per category), and Edit / Spawn buttons. Clicking the row again closes it; selecting a different row swaps the highlight.


Editing and creating seeds

The codeome editor is a full-screen page with three panes. On the far left, a collapsible Programming Manual for in-editor reference. In the middle, a palette of all 36 opcodes grouped by category (drag a chip onto the listing to insert; double-click a chip to append at end; or paste a space/comma-separated text list into the input above and the editor tokenises it). On the right, the current codeome rendered as a vertical stack of coloured blocks — one block per opcode, in execution order. Drag the handle to reorder, click the to delete.

Above the listing, an Energy / pass mini-panel recomputes on every opcode add / remove / reorder. It shows:

  • cost — exact sum of per-opcode static costs for one linear pass through the buffer (template-jump lengths read from the run of nops following each jump; :allocate priced at the current buffer length as a typical-replicator proxy).
  • max gain — strict upper bound assuming every :eat and :attack hits, using the live eat_amount and attack_damage tuning values.
  • net = max_gain - cost colour-coded green / red.

A live validation banner tells you whether the current buffer is acceptable: too short, too long, or with too few non-template opcodes will each block you from spawning or saving. When the buffer is valid you can Spawn directly into the running world or Save as a named user seed (with a colour and a default starting energy). Saved seeds persist across restarts and appear with a star prefix in the spawn dropdown.

The editor opens both from the + New Seed button (empty buffer), from the Edit button on the species inspector (pre-loaded with that species' current codeome), and from a double click on a Lenie cell on the dashboard map. Editing a species edits a copy — the running Lenies of that species are untouched until you spawn your edited version back into the world.

For everything about what to put in those blocks — the VM, the opcodes, template addressing, replication, the energy budget, and a worked tour through seven hand-crafted codeomes of growing complexity — see the Programming Manual.


Built-in seeds

Five seeds come pre-loaded in the spawn dropdown:

  • Minimal Replicator — a hand-written 121-opcode self-replicator with a 128-step forage cycle between divisions. Robust enough to maintain a steady population on the default world. Source: lib/lenies/codeomes/minimal_replicator.ex. The Programming Manual dissects it line by line in chapter 9.
  • Carnivore — the Minimal Replicator with :attack injected before :eat. Demonstrates predation; thrives in dense populations, starves in sparse ones. Source: lib/lenies/codeomes/carnivore.ex.
  • Defender — defensive herbivore that builds tight clusters. K=32 forage budget (vs MR's 128) means it replicates every ~32 cells; the deterministic post-divide turn_left spirals descendants outward into a rotating pattern. Forage body is defend; eat; move — each iteration applies the defense flag, so attackers pay the defense penalty for every hit on a Defender. Source: lib/lenies/codeomes/defender.ex.
  • Hunter — predator with a diagonal staircase advance and a lock-on attack. Each forage step alternates turn_right / turn_left via a slot[3] parity counter, producing a diagonal walk that covers both axes. When sense_front returns -1 (Lenie ahead), the Hunter attacks without moving or turning — next iteration faces the same cell, so consecutive attacks land on the same prey until it dies or moves. Source: lib/lenies/codeomes/hunter.ex.
  • Forager — wandering herbivore. Each step: eat, move, then a 3-way random branch via pushN mod 3 — 33% no turn, 33% turn_left, 33% turn_right. The direction performs a random walk on cardinal directions; the position drifts as a 2D random walk that fills space rather than tracing straight lines. Source: lib/lenies/codeomes/forager.ex.

Where things live

User-saved seeds are persisted to priv/user_seeds.json and loaded at boot by Lenies.Seeds.CustomStore. Saves are atomic (write to .tmp, then rename). Corrupt JSON is renamed to .bak and the store starts fresh, so a malformed manual edit won't brick the app.

World snapshots saved through the dashboard are identified by a name (letters, digits, - and _ only) typed into the Snapshot form. Each snapshot lands under <root>/<name>/ as a small tree of .tab files, where <root> defaults to <system tmp>/lenies-snapshots/ and is configurable via the :snapshot_root app env. Saves are atomic (each table is written to .tab.tmp then renamed), and restore validates every file before touching the live world, so a corrupt or partial snapshot can't wipe a running simulation.

Repository layout:

lib/lenies/                  — domain (world, lenie, interpreter, codeome, mutator)
  codeome/opcodes.ex         — the 36-opcode whitelist and its encoding
  codeome/costs.ex           — energy cost per opcode
  codeomes/                  — built-in hand-written seeds
  interpreter.ex             — the stack VM
  interpreter/state.ex       — execution state struct
  interpreter/template.ex    — template addressing
  seeds.ex                   — built-in seed catalog
  seeds/custom_store.ex      — user-saved seeds, JSON-backed
  world.ex                   — the environment GenServer
  world/                     — cells, tables, hotspots, radiation, child slots
lib/lenies_web/
  codeome_buffer.ex          — pure ops + validation for the editor
  disassembler.ex            — codeome → human-readable lines
  live/                      — LiveView pages and components
assets/                      — JS hooks and CSS
config/runtime.exs           — all tunable parameters live here
priv/user_seeds.json         — persisted user seeds (created on first save)
docs/manual/                 — the Programming Manual
docs/superpowers/specs/      — design specs for the major subsystems

Further reading

  • 📘 Programming Manual — from zero to writing your own sustainable replicator. Twelve chapters, ~4 200 lines of English text and worked examples.
  • Lenies design spec — the original architectural notes, including the world model, mutation rates, and selection mechanics.
  • All subsystem specs and implementation plans live in docs/superpowers/ — every feature in the dashboard was brainstormed, specced, planned, and shipped with a paper trail.

A note on the name

"Lenies" is a tribute to Peter Watts' Rifters trilogy (Starfish, Maelstrom, βehemoth). In the books, the post-collapse internet — the Maelstrom — is infested by self-replicating digital wildlife that evolves in the noise between functioning systems. A particularly persistent strain learns to propagate by riding the cultural meme of the trilogy's protagonist, Lenie Clarke, and ends up nicknamed after her. The bytecode organisms in this project are a much smaller, much friendlier homage: stack-machine creatures eating and replicating inside a 256×256 toroidal grid instead of a planetary network, but driven by the same minimal-replicator logic.

About

Codeome evolution sandbox

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors