diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5dcc53b5bb0c8353f23735959f731f583c7002a4..be5fec5110d6163960ab3084db4c75139aea53bf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -23,9 +23,16 @@
 - Level layouts from 2d-grid-overcooked-literature
 - Caching of graph recipe layouts
 - Score label changes color when score changes
+- Control screenshot, replay, single game/study server, gui via cli (sub commands)
 
 ### Changed
 
+- cli control changed `cooperative_cuisine` is now `cooperative-cuisine` (`-` instead of `_`)
+- cli now uses commands. Use `cooperative-cuisine start` now for the same behaviour as before (add arguments).
+- `cooperative-cuisine` with arguments does not work anymore. The "no arguments" call results in running with defaults.
+  If you want to add arguments use the `start` subcommand
+- `cooperative-cuisine -h` provides an overview of all sub commands. For individual help for each coomand,
+  run `cooperative-cuisine COMMAND -h`.
 - `extra_setup_functions` now only contain hook callback classes (`hook_callbacks`). Therefore, the `func` and `kwargs`
   fields were
   removed and the kwargs are now the standard values for defined hooks. This reduced the complexity of the config.
diff --git a/README.md b/README.md
index a4d18ba3c632c9023e719086b710e7636be44ee3..209683444740c4abdef7d1c8551fc1351e1609ca 100644
--- a/README.md
+++ b/README.md
@@ -38,7 +38,7 @@ pip install -e .
 Run it via the command line (in your pyenv/conda environment):
 
 ```bash
-cooperative_cuisine  -s localhost -sp 8080 -g localhost -gp 8000
+cooperative-cuisine start -s localhost -sp 8080 -g localhost -gp 8000
 ```
 
 *The arguments shown are the defaults.*
@@ -47,11 +47,11 @@ You can also start the **Game Server**m **Study Server** (Matchmaking),and the *
 terminals.
 
 ```bash
-python3 cooperative_cuisine/game_server.py -g localhost -gp 8000 --manager-ids SECRETKEY1 SECRETKEY2
+cooperative-cuisine game-server -g localhost -gp 8000 --manager-ids SECRETKEY1 SECRETKEY2
 
-python3 cooperative_cuisine/study_server.py -s localhost -sp 8080 --manager-ids SECRETKEY1
+cooperative-cuisine study-server -s localhost -sp 8080 -g localhost -gp 8000 --manager-ids SECRETKEY1
 
-python3 cooperative_cuisine/pygame_2d_vis/gui.py -s localhost -sp 8080 -g localhost -gp 8000
+cooperative-cuisine gui -s localhost -sp 8080 -g localhost -gp 8000
 ```
 
 You can start also several GUIs. The study server does the matchmaking.
diff --git a/cooperative_cuisine/__init__.py b/cooperative_cuisine/__init__.py
index 17dfc078daff4bf21f66270c4c72fa6d2c460cbf..e30632759d68efe1389179f31f912fecd9ac26f7 100644
--- a/cooperative_cuisine/__init__.py
+++ b/cooperative_cuisine/__init__.py
@@ -21,7 +21,7 @@ like a "real", cooperative, human partner.
 
 # Installation
 
-You need a Python **3.10** or newer codna environment.
+You need a Python **3.10** or newer conda environment.
 ```bash
 conda install -c conda-forge pygraphviz
 pip install cooperative_cuisine@git+https://gitlab.ub.uni-bielefeld.de/scs/cocosy/overcooked-simulator@main
@@ -43,7 +43,7 @@ options.
 Run it via the command line (in your pyenv/conda environment):
 
 ```bash
-cooperative_cuisine  -s localhost -sp 8080 -g localhost -gp 8000
+cooperative-cuisine start  -s localhost -sp 8080 -g localhost -gp 8000
 ```
 
 *The arguments shown are the defaults.*
@@ -51,13 +51,15 @@ cooperative_cuisine  -s localhost -sp 8080 -g localhost -gp 8000
 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
+cooperative-cuisine game-server -g localhost -gp 8000 --manager-ids SECRETKEY1 SECRETKEY2
 
-python3 cooperative_cuisine/study_server.py -s localhost -sp 8080 --manager-ids SECRETKEY1
+cooperative-cuisine study-server -s localhost -sp 8080 -g localhost -gp 8000 --manager-ids SECRETKEY1
 
-python3 cooperative_cuisine/pygame_2d_vis/gui.py -s localhost -sp 8080 -g localhost -gp 8000
+cooperative-cuisine gui -s localhost -sp 8080
 ```
 
+For more CLI arguments and a description of possible arguments, run `cooperative-cuisine -h`
+
 ## Connect with agent and receive game state
 Or you start a game server, create an environment and connect each player/agent via a websocket connection.
 
@@ -210,7 +212,7 @@ returns.
 You might have stored some json states and now you want to visualize them via the
 pygame-2d visualization. You can do that by running the `drawing.py` script and referencing a json file.
 ```bash
-python3 cooperative_cuisine/pygame_2d_vis/drawing.py --state my_state.json
+cooperative-cuisine screenshot --state my_state.json
 ```
 - You can specify a different visualization config with `-v` or `--visualization_config`.
 - You can specify the name of the output file with `-o` or `--output_file`. The default is `screenshot.jpg`.
@@ -370,6 +372,7 @@ num_bots: 0
 The API documentation follows the file and content structure in the repo.
 On the left you can find the navigation panel that brings you to the implementation of
 - the **action**s the player can perform,
+- the **argument parser** definitions for the cli,
 - the **counter factory** converts the characters in the layout file to counter instances,
 - the **counters**, including the kitchen utility objects like dispenser, cooking counter (stove, deep fryer, oven),
   sink, etc.,
diff --git a/cooperative_cuisine/__main__.py b/cooperative_cuisine/__main__.py
index 685d2402c807800d377b561eaef4c1010009aead..7d63c878ff435371ddcf344f476cf9bc34e89130 100644
--- a/cooperative_cuisine/__main__.py
+++ b/cooperative_cuisine/__main__.py
@@ -2,13 +2,15 @@ import argparse
 import time
 from multiprocessing import Process
 
-from cooperative_cuisine.utils import (
-    url_and_port_arguments,
-    disable_websocket_logging_arguments,
-    add_list_of_manager_ids_arguments,
-    add_study_arguments,
-    add_gui_arguments,
+from cooperative_cuisine.argument_parser import (
+    create_screenshot_parser,
+    create_study_server_parser,
+    create_game_server_parser,
+    create_normal_parser,
+    create_gui_parser,
+    create_server_parser,
 )
+from cooperative_cuisine.pygame_2d_vis.video_replay import create_replay_parser
 
 USE_STUDY_SERVER = True
 
@@ -29,6 +31,7 @@ def start_study_server(cli_args):
         game_port=cli_args.game_port,
         manager_ids=cli_args.manager_ids,
         study_config_path=cli_args.study_config,
+        use_ssl=cli_args.ssl,
     )
 
 
