diff --git a/.gitignore b/.gitignore
index eb6bba84b50a43973ce3844834114045c6c25b17..7d7fad54966a8b83708a116ccf45f8bafb79a459 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@
 # Edit at https://www.toptal.com/developers/gitignore?templates=python,intellij,visualstudiocode,pycharm,git,flask,django,docusaurus,ros,ros2,linux,macos,windows
 
 playground
+generated
 
 ### Django ###
 *.log
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d7fbaa1bf993c21c9d51759ebe9e56487eaabe6a..06424229295ebdb3a3bb77fd9da41a1eab1d1299 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -17,8 +17,8 @@ pages:
     - apt-get update -qy
     - apt-get install -y python3-dev python3-pip graphviz graphviz-dev
     - pip install pdoc
-    - pip install ".[rl]"
-    - pdoc --output-dir public cooperative_cuisine !cooperative_cuisine.reinforcement_learning --logo https://gitlab.ub.uni-bielefeld.de/uploads/-/system/project/avatar/6780/Cooking-Vector-Illustration-Icon-Graphics-4267218-1-580x435.jpg --docformat google
+    - pip install .
+    - pdoc --output-dir public cooperative_cuisine !cooperative_cuisine.reinforcement_learning --logo https://gitlab.ub.uni-bielefeld.de/uploads/-/system/project/avatar/6780/Cooking-Vector-Illustration-Icon-Graphics-4267218-1-580x435.jpg --docformat google --favicon overcooked-simulator/cooperative_cuisine/pygame_2d_vis/images/favicon.ico --footer-text "Developed@SCS"
   artifacts:
     paths:
       - public
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 61a757b8804a2013b67217e77f1924b41c9abf13..54668c955b4d9c4e2017e04821df1e177e400b66 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,57 @@
 # Release Notes
 
