The Eustress Philosophy
Eustress is a source-available simulation and data platform, written in Rust, where people and AI agents build and run the same Spaces. These are the principles behind it, each tied to a mechanism you can inspect yourself.
01Overview
What Eustress Is For
Eustress is for modeling physical systems, running them forward in time and measuring what happens: a battery cell under load, heat moving through a part, a structure an agent assembles and tests. The 3D view and the entity component system underneath are how it does that. The product is the simulation and the data it produces.
Every principle below is a decision you can check in the product or in the source, which is public. Where a principle is still partly a goal, the page says which part.
Six Principles
| Principle | What to look at |
|---|---|
| Agents and people work in the same Spaces | The MCP server, the engine bridge, the AI camera |
| Your work is yours | Space folders, TOML files, git history, the WorldDb |
| One language underneath | Rust in the engine, Studio, tools and website |
| Measured in SI | Meters in every system, SI types in the physics |
| Same inputs, same world | A fixed 60 Hz step, pinned physics settings, one seed |
| Source-available | PolyForm Shield 1.0.0, plus a commercial license |
02Agents and People
The Same Spaces
An agent in Eustress works in the Space you have open, not in a copy and not
by reading screenshots of the interface. The parts it creates appear in your
Explorer, and the editor actions your keyboard shortcuts run are one bridge call
away (action.invoke).
Studio's Workshop panel and the MCP server take their tools from one crate, eustress-tools, so a tool added there is available to an agent in
either place.
The MCP Server
The MCP server, eustress-mcp, speaks the Model Context Protocol over
standard input and output, the way MCP clients such as Claude Desktop, Cursor and
Windsurf launch a server. Through it an agent lists Universes and Spaces, reads and
edits entities and scripts, runs simulations and experiments, and reads the
op-log.
When an engine is running, entity edits go through it and appear in the open Space at once. When none is, they are written to the Space's files instead. MCP Server lists the tools and how to connect a client.
The Engine Bridge
Every running engine, windowed or headless, opens a bridge: a JSON-RPC listener
on 127.0.0.1 whose port it writes to .eustress/engine.port in its Universe. The MCP server and the eustress command-line tool
are both clients of it. Each request and each reply is one line of JSON:
{"jsonrpc":"2.0","id":1,"method":"ecs.inspect","params":{"limit":10}}
{"jsonrpc":"2.0","id":1,"result":{...}}Its methods cover what acting in a world takes: query and edit entities (ecs.query, entity.create, entity.update), advance physics one fixed tick at a time (sim.step), cast rays
against live colliders (scene.raycast), run editor actions (action.invoke), read the op-log (oplog.tail) and
capture images (viewport.capture, ai_camera.capture).
The AI Camera
An agent that builds something needs to look at it without taking over your
view. The AI camera is a second camera that renders 1280 by 720 images into an
off-screen texture instead of the window. It appears in the Explorer as a Camera
named AI Camera, and the ai_camera_set_pose, ai_camera_orbit, ai_camera_frame and ai_camera_capture tools move it and save what it sees, while your
viewport stays where you left it.
03Your Work Is Yours
Files You Can Read
A Space is a folder you can open without Eustress. Services, instances and
settings are TOML; scripts are .rune and .luau files;
meshes are .glb. Edit any of them in another editor and the file
watcher applies the save to the open Space. Rune scripts also get completions
from the Rune language server.
Universes walks through the folder layout, from
the Eustress folder down to a single _instance.toml.
History You Keep
Ctrl+S and autosave, every 300 seconds by default, each commit the
Space folder to git. The record of how a Space changed is ordinary git history on
your own disk: any git client reads it, and you can push it to any git host you
choose.
Parts that live only in the Space's database are not in these commits. What Git Captures lists what a commit covers and how to export the rest as TOML first.
A Database for Scale
One file per part stops scaling long before a large world does, so each Space
also has a database, world.fjalldb/, and Studio builds the scene
from it. Files are read into it when the Space opens. A Space with more than
100,000 binary parts streams them around the camera, 350 m out by default,
instead of loading them all.
What lives only in the database can still be read as text. The export_instances_toml tool writes it out as ordinary _instance.toml files from a running engine, and eustress-space export does the same with no engine at all.
What Leaves Your Machine
Studio sends anonymous usage statistics by default, so that the tools people reach for get built first. Each ribbon click is recorded as the tool, the mode and discipline it was clicked in, whether the tool is wired, and a timestamp. Scene content, file names and entity names are not part of it.
Clicks are kept as JSON lines in %LOCALAPPDATA%\Eustress\telemetry on Windows (the local application data folder on other systems), so you can
read exactly what is collected. Only per-tool totals are sent: when a session
ends, or at the next launch if that send did not go through. To stop it, clear Send anonymous usage statistics under Settings > Notifications > Privacy.
04One Language
Rust Throughout
The engine, Studio, the WorldDb, the MCP server, the eustress command-line tool and the headless runner are Rust, and so is this website,
written with Leptos and compiled to WebAssembly. That is about 574,000 lines of
Rust across 1,342 files under eustress/crates.
One language means one compiler checks the whole path, from a record in the database to a field in the Properties panel. Rust's ownership rules give memory safety without a garbage collector, so no collector pause can land in the middle of a fixed-rate simulation step.
Slint Is Rust
Studio's interface is written in Slint, a declarative language for user
interfaces, across 66 .slint files. Slint is compiled, not
interpreted: the engine's build script turns the interface into Rust, and the
editor includes the result with slint::include_modules!().
let slint_config = slint_build::CompilerConfiguration::new()
.with_style("fluent-dark".into());
slint_build::compile_with_config(
"ui/slint/main.slint",
slint_config,
).expect("Failed to compile Slint UI");A panel's properties and callbacks are therefore Rust types, checked by the same compiler as the engine that feeds them.
What Is Not Rust
Rust is the rule. These are the exceptions:
| Part | Language | Why |
|---|---|---|
| The Luau virtual machine | C++ | Luau scripts run in Roblox's Luau VM, built into the engine through the mlua crate. Rune scripts run in a VM written in Rust. |
Workers behind api.eustress.dev | JavaScript | They run on Cloudflare Workers. The content API server, eustress-backend, is Rust. |
| The VS Code extension | TypeScript | VS Code loads extensions written in JavaScript or TypeScript. |
| Asset scripts | Python | They run inside Blender to build the avatar and export the primitive part meshes. |
| GPU shaders | WGSL | Five shader files, for billboards, the sun disc, the moon's phase and instanced part materials. |
05Measured in SI
Meters Everywhere
One unit is one meter. The engine stores every length in meters (ENGINE_NATIVE_UNIT is Unit::Meter), and gravity is
standard gravity, pointing down:
Conversions happen only at the edges: when a file written in another unit loads, and when the Properties panel shows or takes a value in your display unit. A value read from a file, a script or a physics result is already in meters.
Display Units
If you think in other units, pick one from the unit badge, which reads m until you change it: centimeters, millimeters, feet and inches
are among the choices. The Properties panel then shows and accepts lengths in that
unit and converts them to meters. The world itself does not change.
A file can be written in another unit too. Name it with unit under [metadata], and the loader converts the position and scale to meters
once, as it loads:
[metadata]
class_name = "Part"
unit = "cm"
[asset]
mesh = "parts/block.glb"
scene = "Scene0"
[transform]
position = [0.0, 50.0, 0.0] # 0.5 m
rotation = [0.0, 0.0, 0.0, 1.0]
scale = [10.0, 10.0, 10.0] # a 10 cm cubeSI in the Physics
The physics libraries use SI throughout, and each quantity is its own Rust type: Meters, Kilograms, Seconds, Kelvin, Moles and Amperes, with derived
types such as Newtons, Pascals, Joules and Watts. A mass cannot be passed where a length is expected, and
the compiler says so.
Physical constants such as the gravitational constant and the speed of light are stored in SI too. Realism covers the laws built on them.
06Same Inputs, Same World
The Pins
A result is worth comparing only if running it again gives the same answer, so Eustress fixes every setting that shapes a physics step:
| Setting | Value |
|---|---|
| Fixed timestep | 60 Hz |
| Physics substeps | 6 per step |
| Solver settings | Avian's defaults, set explicitly |
| Gravity | 9.80665 m/s², downward |
| Random seed | GlobalRngSeed, a fixed constant by default |
.insert_resource(avian3d::prelude::Gravity(bevy::math::Vec3::NEG_Y * 9.80665))
.insert_resource(Time::<bevy::time::Fixed>::from_hz(60.0))
.insert_resource(avian3d::prelude::SubstepCount(6))
.insert_resource(avian3d::dynamics::solver::SolverConfig::default())
.add_plugins(eustress_common::physics::DeterminismPlugin)The timestep and the substep count are written into the engine as values rather than left to Avian's defaults, so a physics library update cannot change them quietly.
One Seed
Randomness that shapes a simulation comes from one seed. GlobalRngSeed is a fixed constant unless you set another, and the particle simulation and the
scenario engine derive their random streams from it. A run that uses randomness can
be repeated from the Space alone, and changing the seed varies it on purpose.
The headless runner makes a run a function of its inputs. This simulates 600 ticks, 10 seconds at 60 Hz, writes the recording and exits with a status code:
eustress run ~/Documents/Eustress/Universe1/Spaces/Space1 --ticks 600CLI & Headless covers the runner and its options.
07Source-Available
PolyForm Shield
Eustress is source-available. The source is public on GitHub, and the root LICENSE is the PolyForm Shield License 1.0.0. It lets you use the
software for any purpose, change it, build new works on it and distribute copies,
with one exception: providing a product that competes with Eustress, or with a
product Eustress LLC provides using it. Copies you distribute must carry the
license terms and its Required Notice line.
At no cost, the license covers:
- Products made with Eustress: building, shipping and selling simulations, digital twins, training environments and visualizations.
- Internal use: at a company of any size, including in production.
- Changes: modifying and forking the engine for your own products.
- Learning: academic use, research, evaluation and personal projects.
If your product is built with Eustress rather than being a substitute for it, you owe nothing and you do not need to ask.
Third-party crates such as Bevy, Slint and Avian keep their own licenses, and
one first-party crate, eustress-embedvec, declares MIT in its
manifest.
The Commercial License
For rights the Shield license does not give, LICENSE-COMMERCIAL.md describes a negotiated commercial license: to offer Eustress, a fork of it or a
substantially similar platform as your own product, or to get conventional terms
such as warranties, indemnification, support SLAs or a perpetual grant. Pricing
follows the rights granted, not your revenue from products the Shield license
already permits.
Write to licensing@eustress.dev, or read the full terms on the License page.
08What's Next
A Determinism Gate
The pins make determinism testable, and the next step is the test itself. The headless runtime plan sets a gate: the same Space, run twice for the same number of ticks, will have to produce byte-identical recordings.
Branching the Whole World
Agents already share your Spaces. Next, they will be able to fork one, database included, try a change and keep it only if it wins. The storage library's copy-on-write branches are built and tested, and Universes describes what is left to wire.
Build it, run it, measure it, and keep the files.