Status: reference for adding resources, machines, recipes, build recipes, and scenarios to the current data-driven slice.
This guide is for the current sim_core content model in content.rs. If a new idea does not fit one of the existing behavior types, it is not a pure data change and will require Rust work in both the simulation and client.
Primary data files:
Validation happens when the catalog loads. The workspace tests already cover content loading, so broken links should fail fast during cargo test.
Add new slice content in this order:
- Add any new resources
- Add recipes that use those resources
- Add the machine that runs the recipe
- Add a build recipe if the machine should be fabricable
- Add the machine to a scenario starter inventory if needed
- Add or update a scenario that exercises the content
- Add a simulation test if the new content introduces a new edge case
Schema is defined by ResourceDef in content.rs.
Fields:
id: stable machine-readable iddisplay_name: player-facing labelkind:solid,field, orutilitycolor: RGB floats in0.0..=1.0
Example:
(
id: "slag",
display_name: "Slag",
kind: solid,
color: (0.42, 0.38, 0.35),
)Use ids that are short, stable, and lowercase snake case.
Schema is defined by RecipeDef.
Fields:
idmachine: machine id that owns the recipeinputsoutputscycle_tickscontamination_risk
Example:
(
id: "smelt_slag",
machine: "crusher",
inputs: [
(resource: "ore_chunk", amount: 1),
],
outputs: [
(resource: "slag", amount: 1),
],
cycle_ticks: 8,
contamination_risk: 0.0,
)Rules:
- every referenced resource must exist
- the owning machine must exist
- for
processormachines, the machine's default recipe must point back to that machine id
Schema is defined by MachineDef, PortDef, and BehaviorDef.
Important fields:
iddisplay_namecategoryfootprintportsbehaviorrender.colorrender.modelrender.model_scalerender.model_offset
render is the current data contract between sim_core content and the Bevy client.
Fields:
color: fallback graybox/body tintmodel: optional asset path such asmodels/mixer.glbmodel_scale: optional XYZ scale multiplier for the imported scenemodel_offset: optional XYZ local offset from the machine origin cell
Rules:
- omit
modelto keep the machine on the built-in cube fallback - author one canonical
north-facingasset and let runtime rotate it - keep
model_scaleat(1.0, 1.0, 1.0)unless the source asset needs correction - use
model_offsetsparingly; fix pivots in Blender first if possible - the client still falls back to cube visuals when overlays or slice rules would make the model less readable
Example:
render: (
color: (0.63, 0.56, 0.42),
model: "models/mixer.glb",
model_scale: (1.0, 1.0, 1.0),
model_offset: (0.0, 0.0, 0.0),
),footprint is a list of local occupied cells.
Rules:
- must not be empty
- must not contain duplicates
- cells are authored in local
north-facingspace - runtime rotation is horizontal only right now
Example:
footprint: [
(x: 0, y: 0, z: 0),
(x: 0, y: 1, z: 0),
]PortDef fields:
idcell: local footprint cellface:north,east,south,west,up,downkind:itemorpowerflow:input,output, orbidirectionalallowed_resources
Rules:
- a port cell must belong to the machine footprint
- every resource in
allowed_resourcesmust exist - author ports in
north-facinglocal space
World direction convention:
north = -Zeast = +Xup = +Y
Current supported behaviors:
structuralwireconveyorliftgeneratorextractorprocessorfabricator
If the machine idea does not fit one of these, it requires code changes.
Inert support or construction piece.
behavior: (type: "structural")Participates in the power transport network.
behavior: (type: "wire")Directed item movement on one cell.
behavior: (type: "conveyor", move_ticks: 3)Vertical directed item transfer.
behavior: (type: "lift", move_ticks: 5)Provides power to the network.
behavior: (type: "generator", power_output: 16)Produces a resource directly from a matching map node.
behavior: (
type: "extractor",
allowed_nodes: ["ore_chunk", "biomass"],
cycle_ticks: 8,
)Uses one recipe from recipes.ron.
behavior: (
type: "processor",
recipe: "crush_ore",
contamination_on_interrupt: 0.0,
)Consumes routed items and credits global build inventory.
behavior: (
type: "fabricator",
allowed_build_recipes: [
"build_belt",
"build_wire",
],
cycle_ticks: 10,
)Schema is defined by BuildRecipeDef.
Fields:
idoutput_partinputscycle_ticks
Rules:
output_partmust be a valid machine/part id- every input resource must exist
- if a fabricator should be able to produce it, the build recipe id must appear in the fabricator's
allowed_build_recipes
Example:
(
id: "build_belt",
output_part: "belt",
inputs: [(resource: "stabilized_plate", amount: 1)],
cycle_ticks: 6,
)Each scenario lives in its own .ron file under assets/data/scenarios.
Important fields:
iddisplay_namesizeterrain_boxesresource_nodesstarter_inventorypreplaced_partsobjectiveprompts
Rules:
- terrain and resource nodes must be in bounds
- starter inventory parts must exist
- objective resources must exist
- preplaced parts should only be used when the scenario truly needs them
These changes should usually stay data-only:
- new resource ids
- new processor recipes
- different machine colors
- different machine footprints
- different port layouts
- different starter inventories
- different scenario terrain/resource distributions
- new build costs
- alternate objective definitions using the existing objective variants
These are not just data edits:
- new machine behavior families
- fluids, gases, or continuous transport
- new objective types
- new overlay logic
- new port kinds beyond
itemandpower - new simulation commands
- different rotation rules such as vertical-facing placement
For a new machine that fits existing behavior:
- Add any missing resources in resources.ron
- Add a recipe in recipes.ron if needed
- Add the machine to machines.ron
- Add a build recipe in build_recipes.ron if fabricable
- Add the build recipe id to a fabricator's
allowed_build_recipesif needed - Add the machine to scenario starter inventory if the scenario depends on it
- Run
cargo test - Run
cargo clippy --workspace --all-targets -- -D warnings
- Add the resource to resources.ron
- Reference it from recipes and port restrictions
- Add scenario nodes only if it is a raw extractable resource
- Verify the machine chain can actually route it through valid ports
- Run
cargo test
Keep authoring narrow. Prefer:
- more scenario variation
- clearer machine definitions
- better balance values
Do not widen the content surface casually. The first slice only proves the current machineworks loop if every added machine still helps readability instead of diluting it.