@@ -41,31 +44,18 @@ def start_pygame_gui(cli_args):
         cli_args.game_url,
         cli_args.game_port,
         cli_args.manager_ids,
-        CONNECT_WITH_STUDY_SERVER=USE_STUDY_SERVER,
-        debug=cli_args.do_study,
+        debug=cli_args.debug,
+        do_study=cli_args.do_study,
+        use_ssl=cli_args.ssl,
     )
 
 
-def main(cli_args=None):
-    study_server = None
-
-    parser = argparse.ArgumentParser(
-        prog="Cooperative Cuisine",
-        description="Game Engine Server + PyGameGUI: Starts overcooked game engine server and a PyGame 2D Visualization window in two processes.",
-        epilog="For further information, see https://scs.pages.ub.uni-bielefeld.de/cocosy/overcooked-simulator/overcooked_simulator.html",
-    )
-    url_and_port_arguments(parser)
-    disable_websocket_logging_arguments(parser)
-    add_list_of_manager_ids_arguments(parser)
-    add_study_arguments(parser)
-    add_gui_arguments(parser)
-
-    cli_args = parser.parse_args()
-
+def start_server_and_gui(cli_args, no_gui=False):
+    study_sever = None
     game_server = None
     pygame_gui = None
     try:
-        if USE_STUDY_SERVER:
+        if no_gui or cli_args.do_study or not cli_args.debug:
             print("Start study server:")
             study_server = Process(target=start_study_server, args=(cli_args,))
             study_server.start()
@@ -75,38 +65,21 @@ def main(cli_args=None):
         game_server = Process(target=start_game_server, args=(cli_args,))
         game_server.start()
         time.sleep(0.5)
+        if no_gui:
+            while True:
+                time.sleep(1)
+        else:
+            print("Start PyGame GUI 1:")
+            pygame_gui = Process(target=start_pygame_gui, args=(cli_args,))
+            pygame_gui.start()
 
-        print("Start PyGame GUI 1:")
-        pygame_gui = Process(target=start_pygame_gui, args=(cli_args,))
-        pygame_gui.start()
-
-        if USE_STUDY_SERVER:
-            pass
-            # print("Start PyGame GUI 2:")
-            # pygame_gui_2 = Process(target=start_pygame_gui, args=(cli_args,))
-            # pygame_gui_2.start()
-            # # #
-            # print("Start PyGame GUI 3:")
-            # pygame_gui_3 = Process(target=start_pygame_gui, args=(cli_args,))
-            # pygame_gui_3.start()
-            #
-            # print("Start PyGame GUI 4:")
-            # pygame_gui_4 = Process(target=start_pygame_gui, args=(cli_args,))
-            # pygame_gui_4.start()
-            # while (
-            #     pygame_gui.is_alive()
-            #     and pygame_gui_2.is_alive()
-            #     and pygame_gui_3.is_alive()
-            # ):
-            #     time.sleep(1)
-
-        while pygame_gui.is_alive():
-            time.sleep(1)
+            while pygame_gui.is_alive():
+                time.sleep(1)
 
     except KeyboardInterrupt:
         print("Received Keyboard interrupt")
     finally:
-        if USE_STUDY_SERVER and study_server is not None and study_server.is_alive():
+        if study_server is not None and study_server.is_alive():
             print("Terminate study server")
             study_server.terminate()
         if game_server is not None and game_server.is_alive():
@@ -118,5 +91,88 @@ def main(cli_args=None):
         time.sleep(0.1)
 
 
+def main(cli_args=None):
+    parser = argparse.ArgumentParser(
+        prog="Cooperative Cuisine",
+        description="CLI control of cooperative cuisine. Start server, guis, execute utility code, etc. Use sub "
+        "commands to configure the execution. No commands or arguments results in starting a study "
+        "server, game server and a gui.",
+        epilog="For further information, see https://scs.pages.ub.uni-bielefeld.de/cocosy/overcooked-simulator/overcooked_simulator.html",
+    )
+
+    subparsers = parser.add_subparsers(
+        help="Available CLI of Cooperative Cuisine", dest="command"
+    )
+
+    normal_parser = subparsers.add_parser(
+        "start",
+        help="Start a game server, study server and a PyGame 2D Visualization.",
+    )
+    create_normal_parser(normal_parser)
+
+    study_server_parser = subparsers.add_parser(
+        "study-server", help="Start a study server.", aliases=["study"]
+    )
+    create_study_server_parser(study_server_parser)
+
+    game_server_parser = subparsers.add_parser(
+        "game-server", help="Start a game server.", aliases=["game"]
+    )
+    create_game_server_parser(game_server_parser)
+
+    gui_parser = subparsers.add_parser(
+        "gui", help="Start a PyGame 2D Visualization (a client).", aliases=["client"]
+    )
+    create_gui_parser(gui_parser)
+
+    screenshot_parser = subparsers.add_parser(
+        "screenshot", help="Create a screenshot from a json state.", aliases=["image"]
+    )
+    create_screenshot_parser(screenshot_parser)
+
+    replay_parser = subparsers.add_parser(
+        "replay",
+        help="Create replay from json states or recordings.",
+        aliases=["video", "video-replay"],
+    )
+    create_replay_parser(replay_parser)
+
+    server_parser = subparsers.add_parser(
+        "server",
+        help="Start game and study server.",
+        aliases=["game-and-study", "study-and-game"],
+    )
+    create_server_parser(server_parser)
+
+    cli_args = parser.parse_args()
+
+    if cli_args.command:
+        match cli_args.command:
+            case "screenshot" | "image":
+                from cooperative_cuisine.pygame_2d_vis.drawing import main
+
+                main(cli_args)
+            case "study-server" | "study":
+                start_study_server(cli_args)
+            case "game-server" | "game":
+                start_game_server(cli_args)
+            case "replay" | "video" | "video-replay":
+                from cooperative_cuisine.pygame_2d_vis.video_replay import main
+
+                main(cli_args)
+            case "start":
+                start_server_and_gui(cli_args)
+            case "gui" | "client":
+                start_pygame_gui(cli_args)
+            case "server" | "game-and-study" | "study-and-game":
+                start_server_and_gui(cli_args, no_gui=True)
+            case _:
+                parser.print_help()
+    else:
+        default_parser = argparse.ArgumentParser()
+        create_normal_parser(default_parser)
+        start_server_and_gui(default_parser.parse_args())
+
+
 if __name__ == "__main__":
     main()
