Start here
LivingSim is a social-memory and consequence engine for games. You feed it typed events — "Mara accused Brann", "Brann apologized", "someone stole from Tovin" — and it updates each character's memory, emotions, relationships, and goals. The point: NPCs remember what happened and later change what they do because of it. A bystander who watched you steal will distrust you, avoid you, and warn others days later, without you scripting that reaction. It's a plain C# library (.NET 8, Unity-compatible), runs offline with no network or model calls, and every reaction is traceable back to the events that caused it.
Fastest path for a Unity / C# game? The first-hour SDK getting-started takes you from one player action to memory, feeling, why, and next move through a single facade type (
LivingSimSdk) — the demo-first route. The rest of this page is the broader engine intro (the full Core API, authoring worlds).
What it is not
- Not a dialogue system. It doesn't write or choose lines of dialogue.
- Not a behavior tree or state machine. You don't hand-author per-NPC logic; goals emerge from accumulated state.
- Not an LLM or chat system. No model calls, no prompts, no generated prose — the simulation is typed data, deterministic from a seed.
- Not a game framework. No rendering, physics, scenes, or input. It's the "memory and consequence" layer your game calls into.
Run the demo (one command)
dotnet run --project tools/LivingSim.ProductProof -- --scenario village-council-hearing
A small village-council hearing plays out. What to notice:
- The chair warms to the accused man after he apologizes — she forms a goal to befriend him.
- Then someone reveals his hidden allegiance. She learns it, grows wary, and her goal flips to avoid him — she walks out of the hall.
- Nobody scripted her reaction. The engine computed it from what she learned.
(Add
--developerto the command to see the step-by-step trace.)
Use it directly from C#
No JSON, no config files — create an engine and record events:
using LivingSim.Core;
var time = new DateTime(2026, 1, 1, 12, 0, 0, DateTimeKind.Utc);
var engine = new SimulationEngine(seed: 1);
// Put two characters in the same room, then one helps the other.
engine.GetOrCreateCharacter("ada").MoveTo("studio");
engine.GetOrCreateCharacter("bo").MoveTo("studio");
engine.RecordEvent(new WorldEvent(
Type: EventType.Help, ActorId: "ada", TargetId: "bo",
PlaceId: "studio", Impact: 20, Timestamp: time));
// Bo now remembers it — and warms toward Ada.
var bo = engine.Characters.Single(c => c.Id == "bo");
foreach (var m in bo.Memory.All)
Console.WriteLine($"{m.Event.Type} (importance {m.Importance})");
Console.WriteLine($"bo -> ada affinity: {bo.Relationships.Get("ada")?.Affinity}");
That's the whole idea: record typed events, then read the durable state they form
(memory, relationships, emotions, goals). Call engine.Step(time) to advance the
clock one tick: it may emit a random event, then ages state. Goal-driven action
only runs when the tuning enables AutoBehaviorEnabled — off in the
BehaviorTuning.Default that new SimulationEngine(seed) uses; the facade's
default Showcase profile turns it on.
Use JSON only if you want authored seed data
If you'd rather declare a starting world as a data file — a cast, their
relationships, a secret someone is hiding, a rule of a place — instead of writing
setup code, there's an optional JSON format that loads into a ready-to-run engine
in one call (ScenarioLoader.LoadFromJson). You never need it to use LivingSim;
it's a convenience for authored scenarios, and it only sets up starting state —
the engine still computes everything that happens next. The full format lives in
SCENARIO_SCHEMA.md.
What to read next
- This doc — what LivingSim is and the five-minute mental model.
- Developer quick start — the
LivingSimSdkAPI, one minimal example at a time; its end-to-end block is run by the test suite as written. - Running the Core — driving the engine: recording events, advancing time, inspecting state, saving and loading.
- Scenario JSON schema — the optional authoring format, field by field (reference, read it when you need it).
- HTML API reference — every public type and method. Build it with
scripts/build-api-docs.sh, then open_site/index.html.