Skip to main content

Preset Schema

RODENT experiment presets are JSON files that describe the complete configuration of an experiment.

Preset files are stored in:

presets/

The current preset format is:

schema_version: 2

The application contains migration and validation support for the preset format.

Top-Level Structure

A preset has the following structure:

{
"schema_version": 2,
"metadata": {},
"simulation": {},
"arena": {},
"stimuli": [],
"protocol": [],
"treatment": {},
"controller": {},
"rodent": {},
"ui": {}
}

The required top-level sections are:

schema_version
metadata
simulation
arena
stimuli
protocol
treatment
rodent
controller

The ui section is supported by the current presets but is not required by the Python preset validator.


schema_version

The current schema version is:

"schema_version": 2

Custom presets should be authored directly against version 2.

The application also contains migration support for older preset data.


metadata

The metadata section identifies and describes the preset.

Required fields:

"metadata": {
"id": "example_arena",
"name": "Example Arena",
"version": "1.0",
"description": "Example arena configuration"
}
FieldTypeRequiredDescription
idstringYesUnique preset identifier
namestringYesHuman-readable preset name
versionstringYesPreset version
descriptionstringYesDescription of the preset

simulation

The simulation section defines deterministic simulation settings.

Example:

"simulation": {
"fixed_delta": 0.02,
"seed": 42
}
FieldTypeRequiredDescription
fixed_deltanumberYesFixed simulation timestep
seedintegerYesRandom seed used by the simulation

The fixed timestep must be greater than zero.

The seed must be an integer.

These values are also used by the project's determinism checks.


arena

The arena section contains the physical and visual environment.

Required fields:

"arena": {
"id": "example_arena",
"dimensions": {},
"materials": {},
"regions": []
}

Required arena fields:

FieldTypeRequiredDescription
idstringYesArena identifier
dimensionsobjectYesArena width and height
materialsobjectYesMaterial definitions
regionsarrayYesArena regions

Optional arena fields include:

inner_walls
doors
treatment_chamber
show_labels
outer_wall_height
use_outer_walls
outer_wall_material_id
structures

Arena Dimensions

Example:

"dimensions": {
"width": 100,
"height": 100
}

Width and height must be positive.

Preset coordinates use this two-dimensional arena space.


arena.materials

Materials are stored as an object keyed by material ID.

Example:

"materials": {
"solid_floor": {
"display_name": "Solid Floor",
"categories": ["floor"],
"visual": {
"color": "#64748b",
"roughness": 0.75,
"metallic": 0.0,
"transparency": 0.0
},
"physical": {
"speed_multiplier": 1.0
}
}
}

A material contains:

display_name
categories
visual
physical

The visual definition contains:

color
roughness
metallic
transparency

The physical definition currently contains:

speed_multiplier

Standard Material IDs

The application defines the following standard materials:

IDDescriptionSpeed multiplier
solid_floorSolid floor1.00
rubberRubber surface0.95
wire_meshWire mesh0.85
wood_chipWood-chip bedding0.80
painted_steelPainted steel1.00
clear_acrylicClear acrylic1.00

The renderer uses material properties such as roughness, metallic appearance and transparency when constructing the 3D scene.


arena.regions

Regions define areas of the arena.

A region must contain:

{
"id": "open_area",
"label": "Open Area",
"semantic_type": "open",
"material_id": "solid_floor",
"rect": [0, 0, 100, 100],
"color": "#64748b",
"object_type": "region",
"enabled": true
}

Required fields:

FieldTypeRequiredDescription
idstringYesUnique region ID
labelstringYesDisplay name
semantic_typestringYesFunctional region type
material_idstringYesMaterial reference
rectarrayYes[x, y, width, height]
colorstringYesRegion colour
object_typestringYesRegion object type
enabledbooleanYesWhether the region is active

The region ID must be unique within the preset.

The rect array must contain exactly four numeric values.

Standard Semantic Types

The standard semantic types are:

open
corridor
shelter
risk
exploration
transition

Other semantic types may produce validator warnings.

Optional Region Fields

The renderer supports additional fields such as:

shape
radius
surface
rotation_y
elevation
height_mode
height_target_region_id
covered

Shape

A region can use:

"shape": "rect"

or:

"shape": "circle"

Circular regions can specify:

"radius": 10

Rotation

Example:

"rotation_y": 45

Elevation

Example:

"elevation": 6

Elevation is represented in the preset coordinate system and converted to the Godot 3D Y axis by the renderer.

Covered Regions

Example:

"covered": true

Covered regions can receive the DCR roof treatment in the renderer.


arena.inner_walls