diff --git a/cooperative_cuisine/argument_parser.py b/cooperative_cuisine/argument_parser.py
new file mode 100644
index 0000000000000000000000000000000000000000..f6bc86eb06d4c011239af26b467f2ea42c3541a6
--- /dev/null
+++ b/cooperative_cuisine/argument_parser.py
@@ -0,0 +1,359 @@
+import uuid
+from argparse import ArgumentParser, FileType
+
+from cooperative_cuisine import ROOT_DIR
+
+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 study_server_arguments(
+    parser: ArgumentParser,
+    default_study_port=DEFAULT_SERVER_PORT,
+    default_server_url=DEFAULT_SERVER_URL,
+):
+    """Add arguments for study server ip and port.
+
+    Args:
+        parser: the parser to add the arguments.
+        default_study_port: the default port of the study server `DEFAULT_STUDY_PORT` -> 8080
+        default_server_url: the default ip/url/host of the study server `DEFAULT_SERVER_URL` -> `localhost`
+    """
+    parser.add_argument(
+        "-s",
+        "--study-url",
+        "--study-host",
+        type=str,
+        default=default_server_url,
+        help=f"Overcooked Study Server host url.",
+    )
+    parser.add_argument(
+        "-p",
+        "--study-port",
+        type=int,
+        default=default_study_port,
+        help=f"Port number for the Study Server",
+    )
+
+
+def game_server_arguments(
+    parser: ArgumentParser,
+    default_game_port=DEFAULT_GAME_PORT,
+    default_server_url=DEFAULT_SERVER_URL,
+):
+    """Add arguments for game server ip and port.
+
+    Args:
+        parser: the parser to add the arguments.
+        default_game_port: the default port of the game server `DEFAULT_GAME_PORT` -> 8000
+        default_server_url: the default ip/url/host of the game server `DEFAULT_SERVER_URL` -> `localhost`
+    """
+    parser.add_argument(
+        "-g",
+        "--game-url",
+        "--game-host",
+        type=str,
+        default=default_server_url,
+        help=f"Overcooked Game Server url.",
+    )
+    parser.add_argument(
+        "-gp",
+        "--game-port",
+        type=int,
+        default=default_game_port,
+        help=f"Port number for the Game Server",
+    )
+
+
+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",
+        nargs="+",
+        type=str,
+        default=[uuid.uuid4().hex],
+        help="List of manager IDs that can create environments.",
+    )
+
+
+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,
+        default=ROOT_DIR / "configs" / "study" / "study_config.yaml",
+        help="The config of the study.",
+    )
+
+
+def add_gui_arguments(parser):
+    """Adds the gui debug argument to the given argument parser.
+        If set, additional debug / admin elements are shown.
+
+    Args:
+        parser (argparse.ArgumentParser): The argument parser object.
+
+
+    Example:
+        ```python
+        import argparse
+        parser = argparse.ArgumentParser()
+        add_gui_arguments(parser)
+        ```
+    """
+    parser.add_argument(
+        "--do-study",
+        help="Start GUI in Fullscreen and do not show configuration and quit buttons.",
+        action="store_true",
+    )
+    parser.add_argument(
+        "--debug",
+        help="Debug GUI. No need for a study server. Select layouts in GUI. You need to specify a manager id for the game server.",
+        action="store_true",
+    )
+
+
+def ssl_argument(parser: ArgumentParser):
+    """Add the ssl argument to a parser.
+
+    Args:
+        parser: the parser to add the argument.
+    """
+    parser.add_argument(
+        "--ssl",
+        action="store_true",
+        help="Use SSL certificate. Connect to https and wss.",
+    )
+
+
+def visualization_config_argument(parser: ArgumentParser):
+    """Add the visualization config argument to a parser.
+
+    Args:
+        parser: the parser to add the argument.
+    """
+    parser.add_argument(
+        "-v",
+        "--visualization-config",
+        type=FileType("r", encoding="UTF-8"),
+        default=ROOT_DIR / "pygame_2d_vis" / "visualization.yaml",
+    )
+
+
+def output_file_argument(parser: ArgumentParser, default_file: str):
+    """Add the output file argument to a parser.
+
+    Args:
+        parser: the parser to add the argument.
+        default_file: the default file name (relative location)
+    """
+    parser.add_argument(
+        "-o",
+        "--output-file",
+        type=str,
+        default=default_file,
+    )
+
+
+def create_replay_parser(parser: ArgumentParser):
+    """Add individually arguments for parsers that use the replay function of cooperative cuisine.
+
+    Args:
+        parser (ArgumentParser): The argument parser object.
+    """
+    parser.add_argument("-j", "--json_state", help="Json states file path", type=str)
+    visualization_config_argument(parser)
+    parser.add_argument(
+        "-o",
+        "--output",
+        type=str,
+        default="<json_state_name>",
+    )
+    parser.add_argument(
+        "-p",
+        "--player-id",
+        type=str,
+        default=None,
+        help="Render view for specific player",
+    )
+    parser.add_argument(
+        "-g",
+        "--grid-size",
+        type=int,
+        default=40,
+        help="Number pixel for one cell in the grid.",
+    )
+    parser.add_argument(
+        "-a",
+        "--action-recording",
+        type=str,
+        default=None,
+        help="The path to the action recording",
+    )
+    parser.add_argument(
+        "-e",
+        "--env-configs",
+        type=str,
+        default=None,
+        help="The path to the environment config logs",
+    )
+    parser.add_argument(
+        "-s",
+        "--step-duration",
+        type=float,
+        default=1 / 200,
+        help="Step duration in seconds between environment steps.",
+    )
+    parser.add_argument(
+        "-f",
+        "--fps",
+        type=int,
+        default=24,
+        help="Frames per second to render images from the environment",
+    )
+    parser.add_argument(
+        "-d", "--display", action="store_true", help="Show generated images."
+    )
+    parser.add_argument(
+        "-n",
+        "--number-player",
+        type=int,
+        default=1,
+        help="Number of player to visualize. Should be the same as played the game.",
+    )
+    parser.add_argument(
+        "-b",
+        "--break-when-no-action",
+        action="store_true",
+        help="Stop rendering when no more actions are available.",
+    )
+    parser.add_argument(
+        "--video",
+        "--video-source",
+        type=str,
+        help="Create a video from a folder full of images.",
+    )
+
+
+def create_screenshot_parser(parser: ArgumentParser):
+    """Add cli arguments for running only the screenshot generation.
+
+    Args:
+        parser (ArgumentParser): The argument parser object.
+    """
+    parser.add_argument(
+        "-s",
+        "--state",
+        type=FileType("r", encoding="UTF-8"),
+        default=ROOT_DIR / "pygame_2d_vis" / "sample_state.json",
+    )
+    visualization_config_argument(parser)
+    output_file_argument(parser, ROOT_DIR / "generated" / "screenshot.jpg")
+
+
+def create_game_server_parser(parser: ArgumentParser):
+    """Add cli arguments for running only a game server. For the game-server subcommand.
+
+    Args:
+        parser (ArgumentParser): The argument parser object.
+    """
+    game_server_arguments(parser)
+    disable_websocket_logging_arguments(parser)
+    add_list_of_manager_ids_arguments(parser)
+    ssl_argument(parser)
+
+
+def create_study_server_parser(parser: ArgumentParser):
+    """Add cli arguments for running only a study server. For the study-server subcommand.
+
+    Args:
+        parser (ArgumentParser): The argument parser object.
+    """
+    study_server_arguments(parser)
+    # TODO study server can handle several game server
+    game_server_arguments(parser)
+    add_list_of_manager_ids_arguments(parser=parser)
+    add_study_arguments(parser=parser)
+    ssl_argument(parser)
+
+
+def create_gui_parser(parser: ArgumentParser):
+    """Add cli arguments for running only a gui instance. For the gui / client subcommand.
+
+    Args:
+        parser (ArgumentParser): The argument parser object.
+    """
+    study_server_arguments(parser)
+    disable_websocket_logging_arguments(parser)
+    add_list_of_manager_ids_arguments(parser)
+    add_gui_arguments(parser)
+    ssl_argument(parser)
+    game_server_arguments(parser)
+
+
+def create_normal_parser(parser: ArgumentParser):
+    """Add cli arguments for running the servers and one gui instance. For the start subcommand.
+
+    Args:
+        parser (ArgumentParser): The argument parser object.
+    """
+    game_server_arguments(parser)
+    study_server_arguments(parser)
+    disable_websocket_logging_arguments(parser)
+    add_list_of_manager_ids_arguments(parser)
+    add_gui_arguments(parser)
+    add_study_arguments(parser)
+    ssl_argument(parser)
+
+
+def create_server_parser(parser: ArgumentParser):
+    """Add cli arguments for running the servers (game and study but no gui). For the server subcommand.
+
+    Args:
+        parser (ArgumentParser): The argument parser object.
+    """
+    game_server_arguments(parser)
+    study_server_arguments(parser)
+    disable_websocket_logging_arguments(parser)
+    ssl_argument(parser)
+    add_list_of_manager_ids_arguments(parser)
+    add_study_arguments(parser)
diff --git a/cooperative_cuisine/configs/study/study_config.yaml b/cooperative_cuisine/configs/study/study_config.yaml
index 3796e7f2afd516cc2225980fb88d9167a47fe2f2..e21045a79df9db46299d3da217f95e09b29adeca 100644
--- a/cooperative_cuisine/configs/study/study_config.yaml
+++ b/cooperative_cuisine/configs/study/study_config.yaml
@@ -132,3 +132,5 @@ levels:
 
 num_players: 1
 num_bots: 0
