Emergent AI Civilization Simulator
Project description
Emergent AI Civilization Simulator
Watch factions form, trade, war, betray, and mythologize — all from simple survival rules. No scripted behavior. Pure emergence.
What Is This?
Figure 1: The Streamlit dashboard visualizing a 1,000-tick run on an Intel N95.
Thirty nameless inhabitants are dropped onto a Perlin-noise-generated world. They eat, migrate, and slowly build trust with their neighbors. From that trust come shared beliefs. From those beliefs come factions. From faction rivalry comes trade — and war. Tech trees create asymmetric advantages. Diplomacy builds fragile alliances. Inhabitants form families, bear children, and pass their beliefs to the next generation. When enough time passes, the old world shatters and a new era dawns.
None of it is scripted. Every war, betrayal, and alliance you see is unique — because the civilization that produced it was unique.
An optional LLM mythology layer can write chronicles, myths, and epitaphs using a local model via Ollama — but the simulation runs fully standalone. A live Streamlit dashboard shows the world map, faction borders, and reputation graph updating in real time.
Fully playable on a $150 Intel N95 mini-PC with 16 GB RAM. No GPU required.
| Stat | Value |
|---|---|
| Starting inhabitants | 30 |
| Population cap | 1,000 (configurable) |
| Simulation layers | 9 (0–8) |
| Ticks per run | 10,000 (configurable) |
| Terrain generation | Perlin noise (height + moisture + depth) |
| Biomes | 6 — forest, plains, mountains, desert, coast, sea |
| LLM mythology | Optional — disabled by default |
| External API calls | Zero |
| Scripted events | Zero |
| Python dependencies | noise, streamlit, plotly, numpy, streamlit-autorefresh |
Features
World & Terrain
-
🌍 Three-field Perlin terrain — Height, moisture, and depth noise fields produce coherent biome layouts across a dynamically-scaled grid. Sea coverage is calibrated to 25% of the map via depth-noise percentile thresholding — guaranteed regardless of random seed.
-
🗺 Six distinct biomes — each with unique movement costs, resource caps, and survival characteristics:
Biome Move Cost Notes Plains 5 (baseline) Default food + ore Coast 5 Port bias for settlements; fishing when Sailing researched Forest 10 (0.5× speed) 2× food density (cap 28); dense but slow Desert 7 Surface scrap ore (cap 30); sparse food Mountains 9 High stone; rough terrain Sea 8 Impassable without Sailing tech; 2× travel speed for sailors -
🌊 Navigable seas — Sea tiles block movement until a faction researches Sailing (Industrial tier 2). Sailors traverse sea at 2× effective range. Coastal factions with Sailing earn passive fishing income (+1 food per member every 3 ticks on coast tiles). Settlements prefer coastlines (port bias).
-
🧭 Cost-adjusted pathfinding — Inhabitants score neighbors by
food × (5 / move_cost): plains win over desert treks, forests are lucrative but slow, sailors exploit sea lanes. No A* needed — emergence from local greedy choice. -
📦 Biome integer IDs — Each tile stores a compact
biome_idint for fast O(1) comparisons in hot loops. Sea tiles are skipped entirely during resource regeneration (~25% of tick work eliminated on N95 hardware). -
🌱 Population-scaled food — Resource regeneration scales with population pressure (
1.0 + 0.5 × pop/cap). An extinction guard doubles food output when population drops below 10% of the cap. -
❄ Seasons — A 50-tick cycle with an 8-tick winter window. Winter halts food regeneration (reduced to 0.125×); spring restores it (0.25×). Five resource types: food, wood, ore, stone, water.
-
🏙 Dynamic map scaling — The grid starts at 8×8 and expands every 25 ticks as population grows, generating new biome tiles while preserving existing terrain.
Settlements
-
🏰 Permanent towns — Factions that remain stable in one location for long enough found a Settlement: a named town with housing capacity, storage (surplus food reserves), and optional walls.
-
🛡 Walled cities — Settled factions can build walls; outsiders navigating walled tiles treat them as having 1/3 the food score (effective deterrent without hard barriers).
-
📊 Settlement index — A spatial registry enables O(1) settlement lookup by tile coordinate, used during combat, procreation, and navigation.
Inhabitants & Procreation
-
👤 Survivors, not agents — Each inhabitant moves, gathers food, and builds individual trust scores with every person they meet. They starve, migrate, and die with no guidance. Memory-efficient
__slots__(20 attributes including_can_sail) keeps RAM low at 1,000 population. -
👶 Generational procreation — Pairs on the same tile with mutual trust > 15 and food > 10 each can produce a child. Children inherit 50% of their parents' combined beliefs, cost 5 food per parent, start with 10 food, and are born with trust of 30 toward each parent. Settlement housing caps are respected. One birth per tick maximum; no births during winter.
-
📛 135 fantasy names — Four name pools (Original, Norse, Celtic, Germanic). When all base names are taken,
get_unique_nameappends Roman numeral suffixes (II–X) then numeric (11+) to guarantee uniqueness across generations.
Beliefs
- 🙏 27 event-driven beliefs — Beliefs form organically from experience: survive a winter →
endurance_rewarded; trade successfully →trade_builds_bonds; watch a neighbor starve →trust_no_group. Each inhabitant holds up to 8 beliefs. Co-located neighbors with mutual trust > 10 have a 50% chance to share beliefs each tick.
Factions
-
🏛 Organic faction formation — When three nearby inhabitants (Manhattan distance ≤ 2) share ≥ 2 core beliefs and mutual trust > 8, a faction coalesces around them. Faction names are generated from belief-keyed adjective/noun components ("The Iron Wanderers", "The Salted Few").
-
⚡ Schisms & mergers — Ideological minorities (≥ 30% of members) split off every 25 ticks. Solo-member factions within range can merge every 10 ticks. Four ideological conflict pairs block joining and trigger splits. Factions can also diplomatically merge when reputation is high enough.
-
🏰 Territory & pooling — Factions control territory chunks, pool 20% of surplus food into reserves, and nudge drifting members back toward their land. Members beyond size 10 with
self_relianceleave voluntarily.
Economy
-
💰 Living economy — Each faction mints its own currency (15 possible names: shells, iron bits, marked stones…). Dynamic pricing adjusts every 5 ticks based on supply/demand (clamped 0.5×–4×). Trade routes form after 3 successful trades and give +10% bonus (+20% for allies). Scarcity shocks reduce a random resource by 15% globally every 50 ticks.
-
⚔ Raids — When tension exceeds 35 between factions, 20% chance per tick to raid. Loot scales with tech: scavenging (2×), weaponry (3×), steel (4×). Raiding breaks treaties and costs reputation.
-
📊 Gini coefficient — Wealth inequality is tracked globally across all inhabitants using inventory value plus currency holdings.
Combat
-
⚔ Multi-tick wars — War declarations require crossing a tension threshold of 200 (modified by beliefs and tech). Attackers and defenders recruit alliance chains (60–80% chance per eligible faction). Battles run tick-by-tick with morale-weighted strength. Fallen warriors become named legends.
-
🏳 War outcomes — Surrender at 50%+ losses, ceasefire if both sides are broken, or exhaustion after 40 ticks. Winners claim territory. Losers pay 30% food tribute for 20 ticks. 40% of losers are absorbed into the winning faction; 30% flee to neutral factions; 30% remain.
Technology
-
🔬 16-tech research tree across 3 branches:
Branch Tier 1 Tier 2 Tier 3 Tier 4 Industrial Tools Farming, Sailing Mining, Engineering Currency Martial Scavenging Metalwork Weaponry, Masonry Steel Civic Oral Tradition Medicine Writing Code of Laws -
⛵ Sailing — Unlocks sea traversal for all faction members (
_can_sail = True). Sailors navigate sea tiles at 2× effective score and earn passive fishing income on coast tiles every 3 ticks. -
🧠 Belief-driven AI selection — Factions choose research based on dominant belief affinity (16 belief→branch mappings). Engineering reduces all future research durations by 20%. Research pauses during war and resumes after.
-
⚔ Combat bonuses — Metalwork +30%, Weaponry +50%, Steel +80%. Masonry +20% defense. Medicine heals hunger damage and grants 50% plague resistance.
Diplomacy
-
📜 Council votes — Factions with 3+ members vote on war (60% threshold), alliances (50%), new members (50%), and research (50%). Beliefs influence voting. Close votes seed internal tension that can trigger future schisms.
-
🤝 Formal treaties — Non-Aggression Pacts (cap tension at 100), Trade Agreements (+20% bonus), Mutual Defense Pacts (auto-join ally wars), and Tribute Pacts (imposed by 3× stronger factions). All last 50 ticks. Breaking a treaty costs −3 reputation.
-
⚖ Surrender terms — Belief-driven:
community_sustains→ annexation,the_strong_take→ tribute,migration_brings_hope→ exile,the_wise_must_lead→ vassalization. -
🌟 Reputation — Integer −10 to +10 per faction (reviled → legendary). Recovers +1 every 25 peaceful ticks. Factions with surplus food can share with needy neighbors for +2 reputation.
Live Dashboard
-
📊 Streamlit dashboard (
dashboard.py) — run alongside the simulation for a live 2-FPS view of the world. Auto-refreshes viastreamlit-autorefresh; falls back to a manual refresh button gracefully. -
🗺 World map — Plotly
imshowover an H×W×3 RGB biome image (sea=blue, forest=dark green, plains=yellow-green, desert=tan, mountains=gray, coast=cadet). Faction members overlaid as coloured scatter dots; hover shows name, size, reputation, and techs. -
📈 Reputation chart — Line traces for the top 5 factions over the last 3,000 simulation ticks, with dashed Allied (+5) and Reviled (−5) reference lines.
-
📋 Sidebar metrics — Tick, Alive count, Tick Rate (rolling 30-tick average), Max Generation, Active Factions, per-faction badges (settler status, rep emoji).
-
⚡ N95-safe I/O —
dashboard_bridge.pywritesdashboard_data.jsononly every 25 ticks via atomicos.replace()(temp-file swap). The dashboard reads with@st.cache_data(ttl=2)so it never fights the simulation for disk or CPU.
Anti-Stagnation
-
🌋 World events (every 200 ticks) — Plague (−20 HP all), Golden Age (resources restored), Migration (8 newcomers), Earthquake (2 chunks destroyed), Discovery (free tech to random faction).
-
📅 Era shifts (every 500 ticks) — All tensions halved, +33% food globally, new era announced. Eras are named dynamically: The Crimson Years, The Age of Iron, The Great Famine, The Long Peace, etc.
-
⚡ Disruption events — Triggered by prolonged stagnation or too few factions: Great Migration (10 newcomers, 2 instant rival factions), Plague Sweeps (−30 HP, food halved), Civil War (largest faction splits), Promised Land (barren chunk restored), Prophet (lone visionary arrives).
-
⏱ Peace escalation — At 50 ticks of peace, suspicion grows (+10 tension all pairs). At 75 ticks, resource envy flares (+30 tension on a random pair). At 100 ticks, a mysterious death incident triggers +50 tension and resets the peace tracker.
-
🧳 Traveler waves — Every 40 ticks, if population is low or factions are too few, 5–10 newcomers arrive with food and biome-appropriate beliefs. Solo-faction members waste away (−10 HP every 10 ticks) to prevent lone holdouts from stalling the simulation.
Mythology (Optional)
-
🪦 LLM narrative layer — Disabled by default (
MYTHOLOGY_ENABLED = False). When enabled, a local LLM writes chronicles every 50 ticks, faction creation myths every 100 ticks, and epitaphs for fallen warriors. A Tolkien-style final epic summary is saved to a timestampedhistory_*.txtfile. The system prompt casts the model as "an ancient, nameless scribe of the void." -
📝 Manual chronicle export — When mythology is disabled, the simulation writes structured era data to
manual_chronicle.txtevery 50 ticks, suitable for feeding to any external LLM later. A separateera_export.txtcaptures the last 100 events each period. -
🔒 Read-only observer — The mythology layer never modifies simulation state. It degrades gracefully with fallback text if Ollama is unavailable.
Emergent Variety
- 🔄 Every run is different — Different seeds produce different terrain, belief clusters, faction names, wars, and alliances. The same code produces The Merchant Pact one run and The Iron Shore the next.
Sample Output
Faction Summary (Tick 250)
The Wild Rovers (founded tick 090)
Members : Brea, Brek
Beliefs : the wilds provide, migration brings hope, endurance rewarded
Techs : farming, medicine, metalwork, sailing, tools, weapons, writing
Territory: (1,7) (2,7)
Reserve : 339.9 food
Reputation: +10 (legendary)
The Tidal Survivors (founded tick 150)
Members : Arin
Beliefs : trust no group, the wilds provide, loyalty above all
Techs : tools, writing [→ farming 9t]
Territory: (0,1)
Reserve : 216.0 food
Reputation: -4 (disgraced)
Chronicle Entry (Tick 200–250)
════════════════════════════════════════════════════════════════════════
THE CHRONICLE — Age of Ticks 200–250
════════════════════════════════════════════════════════════════════════
In the age of wars, The Lone Bond raised its banner against The
Trading Bridge, and the heavens shook as five factions answered the
call to arms. Emra of The Bound Ones fell first, at the coast of
(0,2), a champion of loyalty brought low by conquest's hunger. The
Trading Bridge, steadfast in community, repelled the invasion and
exiled its aggressors to the far wastes.
════════════════════════════════════════════════════════════════════════
Epitaphs
🪦 Fenn: Fenn of The Lone Bond, noble warrior fallen at battle's
heart; in unwavering loyalty and strength he kept the ancient oath.
🪦 Sera: Here lies Sera of The Bound Ones — endurance rewarded,
the wise must lead. She proved both, and fell proving them.
🪦 Yeva: Here lies Yeva of The Salted Bridge, who fell defending
self reliance.
Faction Myth
📜 MYTH of The Restless Few:
In times past, when The Salted Bridge stood unyielding against
our fury, we marched beneath loyalty's banner across the scarred
plains. By divine decree our creed was forged in conflict —
endurance is not given, it is carved from loss.
Architecture
sim.py Entry point — 10,000-tick main loop, logging, layer orchestration
│
├── world.py Layer 0 · 3-field Perlin terrain, 6 biomes, sea calibration, seasons
├── inhabitants.py Layer 1 · Survival, cost-adjusted navigation, trust, procreation
├── beliefs.py Layer 2 · 27 event-driven beliefs, peer sharing
├── factions.py Layer 3 · Formation, schisms, merges, territory, settlements
├── economy.py Layer 4 · Currency, dynamic pricing, trade routes, raids, Gini
├── combat.py Layer 5 · War declarations, alliances, multi-tick battles, legends
├── technology.py Layer 6 · 16-tech tree (3 branches), Sailing passive, AI research
├── diplomacy.py Layer 7 · Council votes, treaties, reputation, surrender terms
├── mythology.py Layer 8 · LLM chronicles, myths, epitaphs (optional, read-only)
│
├── dashboard_bridge.py Data bridge — atomic JSON snapshot writer (every 25 ticks)
├── dashboard.py Streamlit live dashboard — world map, rep chart, event feed
├── display.py Terminal rendering — per-tick output, faction summaries
└── config.py Settings — population cap, mythology toggle, LLM parameters
Each layer is a pure function over shared state. Layers 0–7 are deterministic Python. Layer 8 (mythology) is the only one that touches a network socket — disabled by default. The dashboard bridge writes once every 25 ticks via atomic os.replace(), so running the dashboard in parallel has no measurable impact on simulation speed.
The terminal output is selectively filtered: only notable events (war declarations, births, deaths, treaties, tech discoveries, schisms, era shifts) appear live via a keyword filter. Full tick-by-tick detail goes to a timestamped log file in logs/.
Quick Start
Prerequisites
- Python 3.10+
- (Optional) Ollama — only needed if you enable the mythology layer
Setup
Option A: Install via PyPI (Recommended for Play)
The fastest way to run the simulation.
pip install thalren-vale-simulation
thalren-sim
Option B: By Source
# 1. Clone the repo
git clone https://github.com/Kriaetour/ai-sim-emergent-agents
cd ai-civilization-sim
# 2. Create and activate a virtual environment
python -m venv .venv
.venv\Scripts\activate # Windows
# source .venv/bin/activate # macOS / Linux
# 3. Install dependencies
pip install -r requirements.txt
# 4. Run the simulation
python sim.py
Live Dashboard (optional, but recommended)
Open a second terminal and run the dashboard while the simulation is running:
streamlit run dashboard.py
Then open http://localhost:8501 in your browser. The world map, reputation graph, and event feed update automatically at 2 FPS as the simulation writes snapshots every 25 ticks.
To enable the LLM mythology layer:
# Pull a model (any Ollama-compatible model works)
ollama pull internlm2:1.8b-chat-v2.5-q4_K_M
# Set MYTHOLOGY_ENABLED = True in config.py, then run
python sim.py
What You'll See
Log → logs/run_20260223_190041.txt
Running 10000-tick simulation (wars / schisms / deaths show below)
[ 1/10000] Alive:30 Factions:0 Wars:0 Techs:0 Treaties:0
...
Tick 045: ⚡ SCHISM — The Drifting Circle breaks from The Wild Rovers
Tick 060: ⚔ WAR DECLARED — The Lone Bond vs The Trading Bridge (tension 222)
Tick 060: 💀 Fenn (The Lone Bond) fell in battle at (1,6)
Tick 120: 🍼 BIRTH: Sera II born to Brea and Arin
Tick 200: ⛵ TECH DISCOVERED — The Wild Rovers unlock Sailing
Tick 500: 📅 NEW ERA DAWNS — The Age of Iron
...
Hardware
| Tier | Spec | Notes |
|---|---|---|
| Minimum (tested) | Intel N95 · 16 GB RAM | Pure sim runs easily; mythology adds LLM wait time |
| Comfortable | Any modern CPU · 16 GB RAM | Full 10,000-tick run in minutes |
| With GPU | Any iGPU/dGPU supported by Ollama | Mythology calls become near-instant |
No GPU is required. The simulation itself is pure Python and runs without any LLM. The optional mythology layer calls Ollama with keep_alive: 0 (immediate VRAM release) and gc.collect() after each inference to minimize memory pressure on shared-memory iGPU systems.
Several optimizations target N95-class hardware specifically: sea tiles (~25% of the grid) are skipped during resource regeneration, biome comparisons use integer IDs instead of string equality, the spatial partition replaces O(n) neighbor scans with bounded-radius lookups, and the event log is capped at 200 entries in RAM with overflow archived to disk.
Configuration
Key settings in config.py:
# Ollama / LLM (only relevant when mythology is enabled)
GAME_MODEL = "phi3:3.8b-mini-4k-instruct-q4_0"
NARRATIVE_MODEL = "internlm2:1.8b-chat-v2.5-q4_K_M"
OLLAMA_URL = "http://localhost:11434/api/generate"
OLLAMA_TIMEOUT = 150 # seconds per LLM call
# Feature flags
MYTHOLOGY_ENABLED = False # True → enable LLM chronicles; False → manual export
# Population
POP_CAP = 1000 # hard ceiling; world food scales up as population grows
# LLM tuning
LLM_TEMPERATURE = 0.7
LLM_MAX_TOKENS = 200 # default ceiling; overridden per call type
In sim.py:
TICKS = 10000 # Change to run shorter (300) or longer simulations
In dashboard_bridge.py:
DASHBOARD_WRITE_EVERY = 25 # ticks between dashboard snapshots (increase to reduce I/O)
File Outputs
| File | When | Contents |
|---|---|---|
logs/run_*.txt |
Every run | Full tick-by-tick log of all events |
dashboard_data.json |
Every 25 ticks | Live snapshot: biome grid, faction positions, reputation history, event tail |
manual_chronicle.txt |
Every 50 ticks (mythology disabled) | Structured era events + perished names for external LLM use |
era_export.txt |
Every 50 ticks | Last 100 events + era summaries |
history_*.txt |
End of run (mythology enabled) | Tolkien-style epic summary generated by LLM |
Writing Your Own Plugin
Plugins let you inject custom events into the simulation without touching the engine. Drop a .py file into the plugins/ directory at the project root and the simulation will discover, validate, and run it automatically.
How it works
- The engine calls
load_plugins()once at startup and imports every.pyfile inplugins/(except__init__.py). - Any class that inherits from
ThalrenPluginis instantiated and registered. - Each registered plugin is evaluated on every tick that is a multiple of its
tick_interval. - If
on_trigger()returnsTrue,execute()is called and its returned commands are validated and applied. - Plugins cannot write directly to simulation state — they return
PluginCommandobjects and the engine applies them after safety checks.
Minimal plugin skeleton
# plugins/my_plugin.py
from thalren_vale.plugin_api import ThalrenPlugin, SimulationBridge, PluginCommand
from typing import List
class MyPlugin(ThalrenPlugin):
name = "my_plugin" # shown in log messages
tick_interval = 50 # evaluated every 50 ticks
def on_trigger(self, bridge: SimulationBridge) -> bool:
"""Return True when your event should fire."""
return True # always fires (when the interval hits)
def execute(self, bridge: SimulationBridge) -> List[PluginCommand]:
"""Return the list of changes you want to make."""
return [] # return commands here
Available commands
SpawnInhabitants(count, location)
Inject new inhabitants onto the map.
from thalren_vale.plugin_api import SpawnInhabitants
SpawnInhabitants(
count = 5, # how many to spawn (clamped to 1–20; POP_CAP is always respected)
location = (3, 4), # (row, col) tile to spawn on; falls back to nearest habitable tile
)
AdjustResource(target, resource, amount)
Add or remove a resource on a single tile or across an entire biome.
from thalren_vale.plugin_api import AdjustResource
# On one specific tile
AdjustResource(target=(2, 5), resource='food', amount=10)
# Across every tile of a biome (positive or negative)
AdjustResource(target='forest', resource='food', amount=-8)
resource |
valid values |
|---|---|
| Food | 'food' |
| Wood | 'wood' |
| Ore | 'ore' |
| Stone | 'stone' |
| Water | 'water' |
amount is clamped to [0, BIOME_MAX[biome][resource]] per tile — you cannot over-fill or drain to negative.
SimulationBridge reference
The bridge object passed to on_trigger and execute is a read-only snapshot of the current tick's state. Do not mutate anything you receive from it.
| Property / Method | Type | Description |
|---|---|---|
bridge.current_tick |
int |
Current tick number |
bridge.total_population |
int |
Number of living inhabitants |
bridge.population_cap |
int |
Hard ceiling from config.POP_CAP |
bridge.active_factions |
list[Faction] |
Factions with at least one member |
bridge.faction_names |
list[str] |
Names of all active factions |
bridge.biome_map |
list[list[dict]] |
Raw world grid — biome_map[r][c] is a tile dict |
bridge.grid_size |
int |
Current grid side-length |
bridge.habitable_tiles |
list[(int,int)] |
All (r, c) coordinates that are habitable |
bridge.recent_events |
list[str] |
Last 20 event log entries |
bridge.tile_biome(r, c) |
str |
Biome name at tile (r, c) |
bridge.tile_resources(r, c) |
dict |
Copy of resource dict at tile (r, c) |
bridge.faction_by_name(name) |
Faction | None |
Look up a faction by name |
Optional lifecycle hooks
def on_load(self) -> None:
"""Called once when the plugin is registered at simulation start."""
def on_unload(self) -> None:
"""Called once when the simulation ends."""
Full working example
# plugins/drought_plugin.py
"""
Drought plugin — periodically drains water from desert tiles.
Fires only when at least 2 factions are active and the world is past tick 200.
"""
from thalren_vale.plugin_api import (
ThalrenPlugin, SimulationBridge, PluginCommand, AdjustResource, SpawnInhabitants
)
from typing import List
class Drought(ThalrenPlugin):
name = "drought"
tick_interval = 150 # fires every 150 ticks
def on_trigger(self, bridge: SimulationBridge) -> bool:
return (
bridge.current_tick >= 200
and len(bridge.active_factions) >= 2
)
def execute(self, bridge: SimulationBridge) -> List[PluginCommand]:
commands = [
# Strip water from all desert tiles
AdjustResource(target='desert', resource='water', amount=-4),
# Compensate with a small coastal food bonus (fishing boom)
AdjustResource(target='coast', resource='food', amount=6),
]
# If the world is close to collapse, bring in refugees
if bridge.total_population < 15:
hab = bridge.habitable_tiles
if hab:
import random
commands.append(
SpawnInhabitants(count=4, location=random.choice(hab))
)
return commands
Safety rules
countis clamped —SpawnInhabitants.countis silently clamped to[1, 20]. IfPOP_CAPis already reached, no inhabitants are spawned and a log entry is written instead.- Resources are clamped —
AdjustResourcenever sets a resource above its biome maximum or below zero. - Invalid targets are silently rejected — unknown resource keys and out-of-bounds tile coordinates are logged and skipped; the simulation continues.
- Exceptions are caught — any unhandled exception inside
on_triggerorexecuteis written to the event log and the simulation continues uninterrupted. - Commands are the only write path — plugins receive a read-only bridge. Directly mutating
bridge.biome_maporbridge.active_factionsis undefined behaviour and will not produce logged events.
Roadmap
- Generational agents — children inherit beliefs and faction membership from parents
- Streamlit live dashboard — world map, faction borders, and reputation graph updating in real time
- Religion system — formalized beliefs become institutions with priests, temples, and schismatic holy wars
- Larger world scale — dynamic grid expansion, 6 biome types, calibrated 25% sea coverage
- Navigable seas — Sailing tech, coast fishing, port bias for settlements
- Multiple settlements — factions build fixed towns with storage, walls, and population caps
- Persistent history — cross-run chronicles where great factions from past runs become legends in new ones
License
This project is licensed under the Polyform Noncommercial License 1.0.0.
Commercial use is not permitted without explicit written consent from the author.
See the LICENSE file for the full terms.
Legal
Copyright (c) 2026 (KriaetvAspie / AspieTheBard). All rights reserved. This engine and its emergent logic layers are proprietary intellectual property.
Built to answer the question: how much civilization can emerge from how little code?
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file thalren_vale_simulation-1.1.1.tar.gz.
File metadata
- Download URL: thalren_vale_simulation-1.1.1.tar.gz
- Upload date:
- Size: 136.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8f570430022a0c74f589b5320aa5a23f58fd664b6c769e1ab473c7e9fcaea592
|
|
| MD5 |
c841b203c948afa70839b7f89de63702
|
|
| BLAKE2b-256 |
28b8ab8a993a1d5d7b2294f842c49c0d4d12030fd6387b2b6fdbc2e2febadfa3
|
File details
Details for the file thalren_vale_simulation-1.1.1-py3-none-any.whl.
File metadata
- Download URL: thalren_vale_simulation-1.1.1-py3-none-any.whl
- Upload date:
- Size: 134.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6a6889f8de9a4bdaf4c01200ca73b6551dd0b920e78cf945f3ee14ae3e8471b6
|
|
| MD5 |
8d6d0a79cf3ba766492e7d9e8cc0de2f
|
|
| BLAKE2b-256 |
c79d69dd554f000976f3c2b68ac9741c59dfde8e716d0b5504e4b7c0e403e6e2
|