Inner walls divide regions and create physical boundaries.

Example:

"inner_walls": [
{
"id": "divider",
"rect": [48, 20, 4, 60],
"object_type": "wall",
"enabled": true,
"height": 20,
"material_id": "painted_steel"
}
]

Required fields:

FieldTypeRequiredDescription
idstringYesUnique wall ID
rectarrayYes[x, y, width, height]
object_typestringYesWall object type
enabledbooleanYesWhether the wall is enabled
heightnumberYesWall height
material_idstringYesMaterial reference

Optional field:

rotation_y

Wall IDs must be unique.

The wall height must be greater than zero.

Very large wall heights may produce validator warnings.


arena.doors

Doors create controlled openings through walls.

Example:

"doors": [
{
"id": "door_1",
"label": "Main Door",
"type": "gap",
"wall": "divider",
"position": [50, 50],
"width": 8,
"default_state": "closed",
"material_id": "painted_steel"
}
]

Required fields:

FieldTypeRequiredDescription
idstringYesDoor ID
labelstringYesDisplay label
typestringYesDoor type
wallstringYesReferenced wall ID
positionarrayYesTwo-dimensional position
widthnumberYesDoor width
default_statestringYesInitial door state
material_idstringYesMaterial reference

Supported door types:

gap
circular

Supported default states:

open
closed
locked

The referenced wall must exist.

The door position must contain exactly two numeric values.

The door width must be greater than zero.

Optional Door Fields

The current renderer also supports:

open
state
enabled
object_type
rotation_y
render_visual

Door state changes can occur while an experiment is running.


arena.treatment_chamber

A treatment chamber is optional.

Example:

"treatment_chamber": {
"id": "treatment_chamber",
"object_type": "treatment_chamber",
"label": "Treatment Chamber",
"position": [50, 50],
"size": [20, 20],
"rotation_y": 0,
"material_id": "clear_acrylic",
"enabled": true,
"collidable": true
}

The treatment chamber can define:

id
object_type
label
position
size
rotation_y
material_id
enabled
collidable

The treatment section must reference the appropriate chamber ID.


arena.structures

The renderer supports additional structures.

Currently supported structure types include:

bridge
ramp

Bridge

A bridge can specify:

{
"id": "bridge_1",
"type": "bridge",
"region_id": "bridge",
"entry_region_id": "entry",
"exit_region_id": "exit",
"elevation": 6.0
}

The bridge renderer creates an elevated base with entry and exit ramps.

Ramp

Ramp structures provide sloped visual geometry.

The bridge and ramp renderer should not be assumed to provide generic collision geometry for every structure.


stimuli

Stimuli are stored as an array.

Example:

"stimuli": [
{
"id": "field_light",
"type": "light",
"position": [50, 50],
"radius": 10,
"initially_active": true,
"enabled": true,
"object_type": "stimulus",
"rotation_y": 0,
"properties": {}
}
]

Required stimulus fields:

id
type
position

The position must contain two numeric values.

Additional fields can describe:

radius
initially_active
enabled
object_type
rotation_y
properties

The renderer uses stimulus data to create visual markers and, for light stimuli, actual light sources.


protocol

Protocol events are stored as an array.

Example:

"protocol": [
{
"step": 30,
"source_id": "field_light",
"active": true
},
{
"step": 60,
"source_id": "field_light",
"active": false
}
]

Each protocol event requires:

FieldTypeRequired
stepinteger/numberYes
source_idstringYes
activebooleanYes

source_id identifies the stimulus or source affected by the protocol event.


treatment

The treatment section is required.

Example:

"treatment": {
"id": "control",
"name": "Control",
"category": "control",
"condition": "none",
"dose": 0,
"unit": "mg",
"administration_step": 0,
"chamber_id": "treatment_chamber"
}

Required fields:

FieldTypeRequired
idstringYes
namestringYes
categorystringYes
conditionstringYes
dosenumberYes
unitstringYes
administration_stepnumberYes
chamber_idstringYes

The chamber ID should correspond to the configured treatment chamber when a treatment chamber is present.


rodent

The rodent section defines the simulated animal parameters.

Example:

"rodent": {
"weight_grams": 300,
"size_scale": 1.0,
"base_speed": 1.0,
"turn_tendency": 0.5,
"activity": 0.5,
"risk_tolerance": 0.5
}

Required fields:

FieldTypeRequired
weight_gramsnumberYes
size_scalenumberYes
base_speednumberYes
turn_tendencynumberYes
activitynumberYes
risk_tolerancenumberYes

These values form part of the simulated rodent configuration.


controller