+
+study_log_path: USER_LOG_DIR/ENV_NAME/
\ No newline at end of file
diff --git a/cooperative_cuisine/game_server.py b/cooperative_cuisine/game_server.py
index 5b5d2fa38a7aebebb906db5ffcc7f1551988607b..e565cbe91a1652af87d51cbc3b7de066e8903700 100644
--- a/cooperative_cuisine/game_server.py
+++ b/cooperative_cuisine/game_server.py
@@ -30,6 +30,7 @@ from starlette.websockets import WebSocketDisconnect
 from typing_extensions import TypedDict
 
 from cooperative_cuisine.action import Action
+from cooperative_cuisine.argument_parser import create_game_server_parser
 from cooperative_cuisine.environment import Environment
 from cooperative_cuisine.server_results import (
     CreateEnvResult,
@@ -37,9 +38,6 @@ from cooperative_cuisine.server_results import (
     PlayerRequestResult,
 )
 from cooperative_cuisine.utils import (
-    url_and_port_arguments,
-    add_list_of_manager_ids_arguments,
-    disable_websocket_logging_arguments,
     setup_logging,
     UUID_CUTOFF,
 )
@@ -831,6 +829,7 @@ async def websocket_player_endpoint(websocket: WebSocket, client_id: str):
 def main(
     host: str, port: int, manager_ids: list[str], enable_websocket_logging: bool = False
 ):
+    print("Manager IDs:", manager_ids)
     setup_logging(enable_websocket_logging)
     loop = asyncio.new_event_loop()
     asyncio.set_event_loop(loop)
@@ -849,10 +848,7 @@ if __name__ == "__main__":
         epilog="For further information, see "
         "https://scs.pages.ub.uni-bielefeld.de/cocosy/overcooked-simulator/cooperative_cuisine.html",
     )
-
-    url_and_port_arguments(parser)
-    disable_websocket_logging_arguments(parser)
-    add_list_of_manager_ids_arguments(parser)
+    create_game_server_parser(parser)
     args = parser.parse_args()
     main(args.game_url, args.game_port, args.manager_ids, args.enable_websocket_logging)
     """
diff --git a/cooperative_cuisine/pygame_2d_vis/drawing.py b/cooperative_cuisine/pygame_2d_vis/drawing.py
index c416278e8fcc0259bdef231b5db85ab01f42614b..6896a7bee8ec9332e444f68a95de22f39176b874 100644
--- a/cooperative_cuisine/pygame_2d_vis/drawing.py
+++ b/cooperative_cuisine/pygame_2d_vis/drawing.py
@@ -2,7 +2,6 @@ import argparse
 import colorsys
 import json
 import os
-import sys
 from datetime import datetime, timedelta
 from pathlib import Path
 
@@ -13,6 +12,7 @@ import yaml
 from scipy.spatial import KDTree
 
 from cooperative_cuisine import ROOT_DIR
+from cooperative_cuisine.argument_parser import create_screenshot_parser
 from cooperative_cuisine.environment import Environment
 from cooperative_cuisine.pygame_2d_vis.game_colors import colors, RGB
 from cooperative_cuisine.state_representation import (
@@ -1035,7 +1035,7 @@ def generate_recipe_images(config: dict, folder_path: str | Path):
         pygame.image.save(screen, f"{folder_path}/{graph_dict['meal']}.png")
 
 
-def main(args):
+def main(cli_args):
     """Runs the Cooperative Cuisine Image Generation process.
 
     This method takes command line arguments to specify the state file, visualization configuration file, and output
@@ -1049,37 +1049,21 @@ def main(args):
 
         -o, --output_file: A command line argument of type `str`. Specifies the output file path for the generated image. If not provided, the default value is 'ROOT_DIR / "generated" / "screenshot.jpg"'.
     """
-    parser = argparse.ArgumentParser(
-        prog="Cooperative Cuisine Image Generation",
-        description="Generate images for a state in json.",
-        epilog="For further information, see https://scs.pages.ub.uni-bielefeld.de/cocosy/overcooked-simulator/overcooked_simulator.html",
-    )
-    parser.add_argument(
-        "-s",
-        "--state",
-        type=argparse.FileType("r", encoding="UTF-8"),
-        default=ROOT_DIR / "pygame_2d_vis" / "sample_state.json",
-    )
-    parser.add_argument(
-        "-v",
-        "--visualization_config",
-        type=argparse.FileType("r", encoding="UTF-8"),
-        default=ROOT_DIR / "pygame_2d_vis" / "visualization.yaml",
-    )
-    parser.add_argument(
-        "-o",
-        "--output_file",
-        type=str,
-        default=ROOT_DIR / "generated" / "screenshot.jpg",
-    )
-    args = parser.parse_args(args)
-    with open(args.visualization_config, "r") as f:
+
+    with open(cli_args.visualization_config, "r") as f:
         viz_config = yaml.safe_load(f)
-    with open(args.state, "r") as f:
+    with open(cli_args.state, "r") as f:
         state = json.load(f)
-    save_screenshot(state, viz_config, args.output_file)
-    generate_recipe_images(viz_config, args.output_file.parent)
+    save_screenshot(state, viz_config, cli_args.output_file)
+    generate_recipe_images(viz_config, cli_args.output_file.parent)
 
 
 if __name__ == "__main__":
-    main(sys.argv[1:])
+    parser = argparse.ArgumentParser(
+        prog="Cooperative Cuisine Image Generation",
+        description="Generate images for a state in json.",
+        epilog="For further information, see https://scs.pages.ub.uni-bielefeld.de/cocosy/overcooked-simulator/overcooked_simulator.html",
+    )
+    create_screenshot_parser(parser)
+    args = parser.parse_args()
+    main(args)
diff --git a/cooperative_cuisine/pygame_2d_vis/gui.py b/cooperative_cuisine/pygame_2d_vis/gui.py
index a245e5fe375920e17e1ac4df1798441961568662..7d6fca9f7418cb593acbbc2e3af210c62a81709a 100644
--- a/cooperative_cuisine/pygame_2d_vis/gui.py
+++ b/cooperative_cuisine/pygame_2d_vis/gui.py
@@ -21,6 +21,7 @@ from websockets.sync.client import connect
 
 from cooperative_cuisine import ROOT_DIR
 from cooperative_cuisine.action import ActionType, InterActionData, Action
+from cooperative_cuisine.argument_parser import create_gui_parser
 from cooperative_cuisine.game_server import (
     CreateEnvironmentConfig,
     WebsocketMessage,
@@ -31,11 +32,7 @@ from cooperative_cuisine.pygame_2d_vis.game_colors import colors
 from cooperative_cuisine.server_results import PlayerInfo
 from cooperative_cuisine.state_representation import StateRepresentation
 from cooperative_cuisine.utils import (
-    url_and_port_arguments,
-    disable_websocket_logging_arguments,
-    add_list_of_manager_ids_arguments,
     setup_logging,
-    add_gui_arguments,
 )
 
 
@@ -129,14 +126,14 @@ class PyGameGUI:
         game_host: str,
         game_port: int,
         manager_ids: list[str],
-        CONNECT_WITH_STUDY_SERVER: bool,
         USE_AAAMBOS_AGENT: bool,
         debug: bool,
+        do_study: bool,
+        use_ssl: bool,
     ):
-        self.CONNECT_WITH_STUDY_SERVER = CONNECT_WITH_STUDY_SERVER
         self.USE_AAAMBOS_AGENT = USE_AAAMBOS_AGENT
-
-        self.show_debug_elements = debug
+        self.show_debug_elements = not do_study
+        self.CONNECT_WITH_STUDY_SERVER = not debug
 
         pygame.init()
         pygame.display.set_icon(
@@ -152,10 +149,12 @@ class PyGameGUI:
 
         self.websockets = {}
 
-        if CONNECT_WITH_STUDY_SERVER:
-            self.request_url = f"http://{study_host}:{study_port}"
+        if self.CONNECT_WITH_STUDY_SERVER:
+            self.request_url = (
+                f"http{'s' if use_ssl else ''}://{study_host}:{study_port}"
+            )
         else:
-            self.request_url = f"http://{game_host}:{game_port}"
+            self.request_url = f"http{'s' if use_ssl else ''}://{game_host}:{game_port}"
 
         self.manager_id = random.choice(manager_ids)
 
@@ -206,7 +205,7 @@ class PyGameGUI:
         self.switch_score_color: bool = False
         self.count_frames_score_label: int = 0
 
-        self.fullscreen = False if self.show_debug_elements else True
+        self.fullscreen = do_study
 
         self.menu_state = MenuStates.Start
         self.manager: pygame_gui.UIManager
@@ -2226,9 +2225,10 @@ def main(
     game_url: str,
     game_port: int,
     manager_ids: list[str],
-    CONNECT_WITH_STUDY_SERVER=False,
     USE_AAAMBOS_AGENT=False,
     debug=False,
+    do_study=False,
+    use_ssl=False,
 ):
     setup_logging()
     gui = PyGameGUI(
@@ -2237,9 +2237,10 @@ def main(
         game_host=game_url,
         game_port=game_port,
         manager_ids=manager_ids,
-        CONNECT_WITH_STUDY_SERVER=CONNECT_WITH_STUDY_SERVER,
         USE_AAAMBOS_AGENT=USE_AAAMBOS_AGENT,
         debug=debug,
+        do_study=do_study,
+        use_ssl=use_ssl,
     )
     gui.start_pygame()
 
@@ -2251,11 +2252,7 @@ if __name__ == "__main__":
         epilog="For further information, "
         "see https://scs.pages.ub.uni-bielefeld.de/cocosy/overcooked-simulator/overcooked_simulator.html",
     )
-
-    url_and_port_arguments(parser)
-    disable_websocket_logging_arguments(parser)
-    add_list_of_manager_ids_arguments(parser)
-    add_gui_arguments(parser)
+    create_gui_parser(parser)
     args = parser.parse_args()
     main(
         args.study_url,
@@ -2263,6 +2260,7 @@ if __name__ == "__main__":
         args.game_url,
         args.game_port,
         args.manager_ids,
-        CONNECT_WITH_STUDY_SERVER=True,
-        debug=args.do_study,
+        debug=args.debug,
+        do_study=args.do_study,
+        use_ssl=args.ssl,
     )
diff --git a/cooperative_cuisine/pygame_2d_vis/video_replay.py b/cooperative_cuisine/pygame_2d_vis/video_replay.py
index 46521e12524e1c0c2b2074cc5b1f68486d354364..56ee373993d524a001271cb46bc2f455d28e7e47 100644
--- a/cooperative_cuisine/pygame_2d_vis/video_replay.py
+++ b/cooperative_cuisine/pygame_2d_vis/video_replay.py
@@ -7,29 +7,28 @@ based on the actions. Until now, we did not find any deviations from the json st
 # CLI
 Sequence of images replay from actions:
 ```bash
-python video_replay.py -a ~/.local/state/cooperative_cuisine/log/ENV_NAME/actions.jsonl -e ~/.local/state/cooperative_cuisine/log/ENV_NAME/env_configs.jsonl -d -n 2 -p "0"
+cooperative-cuisine replay -a ~/.local/state/cooperative_cuisine/log/ENV_NAME/actions.jsonl -e ~/.local/state/cooperative_cuisine/log/ENV_NAME/env_configs.jsonl -d -n 2 -p "0"
 ```
 
 Sequence of images replay from json states:
 ```bash
-python video_replay.py -j ~/.local/state/cooperative_cuisine/log/ENV_NAME/json_states.jsonl -d -p "0"
+cooperative-cuisine replay -j ~/.local/state/cooperative_cuisine/log/ENV_NAME/json_states.jsonl -d -p "0"
 ```
 
 The `display` (`-d`, `--display`) requires `opencv-python` (cv2) installed. (`pip install opencv-python`)
 
 Generate a video file from images (requires also `opencv-python`):
 ```bash
-python video_replay.py --video ~/.local/state/cooperative_cuisine/log/ENV_NAME/DIR_NAME_WITH_IMAGES
+cooperative-cuisine replay  --video ~/.local/state/cooperative_cuisine/log/ENV_NAME/DIR_NAME_WITH_IMAGES
 ```
 
 For additional CLI arguments:
 ```bash
-python video_replay.py -h
+cooperative-cuisine replay  -h
 ```
 
 # Code Documentation
 """