+[How to keep the changelog](https://keepachangelog.com/en/1.1.0/):
+
+- `Added` for new features.
+- `Changed` for changes in existing functionality.
+- `Deprecated` for soon-to-be removed features.
+- `Removed` for now removed features.
+- `Fixed` for any bug fixes.
+- `Security` in case of vulnerabilities.
+
+## [Unreleased]
+
+### Added
+
+### Changed
+
+### Deprecated
+
+### Removed
+
+### Fixed
+
+### Security
+
+## [1.0.0] (2024-03-XX)
+
+Release of v1. Now change the development process to an incremental updates, use of the changelog and semantic
+versioning.
+_Cooperative Cuisine_ **v1** is feature complete. It contains a usable _Overcooked!_-like environment, game server,
+study server, 2D visualization, etc.
+
+### Added
+
+- continuous-like movement and pushing other players around
+- extending recording, scoring, msgs via hooks at different programm points
+- implemented random-action agent
+- players connect via websockets
+- 2D visualization with pygame
+- Everything is configurable with config files: item info (ingredients, meals, etc.), layout, environment,
+  visualization, study
+- Game server that handles active environments
+- Study environment with study server and study config. Does the match making
+- For study participants: simple control tutorial, recipe guides, end screen.
+- Controller support
+
+### Security
+
+- To manage environments on the game server, the "manager" needs to have a valid `manager_id` which is registered in the
+  game server.
+- Registered players (humans and agents) need to connect to a websockets that are preregistered with a `client_id`.
+- Each player actions need to be references with a `player_hash` that should only be known by the player / client that
+  controls the player.
+
 ## 0.1.0 (2023-11-23)
+
 - Created
\ No newline at end of file
diff --git a/README.md b/README.md
index 4573a8452a3005f43388f9e8f1441c754496c7e0..ce6b0966e29b243df4b6e08c86616f5dd1d80706 100644
--- a/README.md
+++ b/README.md
@@ -7,9 +7,11 @@
 
 # Cooperative Cuisine Environment
 
-[Documentation](https://scs.pages.ub.uni-bielefeld.de/cocosy/overcooked-simulator)
-
 The overcooked-like cooperative cuisine environment for real-time human cooperative interactions and artificial agents.
+
+For an extensive introduction, have a look at
+the [Documentation](https://scs.pages.ub.uni-bielefeld.de/cocosy/overcooked-simulator).
+
 <div align="center">
 <img src="cooperative_cuisine/pygame_2d_vis/images/cooperative_cuisine.png"  width="800">
 </div>
diff --git a/cooperative_cuisine/__init__.py b/cooperative_cuisine/__init__.py
index 18fc18e11ab51ab9b8d97b4c3e40a3972dc591ea..e3bd8db959d95c7964ed58ec041e2577f2561113 100644
--- a/cooperative_cuisine/__init__.py
+++ b/cooperative_cuisine/__init__.py
@@ -46,7 +46,7 @@ cooperative_cuisine  -s localhost -sp 8080 -g localhost -gp 8000
 
 *The arguments shown are the defaults.*
 
-You can also start the **Game Server**m **Study Server** (Matchmaking),and the **PyGame GUI** individually in different terminals.
+You can also start the **Game Server**, **Study Server** (Matchmaking),and the **PyGame GUI** individually in different terminals.
 
 ```bash
 python3 cooperative_cuisine/game_server.py -g localhost -gp 8000 --manager_ids SECRETKEY1 SECRETKEY2
@@ -82,21 +82,22 @@ create_env = CreateEnvironmentConfig(
     item_info_config=item_info,
     environment_config=environment_config,
     layout_config=layout,
+    seed=123456789,
 ).model_dump(mode="json")
 
-env_info = requests.post("http://localhost:8000/manage/create_env", json=create_env)
-if env_info.status_code == 403:
-    raise ValueError(f"Forbidden Request: {env_info.json()['detail']}")
-env_info: CreateEnvResult = env_info.json()
+post_result = requests.post("http://localhost:8000/manage/create_env", json=create_env)
+if post_result.status_code == 403:
+    raise ValueError(f"Forbidden Request: {post_result.json()['detail']}")
+env_info: CreateEnvResult = post_result.json()
 ```
 
 Connect each player via a websocket (threaded or async).
 ```python
 import json
 import dataclasses
-from websockets import connect
+from websockets.sync.client import connect
 
-from cooperative_cuisine.environment import Action, ActionType, InterActionData
+from cooperative_cuisine.action import Action, ActionType, InterActionData
 from cooperative_cuisine.utils import custom_asdict_factory
 
 
@@ -104,12 +105,12 @@ p1_websocket = connect("ws://localhost:8000/ws/player/" + env_info["player_info"
 
 # set player "0" as ready
 p1_websocket.send(json.dumps({"type": "ready", "player_hash": env_info["player_info"]["0"]["player_hash"]}))
-assert json.loads(websocket.recv())["status"] == 200, "not accepted player"
+assert json.loads(p1_websocket.recv())["status"] == 200, "not accepted player"
 
 
 # get the state for player "0", call it on every frame/step
 p1_websocket.send(json.dumps({"type": "get_state", "player_hash": env_info["player_info"]["0"]["player_hash"]}))
-state = json.loads(websocket.recv())
+state = json.loads(p1_websocket.recv())
 
 # send an action for player "0"
 # --- movement ---
@@ -139,7 +140,7 @@ p1_websocket.send(json.dumps({
         action, dict_factory=custom_asdict_factory
     ),
 }))
-websocket.recv()
+p1_websocket.recv()
 
 ```
 
@@ -160,10 +161,12 @@ You can use the `cooperative_cuisine.environment.Environment` class
 and call the `step`, `get_json_state`, and `perform_action` methods directly.
 
 ```python
+import json
 from datetime import timedelta
 
 from cooperative_cuisine import ROOT_DIR
-from cooperative_cuisine.environment import Action, Environment
+from cooperative_cuisine.action import Action
+from cooperative_cuisine.environment import Environment
 
 env = Environment(
     env_config=ROOT_DIR / "configs" / "environment_config.yaml",
@@ -182,7 +185,7 @@ while True:
     if player_0_state["ended"]:
         break
 
-    action = ...  # Please refer to the above code but remember to use np.array instead of list for the movement direction vector
+    action = Action(...)  # Please refer to the above code but remember to use np.array instead of list for the movement direction vector
     env.perform_action(action)
 ```
 
@@ -191,11 +194,12 @@ The JSON schema for the state of the environment for a player can be generated b
 ```bash
 python state_representation.py
 ```
-Should look like
+Should look like - to have an interactive view, have a look at [jsonschemaviewer](https://navneethg.github.io/jsonschemaviewer/):
 ```
 {'$defs': {'CookingEquipmentState': {'properties': {'content_list': {'items': {'$ref': '#/$defs/ItemState'}, 'title': 'Content List', 'type': 'array'}, 'content_ready': {'anyOf': [{'$ref': '#/$defs/ItemState'}, {'type': 'null'}]}}, 'required': ['content_list', 'content_ready'], 'title': 'CookingEquipmentState', 'type': 'object'}, 'CounterState': {'properties': {'id': {'title': 'Id', 'type': 'string'}, 'category': {'const': 'Counter', 'title': 'Category'}, 'type': {'title': 'Type', 'type': 'string'}, 'pos': {'items': {'type': 'number'}, 'title': 'Pos', 'type': 'array'}, 'orientation': {'items': {'type': 'number'}, 'title': 'Orientation', 'type': 'array'}, 'occupied_by': {'anyOf': [{'items': {'anyOf': [{'$ref': '#/$defs/ItemState'}, {'$ref': '#/$defs/CookingEquipmentState'}]}, 'type': 'array'}, {'$ref': '#/$defs/ItemState'}, {'$ref': '#/$defs/CookingEquipmentState'}, {'type': 'null'}], 'title': 'Occupied By'}, 'active_effects': {'items': {'$ref': '#/$defs/EffectState'}, 'title': 'Active Effects', 'type': 'array'}}, 'required': ['id', 'category', 'type', 'pos', 'orientation', 'occupied_by', 'active_effects'], 'title': 'CounterState', 'type': 'object'}, 'EffectState': {'properties': {'id': {'title': 'Id', 'type': 'string'}, 'type': {'title': 'Type', 'type': 'string'}, 'progress_percentage': {'anyOf': [{'type': 'number'}, {'type': 'integer'}], 'title': 'Progress Percentage'}, 'inverse_progress': {'title': 'Inverse Progress', 'type': 'boolean'}}, 'required': ['id', 'type', 'progress_percentage', 'inverse_progress'], 'title': 'EffectState', 'type': 'object'}, 'ItemState': {'properties': {'id': {'title': 'Id', 'type': 'string'}, 'category': {'anyOf': [{'const': 'Item'}, {'const': 'ItemCookingEquipment'}], 'title': 'Category'}, 'type': {'title': 'Type', 'type': 'string'}, 'progress_percentage': {'anyOf': [{'type': 'number'}, {'type': 'integer'}], 'title': 'Progress Percentage'}, 'inverse_progress': {'title': 'Inverse Progress', 'type': 'boolean'}, 'active_effects': {'items': {'$ref': '#/$defs/EffectState'}, 'title': 'Active Effects', 'type': 'array'}}, 'required': ['id', 'category', 'type', 'progress_percentage', 'inverse_progress', 'active_effects'], 'title': 'ItemState', 'type': 'object'}, 'KitchenInfo': {'description': 'Basic information of the kitchen.', 'properties': {'width': {'title': 'Width', 'type': 'number'}, 'height': {'title': 'Height', 'type': 'number'}}, 'required': ['width', 'height'], 'title': 'KitchenInfo', 'type': 'object'}, 'OrderState': {'properties': {'id': {'title': 'Id', 'type': 'string'}, 'category': {'const': 'Order', 'title': 'Category'}, 'meal': {'title': 'Meal', 'type': 'string'}, 'start_time': {'format': 'date-time', 'title': 'Start Time', 'type': 'string'}, 'max_duration': {'title': 'Max Duration', 'type': 'number'}}, 'required': ['id', 'category', 'meal', 'start_time', 'max_duration'], 'title': 'OrderState', 'type': 'object'}, 'PlayerState': {'properties': {'id': {'title': 'Id', 'type': 'string'}, 'pos': {'items': {'type': 'number'}, 'title': 'Pos', 'type': 'array'}, 'facing_direction': {'items': {'type': 'number'}, 'title': 'Facing Direction', 'type': 'array'}, 'holding': {'anyOf': [{'$ref': '#/$defs/ItemState'}, {'$ref': '#/$defs/CookingEquipmentState'}, {'type': 'null'}], 'title': 'Holding'}, 'current_nearest_counter_pos': {'anyOf': [{'items': {'type': 'number'}, 'type': 'array'}, {'type': 'null'}], 'title': 'Current Nearest Counter Pos'}, 'current_nearest_counter_id': {'anyOf': [{'type': 'string'}, {'type': 'null'}], 'title': 'Current Nearest Counter Id'}}, 'required': ['id', 'pos', 'facing_direction', 'holding', 'current_nearest_counter_pos', 'current_nearest_counter_id'], 'title': 'PlayerState', 'type': 'object'}, 'ViewRestriction': {'properties': {'direction': {'items': {'type': 'number'}, 'title': 'Direction', 'type': 'array'}, 'position': {'items': {'type': 'number'}, 'title': 'Position', 'type': 'array'}, 'angle': {'title': 'Angle', 'type': 'integer'}, 'counter_mask': {'anyOf': [{'items': {'type': 'boolean'}, 'type': 'array'}, {'type': 'null'}], 'title': 'Counter Mask'}, 'range': {'anyOf': [{'type': 'number'}, {'type': 'null'}], 'title': 'Range'}}, 'required': ['direction', 'position', 'angle', 'counter_mask', 'range'], 'title': 'ViewRestriction', 'type': 'object'}}, 'description': 'The format of the returned state representation.', 'properties': {'players': {'items': {'$ref': '#/$defs/PlayerState'}, 'title': 'Players', 'type': 'array'}, 'counters': {'items': {'$ref': '#/$defs/CounterState'}, 'title': 'Counters', 'type': 'array'}, 'kitchen': {'$ref': '#/$defs/KitchenInfo'}, 'score': {'anyOf': [{'type': 'number'}, {'type': 'integer'}], 'title': 'Score'}, 'orders': {'items': {'$ref': '#/$defs/OrderState'}, 'title': 'Orders', 'type': 'array'}, 'all_players_ready': {'title': 'All Players Ready', 'type': 'boolean'}, 'ended': {'title': 'Ended', 'type': 'boolean'}, 'env_time': {'format': 'date-time', 'title': 'Env Time', 'type': 'string'}, 'remaining_time': {'title': 'Remaining Time', 'type': 'number'}, 'view_restrictions': {'anyOf': [{'items': {'$ref': '#/$defs/ViewRestriction'}, 'type': 'array'}, {'type': 'null'}], 'title': 'View Restrictions'}, 'served_meals': {'items': {'maxItems': 2, 'minItems': 2, 'prefixItems': [{'type': 'string'}, {'type': 'string'}], 'type': 'array'}, 'title': 'Served Meals', 'type': 'array'}, 'info_msg': {'items': {'maxItems': 2, 'minItems': 2, 'prefixItems': [{'type': 'string'}, {'type': 'string'}], 'type': 'array'}, 'title': 'Info Msg', 'type': 'array'}}, 'required': ['players', 'counters', 'kitchen', 'score', 'orders', 'all_players_ready', 'ended', 'env_time', 'remaining_time', 'view_restrictions', 'served_meals', 'info_msg'], 'title': 'StateRepresentation', 'type': 'object'}
 ```
 
+
 The BaseModel and TypedDicts can be found in `cooperative_cuisine.state_representation`. The
 `cooperative_cuisine.state_representation.StateRepresentation` represents the json state that the `get_json_state`
 returns.
@@ -261,14 +265,14 @@ For example
 
 ```
 #QU#FO#TNLB#
-#__________M
-#__________K
-W__________I
-#__A_____A_D
+@__________M
+|__________K
+$__________I
+#__A____A__D
 C__________E
-C__________G
-#__________#
-#P#S+#X##S+#
+#__________G
+C__________#
+##PS+#X##S+#
 ```
 
 ## Environment Config
@@ -287,6 +291,7 @@ plates:
 
 game:
   time_limit_seconds: 300
+    undo_dispenser_pickup: true
 
 meals:
   all: true
@@ -304,52 +309,58 @@ layout_chars:
   U: Pot  # with Stove
   T: Tomato
 
-orders:
+orders:  # how to create orders
   ...
 
 player_config:
   radius: 0.4
-  speed_units_per_seconds: 8
+  speed_units_per_seconds: 6
   interaction_range: 1.6
+  restricted_view: False
+  view_angle: 70
+  view_range: 4  # in grid units, can be "null"
+
+effect_manager:  # fire effect
+  ...
+
+extra_setup_functions:  # scores, recording, msgs, etc.
+  ...
 ```
 
 ## PyGame Visualization Config
 
 Here the visualisation for all objects is defined. Reference the images or define a list of base shapes that represent
-the counters, ingredients, meals and players.
+the counters, ingredients, meals and players. Cooperative Cuisine comes with images for the defined meals.
+You can extend it easily. Just have a look at the default [`visualisation.yml`](https://gitlab.ub.uni-bielefeld.de/scs/cocosy/overcooked-simulator/-/blob/main/cooperative_cuisine/pygame_2d_vis/visualization.yaml?ref_type=heads).
+Further, here, you can configure the size of the visualization like screen width, button sizes, fps, colors, etc.
 
 ## Study Config
 
 You can setup a study with a study config.
 It defines which levels the player will play after they connect to the study server.
-Further, you define how many players play together within on environment.
+Further, you define how many players play together within an environment.
 
-An example study config is:
 ```yaml
-# Config paths are relative to configs folder.
-# Layout files are relative to layouts folder.
-
-
 levels:
-  - config_path: study/level1/level1_config.yaml
-    layout_path: overcooked-1/1-1-far-apart.layout
-    item_info_path: study/level1/level1_item_info.yaml
+  - config_path: STUDY_DIR/level1/level1_config.yaml
+    layout_path: LAYOUTS_DIR/overcooked-1/1-1-far-apart.layout
+    item_info_path: STUDY_DIR/level1/level1_item_info.yaml
     name: "Level 1-1: Far Apart"
 
-  - config_path: environment_config.yaml
-    layout_path: basic.layout
-    item_info_path: item_info.yaml
+  - config_path: CONFIGS_DIR/environment_config.yaml
+    layout_path: LAYOUTS_DIR/basic.layout
+    item_info_path: CONFIGS_DIR/item_info.yaml
     name: "Basic"
 
-  - config_path: study/level2/level2_config.yaml
-    layout_path: overcooked-1/1-4-bottleneck.layout
-    item_info_path: study/level2/level2_item_info.yaml
+  - config_path: STUDY_DIR/level2/level2_config.yaml
+    layout_path: LAYOUTS_DIR/overcooked-1/1-4-bottleneck.layout
+    item_info_path: STUDY_DIR/level2/level2_item_info.yaml
     name: "Level 1-4: Bottleneck"
 
-
 num_players: 1
 num_bots: 0
 ```
+`STUDY_DIR`, `LAYOUTS_DIR`, `CONFIG_DIR`, etc. will be replaced accordingly to their names.
 
 # Citation
 
diff --git a/cooperative_cuisine/configs/layouts/basic.layout b/cooperative_cuisine/configs/layouts/basic.layout
index 556080f3de7eccbc827bb77b3e74058b4ef55c64..4e78d2971379c8d37c3e12986baaba68bff09287 100644
--- a/cooperative_cuisine/configs/layouts/basic.layout
+++ b/cooperative_cuisine/configs/layouts/basic.layout
@@ -2,7 +2,7 @@
 @__________M
 |__________K
 $__________I
-#__A_____A_D
+#__A____A__D
 C__________E
 #__________G
 C__________#
diff --git a/cooperative_cuisine/configs/study/level1/level1_config.yaml b/cooperative_cuisine/configs/study/level1/level1_config.yaml
index 5a5e4b8f2183b22685bfab941a93128037b3dda0..788921d229b341f8d6b77d5ad9eacb4daccbf66f 100644
--- a/cooperative_cuisine/configs/study/level1/level1_config.yaml
+++ b/cooperative_cuisine/configs/study/level1/level1_config.yaml
@@ -15,7 +15,8 @@ meals:
   # if all: false -> only orders for these meals are generated
   # TODO: what if this list is empty?
   list:
-    - Burger
+    - TomatoSoup
+    - Salad
 
 layout_chars:
   _: Free
diff --git a/cooperative_cuisine/counter_factory.py b/cooperative_cuisine/counter_factory.py
index 592def76bf602af71e453b3e4e6543858c04642f..02f6d5d73d1ae78c329dd31a0678b1b06b7eb71c 100644
--- a/cooperative_cuisine/counter_factory.py
+++ b/cooperative_cuisine/counter_factory.py
@@ -371,7 +371,6 @@ class CounterFactory:
                     random=self.random,
                     **self.effect_manager_config[effect.manager]["kwargs"],
                 )
-                manager.set_counters(counters)
                 effect_manager[effect.manager] = manager
 
             manager.add_effect(effect)
diff --git a/cooperative_cuisine/effects.py b/cooperative_cuisine/effects.py
index 0e5d3ec63a257022f5edaedb7d9046f6802ac015..fe73ddf40f123030dd9b7c406e2473f3ed77111b 100644
--- a/cooperative_cuisine/effects.py
+++ b/cooperative_cuisine/effects.py
@@ -30,32 +30,87 @@ if TYPE_CHECKING:
 
 
 class EffectManager:
+    """The EffectManager class is responsible for managing effects in an environment.
+
+    It provides methods to add effects, set counters, register new active effects, check if an effect is active,
+    remove active effects, and progress the manager.
+    """
+
     def __init__(self, hook: Hooks, random: Random) -> None:
         self.effects = []
+        """A list of ItemInfo objects representing the effects managed by the manager."""
         self.counters = []
+        """A list of Counter objects representing the counters in the environment."""
         self.hook = hook
+        """An instance of the Hooks class representing the hooks in the environment."""
         self.new_effects: list[Tuple[Effect, Item | Counter]] = []
+        """A list of tuples containing an Effect object and either an Item or Counter object representing the new 
+        active effects."""
         self.random = random
+        """An instance of the Random class representing the random number generator."""
 
     def add_effect(self, effect: ItemInfo):
+        """Add the effect (item) info that the manager handles.
+
+        Args:
+            effect: An object of type ItemInfo representing the effect to be added.
+
+        """
         self.effects.append(effect)
 
     def set_counters(self, counters: list[Counter]):
-        self.counters.extend(counters)
+        """Sets the counters of the environment.
+
+        Args:
+            counters: A list of Counter objects representing the counters.
+        """
+        self.counters = counters.copy()
 
     def register_active_effect(self, effect: Effect, target: Item | Counter):
+        """Register new active effects on a target item or counter.
+
+        Args:
+            effect: An instance of the Effect class representing the active effect to be registered.
+            target: An instance of either the Item or Counter class to which the effect will be applied.
+
+        """
         target.active_effects.append(effect)
         self.new_effects.append((effect, target))
 
     def progress(self, passed_time: timedelta, now: datetime):
+        """Iterative progress call on the manager.
+
+        Similar to the `Counter.progress` method.
+        How often it is called depends on the `env_step_frequency` or how often `step` is called.
+
+        Args:
+            passed_time: The amount of time that has passed since the last call of the method.
+            now: The current env time.
+        """
         ...
 
-    def can_start_effect_transition(
-        self, effect: ItemInfo, target: Item | Counter
-    ) -> bool:
-        return effect.name not in [e.name for e in target.active_effects]
+    @staticmethod
+    def effect_is_active(effect: ItemInfo, target: Item | Counter) -> bool:
+        """Checks if a given effect is active on a specified target.
+
+        Args:
+            effect: An instance of ItemInfo representing the effect to check.
+            target: An instance of Item or Counter representing the target on which the effect is being checked.
+
+        Returns:
+            A boolean value indicating whether the effect is active on the target. True if active, False otherwise.
+
+        """
+        return effect.name in [e.name for e in target.active_effects]
 
     def remove_active_effect(self, effect: Effect, target: Item | Counter):
+        """Removes an active effect from a target item or counter.
+
+        Args:
+            effect (Effect): The effect to be removed.
+            target (Item | Counter): The target item or counter from which the effect will be removed.
+
+        """
         ...
 
 
@@ -89,7 +144,9 @@ class FireEffectManager(EffectManager):
 
         """
         if self.new_effects:
+            # new effects since the last progress call
             for effect, target in self.new_effects:
+                # update next fire spreading
                 self.effect_to_timer[effect.uuid] = now + timedelta(
                     seconds=self.random.uniform(*self.spreading_duration)
                 )
@@ -98,6 +155,7 @@ class FireEffectManager(EffectManager):
                 )
                 self.hook(NEW_FIRE, target=target)
                 self.active_effects.append((effect, target))
+            # reset new effects
             self.new_effects = []
         if self.next_finished_timer < now:
             for effect, target in self.active_effects:
@@ -109,6 +167,7 @@ class FireEffectManager(EffectManager):
                         for counter in touching:
                             if counter.occupied_by:
                                 if isinstance(counter.occupied_by, deque):
+                                    # only the top object on a plate stack is burning
                                     self.apply_effect(effect, counter.occupied_by[-1])
                                 else:
                                     self.apply_effect(effect, counter.occupied_by)
diff --git a/cooperative_cuisine/environment.py b/cooperative_cuisine/environment.py
index 23e02704e685f87ff3f5fd4fd770d2d116e8af52..8f29213a50abf5aaf43ae06b0c7ef5b8c5fa49c3 100644
--- a/cooperative_cuisine/environment.py
+++ b/cooperative_cuisine/environment.py
@@ -1,3 +1,12 @@
+"""
+The _Cooperative Cuisine_ environment. It is configured via three configs:
+- [`environment_config.yml`](https://gitlab.ub.uni-bielefeld.de/scs/cocosy/overcooked-simulator/-/blob/main/cooperative_cuisine/configs/environment_config.yaml?ref_type=heads)
+- [`xyz.layout`](https://gitlab.ub.uni-bielefeld.de/scs/cocosy/overcooked-simulator/-/blob/main/cooperative_cuisine/configs/layouts/basic.layout?ref_type=heads)
+- [`item_info.yml`](https://gitlab.ub.uni-bielefeld.de/scs/cocosy/overcooked-simulator/-/blob/main/cooperative_cuisine/configs/item_info.yaml?ref_type=heads)
+
+You can pass either the file path or the file content (str) to the `Environment`class of the config files. Set the `as_files` parameter accordingly.
+
+"""
 from __future__ import annotations
 
 import inspect
@@ -60,9 +69,7 @@ from cooperative_cuisine.utils import (
 from cooperative_cuisine.validation import Validation
 
 log = logging.getLogger(__name__)
-
-
-PREVENT_SQUEEZING_INTO_OTHER_PLAYERS = True
+"""The logger for this module."""
 
 
 class EnvironmentConfig(TypedDict):
@@ -216,6 +223,11 @@ class Environment:
 
         self.progressing_counters = []
         """Counters that needs to be called in the step function via the `progress` method."""
+
+        self.effect_manager: dict[
+            str, EffectManager
+        ] = self.counter_factory.setup_effect_manger(self.counters)
+
         self.overwrite_counters(self.counters)
 
         do_validation = (
@@ -251,10 +263,6 @@ class Environment:
         """The relative env time when it will stop/end"""
         log.debug(f"End time: {self.env_time_end}")
 
-        self.effect_manager: dict[
-            str, EffectManager
-        ] = self.counter_factory.setup_effect_manger(self.counters)
-
         self.info_msgs_per_player: dict[str, list[InfoMsg]] = defaultdict(list)
 
         self.hook(
@@ -285,6 +293,8 @@ class Environment:
                 self.counters,
             )
         )
+        for manager in self.effect_manager.values():
+            manager.set_counters(counters)
 
     @property
     def game_ended(self) -> bool:
diff --git a/cooperative_cuisine/game_server.py b/cooperative_cuisine/game_server.py
index 53205d1fd284a003086e4905ba0f8a30b999ad45..57bba2b7ca5552bc1993b8e887df84088e27ccfe 100644
--- a/cooperative_cuisine/game_server.py
+++ b/cooperative_cuisine/game_server.py
@@ -43,11 +43,15 @@ from cooperative_cuisine.utils import (
 )
 
 log = logging.getLogger(__name__)
+"""The logger for this module."""
 
 
 app = FastAPI()
+"""The FastAPI app that runs the game server."""
+
 
 TIME_AFTER_STOP_TO_DEL_ENV = 30
+"""Time after stopping an environment how long it takes to delete the env data from the game server. In seconds."""
 
 
 @dataclasses.dataclass
@@ -788,7 +792,7 @@ if __name__ == "__main__":
     disable_websocket_logging_arguments(parser)
     add_list_of_manager_ids_arguments(parser)
     args = parser.parse_args()
-    main(args.url, args.port, args.manager_ids, args.enable_websocket_logging)
+    main(args.game_url, args.game_port, args.manager_ids, args.enable_websocket_logging)
     """
     Or in console: 
     uvicorn cooperative_cuisine.fastapi_game_server:app --reload
diff --git a/cooperative_cuisine/hooks.py b/cooperative_cuisine/hooks.py
index 959103602194ad4ba2b5aa423eb5dc1895f7fb07..9435c432e484dc917bfb2f40201a3ca55df82c19 100644
--- a/cooperative_cuisine/hooks.py
+++ b/cooperative_cuisine/hooks.py
@@ -21,7 +21,6 @@ from typing import Callable, Any, TYPE_CHECKING, Type
 if TYPE_CHECKING:
     from cooperative_cuisine.environment import Environment
 
-# TODO add player_id as kwarg to all hooks -> pass player id to all methods
 
 ITEM_INFO_LOADED = "item_info_load"
 """Called after the item info is loaded and stored in the env attribute `item_info`. The kwargs are the passed config 
@@ -128,6 +127,30 @@ DROP_OFF_ON_COOKING_EQUIPMENT = "drop_off_on_cooking_equipment"
 
 
 class Hooks:
+    """
+    Class Hooks
+
+    Represents a collection of hooks and provides methods to register callbacks for hooks and invoke the callbacks when hooks are triggered.
+
+    Attributes:
+        hooks (defaultdict[list]): A defaultdict containing lists of callbacks for each hook reference.
+        env (any): The environment variable passed to the Hooks instance.
+
+    Methods:
+        __init__(self, env)
+            Initializes a new instance of Hooks.
+
+            Args:
+                env (any): The environment variable to be stored in the env attribute.
+
+        __call__(self, hook_ref, **kwargs)
+            Invokes the callbacks associated with the specified hook reference.
+
+            Args:
+                hook_ref (str): The hook reference to trigger the callbacks for.
+                **kwargs: Additional keyword arguments to be passed to the callbacks.
+    """
+
     def __init__(self, env):
         self.hooks = defaultdict(list)
         self.env = env
@@ -137,6 +160,12 @@ class Hooks:
             callback(hook_ref=hook_ref, env=self.env, **kwargs)
 
     def register_callback(self, hook_ref: str | list[str], callback: Callable):
+        """Register a callback for a hook which is called when the hook is touched during execution.
+
+        Args:
+            hook_ref: A string or a list of strings representing the reference(s) of the hook(s) to register the callback for.
+            callback: A callable object (function or method) to be registered as a callback.
+        """
         if isinstance(hook_ref, (tuple, list, set)):  # TODO check for iterable
             for ref in hook_ref:
                 self.hooks[ref].append(callback)
@@ -149,9 +178,49 @@ def print_hook_callback(text, env, **kwargs):
 
 
 class HookCallbackClass:
+    """
+    Class: HookCallbackClass
+
+    Represents a callback class for hook events.
+
+    Attributes:
+    - name: A string representing the name of the callback.
+    - env: An Environment object representing the environment in which the callback is being executed.
+
+    Methods:
+    - __init__(self, name: str, env: Environment, **kwargs):
+        Initializes a new instance of HookCallbackClass.
+
+    - __call__(self, hook_ref: str, env: Environment, **kwargs):
+        Abstract method that executes the callback logic when called.
+
+    Note:
+    - This class is meant to be subclassed and the __call__ method implemented according to specific needs.
+    - The **kwargs parameter allows for additional arguments to be passed to the callback function.
+
+    Usage Example:
+        ```python
+        # Create an instance of HookCallbackClass
+        callback = HookCallbackClass("my_callback", my_env)
+
+        # Subclass HookCallbackClass and implement the __call__ method
+        class MyCallback(HookCallbackClass):
+            def __call__(self, hook_ref: str, env: Environment, **kwargs):
+                # Add custom callback logic here
+
+        # Create an instance of the subclass
+        my_callback = MyCallback("my_callback", my_env)
+
+        # Call the callback
+        my_callback("hook_reference", my_env)
+        ```
+    """
+
     def __init__(self, name: str, env: Environment, **kwargs):
         self.name = name
+        """The name of the callback."""
         self.env = env
+        """Reference to the environment."""
 
     @abstractmethod
     def __call__(self, hook_ref: str, env: Environment, **kwargs):
@@ -165,12 +234,40 @@ def hooks_via_callback_class(
     callback_class: Type[HookCallbackClass],
     callback_class_kwargs: dict[str, Any],
 ):
+    """Function to reference in the `environment_config.yml` to add functionality via hooks and a configured callback class.
+
+    Args:
+        name: A string representing the name of the callback class instance.
+        env: An instance of the Environment class.
+        hooks: A list of strings representing the hooks for which the callback class instance needs to be registered.
+        callback_class: A type representing the class of the callback instance to be created.
+        callback_class_kwargs: A dictionary containing additional keyword arguments to be passed to the callback class constructor.
+    """
     recorder = callback_class(name=name, env=env, **callback_class_kwargs)
     for hook in hooks:
         env.register_callback_for_hook(hook, recorder)
 
 
 def add_dummy_callbacks(env):
+    """Checking the hooks-callback functionality.
+
+    Args:
+        env: The environment object that represents the system environment.
+
+    This method adds dummy callbacks to the given environment object. Each callback is registered for a specific hook using the `register_callback_for_hook` method of the environment.
+
+    The callbacks are defined using the `partial` function from the `functools` module. This allows us to pass additional arguments to the callback while registering it. The `print_hook
+    *_callback` function is used as the callback function, and it prints a message to the console.
+
+    Here are the hooks and corresponding messages that are registered:
+
+    1. SERVE_NOT_ORDERED_MEAL: Prints the message "You tried to serve a meal that was not ordered!"
+    2. SINK_START_INTERACT: Prints the message "You started to use the Sink!"
+    3. COMPLETED_ORDER: Prints the message "You completed an order!"
+    4. TRASHCAN_USAGE: Prints the message "You used the trashcan!"
+
+    These dummy callbacks can be used for testing or demonstration purposes.
+    """
     env.register_callback_for_hook(
         SERVE_NOT_ORDERED_MEAL,
         partial(
diff --git a/cooperative_cuisine/info_msg.py b/cooperative_cuisine/info_msg.py
index d28ebfb5a3170ce873c00600a6ae258ad89418f2..62b98a84a78902e9a10acc0f728aa76403ae57a3 100644
--- a/cooperative_cuisine/info_msg.py
+++ b/cooperative_cuisine/info_msg.py
@@ -28,6 +28,23 @@ from cooperative_cuisine.hooks import HookCallbackClass
 
 
 class InfoMsgManager(HookCallbackClass):
+    """
+    Class for managing info messages in an environment.
+
+    This class inherits from the `HookCallbackClass` class.
+
+    Attributes:
+        msg (str): The message to be displayed.
+        duration (datetime.timedelta): The duration for which the message should be displayed.
+        level (str): The level of the message.
+
+
+    Methods:
+        __init__(name, env, msg, duration, level, **kwargs): Initializes an instance of InfoMsgManager.
+        __call__(hook_ref, env, **kwargs): Adds the message to the info messages list for each player in the environment.
+        remove_old_msgs(env): Removes old messages from the environment.
+    """
+
     def __init__(
         self,
         name: str,
@@ -56,6 +73,12 @@ class InfoMsgManager(HookCallbackClass):
 
     @staticmethod
     def remove_old_msgs(env: Environment):
+        """
+        Removes old messages from the environment.
+
+        Args:
+            env (Environment): The environment object containing the messages.
+        """
         for player_id, msgs in env.info_msgs_per_player.items():
             delete_msgs = []
             for idx, msg in enumerate(msgs):
diff --git a/cooperative_cuisine/items.py b/cooperative_cuisine/items.py
index 3c6bd7e8c32d96ae6966414ef0c95f683608547c..1de65506e50816d7d6ef17369a1c6e0ced65c1f3 100644
--- a/cooperative_cuisine/items.py
+++ b/cooperative_cuisine/items.py
@@ -116,7 +116,9 @@ class ItemInfo:
 
     def __post_init__(self):
         if self.seconds < 0.0:
-            raise ValueError(f"Expected seconds >= 0 for item '{self.name}', but got {self.seconds} in item info")
+            raise ValueError(
+                f"Expected seconds >= 0 for item '{self.name}', but got {self.seconds} in item info"
+            )
         self.type = ItemType(self.type)
         if self.effect_type:
             self.effect_type = EffectType(self.effect_type)
@@ -302,7 +304,7 @@ class CookingEquipment(Item):
             if transition.type == ItemType.Effect:
                 if set(ingredients.keys()).issubset(
                     transition.needs
-                ) and transition.manager.can_start_effect_transition(transition, self):
+                ) and not transition.manager.effect_is_active(transition, self):
                     if transition.seconds == 0:
                         transition.manager.register_active_effect(
                             Effect(name=transition.name, item_info=transition), self
diff --git a/cooperative_cuisine/movement.py b/cooperative_cuisine/movement.py
index 3a082ed5509694eff0ba2cd9512fcdc526455f5c..fa554ad52fab568cf6f741878fb01128caae4975 100644
--- a/cooperative_cuisine/movement.py
+++ b/cooperative_cuisine/movement.py
@@ -1,6 +1,13 @@
+"""
+Implements the moving of the players. Checks collisions and pushing other around.
+For efficiency, we tried to do everything with numpy arrays and functions. 
+"""
+
 from datetime import timedelta, datetime
+from typing import Tuple
 
 import numpy as np
+import numpy.typing as npt
 from scipy.spatial import distance_matrix
 
 from cooperative_cuisine.counters import Counter
@@ -8,18 +15,33 @@ from cooperative_cuisine.player import Player
 
 
 class Movement:
+    """Does the movement of the players."""
+
     world_borders_lower = None
+    """World borders lower bounds."""
     world_borders_upper = None
+    """World borders upper bounds."""
 
     def __init__(self, counter_positions, player_config, world_borders):
         self.counter_positions = counter_positions
+        """Positions of all counters in an environment. Needs to be updated if the counters position changes."""
         self.player_radius = player_config["radius"]
+        """The radius of a player (indicating its size and collision sphere). Relative to one grid cell, e.g., `0.4`."""
         self.player_interaction_range = player_config["interaction_range"]
+        """The range of how far a player can interact with the closest counter."""
         self.player_movement_speed = player_config["speed_units_per_seconds"]
+        """How many grid cells a player can move in a second."""
         self.world_borders = world_borders
+        """The world border arrays. For easier numpy comparison with player position. The outer dimension needs to be 
+        equal to the number of player."""
         self.set_collision_arrays(1)
 
-    def set_collision_arrays(self, number_players):
+    def set_collision_arrays(self, number_players: int):
+        """Sets collision arrays for the given number of players.
+
+        Args:
+            number_players (int): The number of players.
+        """
         self.world_borders_lower = self.world_borders[np.newaxis, :, 0].repeat(
             number_players, axis=0
         )
@@ -27,7 +49,18 @@ class Movement:
             number_players, axis=0
         )
 
-    def get_counter_collisions(self, player_positions):
+    def get_counter_collisions(
+        self, player_positions: npt.NDArray[float]
+    ) -> Tuple[npt.NDArray[bool], npt.NDArray[int], npt.NDArray[float]]:
+        """
+        Args:
+            player_positions: 2D numpy array containing the positions of the players.
+
+        Returns:
+            collided: 1D numpy array indicating whether each player has collided with a counter.
+            relevant_axes: 1D numpy array indicating the relevant axis for each player's collision.
+            nearest_counter_to_player: 2D numpy array indicating the vector from each player to the nearest counter.
+        """
         counter_diff_vecs = (
             player_positions[:, np.newaxis, :]
             - self.counter_positions[np.newaxis, :, :]
@@ -54,7 +87,19 @@ class Movement:
 
         return collided, relevant_axes, nearest_counter_to_player
 
-    def get_player_push(self, player_positions):
+    def get_player_push(
+        self, player_positions: npt.NDArray[float]
+    ) -> Tuple[npt.NDArray[bool], npt.NDArray[float]]:
+        """Calculates the collision and push vectors for each player.
+
+        Args:
+            player_positions (numpy.ndarray): An array of shape (n, 2) representing the positions of the players.
+
+        Returns:
+            tuple: A tuple containing two numpy arrays. The first array (collisions) is a boolean array of shape (n,) indicating
+            whether each player has collided with another player. The second array (push_vectors) is a numpy array of shape (2,)
+            representing the total push vector for each player.
+        """
         distances_players_after_scipy = distance_matrix(
             player_positions, player_positions
         )
@@ -77,8 +122,9 @@ class Movement:
         players: dict[str, Player],
         counters: list[Counter],
     ):
-        """Moves a player in the direction specified in the action.action. If the player collides with a
-        counter or other player through this movement, then they are not moved.
+        """Moves a player in the direction specified in the action.action.
+
+        If the player collides with a counter or other player through this movement, then they are not moved.
         (The extended code with the two ifs is for sliding movement at the counters, which feels a bit smoother.
         This happens, when the player moves diagonally against the counters or world boundary.
         This just checks if the single axis party of the movement could move the player and does so at a lower rate.)
diff --git a/cooperative_cuisine/orders.py b/cooperative_cuisine/orders.py
index 71c3d0fee28c966e1e799b165b356e43c5ea47e7..249d12bade770efa478fa6267054a9c5f87419f0 100644
--- a/cooperative_cuisine/orders.py
+++ b/cooperative_cuisine/orders.py
@@ -174,6 +174,11 @@ class OrderManager:
         """Reference to the hook manager."""
 
     def set_available_meals(self, available_meals):
+        """Set the available meals from which orders can be generated.
+
+        Args:
+            available_meals (dict): A dictionary containing the available meals and their quantities.
+        """
         self.available_meals = available_meals
         self.order_gen.available_meals = list(available_meals.values())
 
@@ -370,8 +375,11 @@ class RandomOrderGeneration(OrderGeneration):
     ):
         super().__init__(hook, random, **kwargs)
         self.kwargs: RandomOrderKwarg = RandomOrderKwarg(**kwargs["kwargs"])
+        """Configuration og the RandomOrder genration. See `RandomOrderKwarg`"""
         self.next_order_time: datetime | None = datetime.max
+        """For efficient checking to update order removable."""
         self.number_cur_orders: int = 0
+        """How many orders are currently open."""
         self.needed_orders: int = 0
         """For the sample on dur but when it was restricted due to max order number."""
 
@@ -387,6 +395,7 @@ class RandomOrderGeneration(OrderGeneration):
                 now,
                 self.kwargs.sample_on_serving,
             )
+        self.number_cur_orders = 0
         return []
 
     def get_orders(
diff --git a/cooperative_cuisine/player.py b/cooperative_cuisine/player.py
index f4e69c3aa66310f893b854944566a9826bf070f0..a92f12f38886cafac974aa796aff167bc454fc74 100644
--- a/cooperative_cuisine/player.py
+++ b/cooperative_cuisine/player.py
@@ -85,6 +85,7 @@ class Player:
         """The env time until the player wants to move."""
 
         self.interacting: bool = False
+        """Is the player currently interacting with a counter."""
 
     def set_movement(self, move_vector, move_until):
         """Called by the `perform_action` method. Movements will be performed (pos will be updated) in the `step`
@@ -182,6 +183,15 @@ class Player:
         self.last_interacted_counter = None
 
     def progress(self, passed_time: timedelta, now: datetime):
+        """Iterative progress call on the player.
+
+        Similar to the `Counter.progress` method.
+        How often it is called depends on the `env_step_frequency` or how often `step` is called.
+
+        Args:
+            passed_time: The amount of time that has passed since the last call of the method.
+            now: The current env time.
+        """
         if self.interacting and self.last_interacted_counter:
             # TODO only interact on counter (Sink/CuttingBoard) if hands are free configure in config?
             if self.holding:
diff --git a/cooperative_cuisine/pygame_2d_vis/__init__.py b/cooperative_cuisine/pygame_2d_vis/__init__.py
index f76fc15e4010460e9cb062aadf330b36249c7935..c5a1185e214dc7d99eb02ebc704666bfbfa44041 100644
--- a/cooperative_cuisine/pygame_2d_vis/__init__.py
+++ b/cooperative_cuisine/pygame_2d_vis/__init__.py
@@ -2,9 +2,11 @@
 2D visualization of the CooperativeCuisine.
 
 You can select the layout and start an environment:
-- You can play the CooperativeCuisine. You can quit the application in the top right or end the level in the bottom right: [Screenshot](https://gitlab.ub.uni-bielefeld.de/scs/cocosy/overcooked-simulator/-/raw/main/overcooked_simulator/pygame_2d_vis/images/overcooked-start-screen.png?ref_type=heads)
-- The orders are pictured in the top, the current score in the bottom left and the remaining time in the bottom: [Screenshot](https://gitlab.ub.uni-bielefeld.de/scs/cocosy/overcooked-simulator/-/raw/main/overcooked_simulator/pygame_2d_vis/images/overcooked-level-screen.png?ref_type=heads)
-- The final screen after ending a level shows the score: [Screenshot](https://gitlab.ub.uni-bielefeld.de/scs/cocosy/overcooked-simulator/-/raw/main/overcooked_simulator/pygame_2d_vis/images/overcooked-end-screen.png?ref_type=heads)
+- You can play the CooperativeCuisine. You can quit the application in the top right or end the level in the bottom right
+- The orders are pictured in the top, the current score in the bottom left and the remaining time in the bottom
+- The final screen after ending a level shows the score
+
+.. include:: images/images_md_for_docs.md
 
 The keys for the control of the players are:
 
@@ -12,9 +14,12 @@ The keys for the control of the players are:
 - Movement: `W`, `A`, `S`, `D`,
 - Pickup: `E`
 - Interact: `F`
+- Swap Players (if configured): `SPACE`
 
 ### Player 2:
 - Movement: `⬆`, `⬅`, `⬇`, `➡` (arrow keys)
 - Pickup: `I`
-- Interact: `SPACE`
+- Interact: `O`
+- Swap Players (if configured): `P`
+
 """
diff --git a/cooperative_cuisine/pygame_2d_vis/gui.py b/cooperative_cuisine/pygame_2d_vis/gui.py
index e3819454cd133759191ccc447098227f40d9f932..15856bb9b153f9d5f852e34e2a98f214bbad8703 100644
--- a/cooperative_cuisine/pygame_2d_vis/gui.py
+++ b/cooperative_cuisine/pygame_2d_vis/gui.py
@@ -45,6 +45,7 @@ class MenuStates(Enum):
 
 
 log = logging.getLogger(__name__)
+"""The logger for this module."""
 
 
 class PlayerKeySet:
diff --git a/cooperative_cuisine/pygame_2d_vis/images/favicon.ico b/cooperative_cuisine/pygame_2d_vis/images/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..b92dedae6667f610d9239da0fb99c51487520b6e
Binary files /dev/null and b/cooperative_cuisine/pygame_2d_vis/images/favicon.ico differ
diff --git a/cooperative_cuisine/pygame_2d_vis/images/images_md_for_docs.md b/cooperative_cuisine/pygame_2d_vis/images/images_md_for_docs.md
new file mode 100644
index 0000000000000000000000000000000000000000..2870f1a15541f0eeb0298731962361f9daf9201a
--- /dev/null
+++ b/cooperative_cuisine/pygame_2d_vis/images/images_md_for_docs.md
@@ -0,0 +1 @@
+![image](cooperative_cuisine.png)
\ No newline at end of file
diff --git a/cooperative_cuisine/pygame_2d_vis/images/overcooked-end-screen.png b/cooperative_cuisine/pygame_2d_vis/images/overcooked-end-screen.png
deleted file mode 100644
index d678687d61277930d839882aa5f6956caeb5e9a6..0000000000000000000000000000000000000000
Binary files a/cooperative_cuisine/pygame_2d_vis/images/overcooked-end-screen.png and /dev/null differ
diff --git a/cooperative_cuisine/pygame_2d_vis/images/overcooked-level-screen.png b/cooperative_cuisine/pygame_2d_vis/images/overcooked-level-screen.png
deleted file mode 100644
index 0f2cc384aacabcd80d3b88542fd9a3345506b35d..0000000000000000000000000000000000000000
Binary files a/cooperative_cuisine/pygame_2d_vis/images/overcooked-level-screen.png and /dev/null differ
diff --git a/cooperative_cuisine/pygame_2d_vis/images/overcooked-start-screen.png b/cooperative_cuisine/pygame_2d_vis/images/overcooked-start-screen.png
deleted file mode 100644
index 420d1eedb6cf57a493aba7dbabe7e3ba80ecb1b4..0000000000000000000000000000000000000000
Binary files a/cooperative_cuisine/pygame_2d_vis/images/overcooked-start-screen.png and /dev/null differ
diff --git a/cooperative_cuisine/recording.py b/cooperative_cuisine/recording.py
index 01f0de86833e7f81290fb70438e3c98ec36f9775..7f540b055f933a5b6410afc12ec785a337b00d4f 100644
--- a/cooperative_cuisine/recording.py
+++ b/cooperative_cuisine/recording.py
@@ -51,21 +51,11 @@ from cooperative_cuisine.hooks import HookCallbackClass
 from cooperative_cuisine.utils import NumpyAndDataclassEncoder, expand_path
 
 log = logging.getLogger(__name__)
+"""The logger for this module."""
 
 
 class FileRecorder(HookCallbackClass):
-    """
-    Class: FileRecorder
-
-    This class is responsible for recording data to a file.
-
-    Attributes:
-        name (str): The name of the recorder.
-        env (Environment): The environment instance.
-        log_path (str): The path to the log file. Default value is "USER_LOG_DIR/ENV_NAME/LOG_RECORD_NAME.jsonl".
-        add_hook_ref (bool): Indicates whether to add a hook reference to the recorded data. Default value is False.
-
-    """
+    """This class is responsible for recording data to a file."""
 
     def __init__(
         self,
@@ -77,9 +67,11 @@ class FileRecorder(HookCallbackClass):
     ):
         super().__init__(name, env, **kwargs)
         self.add_hook_ref = add_hook_ref
+        """Indicates whether to add a hook reference to the recorded data. Default value is False."""
         log_path = log_path.replace("LOG_RECORD_NAME", name)
         log_path = Path(expand_path(log_path, env_name=env.env_name))
         self.log_path = log_path
+        """The path to the log file. Default value is "USER_LOG_DIR/ENV_NAME/LOG_RECORD_NAME.jsonl"."""
         log.info(f"Recorder record for {name} in file://{log_path}")
         os.makedirs(log_path.parent, exist_ok=True)
 
diff --git a/cooperative_cuisine/scores.py b/cooperative_cuisine/scores.py
index b0f968bd7cfc3d2e44bafd91827b7d4ba3e7ccab..b8cd11b739d66c2b59b37a15b49ed02e198dd379 100644
--- a/cooperative_cuisine/scores.py
+++ b/cooperative_cuisine/scores.py
@@ -84,9 +84,13 @@ class ScoreViaHooks(HookCallbackClass):
     ):
         super().__init__(name, env, **kwargs)
         self.score_map = score_map
+        """Mapping of hook references to scores."""
         self.static_score = static_score
+        """The static score to be added if no other conditions are met."""
         self.kwarg_filter = kwarg_filter
+        """Filtering condition for keyword arguments."""
         self.score_on_specific_kwarg = score_on_specific_kwarg
+        """The specific keyword argument to score on."""
 
     def __call__(self, hook_ref: str, env: Environment, **kwargs):
         if self.score_on_specific_kwarg:
diff --git a/cooperative_cuisine/state_representation.py b/cooperative_cuisine/state_representation.py
index cfa023f82f88bc153c90ef44dec20374e61a6dcb..a8377e4562356859dfead8f1bca151c9ee2afb49 100644
--- a/cooperative_cuisine/state_representation.py
+++ b/cooperative_cuisine/state_representation.py
@@ -1,6 +1,7 @@
 """
 Type hint classes for the representation of the json state.
 """
+import json
 from datetime import datetime
 from enum import Enum
 
@@ -111,4 +112,4 @@ def create_json_schema():
 
 
 if __name__ == "__main__":
-    print(create_json_schema())
+    print(json.dumps(create_json_schema()))
diff --git a/cooperative_cuisine/study_server.py b/cooperative_cuisine/study_server.py
index b11fb5c891b8adc3f127d420ad11cc94687ed142..887c686c22e9282163748b4f03ee27fdfe503ec0 100644
--- a/cooperative_cuisine/study_server.py
+++ b/cooperative_cuisine/study_server.py
@@ -43,13 +43,14 @@ from cooperative_cuisine.utils import (
 NUMBER_PLAYER_PER_ENV = 2
 
 log = logging.getLogger(__name__)
-
-app = FastAPI()
+"""The logger for this module."""
 
 
-# HARDCODED_MANAGER_ID = "1234"
+app = FastAPI()
+"""The FastAPI app that runs the study server."""
 
 USE_AAAMBOS_AGENT = False
+"""Use the aaambos random agents instead of the simpler python script agents."""
 
 
 class LevelConfig(BaseModel):
@@ -96,7 +97,9 @@ class Study:
         self.current_config: dict | None = None
         """Save current environment config"""
 
-        self.use_aaambos_agent: bool = False
+        self.use_aaambos_agent: bool = USE_AAAMBOS_AGENT
+        """Use aaambos-agents or simple python scripts."""
+
         """Use aaambos-agents or simple python scripts."""
         self.bot_websocket_url: str = f"ws://{game_url}:{game_port}/ws/player/"
         """The websocket url for the bots to use."""
@@ -604,8 +607,6 @@ if __name__ == "__main__":
     url_and_port_arguments(
         parser=parser,
         server_name="Study Server",
-        default_study_port=8080,
-        default_game_port=8000,
     )
     add_list_of_manager_ids_arguments(parser=parser)
     add_study_arguments(parser=parser)
@@ -614,7 +615,7 @@ if __name__ == "__main__":
     game_server_url = f"https://{args.game_url}:{args.game_port}"
     main(
         args.study_url,
-        args.port,
+        args.study_port,
         game_host=args.game_url,
         game_port=args.game_port,
         manager_ids=args.manager_ids,
diff --git a/cooperative_cuisine/utils.py b/cooperative_cuisine/utils.py
index d6e0bfdb341d1686cc99a2fb94d8b04e6952745a..1b28523bbc3a14f059ffcd15fa1dc3a0bce4269e 100644
--- a/cooperative_cuisine/utils.py
+++ b/cooperative_cuisine/utils.py
@@ -26,9 +26,35 @@ if TYPE_CHECKING:
 from cooperative_cuisine.player import Player
 
 DEFAULT_SERVER_URL = "localhost"
+"""Default server URL of game and server study."""
+
+DEFAULT_SERVER_PORT = 8080
+"""Default study server port."""
+
+DEFAULT_GAME_PORT = 8000
+"""Default game server port."""
 
 
 def expand_path(path: str, env_name: str = "") -> str:
+    """Expand a path with VARIABLES to the path variables based on the user's OS or installation location of the Cooperative Cuisine.
+    Args:
+        path: A string representing the path to be expanded. This can contain placeholders like "ROOT_DIR", "ENV_NAME", "USER_LOG_DIR", "LAYOUTS_DIR", "STUDY_DIR", and "CONFIGS_DIR" which will be replaced with their corresponding values.
+        env_name (optional): A string representing the environment name to be used for expanding the path. This will be used to replace the "ENV_NAME" placeholder.
+
+    Returns:
+        A string representing the expanded path, where all placeholders have been replaced with their corresponding values.
+
+    Example:
+        expand_path("~/ROOT_DIR/ENV_NAME", "development")
+        -> "/home/user/path/to/ROOT_DIR/development"
+
+    Note:
+        - The "ROOT_DIR" placeholder will be replaced with the value of the `ROOT_DIR` constant.
+        - The "USER_LOG_DIR" placeholder will be replaced with the user-specific directory for log files.
+        - The "LAYOUTS_DIR" placeholder will be replaced with the directory path to layouts config files.
+        - The "STUDY_DIR" placeholder will be replaced with the directory path to study config files.
+        - The "CONFIGS_DIR" placeholder will be replaced with the directory path to general config files.
+    """
     return os.path.expanduser(
         path.replace("ROOT_DIR", str(ROOT_DIR))
         .replace("ENV_NAME", env_name)
@@ -41,6 +67,18 @@ def expand_path(path: str, env_name: str = "") -> str:
 
 @dataclasses.dataclass
 class VectorStateGenerationData:
+    """
+    A class representing data used for vector state generation.
+
+    Attributes:
+        grid_base_array (numpy.ndarray): A 2D array representing the state grid.
+        oh_len (int): The length of the one-hot encoding vector.
+        number_normal_ingredients (int): The number of normal ingredients.
+        meals (List[str]): A list of meal names.
+        equipments (List[str]): A list of equipment names.
+        ingredients (List[str]): A list of ingredient names.
+    """
+
     grid_base_array: npt.NDArray[npt.NDArray[float]]
     oh_len: int
 
@@ -81,6 +119,24 @@ class VectorStateGenerationData:
 
 @dataclasses.dataclass
 class VectorStateGenerationDataSimple:
+    """Relevant for reinforcment learning.
+
+    VectorStateGenerationDataSimple class represents the data required for generating vector states. It includes the
+    grid base array, the length of the one-hot encoded representations, and * other information related to meals,
+    equipments, and ingredients.
+
+    Attributes:
+    - grid_base_array (numpy.ndarray): A 2D NumPy array representing the grid base.
+    - oh_len (int): The length of the one-hot encoded representations.
+
+    Constants:
+    - number_normal_ingredients (int): The number of normal ingredients.
+    - meals (list): A list of meal names.
+    - equipments (list): A list of equipment names.
+    - ingredients (list): A list of ingredient names.
+
+    """
+
     grid_base_array: npt.NDArray[npt.NDArray[float]]
     oh_len: int
 
@@ -125,6 +181,16 @@ def get_closest(point: npt.NDArray[float], counters: list[Counter]):
 def get_collided_players(
     player_idx, players: list[Player], player_radius: float
 ) -> list[Player]:
+    """Filter players if they collide.
+
+    Args:
+        player_idx: The index of the player for which to find collided players.
+        players: A list of Player objects representing all the players.
+        player_radius: The radius of the player.
+
+    Returns:
+        A list of Player objects representing the players that have collided with the player at the given index.
+    """
     player_positions = np.array([p.pos for p in players], dtype=float)
     distances = distance_matrix(player_positions, player_positions)[player_idx]
     player_radiuses = np.array([player_radius for p in players], dtype=float)
@@ -135,6 +201,16 @@ def get_collided_players(
 
 
 def get_touching_counters(target: Counter, counters: list[Counter]) -> list[Counter]:
+    """Filter the list of counters if they touch the target counter.
+
+    Args:
+        target: A Counter object representing the target counter.
+        counters: A list of Counter objects representing the counters to be checked.
+
+    Returns:
+        A list of Counter objects that are touching the target counter.
+
+    """
     return list(
         filter(
             lambda counter: np.linalg.norm(counter.pos - target.pos) == 1.0, counters
@@ -143,6 +219,21 @@ def get_touching_counters(target: Counter, counters: list[Counter]) -> list[Coun
 
 
 def find_item_on_counters(item_uuid: str, counters: list[Counter]) -> Counter | None:
+    """This method searches for a specific item with the given UUID on a list of counters.
+
+    It iterates through each counter and checks if it is occupied. If the counter is occupied by a deque, it further
+    iterates through each item in the deque to find a match with the given UUID. If a match is found, the respective
+    counter is returned. If the counter is occupied by a single, item (not a deque), it directly compares the UUID of
+    the occupied item with the given UUID. If they match, the respective counter is returned. If no match is found
+    for the given UUID on any counter, None is returned.
+
+    Args:
+        item_uuid (str): The UUID of the item to be searched for on counters.
+        counters (list[Counter]): The list of counters to search for the item.
+
+    Returns:
+        Counter | None: The counter where the item was found, or None if the item was not found.
+    """
     for counter in counters:
         if counter.occupied_by:
             if isinstance(counter.occupied_by, deque):
@@ -155,7 +246,15 @@ def find_item_on_counters(item_uuid: str, counters: list[Counter]) -> Counter |
 
 
 def custom_asdict_factory(data):
-    """Convert enums to their value."""
+    """Converts enums to their value.
+
+    Args:
+        data: The data to be converted to a dictionary.
+
+    Returns:
+        dict: A dictionary where the values in the data are converted based on the `convert_value` function.
+
+    """
 
     def convert_value(obj):
         if isinstance(obj, Enum):
@@ -166,6 +265,11 @@ def custom_asdict_factory(data):
 
 
 def setup_logging(enable_websocket_logging=False):
+    """Setup logging configuration.
+
+    Args:
+        enable_websocket_logging (bool, optional): Flag to enable websocket logging. Default is False.
+    """
     path_logs = ROOT_DIR.parent / "logs"
     os.makedirs(path_logs, exist_ok=True)
     logging.basicConfig(
@@ -189,14 +293,27 @@ def setup_logging(enable_websocket_logging=False):
 
 
 def url_and_port_arguments(
-    parser, server_name="game server", default_study_port=8080, default_game_port=8000
+    parser,
+    server_name="game server",
+    default_study_port=DEFAULT_SERVER_PORT,
+    default_game_port=DEFAULT_GAME_PORT,
+    default_server_url=DEFAULT_SERVER_URL,
 ):
+    """Adds arguments to the given parser for the URL and port configuration of a server.
+
+    Args:
+        parser: The argument parser to add arguments to.
+        server_name: (Optional) The name of the server. Defaults to "game server".
+        default_study_port: (Optional) The default port number for the study URL. Defaults to 8080.
+        default_game_port: (Optional) The default port number for the game URL. Defaults to 8000.
+        default_server_url: (Optional) The default url for the server. Defaults to "localhost".
+    """
     parser.add_argument(
         "-s",
         "--study-url",
         "--study-host",
         type=str,
-        default=DEFAULT_SERVER_URL,
+        default=default_server_url,
         help=f"Overcooked {server_name} study host url.",
     )
     parser.add_argument(
@@ -224,12 +341,27 @@ def url_and_port_arguments(
 
 
 def disable_websocket_logging_arguments(parser):
+    """Disables the logging of WebSocket arguments in the provided parser.
+
+    Args:
+        parser: The argument parser object (argparse.ArgumentParser) to which the
+            "--enable-websocket-logging" argument will be added.
+
+    """
     parser.add_argument(
         "--enable-websocket-logging" "", action="store_true", default=True
     )
 
 
 def add_list_of_manager_ids_arguments(parser):
+    """This function adds the manager ids argument to the given argument parser.
+
+    Args:
+        parser: An ArgumentParser object used to parse command line arguments.
+
+    Returns:
+        None
+    """
     parser.add_argument(
         "-m",
         "--manager_ids",
@@ -241,6 +373,19 @@ def add_list_of_manager_ids_arguments(parser):
 
 
 def add_study_arguments(parser):
+    """This function adds the study configuration argument to the given argument parser.
+
+    Args:
+        parser (argparse.ArgumentParser): The argument parser object.
+
+
+    Example:
+        ```python
+        import argparse
+        parser = argparse.ArgumentParser()
+        add_study_arguments(parser)
+        ```
+    """
     parser.add_argument(
         "--study-config",
         type=str,
@@ -271,7 +416,13 @@ class NumpyAndDataclassEncoder(json.JSONEncoder):
         return json.JSONEncoder.default(self, obj)
 
 
-def create_layout(w, h):
+def create_layout_with_counters(w, h):
+    """Print a layout string that has counters at the world borders.
+
+    Args:
+        w: The width of the layout.
+        h: The height of the layout.
+    """
     for y in range(h):
         for x in range(w):
             if x == 0 or y == 0 or x == w - 1 or y == h - 1: