# `Monty.Simulators.Synthetic.Environment`
[🔗](https://github.com/d-led/ex.tbp.monty/blob/v0.1.0/packages/ex_tbp_monty_core/lib/monty/simulators/synthetic/environment.ex#L1)

A stand-in world for developing the runtime, driven by the actions it is given.

Monty's world is a Python process; until that bridge runs here
(`docs/simulator-port.md`), the runtime needs something deterministic to step.
This one moves a single agent according to the actions the motor system chose —
see `Monty.Simulators.Synthetic.Kinematics` for which actions it honours and
the conventions it follows — and answers the two payloads Monty's
`Interface.step/1` returns: observations per agent and sensor, and the
proprioceptive state in global coordinates.

It has **no geometry**: nothing is out there, so an observation is what the
sensor's own pose says, and the only feature is a value that follows the
agent's x. That is enough for the runtime and for the pages that watch it, and
it is worth being plain about what it is not: a run against this world says
nothing about a learned object, while a run against a simulator says
everything.

It is a simulator, not a ported module: nothing here claims to mirror a Python
file.

# `t`

```elixir
@type t() :: %Monty.Simulators.Synthetic.Environment{
  agent: Monty.Simulators.Synthetic.Kinematics.pose() | nil,
  last_observations: map() | nil,
  scene: Monty.Simulators.Synthetic.Scene.t() | nil,
  sensor_ids: [Monty.Simulators.Environment.sensor_id()],
  sensors: %{
    optional(Monty.Simulators.Environment.sensor_id()) =&gt;
      Monty.Simulators.Synthetic.Kinematics.pose()
  },
  views: %{optional(Monty.Simulators.Environment.sensor_id()) =&gt; keyword()},
  world: Monty.Simulators.Synthetic.Kinematics.t()
}
```

# `agent_id`

```elixir
@spec agent_id() :: String.t()
```

How the runtime addresses this environment's parts in a module spec.

# `new`

```elixir
@spec new(
  [Monty.Simulators.Environment.sensor_id()],
  Monty.Simulators.Synthetic.Scene.t() | nil,
  keyword()
) :: t()
```

A world looking at `scene`, each sensor through its own camera.

`:views` is a camera per sensor, keyed by sensor id, in the terms
`Monty.Simulators.Synthetic.Scene.render/3` takes — a resolution, a zoom and a
field of view. A sensor with no camera renders one ray down its own axis.
`:agent` and `:sensors` are where the episode starts, as an experiment's
simulator is configured.

Geometry is a choice, not an assumption: with a scene the world renders depth,
colour and semantic id for every sensor, which is what a ported surface policy
steers by; without one it reports only where the sensors are, and a percept
built from it says its pose is undefined.

# `observation`

```elixir
@spec observation(t()) :: map() | nil
```

What the world rendered on its last step, before any transform ran.

A page that shows the object wants the picture the world drew, not the one a
transform rewrote: `MissingToMaxDepth` turns "no return" into a metre, and a
surface experiment clips everything past five centimetres, which is right for
matching and useless for looking at.

# `primary_target`

```elixir
@spec primary_target(t()) :: nil
```

Nothing: this world places no object it could name.

Monty's worlds sample an object and say which; the stand-in has one sphere at
the centre an experiment's scene put it, and calling that an object would tell a
model to score itself against something nobody chose.

# `step`

```elixir
@spec step(t(), [Monty.Frameworks.Actions.Action.t()]) :: {map(), map(), t()}
```

Observations and proprioceptive state after `actions`.

Keys and units follow Monty: metres, sensor positions in the world, the
agent's pose absolute, each sensor's pose relative to the agent.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