-import argparse
 import json
 import os
 import os.path
@@ -42,8 +41,10 @@ import yaml
 from PIL import Image
 from tqdm import tqdm
 
-from cooperative_cuisine import ROOT_DIR
 from cooperative_cuisine.action import Action
+from cooperative_cuisine.argument_parser import (
+    create_replay_parser,
+)
 from cooperative_cuisine.environment import Environment
 from cooperative_cuisine.pygame_2d_vis.drawing import Visualizer
 from cooperative_cuisine.recording import FileRecorder
@@ -297,127 +298,63 @@ def video_from_images(image_paths, video_name, fps):
     print("See:", video_name)
 
 
-if __name__ == "__main__":
-    parser = ArgumentParser(
-        prog="Cooperative Cuisine Video Generation",
-        description="Generate videos from recorded data.",
-        epilog="For further information, see https://scs.pages.ub.uni-bielefeld.de/cocosy/overcooked-simulator/overcooked_simulator.html",
-    )
-    parser.add_argument("-j", "--json_state", help="Json states file path", type=str)
-    parser.add_argument(
-        "-v",
-        "--visualization_config",
-        type=argparse.FileType("r", encoding="UTF-8"),
-        default=ROOT_DIR / "pygame_2d_vis" / "visualization.yaml",
-    )
-    parser.add_argument(
-        "-o",
-        "--output",
-        type=str,
-        default="<json_state_name>",
-    )
-    parser.add_argument(
-        "-p",
-        "--player_id",
-        type=str,
-        default=None,
-        help="Render view for specific player",
-    )
-    parser.add_argument(
-        "-g",
-        "--grid_size",
-        type=int,
-        default=GRID_SIZE_DEFAULT,
-        help="Number pixel for one cell in the grid.",
-    )
-    parser.add_argument(
-        "-a",
-        "--action_recording",
-        type=str,
-        default=None,
-        help="The path to the action recording",
-    )
-    parser.add_argument(
-        "-e",
-        "--env_configs",
-        type=str,
-        default=None,
-        help="The path to the environment config logs",
-    )
-    parser.add_argument(
-        "-s",
-        "--step_duration",
-        type=float,
-        default=1 / STEP_DURATION_DEFAULT,
-        help="Step duration in seconds between environment steps.",
-    )
-    parser.add_argument(
-        "-f",
-        "--fps",
-        type=int,
-        default=FPS_DEFAULT,
-        help="Frames per second to render images from the environment",
-    )
-    parser.add_argument(
-        "-d", "--display", action="store_true", help="Show generated images."
-    )
-    parser.add_argument(
-        "-n",
-        "--number_player",
-        type=int,
-        default=NUMBER_PLAYERS_DEFAULT,
-        help="Number of player to visualize. Should be the same as played the game.",
-    )
-    parser.add_argument(
-        "-b",
-        "--break_when_no_action",
-        action="store_true",
-        help="Stop rendering when no more actions are available.",
-    )
-    parser.add_argument(
-        "--video",
-        "--video_source",
-        type=str,
-        help="Create a video from a folder full of images.",
-    )
-    args = parser.parse_args()
-    with open(args.visualization_config, "r") as f:
+def main(cli_args):
+    """
+    Runs the video replay with the given command line arguments.
+
+    Args:
+        cli_args: An object containing the command line arguments.
+    """
+    with open(cli_args.visualization_config, "r") as f:
         viz_config = yaml.safe_load(f)
-    if args.json_state:
+    if cli_args.json_state:
         target_directory = (
-            args.json_state.rsplit(".", maxsplit=1)[0]
-            if args.output == "<json_state_name>"
-            else args.output
+            cli_args.json_state.rsplit(".", maxsplit=1)[0]
+            if cli_args.output == "<json_state_name>"
+            else cli_args.output
         )
         from_json_states(
-            args.json_state,
+            cli_args.json_state,
             viz_config,
             target_directory,
-            args.player_id,
-            args.display,
-            args.grid_size,
+            cli_args.player_id,
+            cli_args.display,
+            cli_args.grid_size,
         )
-    elif args.video:
+    elif cli_args.video:
         target_directory = (
-            args.video + ".mp4" if args.output == "<json_state_name>" else args.output
+            cli_args.video + ".mp4"
+            if cli_args.output == "<json_state_name>"
+            else cli_args.output
         )
-        video_from_images(args.video, target_directory, args.fps)
+        video_from_images(cli_args.video, target_directory, cli_args.fps)
     else:
         target_directory = (
-            args.action_recording.rsplit(".", maxsplit=1)[0]
-            if args.output == "<json_state_name>"
-            else args.output
+            cli_args.action_recording.rsplit(".", maxsplit=1)[0]
+            if cli_args.output == "<json_state_name>"
+            else cli_args.output
         )
         simulate(
-            args.action_recording,
-            args.env_configs,
+            cli_args.action_recording,
+            cli_args.env_configs,
             viz_config,
             target_directory,
-            args.player_id,
-            args.step_duration,
-            args.fps,
-            args.display,
-            args.number_player,
-            args.break_when_no_action,
-            args.grid_size,
+            cli_args.player_id,
+            cli_args.step_duration,
+            cli_args.fps,
+            cli_args.display,
+            cli_args.number_player,
+            cli_args.break_when_no_action,
+            cli_args.grid_size,
         )
+
+
+if __name__ == "__main__":
+    parser = ArgumentParser(
+        prog="Cooperative Cuisine Video Generation",
+        description="Generate videos from recorded data.",
+        epilog="For further information, see https://scs.pages.ub.uni-bielefeld.de/cocosy/overcooked-simulator/overcooked_simulator.html",
+    )
+    create_replay_parser(parser)
+    args = parser.parse_args()
+    main(args)
diff --git a/cooperative_cuisine/study_server.py b/cooperative_cuisine/study_server.py
index e136fa9545771a0b566cd4e5c7d3e7ccde9a6771..657c4c00aa6a3624cd963553a4a226e068b3314f 100644
--- a/cooperative_cuisine/study_server.py
+++ b/cooperative_cuisine/study_server.py
@@ -10,9 +10,9 @@ python game_server.py --manager-ids COPIED_UUID
 
 The environment starts when all players connected.
 """
-
 import argparse
 import asyncio
+import json
 import logging
 import os
 import signal
@@ -25,18 +25,16 @@ from typing import Tuple, Any
 import requests
 import uvicorn
 import yaml
-from fastapi import FastAPI, HTTPException
+from fastapi import FastAPI, HTTPException, Request
 from pydantic import BaseModel
 
 from cooperative_cuisine import ROOT_DIR
+from cooperative_cuisine.argument_parser import create_study_server_parser
 from cooperative_cuisine.environment import EnvironmentConfig
 from cooperative_cuisine.game_server import CreateEnvironmentConfig, EnvironmentData
 from cooperative_cuisine.server_results import PlayerInfo, CreateEnvResult
 from cooperative_cuisine.utils import (
-    url_and_port_arguments,
-    add_list_of_manager_ids_arguments,
     expand_path,
-    add_study_arguments,
     deep_update,
     UUID_CUTOFF,
 )
@@ -295,7 +293,7 @@ class Study:
             self.next_level()
 
     def get_connection(
-        self, participant_id: str
+        self, participant_id: str, participant_host: str
     ) -> Tuple[dict[str, PlayerInfo] | None, LevelInfo | None]:
         """Get the assigned connections to the game server for a participant.
 