The controller defines the starting state and movement parameters.

Example:

"controller": {
"type": "default",
"start_position": [50, 50],
"start_heading": 0,
"speed": 1.0,
"turn_noise": 0.1
}

Required fields:

FieldTypeRequired
typestringYes
start_positionarrayYes
start_headingnumberYes
speednumberYes
turn_noisenumberYes

The start position must contain two values.

Presets may also include a controller behaviour preset where supported by the application.


ui

The UI section contains user-interface preferences.

Current presets can contain camera configuration such as:

"ui": {
"camera": {
"sensitivity": 0.4,
"invert_horizontal": false,
"invert_vertical": false,
"follow_distance": 1.6
}
}

These values control camera behaviour rather than the physical arena itself.

The Python preset validator does not require the ui section.


Coordinate System

Preset arena positions use two-dimensional coordinates.

JSON plane

y



└────────── x

The Godot renderer maps them to:

JSON x → Godot X
JSON y → Godot Z
elevation → Godot Y

The renderer uses a scale factor of:

0.1

Therefore:

Godot X = JSON x × 0.1
Godot Z = JSON y × 0.1
Godot Y = elevation × 0.1

IDs and References

Object IDs should be unique within their respective collections.

For example:

region IDs → unique
wall IDs → unique
door IDs → unique
stimulus IDs → unique

References must point to existing objects.

For example:

"wall": "divider"

requires a wall with:

"id": "divider"

Material references must point to IDs defined in:

arena.materials

Minimal Complete Preset

The following is a complete minimal preset structure suitable as a starting point for a custom configuration:

{
"schema_version": 2,
"metadata": {
"id": "custom_arena",
"name": "Custom Arena",
"version": "1.0",
"description": "Custom RODENT arena"
},
"simulation": {
"fixed_delta": 0.02,
"seed": 42
},
"arena": {
"id": "custom_arena",
"dimensions": {
"width": 100,
"height": 100
},
"materials": {
"solid_floor": {
"display_name": "Solid Floor",
"categories": [
"floor"
],
"visual": {
"color": "#64748b",
"roughness": 0.75,
"metallic": 0.0,
"transparency": 0.0
},
"physical": {
"speed_multiplier": 1.0
}
}
},
"regions": [
{
"id": "open_area",
"label": "Open Area",
"semantic_type": "open",
"material_id": "solid_floor",
"rect": [
0,
0,
100,
100
],
"color": "#64748b",
"object_type": "region",
"enabled": true
}
],
"inner_walls": [],
"doors": [],
"use_outer_walls": true,
"outer_wall_height": 28,
"outer_wall_material_id": "solid_floor"
},
"stimuli": [],
"protocol": [],
"treatment": {
"id": "control",
"name": "Control",
"category": "control",
"condition": "none",
"dose": 0,
"unit": "mg",
"administration_step": 0,
"chamber_id": "treatment_chamber"
},
"rodent": {
"weight_grams": 300,
"size_scale": 1.0,
"base_speed": 1.0,
"turn_tendency": 0.5,
"activity": 0.5,
"risk_tolerance": 0.5
},
"controller": {
"type": "default",
"start_position": [
50,
50
],
"start_heading": 0,
"speed": 1.0,
"turn_noise": 0.1
},
"ui": {
"camera": {
"sensitivity": 0.4,
"invert_horizontal": false,
"invert_vertical": false,
"follow_distance": 1.6
}
}
}

Validation

The Python validator is located at:

tests/validate_presets.py

Run:

python tests/validate_presets.py

The validator checks all JSON files under:

presets/

It checks:

  • schema version
  • metadata
  • simulation settings
  • arena dimensions
  • materials
  • regions
  • walls
  • doors
  • stimuli
  • protocol events
  • treatment
  • rodent configuration
  • controller configuration
  • references between objects

The deterministic configuration check is located at:

tests/test_determinism_ci.py

Run:

python tests/test_determinism_ci.py

The determinism check verifies that the determinism-relevant configuration produces a stable configuration hash. It does not execute two complete simulations.


Creating a Custom Preset

To create a new preset:

  1. Create a JSON file under:
presets/
  1. Set:
"schema_version": 2
  1. Add all required top-level sections.

  2. Define the arena dimensions.

  3. Define the materials used by regions, walls and doors.

  4. Define the regions.

  5. Add walls and doors where required.

  6. Add stimuli and protocol events if required.

  7. Configure treatment, rodent and controller settings.

  8. Run:

python tests/validate_presets.py
  1. Run:
python tests/test_determinism_ci.py

A preset should pass these checks before being committed to the repository.