@@ -319,6 +317,22 @@ class Study:
                 number_players=len(self.current_running_env["player_info"]),
                 kitchen_size=self.current_running_env["kitchen_size"],
             )
+            log_path = expand_path(
+                self.study_config["study_log_path"],
+                env_name=self.current_running_env["env_id"],
+            )
+            os.makedirs(log_path, exist_ok=True)
+            with open(Path(log_path) / "study_log", "a") as log_file:
+                log_file.write(
+                    json.dumps(
+                        {
+                            "env_id": self.current_running_env["env_id"],
+                            "participant_ip": participant_host,
+                            "level_info": level_info.dict(),
+                            "player_info": player_info,
+                        }
+                    )
+                )
             return player_info, level_info
         else:
             raise HTTPException(
@@ -403,7 +417,7 @@ class StudyManager:
         """Port of the game server where the studies are running their environments."""
         self.game_server_url: str = ""
         """Combined URL of the game server where the studies are running their environments."""
-        self.create_game_server_url()
+        self.create_game_server_url(use_ssl=False)
 
         self.server_manager_id: str = ""
         """Manager id of this manager which will be registered in the game server."""
@@ -467,7 +481,7 @@ class StudyManager:
             raise HTTPException(status_code=409, detail="Participant not in any study.")
 
     def get_participant_game_connection(
-        self, participant_id: str
+        self, participant_id: str, participant_host: str
     ) -> Tuple[dict[str, PlayerInfo], LevelInfo]:
         """Get the assigned connections to the game server for a participant.
 
@@ -495,12 +509,15 @@ class StudyManager:
 
         if participant_id in self.participant_id_to_study_map.keys():
             assigned_study = self.participant_id_to_study_map[participant_id]
-            player_info, level_info = assigned_study.get_connection(participant_id)
+            player_info, level_info = assigned_study.get_connection(
+                participant_id, participant_host
+            )
+
             return player_info, level_info
         else:
             raise HTTPException(status_code=409, detail="Participant not in any study.")
 
-    def set_game_server_url(self, game_host: str, game_port: int):
+    def set_game_server_url(self, game_host: str, game_port: int, use_ssl: bool):
         """Set the game server host address, port and combined url. These values are set this way because
         the fastapi requests act on top level of the python script.
 
@@ -510,10 +527,12 @@ class StudyManager:
         """
         self.game_host = game_host
         self.game_port = game_port
-        self.create_game_server_url()
+        self.create_game_server_url(use_ssl)
 
-    def create_game_server_url(self):
-        self.game_server_url = f"http://{self.game_host}:{self.game_port}"
+    def create_game_server_url(self, use_ssl: bool):
+        self.game_server_url = (
+            f"http{'s' if use_ssl else ''}://{self.game_host}:{self.game_port}"
+        )
 
     def set_manager_id(self, manager_id: str):
         """Set the manager id of the study server. This value is set this way because
@@ -623,6 +642,7 @@ async def level_done(participant_id: str):
 @app.post("/get_game_connection/{participant_id}")
 async def get_game_connection(
     participant_id: str,
+    request: Request,
 ) -> dict[str, dict[str, PlayerInfo] | LevelInfo]:
     """Request to get the connection to the game server of a participant.
 
@@ -634,7 +654,7 @@ async def get_game_connection(
 
     """
     player_info, level_info = study_manager.get_participant_game_connection(
-        participant_id
+        participant_id, request.client.host if request.client is not None else "Test"
     )
     return {"player_info": player_info, "level_info": level_info}
 
@@ -664,8 +684,18 @@ async def disconnect_from_tutorial(participant_id: str):
     study_manager.end_tutorial(participant_id)
 
 
-def main(study_host, study_port, game_host, game_port, manager_ids, study_config_path):
-    study_manager.set_game_server_url(game_host=game_host, game_port=game_port)
+def main(
+    study_host,
+    study_port,
+    game_host,
+    game_port,
+    manager_ids,
+    study_config_path,
+    use_ssl,
+):
+    study_manager.set_game_server_url(
+        game_host=game_host, game_port=game_port, use_ssl=use_ssl
+    )
     study_manager.set_manager_id(manager_id=manager_ids[0])
     study_manager.set_study_config(study_config_path=study_config_path)
 
@@ -685,15 +715,8 @@ if __name__ == "__main__":
         epilog="For further information, "
         "see https://scs.pages.ub.uni-bielefeld.de/cocosy/overcooked-simulator/overcooked_simulator.html",
     )
-    url_and_port_arguments(
-        parser=parser,
-        server_name="Study Server",
-    )
-    add_list_of_manager_ids_arguments(parser=parser)
-    add_study_arguments(parser=parser)
+    create_study_server_parser(parser)
     args = parser.parse_args()
-
-    game_server_url = f"https://{args.game_url}:{args.game_port}"
     main(
         args.study_url,
         args.study_port,
@@ -701,4 +724,5 @@ if __name__ == "__main__":
         game_port=args.game_port,
         manager_ids=args.manager_ids,
         study_config_path=args.study_config,
+        use_ssl=args.ssl,
     )
diff --git a/cooperative_cuisine/utils.py b/cooperative_cuisine/utils.py
index 88719d54d8fc2fc00cf67d464af0a8c764f9457e..601a1f3dc946b7901665e0d74f16cfc63a6df1df 100644
--- a/cooperative_cuisine/utils.py
+++ b/cooperative_cuisine/utils.py
@@ -9,7 +9,6 @@ import json
 import logging
 import os
 import sys
-import uuid
 from collections import deque
 from datetime import datetime, timedelta
 from enum import Enum
@@ -26,15 +25,6 @@ if TYPE_CHECKING:
     from cooperative_cuisine.counters import Counter
 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."""
-
 UUID_CUTOFF = 8
 """The cutoff length for UUIDs."""
 
@@ -297,131 +287,6 @@ def setup_logging(enable_websocket_logging=False):
         logging.getLogger("websockets.client").setLevel(logging.ERROR)
 
 
-def url_and_port_arguments(
-    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,
-        help=f"Overcooked {server_name} study host url.",
-    )
-    parser.add_argument(
-        "-sp",
-        "--study-port",
-        type=int,
-        default=default_study_port,
-        help=f"Port number for the {server_name}",
-    )
-    parser.add_argument(
-        "-g",
-        "--game-url",
-        "--game-host",
-        type=str,
-        default=DEFAULT_SERVER_URL,
-        help=f"Overcooked {server_name} game server url.",
-    )
-    parser.add_argument(
-        "-gp",
-        "--game-port",
-        type=int,
-        default=default_game_port,
-        help=f"Port number for the {server_name}",
-    )
-
-
-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",
-        nargs="+",
-        type=str,
-        default=[uuid.uuid4().hex],
-        help="List of manager IDs that can create environments.",
-    )
-
-
-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,
-        default=ROOT_DIR / "configs" / "study" / "study_config.yaml",
-        help="The config of the study.",
-    )
-
-
-def add_gui_arguments(parser):
-    """Adds the gui debug argument to the given argument parser.
-        If set, additional debug / admin elements are shown.
-
-    Args:
-        parser (argparse.ArgumentParser): The argument parser object.
-
-
-    Example:
-        ```python
-        import argparse
-        parser = argparse.ArgumentParser()
-        add_gui_arguments(parser)
-        ```
-    """
-    parser.add_argument(
-        "--do-study",
-        default=True,
-        help="Disable additional debug / admin elements.",
-        action="store_false",
-    )
-
-
 class NumpyAndDataclassEncoder(json.JSONEncoder):
     """Special json encoder for numpy types"""
 
diff --git a/setup.py b/setup.py
index 7fee18c16e6000f9b07ddd17a6b943cd692370b8..c56d169568dcecf132790c2cedbddb911e2e39e4 100644
--- a/setup.py
+++ b/setup.py
@@ -47,7 +47,7 @@ setup(
     ],
     description="The real-time overcooked simulation for a cognitive cooperative system",
     entry_points={
-        "console_scripts": ["cooperative_cuisine = cooperative_cuisine.__main__:main"]
+        "console_scripts": ["cooperative-cuisine = cooperative_cuisine.__main__:main"]
     },
     install_requires=requirements,
     license="MIT license",
diff --git a/tests/test_pygame.py b/tests/test_pygame.py
index 740601f4052972c069ec7fc26c7e832753489c2b..18e1fcf511bca3d5b6cb7b95a6791de73fb00ed7 100644
--- a/tests/test_pygame.py
+++ b/tests/test_pygame.py
@@ -1,9 +1,11 @@
 import json
 import os
+from argparse import ArgumentParser
 
 import yaml
 
 from cooperative_cuisine import ROOT_DIR
+from cooperative_cuisine.argument_parser import create_screenshot_parser
 from cooperative_cuisine.pygame_2d_vis.drawing import (
     calc_angle,
     Visualizer,
@@ -25,7 +27,9 @@ def test_calc_angle():
 
 
 def test_drawing():
-    main([])
+    parser = ArgumentParser()
+    create_screenshot_parser(parser)
+    main(parser.parse_args([]))
     assert os.path.exists(os.path.join(ROOT_DIR, "generated", "screenshot.jpg"))
 
 
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 2802bb3a73f7deea7d1ee169adc0eb132b399096..7b507fb9941e51e41b7ac1e7bba490acf11651a4 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -4,18 +4,34 @@ from argparse import ArgumentParser
 import networkx
 import pytest
 
+from cooperative_cuisine.argument_parser import (
+    game_server_arguments,
+    study_server_arguments,
+    disable_websocket_logging_arguments,
+    add_list_of_manager_ids_arguments,
+    add_gui_arguments,
+    add_study_arguments,
+    ssl_argument,
+    create_study_server_parser,
+    create_game_server_parser,
+    create_gui_parser,
+    create_replay_parser,
+    create_normal_parser,
+    create_server_parser,
+)
 from cooperative_cuisine.environment import Environment
+from cooperative_cuisine.pygame_2d_vis.video_replay import (
+    GRID_SIZE_DEFAULT,
+    STEP_DURATION_DEFAULT,
+    FPS_DEFAULT,
+    NUMBER_PLAYERS_DEFAULT,
+)
 from cooperative_cuisine.state_representation import (
     create_movement_graph,
     restrict_movement_graph,
     astar_heuristic,
 )
 from cooperative_cuisine.utils import (
-    url_and_port_arguments,
-    add_list_of_manager_ids_arguments,
-    disable_websocket_logging_arguments,
-    add_study_arguments,
-    add_gui_arguments,
     create_layout_with_counters,
     setup_logging,
 )
@@ -23,19 +39,20 @@ from tests.test_start import env_config_no_validation
 from tests.test_start import layout_empty_config, item_info
 
 
-def test_parser_gen():
+def test_arguments():
     parser = ArgumentParser()
-    url_and_port_arguments(parser)
+    game_server_arguments(parser)
+    study_server_arguments(parser)
     disable_websocket_logging_arguments(parser)
     add_list_of_manager_ids_arguments(parser)
-    add_study_arguments(parser)
     add_gui_arguments(parser)
-
+    add_study_arguments(parser)
+    ssl_argument(parser)
     parser.parse_args(
         [
             "-s",
             "localhost",
-            "-sp",
+            "-p",
             "8000",
             "-g",
             "localhost",
@@ -49,6 +66,41 @@ def test_parser_gen():
     )
 
 
+def test_parser_creation():
+    parser = ArgumentParser()
+    create_game_server_parser(parser)
+    parser = ArgumentParser()
+    create_study_server_parser(parser)
+    parser = ArgumentParser()
+    create_gui_parser(parser)
+    parser = ArgumentParser()
+    create_replay_parser(parser)
+    print(parser)
+    grid_size_action = [
+        a for a in parser._optionals._actions if "--grid-size" in a.option_strings
+    ][0]
+    assert grid_size_action.default == GRID_SIZE_DEFAULT
+
+    number_player_action = [
+        a for a in parser._optionals._actions if "--number-player" in a.option_strings
+    ][0]
+    assert number_player_action.default == NUMBER_PLAYERS_DEFAULT
+    fps_action = [a for a in parser._optionals._actions if "--fps" in a.option_strings][
+        0
+    ]
+    assert fps_action.default == FPS_DEFAULT
+    step_duration_action = [
+        a for a in parser._optionals._actions if "--step-duration" in a.option_strings
+    ][0]
+    assert step_duration_action.default == 1 / STEP_DURATION_DEFAULT
+
+    parser = ArgumentParser()
+    create_server_parser(parser)
+
+    parser = ArgumentParser()
+    create_normal_parser(parser)
+
+
 def test_layout_creation():
     assert """###\n#_#\n###\n""" == create_layout_with_counters(3, 3)
     assert """###\n#_#\n#_#\n###\n""" == create_layout_with_counters(3, 4)