diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 64b372da1c3f8fc7e9e12173dd274a3d421db08c..987ad16f6ee2b0c829189e3d09d98611fc7583fd 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,49 +1,26 @@
-# This file is a template, and might need editing before it works on your project.
-# This is a sample GitLab CI/CD configuration file that should run without any modifications.
-# It demonstrates a basic 3 stage CI/CD pipeline. Instead of real tests or scripts,
-# it uses echo commands to simulate the pipeline execution.
-#
-# A pipeline is composed of independent jobs that run scripts, grouped into stages.
-# Stages run in sequential order, but jobs within stages run in parallel.
-#
-# For more information, see: https://docs.gitlab.com/ee/ci/yaml/index.html#stages
-#
-# You can copy and paste this template into a new `.gitlab-ci.yml` file.
-# You should not add this template to an existing `.gitlab-ci.yml` file by using the `include:` keyword.
-#
-# To contribute improvements to CI/CD templates, please follow the Development guide at:
-# https://docs.gitlab.com/ee/development/cicd/templates.html
-# This specific template is located at:
-# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml
+image: maven:eclipse-temurin
 
-stages:          # List of stages for jobs, and their order of execution
+stages:
   - build
   - test
-  - deploy
+  - package
 
-build-job:       # This job runs in the build stage, which runs first.
+before_script:
+  - cd ChaosGame  # Navigate to the ChaosGame directory
+
+build:
   stage: build
   script:
-    - echo "Compiling the code..."
-    - echo "Compile complete."
+    - mvn compile
 
-unit-test-job:   # This job runs in the test stage.
-  stage: test    # It only starts when the job in the build stage completes successfully.
+test:
+  stage: test
   script:
-    - echo "Running unit tests... This will take about 60 seconds."
-    - sleep 60
-    - echo "Code coverage is 90%"
+    - mvn clean test
 
-lint-test-job:   # This job also runs in the test stage.
-  stage: test    # It can run at the same time as unit-test-job (in parallel).
+package:
+  stage: package
   script:
-    - echo "Linting code... This will take about 10 seconds."
-    - sleep 10
-    - echo "No lint issues found."
+    - mvn clean package
+
 
-deploy-job:      # This job runs in the deploy stage.
-  stage: deploy  # It only runs when *both* jobs in the test stage complete successfully.
-  environment: production
-  script:
-    - echo "Deploying application..."
-    - echo "Application successfully deployed."
diff --git a/ChaosGame/pom.xml b/ChaosGame/pom.xml
index 99427ddd439c1256ad238550b04ce2bf9c48dcea..819aaee5f89f5c558a36aa210f0c9f3e629e42ff 100644
--- a/ChaosGame/pom.xml
+++ b/ChaosGame/pom.xml
@@ -26,6 +26,11 @@
             <artifactId>javafx-controls</artifactId>
             <version>21.0.1</version>
         </dependency>
+        <dependency>
+            <groupId>org.openjfx</groupId>
+            <artifactId>javafx-media</artifactId>
+            <version>21.0.1</version>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/App.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/App.java
index 14f0a1f105ec695ab263ea6ecddde627d17f1e48..d09eea3af84cffba7537a333f4ff4be809d1b2e6 100644
--- a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/App.java
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/App.java
@@ -1,55 +1,65 @@
 package edu.ntnu.idatt2003.group6;
 
-import edu.ntnu.idatt2003.group6.view.HomePage;
+import edu.ntnu.idatt2003.group6.controller.chaosgame.ChaosGameController;
+import edu.ntnu.idatt2003.group6.controller.navigation.NavigationController;
+import edu.ntnu.idatt2003.group6.models.navigation.NavigationModel;
+import edu.ntnu.idatt2003.group6.view.frames.HomePage;
+import java.util.Objects;
 import javafx.application.Application;
-import javafx.event.ActionEvent;
-import javafx.event.EventHandler;
 import javafx.scene.Scene;
 import javafx.scene.image.Image;
-import javafx.scene.layout.StackPane;
 import javafx.stage.Stage;
-import javafx.stage.StageStyle;
 
-import java.util.Objects;
 
 /**
  * Main class for the application.
  *
- * @version 0.1.1
+ * @version 0.3.2
  * @since 0.1.1
  */
 public class App extends Application {
 
-  private HomePage homePage;
-
+  /**
+   * The main method of the application.
+   *
+   * @param args The arguments to the main method.
+   */
   public static void main(String[] args) {
+
     launch(args);
   }
 
+  /**
+   * The start method of the application.
+   *
+   * @param primaryStage The primary stage of the application.
+   */
   @Override
   public void start(Stage primaryStage) {
     primaryStage.setTitle("Chaos Game");
-    primaryStage.setMaximized(true);
-    primaryStage.setMinWidth(800);
+    primaryStage.setMinWidth(950);
     primaryStage.setMinHeight(600);
-    //primaryStage.getIcons().add(new Image(Objects.requireNonNull(
-    //    getClass().getResourceAsStream("/icon.png"))));
-    ;
+    primaryStage.setWidth(1200);
+    primaryStage.setHeight(800);
+    primaryStage.centerOnScreen();
+    primaryStage.getIcons().add(new Image(Objects.requireNonNull(
+        ChaosGameController.class.getResourceAsStream("/Logo.png"))));
 
-    homePage = new HomePage(primaryStage);
-    homePage.getStylesheets().add(Objects.requireNonNull(
-        getClass().getResource("/globals.css")).toExternalForm());
+    HomePage homePage = new HomePage(primaryStage);
 
-    homePage.setActionOnButton("playGame", event -> playGameButtonAction());
-    homePage.setActionOnButton("files", event -> filesButtonAction());
+    //Creates a new NavigationModel and NavigationController,
+    // these acts to change the view of the application.
+    NavigationModel navigationModel = new NavigationModel();
+    NavigationController.getInstance(homePage, navigationModel);
 
     Scene scene = new Scene(homePage);
     primaryStage.setScene(scene);
     primaryStage.show();
-  }
 
-  private void playGameButtonAction() {
-  }
-  private void filesButtonAction() {
+    //Adds the global stylesheet to the scene.
+    scene.getStylesheets().add(
+        Objects.requireNonNull(getClass().getResource("/stylesheets/globals.css"))
+            .toExternalForm());
   }
 }
+
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/ChaosGame.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/ChaosGame.java
deleted file mode 100644
index 67493408da72fd68abc3a63daa1b8b6fd8d0e14f..0000000000000000000000000000000000000000
--- a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/ChaosGame.java
+++ /dev/null
@@ -1,78 +0,0 @@
-package edu.ntnu.idatt2003.group6.controller;
-
-import edu.ntnu.idatt2003.group6.models.chaosgame.ChaosCanvas;
-import edu.ntnu.idatt2003.group6.models.chaosgame.ChaosGameDescription;
-import edu.ntnu.idatt2003.group6.models.chaosgame.ChaosGameObserver;
-import edu.ntnu.idatt2003.group6.models.vector.Vector2D;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-
-/**
- * This class represents a chaos game. It contains a canvas for rendering the game, a description of
- * the game, and methods for running the game.
- *
- * @version 0.2.3
- * @since 0.2.3
- */
-public class ChaosGame {
-
-  private final List<ChaosGameObserver> observers;
-  private final ChaosCanvas canvas;
-  private final ChaosGameDescription description;
-  public Random random;
-  private Vector2D currentPoint;
-
-  /**
-   * Constructor for the ChaosGame class. Creates a new chaos game with the given description and
-   *
-   * @param description The description of the chaos game.
-   * @param width       The width of the canvas.
-   * @param height      The height of the canvas.
-   */
-  public ChaosGame(ChaosGameDescription description, int width, int height) {
-    this.canvas = new ChaosCanvas(
-        width, height, description.getMinCoords(), description.getMaxCoords());
-    this.description = description;
-    this.currentPoint = new Vector2D(0, 0);
-    this.random = new Random();
-    this.observers = new ArrayList<>();
-  }
-
-  /**
-   * Returns the canvas of the chaos game.
-   *
-   * @return The canvas of the chaos game.
-   */
-  public ChaosCanvas getCanvas() {
-    return canvas;
-  }
-
-  /**
-   * Returns the description of the chaos game.
-   *
-   * @param steps The number of steps to run the chaos game for.
-   */
-  public void runSteps(int steps) {
-    for (int i = 0; i < steps; i++) {
-      int randomIndex = random.nextInt(description.getTransformations().size());
-      currentPoint = description.getTransformations().get(randomIndex).transform(currentPoint);
-      canvas.putPixel(currentPoint);
-    }
-  }
-
-  public void addObserver(ChaosGameObserver observer) {
-    observers.add(observer);
-  }
-
-  public void removeObserver(ChaosGameObserver observer) {
-    observers.remove(observer);
-  }
-
-  public void notifyObservers() {
-    for (ChaosGameObserver observer : observers) {
-      observer.update(this);
-    }
-  }
-}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/chaosgame/ChaosGame.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/chaosgame/ChaosGame.java
new file mode 100644
index 0000000000000000000000000000000000000000..7c6a971f4745a5f1d868e20057829f1a12a7ba8e
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/chaosgame/ChaosGame.java
@@ -0,0 +1,165 @@
+package edu.ntnu.idatt2003.group6.controller.chaosgame;
+
+import edu.ntnu.idatt2003.group6.models.chaosgame.ChaosCanvas;
+import edu.ntnu.idatt2003.group6.models.chaosgame.ChaosGameDescription;
+import edu.ntnu.idatt2003.group6.models.chaosgame.GameType;
+import edu.ntnu.idatt2003.group6.models.vector.Vector2D;
+import edu.ntnu.idatt2003.group6.utils.exceptions.IllegalChaosGameException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * This class represents a chaos game. It contains a canvas for rendering the game, a description of
+ * the game, and methods for running the game.
+ *
+ * @version 0.2.3
+ * @since 0.2.3
+ */
+public class ChaosGame {
+  public final Random random;
+  private final ChaosCanvas canvas;
+  private final ChaosGameDescription description;
+  private final List<ChaosGameObserver> chaosGameObservers;
+  private Vector2D currentPoint;
+  private GameState state;
+
+  /**
+   * Constructor for the ChaosGame class. Creates a new chaos game with the given description and
+   *
+   * @param description The description of the chaos game.
+   * @param width       The width of the canvas.
+   * @param height      The height of the canvas.
+   * @throws IllegalChaosGameException If any of the parameters is invalid.
+   */
+  public ChaosGame(ChaosGameDescription description, int width, int height)
+      throws IllegalChaosGameException {
+    try {
+      if (description == null) {
+        throw new IllegalArgumentException("Description cannot be null");
+      }
+      if (width <= 0) {
+        throw new IllegalArgumentException("Width must be greater than 0");
+      }
+      if (height <= 0) {
+        throw new IllegalArgumentException("Height must be greater than 0");
+      }
+      this.canvas = new ChaosCanvas(
+          width, height, description.getMinCoords(), description.getMaxCoords());
+      this.description = description;
+      this.currentPoint = new Vector2D(0, 0);
+      this.random = new Random();
+      this.chaosGameObservers = new ArrayList<>();
+    } catch (IllegalArgumentException e) {
+      throw new IllegalChaosGameException("Illegal chaos game description", e);
+    }
+  }
+
+  /**
+   * Returns the state of the chaos game.
+   *
+   * @return The state of the chaos game.
+   */
+  public GameState getState() {
+    return state;
+  }
+
+  /**
+   * Sets the state of the chaos game.
+   *
+   * @param state The state of the chaos game.
+   */
+  public void setState(GameState state) {
+    this.state = state;
+    notifyObservers();
+  }
+
+  /**
+   * Adds an observer to the chaos game.
+   *
+   * @param chaosGameObserver The observer to add.
+   * @throws IllegalArgumentException If the observer is null.
+   */
+  public void addObserver(ChaosGameObserver chaosGameObserver) throws IllegalArgumentException {
+    validateObserver(chaosGameObserver);
+    chaosGameObservers.add(chaosGameObserver);
+  }
+
+  /**
+   * Removes an observer from the chaos game.
+   *
+   * @param chaosGameObserver The observer to remove.
+   * @throws IllegalArgumentException If the observer is null.
+   */
+  public void removeObserver(ChaosGameObserver chaosGameObserver) throws IllegalArgumentException {
+    validateObserver(chaosGameObserver);
+    chaosGameObservers.remove(chaosGameObserver);
+  }
+
+  /**
+   * Validates the observer.
+   *
+   * @param chaosGameObserver The observer to validate.
+   */
+  private void validateObserver(ChaosGameObserver chaosGameObserver) {
+    if (chaosGameObserver == null) {
+      throw new IllegalArgumentException("Observer cannot be null");
+    }
+  }
+
+  /**
+   * Notifies the observers of the chaos game changing state.
+   */
+  private void notifyObservers() {
+    chaosGameObservers.forEach(chaosGameObserver -> chaosGameObserver.update(state));
+  }
+
+  /**
+   * Returns the canvas of the chaos game.
+   *
+   * @return The canvas of the chaos game.
+   */
+  public ChaosCanvas getCanvas() {
+    return canvas;
+  }
+
+  /**
+   * Returns the description of the chaos game.
+   *
+   * @param steps The number of steps to run the chaos game for.
+   * @throws IllegalArgumentException If the number of steps is less than 0.
+   */
+  public void runSteps(int steps) throws IllegalArgumentException {
+    if (steps < 1) {
+      throw new IllegalArgumentException("Number of steps must be equal or greater than 1");
+    }
+    for (int i = 0; i < steps; i++) {
+      setState(GameState.RUNNING);
+      notifyObservers();
+      int randomIndex = random.nextInt(description.getTransformations().size());
+      currentPoint = description.getTransformations().get(randomIndex).transform(currentPoint);
+      canvas.putPixel(currentPoint);
+    }
+    setState(GameState.DONE);
+    notifyObservers();
+  }
+
+  /**
+   * Returns the description of the chaos game.
+   *
+   * @return The description of the chaos game.
+   */
+  public ChaosGameDescription getChaosGameDescription() {
+    return description;
+  }
+
+  /**
+   * Returns the game type of the chaos game.
+   *
+   * @return The game type of the chaos game.
+   */
+  public GameType getGameType() {
+    return description.getGameType();
+  }
+
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/chaosgame/ChaosGameController.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/chaosgame/ChaosGameController.java
new file mode 100644
index 0000000000000000000000000000000000000000..b9238ab236f5643ab05c32cd03d1efdf5bc9d711
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/chaosgame/ChaosGameController.java
@@ -0,0 +1,322 @@
+package edu.ntnu.idatt2003.group6.controller.chaosgame;
+
+
+import static edu.ntnu.idatt2003.group6.utils.ControllerUtils.getAttributesAffineControlsList;
+import static edu.ntnu.idatt2003.group6.utils.ControllerUtils.getAttributesJuliaControls;
+import static edu.ntnu.idatt2003.group6.utils.ControllerUtils.getMaxCoordsControls;
+import static edu.ntnu.idatt2003.group6.utils.ControllerUtils.getMinCoordsControls;
+import static edu.ntnu.idatt2003.group6.utils.ControllerUtils.setAttributesAffineControlsList;
+import static edu.ntnu.idatt2003.group6.utils.Utils.inputStringToInt;
+
+import edu.ntnu.idatt2003.group6.models.chaosgame.GameType;
+import edu.ntnu.idatt2003.group6.models.files.FileModel;
+import edu.ntnu.idatt2003.group6.models.transformation.JuliaTransform;
+import edu.ntnu.idatt2003.group6.models.vector.Vector2D;
+import edu.ntnu.idatt2003.group6.utils.ControllerUtils;
+import edu.ntnu.idatt2003.group6.view.alert.AlertError;
+import edu.ntnu.idatt2003.group6.view.alert.AlertInputFileName;
+import edu.ntnu.idatt2003.group6.view.frames.HomePage;
+import edu.ntnu.idatt2003.group6.view.gamecontrols.AffineControlsView;
+import edu.ntnu.idatt2003.group6.view.gamecontrols.AffineTransformationControls;
+import edu.ntnu.idatt2003.group6.view.gamecontrols.JuliaTransformationControls;
+import java.util.List;
+import java.util.Objects;
+import java.util.logging.Logger;
+
+
+/**
+ * The controller for the ChaosGame model. This class is responsible for running the chaos game and
+ * updating the view the result.
+ *
+ * @version 0.3.2
+ * @since 0.3.2
+ */
+public class ChaosGameController implements ChaosGameObserver {
+  private static final Logger LOGGER = Logger.getLogger(ChaosGameController.class.getName());
+  private ChaosGame model;
+  private final HomePage view;
+  private GameType gameType;
+  private final AffineControlsView affineControlsView;
+  private final FileModel fileModel = FileModel.getInstance();
+
+  /**
+   * Creates a new ChaosGameController.
+   *
+   * @param model The model for the chaos game.
+   * @param view  The view for the chaos game.
+   */
+  public ChaosGameController(ChaosGame model, HomePage view) {
+    this.model = model;
+    this.view = view;
+    this.gameType = model.getGameType();
+    this.affineControlsView = view.getAffineControlsView();
+    model.addObserver(this);
+
+    setAttributesView();
+    setButtonActions();
+  }
+
+  /**
+   * Sets the actions for the buttons in the view.
+   */
+  private void setButtonActions() {
+    view.getButtonBoxControls().getRunGameButton().setOnAction(e -> {
+      try {
+        this.runGame();
+      } catch (Exception ex) {
+        String message = ex.getMessage().split("@")[0];
+        String description = ex.getMessage().split("@")[1];
+        AlertError alertError = new AlertError(message, description);
+        alertError.showAlertError();
+        e.consume();
+      }
+    });
+    view.getButtonBoxControls().getLoadParametersButton().setOnAction(e -> {
+      try {
+        this.loadNewParameter();
+      } catch (Exception ex) {
+        String message = ex.getMessage().split("@")[0];
+        String description = ex.getMessage().split("@")[1];
+        AlertError alertError = new AlertError(message, description);
+        alertError.showAlertError();
+        e.consume();
+      }
+    });
+    view.getButtonBoxControls().getSaveButton().setOnAction(e -> {
+      try {
+        this.saveFile();
+      } catch (Exception ex) {
+        String message = ex.getMessage().split("@")[0];
+        String description = ex.getMessage().split("@")[1];
+        AlertError alertError = new AlertError(message, description);
+        alertError.showAlertError();
+        e.consume();
+      }
+    });
+    affineControlsView.getAddTransformButton().setOnAction(e -> {
+      try {
+        this.addAffineTransformation();
+      } catch (Exception ex) {
+        String message = ex.getMessage().split("@")[0];
+        String description = ex.getMessage().split("@")[1];
+        AlertError alertError = new AlertError(message, description);
+        alertError.showAlertError();
+        e.consume();
+      }
+    });
+    affineControlsView.getRemoveTransformButton().setOnAction(e -> {
+      try {
+        this.removeAffineTransformation();
+      } catch (Exception ex) {
+        String message = ex.getMessage().split("@")[0];
+        String description = ex.getMessage().split("@")[1];
+        AlertError alertError = new AlertError(message, description);
+        alertError.showAlertError();
+        e.consume();
+      }
+    });
+  }
+
+  /**
+   * Sets the attributes for the view.
+   */
+  private void setAttributesView() {
+    try {
+      setAttributesCommon();
+      if (gameType == GameType.JULIA) {
+        setJuliaAttributes();
+      } else {
+        setAffineAttributes();
+      }
+    } catch (Exception e) {
+      String message = e.getMessage().split("@")[0];
+      String description = e.getMessage().split("@")[1];
+      AlertError alertError = new AlertError(message, description);
+      alertError.showAlertError();
+    }
+  }
+
+  /**
+   * Sets the common attributes in a chaos game for the view.
+   */
+  private void setAttributesCommon() {
+    try {
+      ControllerUtils.setAttributesCommon(view.getAttributeControls(),
+          model.getChaosGameDescription());
+    } catch (Exception e) {
+      LOGGER.warning("Error setting common attributes");
+      throw new IllegalArgumentException("Error setting common attributes @" + e.getMessage());
+    }
+  }
+
+  /**
+   * Sets the attributes for the Julia transformation in the view.
+   */
+  private void setJuliaAttributes() {
+    JuliaTransformationControls juliaView = view.getJuliaTransformationControls();
+
+    JuliaTransform julia =
+        (JuliaTransform) model.getChaosGameDescription().getTransformations().getFirst();
+    juliaView.setImaginaryC(String.valueOf(julia.getPoint().getX1()));
+    juliaView.setRealC(String.valueOf(julia.getPoint().getX0()));
+
+    view.setJuliaTransformationControls(juliaView);
+  }
+
+  /**
+   * Sets the attributes for the affine transformations in the view.
+   *
+   * @throws IllegalArgumentException If an error occurs while setting the affine attributes.
+   */
+  private void setAffineAttributes() throws IllegalArgumentException {
+    try {
+      List<AffineTransformationControls> affineControls = setAttributesAffineControlsList(
+          model.getChaosGameDescription());
+      affineControlsView.setAffineControlsList(affineControls);
+    } catch (Exception e) {
+      LOGGER.warning("Error setting affine attributes");
+      throw new IllegalArgumentException("Error setting affine attributes @" + e.getMessage());
+    }
+  }
+
+  /**
+   * Adds an affine transformation to the view.
+   */
+  private void addAffineTransformation() {
+    try {
+      List<AffineTransformationControls> affineTransformList =
+          affineControlsView.getAffineControlsList();
+      affineTransformList.add(new AffineTransformationControls());
+      affineControlsView.setAffineControlsList(affineTransformList);
+    } catch (Exception e) {
+      LOGGER.warning("Error adding affine transformation");
+      throw new IllegalArgumentException("Error adding affine transformation @" + e.getMessage());
+    }
+  }
+
+  /**
+   * Removes an affine transformation from the view.
+   */
+  private void removeAffineTransformation() {
+    try {
+      List<AffineTransformationControls> affineTransformList =
+          affineControlsView.getAffineControlsList();
+      if (affineTransformList.size() > 1) {
+        affineTransformList.removeLast();
+      }
+      affineControlsView.setAffineControlsList(affineTransformList);
+    } catch (Exception e) {
+      LOGGER.warning("Error removing affine transformation");
+      throw new IllegalArgumentException("Error removing affine transformation @" + e.getMessage());
+    }
+  }
+
+  /**
+   * runs the chaos game.
+   */
+  private void runGame() {
+    try {
+      model.getCanvas().clear();
+      int steps = inputStringToInt(view.getAttributeControls().getStepsField());
+      model.runSteps(steps);
+    } catch (Exception e) {
+      LOGGER.warning("Error running game");
+      throw new IllegalArgumentException("Error running game @" + e.getMessage());
+    }
+  }
+
+  /**
+   * Saves the game parameters to a file.
+   */
+  private void loadNewParameter() throws IllegalArgumentException {
+    try {
+      Vector2D minCoords = getMinCoordsControls(view.getAttributeControls());
+      Vector2D maxCoords = getMaxCoordsControls(view.getAttributeControls());
+      if (gameType == GameType.JULIA) {
+        loadJulia(minCoords, maxCoords);
+      } else {
+        loadAffine(minCoords, maxCoords);
+      }
+    } catch (Exception e) {
+      LOGGER.warning("Error loading new parameters");
+      throw new IllegalArgumentException("Error loading new parameters @" + e.getMessage());
+    }
+  }
+
+  /**
+   * Loads a Julia transformation.
+   *
+   * @param minCoords the minimum coordinates for the transformation.
+   * @param maxCoords the maximum coordinates for the transformation.
+   * @throws IllegalArgumentException If an error occurs while loading the Julia transformation.
+   */
+  private void loadJulia(Vector2D minCoords, Vector2D maxCoords) throws IllegalArgumentException {
+    model = new ChaosGame(getAttributesJuliaControls(
+        view.getJuliaTransformationControls(), minCoords, maxCoords),
+        1000, 1000);
+    model.addObserver(this);
+    this.gameType = model.getGameType();
+    setAttributesView();
+  }
+
+  /**
+   * Loads an affine transformation.
+   *
+   * @param minCoords the minimum coordinates for the transformation.
+   * @param maxCoords the maximum coordinates for the transformation.
+   * @throws IllegalArgumentException If an error occurs while loading the affine transformation.
+   */
+  private void loadAffine(Vector2D minCoords, Vector2D maxCoords) throws IllegalArgumentException {
+    List<AffineTransformationControls> affineControls = affineControlsView.getAffineControlsList();
+    model = new ChaosGame(getAttributesAffineControlsList(
+        affineControls, minCoords, maxCoords),
+        1000, 1000);
+    model.addObserver(this);
+
+    setAttributesView();
+  }
+
+  /**
+   * Saves the game parameters to a file.
+   *
+   * @throws IllegalArgumentException If an error occurs while saving the file.
+   */
+  private void saveFile() throws IllegalArgumentException {
+    AlertInputFileName alert = new AlertInputFileName();
+    alert.showAlert();
+    String filename = alert.getFileName();
+
+    //Todo: Add try catch
+    if (filename == null || filename.isEmpty()) {
+      throw new IllegalArgumentException("Save to file did not execute @"
+          + " Filename cannot be empty");
+    } else {
+      try {
+        fileModel.addFile(filename, model.getChaosGameDescription());
+      } catch (Exception e) {
+        LOGGER.warning("Error saving file");
+        throw new IllegalArgumentException("Error saving file @" + e.getMessage());
+      }
+    }
+  }
+
+
+  /**
+   * Updates the view with the transformation picture.
+   */
+  private void updateView() {
+    view.setTransformationPicture(model);
+  }
+
+  /**
+   * Updates the controller based on the game state.
+   *
+   * @param state The state of the game.
+   */
+  @Override
+  public void update(GameState state) {
+    if (Objects.requireNonNull(state) == GameState.DONE) {
+      updateView();
+    }
+  }
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/chaosgame/ChaosGameObserver.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/chaosgame/ChaosGameObserver.java
new file mode 100644
index 0000000000000000000000000000000000000000..f25f2656930422531945e22e041881ec3631c151
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/chaosgame/ChaosGameObserver.java
@@ -0,0 +1,12 @@
+package edu.ntnu.idatt2003.group6.controller.chaosgame;
+
+/**
+ * An interface for observing the state of the chaos game.
+ * The observer will be notified when the state of the game changes.
+ *
+ * @version 0.3.1
+ * @since 0.3.1
+ */
+public interface ChaosGameObserver {
+  void update(GameState state);
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/chaosgame/GameState.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/chaosgame/GameState.java
new file mode 100644
index 0000000000000000000000000000000000000000..b9e1f9102d06657ce9e56b09ac4968f08e863ebc
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/chaosgame/GameState.java
@@ -0,0 +1,13 @@
+package edu.ntnu.idatt2003.group6.controller.chaosgame;
+
+/**
+ * An enum representing the state of the game.
+ * Gives a reference to the current state of the game to decide further actions.
+ *
+ * @version 3.2
+ * @since 3.2
+ */
+public enum GameState {
+  RUNNING,
+  DONE
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/file/FileController.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/file/FileController.java
new file mode 100644
index 0000000000000000000000000000000000000000..87bdb079e337bb699d84154477edf24acace5661
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/file/FileController.java
@@ -0,0 +1,400 @@
+package edu.ntnu.idatt2003.group6.controller.file;
+
+import static edu.ntnu.idatt2003.group6.models.chaosgame.ChaosGameDescriptionFactory.createChaosGameDescription;
+import static edu.ntnu.idatt2003.group6.utils.ControllerUtils.getAttributesAffineControlsList;
+import static edu.ntnu.idatt2003.group6.utils.ControllerUtils.getAttributesJuliaControls;
+import static edu.ntnu.idatt2003.group6.utils.ControllerUtils.getMaxCoordsControls;
+import static edu.ntnu.idatt2003.group6.utils.ControllerUtils.getMinCoordsControls;
+import static edu.ntnu.idatt2003.group6.utils.ControllerUtils.setAttributesAffineControlsList;
+import static edu.ntnu.idatt2003.group6.utils.ControllerUtils.setAttributesCommon;
+import static edu.ntnu.idatt2003.group6.utils.ControllerUtils.setAttributesJulia;
+
+import edu.ntnu.idatt2003.group6.controller.navigation.NavigationController;
+import edu.ntnu.idatt2003.group6.models.chaosgame.ChaosGameDescription;
+import edu.ntnu.idatt2003.group6.models.chaosgame.GameType;
+import edu.ntnu.idatt2003.group6.models.files.FileModel;
+import edu.ntnu.idatt2003.group6.models.files.FileObserver;
+import edu.ntnu.idatt2003.group6.models.files.FileState;
+import edu.ntnu.idatt2003.group6.models.vector.Vector2D;
+import edu.ntnu.idatt2003.group6.view.alert.AlertError;
+import edu.ntnu.idatt2003.group6.view.buttonbox.ButtonBoxFiles;
+import edu.ntnu.idatt2003.group6.view.buttonbox.CustomToggleButton;
+import edu.ntnu.idatt2003.group6.view.frames.EditFileFrame;
+import edu.ntnu.idatt2003.group6.view.frames.HomePage;
+import edu.ntnu.idatt2003.group6.view.gamecontrols.AffineControlsView;
+import edu.ntnu.idatt2003.group6.view.gamecontrols.AffineTransformationControls;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.logging.Logger;
+
+/**
+ * FileController is a class that controls the files in the application.
+ * It is used to create, edit and delete files.
+ * It is also used to save and load files.
+ * It is a singleton class.
+ * It implements the FileObserver interface.
+ * It has a list of FileControllerObservers.
+ *
+ * @version 0.3.2
+ * @see FileObserver
+ * @see FileControllerObserver
+ * @since 0.3.2
+ */
+public class FileController implements FileObserver {
+
+  private static final Logger LOGGER = Logger.getLogger(FileController.class.getName());
+  private static FileController instance = null;
+  private final ButtonBoxFiles buttonBoxFiles;
+  private final FileModel files;
+  private final NavigationController controller;
+  private final EditFileFrame editFileFrame;
+  private final AffineControlsView affineControlsView;
+  private final List<FileControllerObserver> observers = new ArrayList<>();
+  private ChaosGameDescription chaosGameDescription;
+  private Vector2D minCoords;
+  private Vector2D maxCoords;
+  private List<CustomToggleButton> fileButtons;
+
+
+  /**
+   * Constructor for FileController.
+   *
+   * @param view       HomePage of the application
+   * @param controller NavigationController of the application
+   */
+  private FileController(HomePage view, NavigationController controller) {
+    this.files = FileModel.getInstance();
+    this.buttonBoxFiles = view.getButtonBoxFiles();
+    this.controller = controller;
+    editFileFrame = view.getEditFileFrame();
+    affineControlsView = editFileFrame.getAffineControlsView();
+
+    files.addObserver(this);
+
+    buttonsController();
+    showEditFileView();
+    deleteFile();
+    updateButtons();
+  }
+
+  /**
+   * Returns an instance of the FileController class.
+   * If the instance is null, it creates a new instance.
+   * Following the singleton design pattern.
+   *
+   * @param view       HomePage of the application
+   * @param controller NavigationController of the application
+   * @return an instance of the FileController class
+   */
+  public static FileController getInstance(HomePage view, NavigationController controller) {
+    if (instance == null) {
+      instance = new FileController(view, controller);
+    }
+    return instance;
+  }
+
+  /**
+   * Adds an observer to the list of observers.
+   *
+   * @param observer the observer to add
+   */
+  public void addObserver(FileControllerObserver observer) {
+    observers.add(observer);
+  }
+
+  /**
+   * Notifies all observers in the list of observers.
+   */
+  public void notifyObservers() {
+    for (FileControllerObserver observer : observers) {
+      observer.update();
+    }
+  }
+
+  /**
+   * Sets the actions of the buttons in the FileController.
+   */
+  private void buttonsController() {
+    affineControlsView.getAddTransformButton().setOnAction(e -> {
+      try {
+        addTransformAffine();
+      } catch (Exception ex) {
+        String message = ex.getMessage().split("@")[0];
+        String description = ex.getMessage().split("@")[1];
+        AlertError alertError = new AlertError(message, description);
+        alertError.showAlertError();
+        e.consume();
+      }
+    });
+
+    affineControlsView.getRemoveTransformButton().setOnAction(e -> {
+      try {
+        removeTransformAffine();
+      } catch (Exception ex) {
+        String message = ex.getMessage().split("@")[0];
+        String description = ex.getMessage().split("@")[1];
+        AlertError alertError = new AlertError(message, description);
+        alertError.showAlertError();
+        e.consume();
+      }
+    });
+
+    editFileFrame.getSaveButton().setOnAction(e -> {
+      try {
+        updateFileAttributes();
+      } catch (Exception ex) {
+        String message = ex.getMessage().split("@")[0];
+        String description = ex.getMessage().split("@")[1];
+        AlertError alertError = new AlertError(message, description);
+        alertError.showAlertError();
+        e.consume();
+      }
+    });
+
+    editFileFrame.getJuliaTransformButton().setOnAction(e -> {
+      try {
+        chaosGameDescription = createChaosGameDescription(GameType.JULIA_NEW);
+        showFileAttributes();
+      } catch (IllegalArgumentException ex) {
+        String message = ex.getMessage().split("@")[0];
+        String description = ex.getMessage().split("@")[1];
+        AlertError alertError = new AlertError(message, description);
+        alertError.showAlertError();
+        e.consume();
+      }
+    });
+
+    editFileFrame.getAffineTransformButton().setOnAction(e -> {
+      try {
+        chaosGameDescription = createChaosGameDescription(GameType.AFFINE_NEW);
+        showFileAttributes();
+      } catch (IllegalArgumentException ex) {
+        String message = ex.getMessage().split("@")[0];
+        String description = ex.getMessage().split("@")[1];
+        AlertError alertError = new AlertError(message, description);
+        alertError.showAlertError();
+        e.consume();
+      }
+    });
+
+    buttonBoxFiles.getNewFileButton().setOnAction(e -> {
+      editFileFrame.clearFields();
+      editFileFrame.setFileNameField("New file");
+      buttonBoxFiles.getToggleButtons().selectToggle(null);
+      controller.goToEditFile();
+    });
+  }
+
+  /**
+   * Adds a new affine transformation to the list of affine transformations.
+   */
+  private void addTransformAffine() {
+    List<AffineTransformationControls> affineTransformationControlsList =
+        affineControlsView.getAffineControlsList();
+    AffineTransformationControls affineView = new AffineTransformationControls();
+    affineView.setTransformationNumber(String.valueOf(affineTransformationControlsList.size() + 1));
+    try {
+      affineTransformationControlsList.add(affineView);
+    } catch (Exception e) {
+      LOGGER.severe(e.getMessage());
+      throw new IllegalArgumentException("Failed to add transformation @" + e.getMessage());
+    }
+    affineControlsView.setAffineControlsList(affineTransformationControlsList);
+  }
+
+  /**
+   * Removes the last affine transformation from the list of affine transformations.
+   */
+  private void removeTransformAffine() {
+    List<AffineTransformationControls> affineTransformationControlsList =
+        affineControlsView.getAffineControlsList();
+    try {
+      affineTransformationControlsList.removeLast();
+    } catch (Exception e) {
+      LOGGER.severe(e.getMessage());
+      throw new IllegalArgumentException("Failed to remove transformation @" + e.getMessage());
+    }
+    affineControlsView.setAffineControlsList(affineTransformationControlsList);
+  }
+
+  /**
+   * Shows the edit file view.
+   */
+  private void showEditFileView() {
+    buttonBoxFiles.getEditFileButton().setOnAction(e -> {
+      try {
+        for (CustomToggleButton fileButton : fileButtons) {
+          if (fileButton.isSelected()) {
+            controller.goToEditFile();
+            chaosGameDescription = files.getFile(fileButton.getText());
+            editFileFrame.setFileNameField(fileButton.getText());
+            showFileAttributes();
+            break;
+          }
+        }
+      } catch (IllegalArgumentException ex) {
+        String message = ex.getMessage().split("@")[0];
+        String description = ex.getMessage().split("@")[1];
+        AlertError alertError = new AlertError(message, description);
+        alertError.showAlertError();
+        e.consume();
+      }
+    });
+  }
+
+  /**
+   * Deletes a file from the list of files depending on the selected file.
+   */
+  private void deleteFile() {
+    buttonBoxFiles.getDeleteFileButton().setOnAction(e -> {
+      try {
+        for (CustomToggleButton fileButton : fileButtons) {
+          if (fileButton.isSelected()) {
+            files.removeFile(fileButton.getText());
+
+            break;
+          }
+        }
+      } catch (IllegalArgumentException ex) {
+        String message = ex.getMessage().split("@")[0];
+        String description = ex.getMessage().split("@")[1];
+        AlertError alertError = new AlertError(message, description);
+        alertError.showAlertError();
+        e.consume();
+      }
+    });
+  }
+
+  /**
+   * Sets the attributes of the file.
+   *
+   * @throws IllegalArgumentException if the file does not contain the correct attributes.
+   */
+  private void showFileAttributes() throws IllegalArgumentException {
+    //Sets min and max coords
+    try {
+      setAttributesCommon(editFileFrame.getAttributeControls(), chaosGameDescription);
+    } catch (Exception e) {
+      LOGGER.severe(e.getMessage());
+      throw new IllegalArgumentException("Failed to set file attributes @" + e.getMessage());
+    }
+    editFileFrame.showFileAttributes();
+    //Checks game type
+    try {
+      if (chaosGameDescription.getGameType().equals(GameType.JULIA)) {
+        showJuliaAttributes();
+      } else if (chaosGameDescription.getGameType().equals(GameType.AFFINE)) {
+        showAffineAttributes();
+      }
+    } catch (Exception e) {
+      LOGGER.severe(e.getMessage());
+      throw new IllegalArgumentException("Failed to show file attributes @" + e.getMessage());
+    }
+  }
+
+  /**
+   * Sets the attributes of the Julia transformation.
+   *
+   * @throws IllegalArgumentException if the file does not contain the correct attributes.
+   */
+  private void showJuliaAttributes() throws IllegalArgumentException {
+    editFileFrame.setJuliaTransformControls(
+        setAttributesJulia(chaosGameDescription));
+    editFileFrame.showJuliaAttributes();
+  }
+
+  /**
+   * Sets the attributes of the affine transformations.
+   *
+   * @throws IllegalArgumentException if the file does not contain the correct attributes.
+   */
+  private void showAffineAttributes() throws IllegalArgumentException {
+    List<AffineTransformationControls> affineControls = setAttributesAffineControlsList(
+        chaosGameDescription);
+
+    affineControlsView.setAffineControlsList(affineControls);
+    editFileFrame.showAffineAttributes();
+  }
+
+
+  /**
+   * Updates the file attributes.
+   *
+   * @throws IllegalArgumentException if the file does not contain the correct attributes.
+   */
+  private void updateFileAttributes() throws IllegalArgumentException {
+    try {
+      minCoords = getMinCoordsControls(editFileFrame.getAttributeControls());
+      maxCoords = getMaxCoordsControls(editFileFrame.getAttributeControls());
+
+      if (chaosGameDescription.getGameType().equals(GameType.JULIA)) {
+        updateJuliaAttributes();
+      } else {
+        updateAffineAttributes();
+      }
+
+    } catch (Exception e) {
+      LOGGER.severe(e.getMessage());
+      throw new IllegalArgumentException("Failed to save file attributes, "
+          + "File did not contain the correct attributes. @" + e.getMessage());
+    }
+  }
+
+  /**
+   * Updates the Julia attributes.
+   *
+   * @throws IllegalArgumentException if the view field does not contain the correct attributes.
+   */
+  private void updateJuliaAttributes() throws IllegalArgumentException {
+    chaosGameDescription = getAttributesJuliaControls(
+        editFileFrame.getJuliaTransformationControls(), minCoords, maxCoords);
+    saveFile();
+  }
+
+  /**
+   * Updates the affine attributes.
+   *
+   * @throws IllegalArgumentException if the view field does not contain the correct attributes.
+   */
+  private void updateAffineAttributes() throws IllegalArgumentException {
+    chaosGameDescription = getAttributesAffineControlsList(
+        editFileFrame.getAffineTransformControls(), minCoords, maxCoords);
+    saveFile();
+  }
+
+  /**
+   * Saves the file.
+   *
+   * @throws IllegalArgumentException if the file does not contain the correct attributes.
+   */
+  private void saveFile() throws IllegalArgumentException {
+    String filename = editFileFrame.getFileNameField();
+    files.addFile(filename, chaosGameDescription);
+  }
+
+
+  /**
+   * Updates the buttons in the file controller.
+   */
+  private void updateButtons() {
+    buttonBoxFiles.clearFileButtons();
+    List<String> file = files.getFiles();
+    file.forEach(buttonBoxFiles::addFileButton);
+    fileButtons = buttonBoxFiles.getFileButtonsToggle();
+  }
+
+
+  /**
+   * Updates the file buttons and notifies the observers.
+   *
+   * @param state the state of the file.
+   */
+  @Override
+  public void update(FileState state) {
+    if (Objects.requireNonNull(state) == FileState.FILES_CHANGED) {
+      updateButtons();
+      notifyObservers();
+    }
+  }
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/file/FileControllerObserver.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/file/FileControllerObserver.java
new file mode 100644
index 0000000000000000000000000000000000000000..53f0b34cc44b9c979cd8fe74d6828235e500d026
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/file/FileControllerObserver.java
@@ -0,0 +1,8 @@
+package edu.ntnu.idatt2003.group6.controller.file;
+
+/**
+ * Interface for the FileControllerObserver class.
+ */
+public interface FileControllerObserver {
+  void update();
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/navigation/NavigationController.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/navigation/NavigationController.java
new file mode 100644
index 0000000000000000000000000000000000000000..6ab0693dd781bf27212e71d1096c0c0e7bf27c2d
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/navigation/NavigationController.java
@@ -0,0 +1,214 @@
+package edu.ntnu.idatt2003.group6.controller.navigation;
+
+import static edu.ntnu.idatt2003.group6.models.chaosgame.ChaosGameDescriptionFactory.createChaosGameDescription;
+
+import edu.ntnu.idatt2003.group6.controller.chaosgame.ChaosGame;
+import edu.ntnu.idatt2003.group6.controller.chaosgame.ChaosGameController;
+import edu.ntnu.idatt2003.group6.controller.file.FileController;
+import edu.ntnu.idatt2003.group6.controller.file.FileControllerObserver;
+import edu.ntnu.idatt2003.group6.models.chaosgame.ChaosGameDescription;
+import edu.ntnu.idatt2003.group6.models.chaosgame.GameType;
+import edu.ntnu.idatt2003.group6.models.files.FileModel;
+import edu.ntnu.idatt2003.group6.models.navigation.NavigationModel;
+import edu.ntnu.idatt2003.group6.models.navigation.NavigationState;
+import edu.ntnu.idatt2003.group6.view.alert.AlertError;
+import edu.ntnu.idatt2003.group6.view.frames.HomePage;
+
+/**
+ * The NavigationController class controls the navigation of the application.
+ * It changes the view of the application based on the NavigationState.
+ *
+ * @version 0.3.2
+ * @since 0.3.2
+ */
+public class NavigationController implements FileControllerObserver {
+
+  private static NavigationController instance = null;
+  private final HomePage view;
+  private final NavigationModel model;
+  @SuppressWarnings("unused")
+  private ChaosGameController gameController;
+  private final FileModel fileModel = FileModel.getInstance();
+
+  /**
+   * Constructor for NavigationController. A singleton class.
+   * Create a new NavigationController with a reference to the HomePage and NavigationModel.
+   *
+   * @param view  The HomePage to bind the navigation to.
+   * @param model The NavigationModel to bind the navigation to.
+   */
+  private NavigationController(HomePage view, NavigationModel model) {
+    this.view = view;
+    this.model = model;
+    model.addObserver(view);
+
+    //Buttons for each of the files are created by the FileController by observing the FileModel
+    FileController fileController = FileController.getInstance(view, this);
+    fileController.addObserver(this);
+
+    SettingsController.getInstance(view);
+
+    //Buttons to go to different views from the menu
+    view.getButtonBoxMenu().getPlayGameButton().setOnAction(e -> this.goToSelectGame());
+    view.getButtonBoxMenu().getFilesButton().setOnAction(e -> this.goToFiles());
+    view.getButtonBoxMenu().getSettingsButton().setOnAction(e -> this.goToSettings());
+    view.getButtonBoxMenu().getQuitButton().setOnAction(e -> System.exit(0));
+
+
+    //Buttons to go to the menu
+    view.getButtonBoxControls().getBackToMenuButton().setOnAction(e -> this.goToMenu());
+    view.getButtonBoxFiles().getBackToMenuButton().setOnAction(e -> this.goToMenu());
+    view.getButtonBoxSettings().getBackToMenuButton().setOnAction(e -> this.goToMenu());
+    view.getButtonBoxGames().getBackToMenuButton().setOnAction(e -> this.goToMenu());
+
+    //Select which game to play
+    selectGame();
+  }
+
+  /**
+   * Returns the instance of the NavigationController.
+   * If the instance is null, a new instance is created.
+   *
+   * @param view  The HomePage to bind the navigation to.
+   * @param model The NavigationModel to bind the navigation to.
+   * @return The instance of the NavigationController.
+   */
+  public static NavigationController getInstance(HomePage view, NavigationModel model) {
+    if (instance == null) {
+      instance = new NavigationController(view, model);
+    }
+    return instance;
+  }
+
+  /**
+   * Starts the Affine game with the given ChaosGame.
+   *
+   * @param game The ChaosGame to start.
+   */
+  private void startGameAffine(ChaosGame game) {
+    gameController = new ChaosGameController(game, view);
+    goToPlayAffine();
+  }
+
+  /**
+   * Starts the Julia game with the given ChaosGame.
+   *
+   * @param game The ChaosGame to start.
+   */
+  private void startGameJulia(ChaosGame game) {
+    gameController = new ChaosGameController(game, view);
+    goToPlayJulia();
+  }
+
+  /**
+   * Selects which game to play.
+   */
+  private void selectGame() {
+    //Empty Affine game
+    view.getButtonBoxGames().getNewAffineButtonButton().setOnAction(e -> this.startGameAffine(
+        new ChaosGame(createChaosGameDescription(GameType.AFFINE_NEW), 700, 700)));
+    //Empty Julia game
+    view.getButtonBoxGames().getNewJuliaButtonButton().setOnAction(e -> this.startGameJulia(
+        new ChaosGame(createChaosGameDescription(GameType.JULIA_NEW), 700, 700)));
+    //Sierpinski game
+    view.getButtonBoxGames().getSierpinskiButton().setOnAction(e -> this.startGameAffine(
+        new ChaosGame(createChaosGameDescription(GameType.SIERPINSKI), 700, 700)));
+    //Julia game
+    view.getButtonBoxGames().getJuliaButton().setOnAction(e -> this.startGameJulia(
+        new ChaosGame(createChaosGameDescription(GameType.JULIA), 700, 700)));
+    //Barnsley game
+    view.getButtonBoxGames().getBarnsleyButton().setOnAction(e -> this.startGameAffine(
+        new ChaosGame(createChaosGameDescription(GameType.BARNSLEY), 700, 700)));
+    //Show games from file
+    view.getButtonBoxGames().getFileButton().setOnAction(e -> this.goToSelectGameFiles());
+
+    selectGameFiles();
+  }
+
+  /**
+   * Selects the game files to play.
+   */
+  public void selectGameFiles() {
+    //Gets the buttons for each file made by the FileController
+    view.getButtonBoxFiles().getFileButtons().forEach(button -> button.setOnAction(e -> {
+      try {
+        ChaosGameDescription game = fileModel.getFile(button.getText());
+        if (game.getGameType().equals(GameType.JULIA)) {
+          startGameJulia(new ChaosGame(game, 700, 700));
+        } else {
+          startGameAffine(new ChaosGame(game, 700, 700));
+        }
+      } catch (Exception ex) {
+        String message = ex.getMessage().split("@")[0];
+        String description = ex.getMessage().split("@")[1];
+        AlertError alertError = new AlertError(message, description);
+        alertError.showAlertError();
+        e.consume();
+      }
+    }));
+  }
+
+  /**
+   * Selects the game files to show.
+   */
+  private void goToFiles() {
+    model.setState(NavigationState.SELECT_FILE);
+  }
+
+  /**
+   * Allows for editing a file.
+   */
+  public void goToEditFile() {
+    model.setState(NavigationState.EDIT_FILE);
+  }
+
+  /**
+   * Allows for selecting a game to play.
+   */
+  private void goToSelectGame() {
+    model.setState(NavigationState.SELECT_GAME);
+  }
+
+  /**
+   * Allows for selecting a game file to play.
+   */
+  private void goToSelectGameFiles() {
+    model.setState(NavigationState.SELECT_GAME_FILES);
+  }
+
+  /**
+   * Allows for playing the Julia game.
+   */
+  private void goToPlayJulia() {
+    model.setState(NavigationState.PLAY_JULIA);
+  }
+
+  /**
+   * Allows for playing the Affine game.
+   */
+  private void goToPlayAffine() {
+    model.setState(NavigationState.PLAY_AFFINE);
+  }
+
+  /**
+   * Allows for going to the settings.
+   */
+  private void goToSettings() {
+    model.setState(NavigationState.SETTINGS);
+  }
+
+  /**
+   * Allows for going to the menu.
+   */
+  private void goToMenu() {
+    model.setState(NavigationState.MENU);
+  }
+
+  /**
+   * Updates the view to show the files in the file directory. With the buttons for each file.
+   */
+  @Override
+  public void update() {
+    selectGameFiles();
+  }
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/navigation/SettingsController.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/navigation/SettingsController.java
new file mode 100644
index 0000000000000000000000000000000000000000..6d2d37aac2a8346268332575b0292f551ec863e2
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/controller/navigation/SettingsController.java
@@ -0,0 +1,77 @@
+package edu.ntnu.idatt2003.group6.controller.navigation;
+
+import edu.ntnu.idatt2003.group6.models.files.FilePath;
+import edu.ntnu.idatt2003.group6.view.frames.HomePage;
+import edu.ntnu.idatt2003.group6.view.frames.SettingsFrame;
+import java.io.File;
+import javafx.scene.control.ToggleGroup;
+import javafx.scene.media.Media;
+import javafx.scene.media.MediaPlayer;
+
+/**
+ * The SettingsController class controls the settings of the application.
+ * Mainly the music settings.
+ *
+ * @version 0.3.2
+ * @since 0.3.2
+ */
+public class SettingsController {
+  private static SettingsController instance = null;
+  private final ToggleGroup musicOption;
+  private final SettingsFrame settingsFrame;
+  private final MediaPlayer mediaPlayer;
+
+  /**
+   * Constructor for SettingsController.
+   * Creates a new SettingsController with a reference to the HomePage.
+   *
+   * @param homePage The HomePage to bind the settings to.
+   */
+  private SettingsController(HomePage homePage) {
+    this.settingsFrame = homePage.getSettingsFrame();
+    this.musicOption = settingsFrame.getMusicOption();
+
+    Media media =
+        new Media(new File(
+            FilePath.MUSIC.getPath() + "Legio_Symphonica.mp3").toURI().toString());
+    mediaPlayer = new MediaPlayer(media);
+    mediaPlayer.setCycleCount(MediaPlayer.INDEFINITE);
+
+    musicOption.selectToggle(settingsFrame.getMusicOff());
+    buttonsController();
+  }
+
+  /**
+   * Returns the instance of the SettingsController.
+   * If the instance is null, a new instance is created.
+   *
+   * @param homepage The HomePage to bind the settings to.
+   * @return The instance of the SettingsController.
+   */
+  public static SettingsController getInstance(HomePage homepage) {
+    if (instance == null) {
+      instance = new SettingsController(homepage);
+    }
+    return instance;
+  }
+
+  /**
+   * Controls the music settings.
+   * If the music is turned off, the mediaPlayer is stopped.
+   * If the music is turned on, the mediaPlayer is played.
+   * The volume of the mediaPlayer is set to the value of the volumeSlider.
+   */
+  private void buttonsController() {
+    musicOption.selectedToggleProperty().addListener((observable, oldValue, newValue) -> {
+      if (musicOption.getSelectedToggle() == settingsFrame.getMusicOn()) {
+        mediaPlayer.play();
+        mediaPlayer.setVolume(settingsFrame.getVolumeSlider().getValue());
+      } else if (musicOption.getSelectedToggle() == settingsFrame.getMusicOff()) {
+        mediaPlayer.stop();
+      }
+    });
+
+    settingsFrame.getVolumeSlider().valueProperty().addListener((observable, oldValue, newValue) ->
+        mediaPlayer.setVolume(settingsFrame.getVolumeSlider().getValue()));
+  }
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosCanvas.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosCanvas.java
index 7cfe1d9f3933903298208fd4a20767053e55413f..7d8e53418040f3d9dce041cfbc4d821a0074528c 100644
--- a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosCanvas.java
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosCanvas.java
@@ -27,8 +27,13 @@ public class ChaosCanvas {
    * @param height    The height of the canvas.
    * @param minCoords The minimum coordinates of the canvas.
    * @param maxCoords The maximum coordinates of the canvas.
+   * @throws IllegalArgumentException If the width or height is less than or equal to 0.
    */
-  public ChaosCanvas(int width, int height, Vector2D minCoords, Vector2D maxCoords) {
+  public ChaosCanvas(int width, int height, Vector2D minCoords, Vector2D maxCoords)
+      throws IllegalArgumentException {
+    if (width <= 0 || height <= 0) {
+      throw new IllegalArgumentException("Width and height must be positive.");
+    }
     this.width = width;
     this.height = height;
     this.minCoords = minCoords;
@@ -45,10 +50,8 @@ public class ChaosCanvas {
    * @return The pixel value at the given point.
    */
   public int getPixel(Vector2D point) {
-    Vector2D transformedPoint = this.transformCoordsToIndices.transform(point);
-    int x = (int) Math.round(transformedPoint.getX0());
-    int y = (int) Math.round(transformedPoint.getX1());
-    return this.canvas[x][y];
+    Vector2D transformedPoint = transformAndCheckPoint(point);
+    return this.canvas[(int) transformedPoint.getX0()][(int) transformedPoint.getX1()];
   }
 
   /**
@@ -57,10 +60,26 @@ public class ChaosCanvas {
    * @param point The point to set the pixel value at.
    */
   public void putPixel(Vector2D point) {
+    Vector2D transformedPoint = transformAndCheckPoint(point);
+    this.canvas[(int) transformedPoint.getX0()][(int) transformedPoint.getX1()]++;
+  }
+
+  /**
+   * Sets the pixel value at the given point.
+   *
+   * @param point The point to get or set the pixel value at.
+   * @return The pixel value at the given point.
+   * @throws IllegalArgumentException If the point is out of bounds.
+   */
+  private Vector2D transformAndCheckPoint(Vector2D point) throws IllegalArgumentException {
     Vector2D transformedPoint = this.transformCoordsToIndices.transform(point);
     int x = (int) Math.round(transformedPoint.getX0());
     int y = (int) Math.round(transformedPoint.getX1());
-    this.canvas[x][y] = 1; // or some other value depending on your fractal rendering logic
+
+    if (x < 0 || x >= width || y < 0 || y >= height) {
+      throw new IllegalArgumentException("Point is out of bounds.");
+    }
+    return transformedPoint;
   }
 
   /**
@@ -76,10 +95,9 @@ public class ChaosCanvas {
    * Clears the canvas by setting all pixels to 0.
    */
   public void clear() {
-    //Using for loop to set all pixels to 0. Since the canvas is a 2D array.
     for (int i = 0; i < this.width; i++) {
       for (int j = 0; j < this.height; j++) {
-        this.canvas[i][j] = 0;
+        this.canvas[j][i] = 0;
       }
     }
   }
@@ -102,7 +120,7 @@ public class ChaosCanvas {
    */
   private Vector2D getVectorForIndices() {
     return new Vector2D(
-      ((height - 1) * maxCoords.getX1()) / (maxCoords.getX1() - minCoords.getX1()),
-      ((width - 1) * minCoords.getX0()) / (minCoords.getX0() - maxCoords.getX0()));
+        ((height - 1) * maxCoords.getX1()) / (maxCoords.getX1() - minCoords.getX1()),
+        ((width - 1) * minCoords.getX0()) / (minCoords.getX0() - maxCoords.getX0()));
   }
 }
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosGameDescription.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosGameDescription.java
index 2efe27ece08282ba823b91e231deedcb89360af5..5f1673411e8f3014fc3262c87e4952c72b61a539 100644
--- a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosGameDescription.java
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosGameDescription.java
@@ -2,6 +2,7 @@ package edu.ntnu.idatt2003.group6.models.chaosgame;
 
 import edu.ntnu.idatt2003.group6.models.transformation.Transform2D;
 import edu.ntnu.idatt2003.group6.models.vector.Vector2D;
+import edu.ntnu.idatt2003.group6.utils.exceptions.IllegalChaosGameException;
 import java.util.List;
 
 /**
@@ -12,6 +13,7 @@ import java.util.List;
  * @since 0.2.1
  */
 public class ChaosGameDescription {
+  private final GameType gameType;
   private Vector2D minCoords;
   private Vector2D maxCoords;
   private List<Transform2D> transformations;
@@ -22,12 +24,19 @@ public class ChaosGameDescription {
    * @param transforms A list of transformations
    * @param minCoords  start coordinates
    * @param maxCoords  stop coordinates
+   * @throws IllegalChaosGameException if the transformations, minCoords or maxCoords are null
    */
   public ChaosGameDescription(List<Transform2D> transforms,
-                              Vector2D minCoords, Vector2D maxCoords) {
+                              Vector2D minCoords, Vector2D maxCoords)
+      throws IllegalChaosGameException {
+    if (transforms == null || minCoords == null || maxCoords == null) {
+      throw new IllegalChaosGameException(
+          "Transformations, minCoords or maxCoords cannot be null.");
+    }
     this.minCoords = minCoords;
     this.maxCoords = maxCoords;
     this.transformations = transforms;
+    this.gameType = transformations.getFirst().gameType();
   }
 
   /**
@@ -83,4 +92,8 @@ public class ChaosGameDescription {
   public void setMaxCoords(Vector2D maxCoords) {
     this.maxCoords = maxCoords;
   }
+
+  public GameType getGameType() {
+    return gameType;
+  }
 }
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosGameDescriptionFactory.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosGameDescriptionFactory.java
index a1d4d0b0d335e3afdefc7143618a3322ef0ab16f..3b14cf7cf46ae47657b97ed9b8102395e9ad2741 100644
--- a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosGameDescriptionFactory.java
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosGameDescriptionFactory.java
@@ -5,7 +5,6 @@ import edu.ntnu.idatt2003.group6.models.transformation.AffineTransform2D;
 import edu.ntnu.idatt2003.group6.models.transformation.JuliaTransform;
 import edu.ntnu.idatt2003.group6.models.vector.Complex;
 import edu.ntnu.idatt2003.group6.models.vector.Vector2D;
-
 import java.util.List;
 
 /**
@@ -17,34 +16,46 @@ import java.util.List;
 public class ChaosGameDescriptionFactory {
 
   /**
-   * Creates a standard ChaosGameDescription based on the game type you want.
+   * Creates a standard ChaosGameDescription based on the game type provided.
    *
    * @param gameType The type of chaos game to create
    * @return A ChaosGameDescription of the type you want
+   * @throws IllegalArgumentException If the game type is null or invalid
    */
-  public static ChaosGameDescription createChaosGameDescription(String gameType) {
-
-    return switch (gameType) {
-      case "Sierpinski" -> new ChaosGameDescription(List.of(
-          new AffineTransform2D(new Matrix2x2(0.5, 0, 0, 0.5), new Vector2D(0, 0)),
-          new AffineTransform2D(new Matrix2x2(0.5, 0, 0, 0.5), new Vector2D(0.25, 0.5)),
-          new AffineTransform2D(new Matrix2x2(0.5, 0, 0, 0.5), new Vector2D(0.5, 0))
+  public static ChaosGameDescription createChaosGameDescription(GameType gameType)
+      throws IllegalArgumentException {
+    try {
+      return switch (gameType) {
+        case SIERPINSKI -> new ChaosGameDescription(List.of(
+            new AffineTransform2D(new Matrix2x2(0.5, 0, 0, 0.5), new Vector2D(0, 0)),
+            new AffineTransform2D(new Matrix2x2(0.5, 0, 0, 0.5), new Vector2D(0.25, 0.5)),
+            new AffineTransform2D(new Matrix2x2(0.5, 0, 0, 0.5), new Vector2D(0.5, 0))
         ), new Vector2D(0, 0), new Vector2D(1, 1));
 
-      case "Barnsley" -> new ChaosGameDescription(List.of(
-          new AffineTransform2D(new Matrix2x2(0, 0, 0, 0.16), new Vector2D(0, 0)),
-          new AffineTransform2D(new Matrix2x2(0.85, 0.04, -0.04, 0.85), new Vector2D(0, 1.6)),
-          new AffineTransform2D(new Matrix2x2(0.2, -0.26, 0.23, 0.22), new Vector2D(0, 1.6)),
-          new AffineTransform2D(new Matrix2x2(-0.15, 0.28, 0.26, 0.24), new Vector2D(0, 0.44))
+        case BARNSLEY -> new ChaosGameDescription(List.of(
+            new AffineTransform2D(new Matrix2x2(0, 0, 0, 0.16), new Vector2D(0, 0)),
+            new AffineTransform2D(new Matrix2x2(0.85, 0.04, -0.04, 0.85), new Vector2D(0, 1.6)),
+            new AffineTransform2D(new Matrix2x2(0.2, -0.26, 0.23, 0.22), new Vector2D(0, 1.6)),
+            new AffineTransform2D(new Matrix2x2(-0.15, 0.28, 0.26, 0.24), new Vector2D(0, 0.44))
         ), new Vector2D(-2.65, 0), new Vector2D(2.65, 10));
 
-      case "Julia" -> new ChaosGameDescription(List.of(
-          new JuliaTransform(new Complex(-0.74543, 0.11301), -1),
-          new JuliaTransform(new Complex(-0.74543, 0.11301), 1)
+        case JULIA -> new ChaosGameDescription(List.of(
+            new JuliaTransform(new Complex(-0.74543, 0.11301), 1),
+            new JuliaTransform(new Complex(-0.74543, 0.11301), -1)
         ), new Vector2D(-1.6, -1), new Vector2D(1.6, 1));
 
-      // TODO Add custom exception
-      default -> null;
-    };
+        case JULIA_NEW -> new ChaosGameDescription(List.of(
+            new JuliaTransform(new Complex(0, 0), -1),
+            new JuliaTransform(new Complex(0, 0), 1)
+        ), new Vector2D(0, 0), new Vector2D(0, 0));
+
+        case AFFINE_NEW -> new ChaosGameDescription(List.of(
+            new AffineTransform2D(new Matrix2x2(0, 0, 0, 0), new Vector2D(0, 0))
+        ), new Vector2D(0, 0), new Vector2D(0, 0));
+        default -> null;
+      };
+    } catch (NullPointerException e) {
+      throw new IllegalArgumentException("Game type cannot be null. @" + e.getMessage(), e);
+    }
   }
 }
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosGameObserver.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosGameObserver.java
deleted file mode 100644
index 599da52c6cb11536f324e72ef3d65861f525f15e..0000000000000000000000000000000000000000
--- a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosGameObserver.java
+++ /dev/null
@@ -1,8 +0,0 @@
-package edu.ntnu.idatt2003.group6.models.chaosgame;
-
-import edu.ntnu.idatt2003.group6.controller.ChaosGame;
-
-public interface ChaosGameObserver {
-
-  void update(ChaosGame chaosGame);
-}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/chaosgame/GameType.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/chaosgame/GameType.java
new file mode 100644
index 0000000000000000000000000000000000000000..ca3dd3c5cd6b31f33efe08038a28a50783c9cb38
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/chaosgame/GameType.java
@@ -0,0 +1,29 @@
+package edu.ntnu.idatt2003.group6.models.chaosgame;
+
+import edu.ntnu.idatt2003.group6.controller.chaosgame.ChaosGame;
+import edu.ntnu.idatt2003.group6.controller.chaosgame.ChaosGameController;
+
+/**
+ * Enum for the different types of games that can be played.
+ * Used to determine certain actions that are different for each game type.
+ * Mainly used in the ChaosGameDescriptionFactory class.
+ * Or when the game type is needed in the ChaosGame class.
+ * The main GameType is AFFINE and JULIA.
+ *
+ * @version 0.3.2
+ * @since 0.3.2
+ * @see ChaosGameDescriptionFactory
+ * @see ChaosGame
+ * @see ChaosGameController
+ * @see edu.ntnu.idatt2003.group6.models.chaosgame.ChaosGameDescription
+ * @see edu.ntnu.idatt2003.group6.models.chaosgame.ChaosGameDescriptionFactory
+ *
+ */
+public enum GameType {
+  SIERPINSKI,
+  BARNSLEY,
+  JULIA,
+  AFFINE,
+  JULIA_NEW,
+  AFFINE_NEW
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/files/FileModel.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/files/FileModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..bcaabe8d461c266856c1ca217f25eb15b032b73e
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/files/FileModel.java
@@ -0,0 +1,174 @@
+package edu.ntnu.idatt2003.group6.models.files;
+
+import edu.ntnu.idatt2003.group6.models.chaosgame.ChaosGameDescription;
+import edu.ntnu.idatt2003.group6.utils.ChaosGameFileHandler;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+
+/**
+ * The FileModel class is a singleton
+ * that manages the files containing the chaos game descriptions.
+ * It is responsible for reading, writing, and deleting files.
+ * It also notifies observers when the amount of files changes.
+ * The class is part of the Model-View-Controller pattern.
+ *
+ * @version 0.3.2
+ * @since 0.3.2
+ */
+public class FileModel {
+  private static final Logger LOGGER = Logger.getLogger(FileModel.class.getName());
+  private static FileModel instance = null;
+  private final List<FileObserver> observers;
+  private FileState state;
+
+  /**
+   * Constructor for the FileModel class.
+   */
+  private FileModel() {
+    observers = new ArrayList<>();
+  }
+
+  /**
+   * Returns the instance of the FileModel class.
+   * Following the singleton design principle.
+   *
+   * @return the instance of the FileModel class.
+   */
+  public static FileModel getInstance() {
+    if (instance == null) {
+      instance = new FileModel();
+    }
+    return instance;
+  }
+
+  /**
+   * Returns a list of the files in the descriptions folder.
+   *
+   * @return List of file names in the descriptions folder.
+   * @throws IllegalArgumentException if the files could not be found.
+   */
+  public List<String> getFiles() throws IllegalArgumentException {
+    try {
+      return ChaosGameFileHandler.showFiles(FilePath.DESCRIPTIONS.getPath());
+    } catch (Exception e) {
+      LOGGER.severe(e.getMessage());
+      throw new IllegalArgumentException("Could not find files @" + e.getMessage());
+    }
+  }
+
+  /**
+   * Adds a file to the descriptions' folder.
+   *
+   * @param fileName  the name of the file to be added.
+   * @param chaosGame the chaos game description to be written to the file.
+   * @throws IllegalArgumentException if the file could not be written.
+   */
+  public void addFile(String fileName, ChaosGameDescription chaosGame)
+      throws IllegalArgumentException {
+    if (fileName == null || chaosGame == null) {
+      throw new IllegalArgumentException("File name and chaos game description cannot be null");
+    }
+    setState(FileState.FILES_UPDATING);
+    try {
+      ChaosGameFileHandler.writeChaosGameDescriptionToFile(
+          FilePath.DESCRIPTIONS.getPath() + fileName, chaosGame);
+      setState(FileState.FILES_CHANGED);
+    } catch (Exception e) {
+      setState(FileState.FILES_UNCHANGED);
+      LOGGER.severe(e.getMessage());
+      throw new IllegalArgumentException("Could not write file @" + e.getMessage());
+    }
+  }
+
+  /**
+   * Returns a ChaosGameDescription object from a file.
+   *
+   * @param fileName the name of the file to be read.
+   * @return the ChaosGameDescription object from the file.
+   * @throws IllegalArgumentException if the file could not be read or if formatting is wrong.
+   */
+  public ChaosGameDescription getFile(String fileName) {
+    if (fileName == null) {
+      throw new IllegalArgumentException("File name cannot be null");
+    }
+    try {
+      return ChaosGameFileHandler.readChaosGameDescriptionFromFile(
+          FilePath.DESCRIPTIONS.getPath() + fileName);
+    } catch (Exception e) {
+      LOGGER.severe(e.getMessage());
+      throw new IllegalArgumentException("Could not read file @" + e.getMessage());
+    }
+  }
+
+  /**
+   * Removes a file from the descriptions' folder.
+   *
+   * @param fileName the name of the file to be removed.
+   * @throws IllegalArgumentException if the file could not be deleted.
+   */
+  public void removeFile(String fileName) throws IllegalArgumentException {
+    if (fileName == null) {
+      throw new IllegalArgumentException("File name cannot be null");
+    }
+    setState(FileState.FILES_UPDATING);
+    try {
+      ChaosGameFileHandler.deleteFile(FilePath.DESCRIPTIONS.getPath() + fileName);
+      setState(FileState.FILES_CHANGED);
+
+    } catch (Exception e) {
+      setState(FileState.FILES_UNCHANGED);
+      LOGGER.severe(e.getMessage());
+      throw new IllegalArgumentException("Could not delete file @" + e.getMessage());
+    }
+  }
+
+  /**
+   * Sets the state of the FileModel.
+   *
+   * @param state the state to be set.
+   * @throws IllegalArgumentException if the state is null.
+   */
+  public void setState(FileState state) throws IllegalArgumentException {
+    if (state == null) {
+      throw new IllegalArgumentException("State cannot be null");
+    }
+    if (!state.equals(this.state)) {
+      this.state = state;
+      notifyObservers();
+    }
+  }
+
+  /**
+   * Adds an observer to be notified when the state of the FileModel changes.
+   *
+   * @param observer the observer to be added.
+   */
+  public void addObserver(FileObserver observer) {
+    if (observer == null) {
+      throw new IllegalArgumentException("Observer cannot be null");
+    }
+    observers.add(observer);
+  }
+
+  /**
+   * Removes an observer from the list of observers.
+   *
+   * @param observer the observer to be removed.
+   */
+  public void removeObserver(FileObserver observer) {
+    if (observer == null) {
+      throw new IllegalArgumentException("Observer cannot be null");
+    }
+    observers.remove(observer);
+  }
+
+  /**
+   * Notifies all observers that the state of the FileModel has changed.
+   */
+  private void notifyObservers() {
+    observers.forEach(observer -> observer.update(state));
+  }
+
+
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/files/FileObserver.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/files/FileObserver.java
new file mode 100644
index 0000000000000000000000000000000000000000..b8c35fd027ce5c2180025df2bd4a3fe0edef0206
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/files/FileObserver.java
@@ -0,0 +1,15 @@
+package edu.ntnu.idatt2003.group6.models.files;
+
+/**
+ * Interface for the FileObserver class.
+ * The FileObserver class is used to observe changes in the FileState class.
+ * The FileObserver class is part of the Observer pattern.
+ *
+ * @version 0.3.2
+ * @see FileState
+ * @see FileObserver
+ * @since 0.3.2
+ */
+public interface FileObserver {
+  void update(FileState state);
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/files/FilePath.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/files/FilePath.java
new file mode 100644
index 0000000000000000000000000000000000000000..98cff2236029ef39b285b5bcb6296f90d02f21e3
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/files/FilePath.java
@@ -0,0 +1,37 @@
+package edu.ntnu.idatt2003.group6.models.files;
+
+/**
+ * Enum class for the file paths.
+ * Contains the paths for the descriptions and images.
+ * The paths are used to locate the files.
+ *
+ * @version 0.3.2
+ * @see FileModel
+ * @since 0.3.2
+ */
+public enum FilePath {
+  DESCRIPTIONS("src/main/resources/descriptions/"),
+  IMAGES("src/main/resources/images/"),
+
+  MUSIC("src/main/resources/mp3/");
+
+  private final String path;
+
+  /**
+   * Constructor for the FilePath class.
+   *
+   * @param path the path of the file.
+   */
+  FilePath(String path) {
+    this.path = path;
+  }
+
+  /**
+   * Returns the path of the file.
+   *
+   * @return the path of the file.
+   */
+  public String getPath() {
+    return path;
+  }
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/files/FileState.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/files/FileState.java
new file mode 100644
index 0000000000000000000000000000000000000000..6be8efbb86bb907e07dcfb69fe46a22ad25c18b6
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/files/FileState.java
@@ -0,0 +1,19 @@
+package edu.ntnu.idatt2003.group6.models.files;
+
+/**
+ * Enum class for the file states used in the FileModel class.
+ * The states are FILES_UPDATING, FILES_UNCHANGED and FILES_CHANGED.
+ * FILES_UPDATING is used when the files are being updated.
+ * FILES_UNCHANGED is used when the files are unchanged.
+ * FILES_CHANGED is used when the files are changed.
+ *
+ * @version 0.3.2
+ * @see edu.ntnu.idatt2003.group6.models.files.FileModel
+ * @since 0.3.2
+ */
+public enum FileState {
+  FILES_UPDATING,
+  FILES_UNCHANGED,
+  FILES_CHANGED
+
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/matrix/Matrix2x2.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/matrix/Matrix2x2.java
index d3f90b095aa13477ea006cd56f82e9280474c95d..c755bdc4a873c7f2533ed1513ef79b5a5c9a4d8f 100644
--- a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/matrix/Matrix2x2.java
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/matrix/Matrix2x2.java
@@ -1,21 +1,16 @@
 package edu.ntnu.idatt2003.group6.models.matrix;
 
 import edu.ntnu.idatt2003.group6.models.vector.Vector2D;
-import edu.ntnu.idatt2003.group6.utils.Utils;
+
 
 /**
- * This class represents a 2x2 matrix.It contains the components of the matrix and methods to
- * multiply a vector by the matrix.
+ * This record represents a 2x2 matrix.
+ * It contains the components of the matrix and methods to multiply a vector by the matrix.
  *
  * @version 0.1.2
  * @since 0.1.2
  */
-public class Matrix2x2 {
-  private final double a00;
-  private final double a01;
-  private final double a10;
-  private final double a11;
-
+public record Matrix2x2(double a00, double a01, double a10, double a11) {
   /**
    * Constructor for the Matrix2x2 class. Creates a new matrix with the given components.
    *
@@ -23,17 +18,9 @@ public class Matrix2x2 {
    * @param a01 The a01 component of the matrix.
    * @param a10 The a10 component of the matrix.
    * @param a11 The a11 component of the matrix.
-   * @throws IllegalArgumentException If the given components are invalid.
    */
-  public Matrix2x2(double a00, double a01, double a10, double a11) {
-    Utils.verifyDoubleParameter(a00, "a00");
-    Utils.verifyDoubleParameter(a01, "a01");
-    Utils.verifyDoubleParameter(a10, "a10");
-    Utils.verifyDoubleParameter(a11, "a11");
-    this.a00 = a00;
-    this.a01 = a01;
-    this.a10 = a10;
-    this.a11 = a11;
+  public Matrix2x2 {
+    // The record class automatically generates a constructor with the given components.
   }
 
   /**
@@ -43,25 +30,12 @@ public class Matrix2x2 {
    * @return A new vector that is the result of the multiplication.
    * @throws IllegalArgumentException If the given vector is null or if its components are invalid.
    */
-  public Vector2D multiply(Vector2D vector) {
+  public Vector2D multiply(Vector2D vector) throws IllegalArgumentException {
+    if (vector == null) {
+      throw new IllegalArgumentException("The given vector cannot be null.");
+    }
     return new Vector2D(this.a00 * vector.getX0() + this.a01 * vector.getX1(),
-      this.a10 * vector.getX0() + this.a11 * vector.getX1());
+        this.a10 * vector.getX0() + this.a11 * vector.getX1());
   }
 
-    public double getA00() {
-        return a00;
-    }
-
-    public double getA01() {
-        return a01;
-    }
-
-    public double getA10() {
-        return a10;
-    }
-
-    public double getA11() {
-        return a11;
-    }
-
 }
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/navigation/NavigationModel.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/navigation/NavigationModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..bfdfd834ffc73dbcda673407daf976550f9b8308
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/navigation/NavigationModel.java
@@ -0,0 +1,79 @@
+package edu.ntnu.idatt2003.group6.models.navigation;
+
+import edu.ntnu.idatt2003.group6.controller.navigation.NavigationController;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The NavigationModel class manages the
+ * state of the navigation in the application.
+ * It provides methods for setting and getting the state
+ * and for adding and removing observers.
+ * The observers are notified when the state changes.
+ * The class is part of the Model-View-Controller pattern.
+ *
+ * @version 0.3.2
+ * @see NavigationState
+ * @see NavigationObserver
+ * @see NavigationController
+ * @since 0.3.2
+ */
+public class NavigationModel {
+  private final List<NavigationObserver> observers = new ArrayList<>();
+  private NavigationState state;
+
+  /**
+   * Returns the current state of the navigation.
+   */
+  public NavigationState getState() {
+    return state;
+  }
+
+  /**
+   * Sets the state of the navigation.
+   *
+   * @param state the new state of the navigation.
+   * @throws IllegalArgumentException if the state is null.
+   */
+  public void setState(NavigationState state) throws IllegalArgumentException {
+    if (state == null) {
+      throw new IllegalArgumentException("State cannot be null");
+    }
+    this.state = state;
+    notifyObservers();
+  }
+
+  /**
+   * Adds an observer to the navigation model.
+   *
+   * @param observer the observer to be added.
+   * @throws IllegalArgumentException if the observer is null.
+   */
+  public void addObserver(NavigationObserver observer) throws IllegalArgumentException {
+    if (observer == null) {
+      throw new IllegalArgumentException("Observer cannot be null");
+    }
+    observers.add(observer);
+  }
+
+  /**
+   * Removes an observer from the navigation model.
+   *
+   * @param observer the observer to be removed.
+   * @throws IllegalArgumentException if the observer is null.
+   */
+  public void removeObserver(NavigationObserver observer) throws IllegalArgumentException {
+    if (observer == null) {
+      throw new IllegalArgumentException("Observer cannot be null");
+    }
+    observers.remove(observer);
+  }
+
+  /**
+   * Notifies all observers that the state has changed.
+   */
+  private void notifyObservers() {
+    observers.forEach(observer -> observer.update(state));
+  }
+
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/navigation/NavigationObserver.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/navigation/NavigationObserver.java
new file mode 100644
index 0000000000000000000000000000000000000000..360b7367729377880a512492314b836fe243f26f
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/navigation/NavigationObserver.java
@@ -0,0 +1,13 @@
+package edu.ntnu.idatt2003.group6.models.navigation;
+
+/**
+ * Interface for an observer of the NavigationState.
+ *
+ * @version 3.2
+ * @see NavigationState
+ * @see NavigationModel
+ * @since 3.2
+ */
+public interface NavigationObserver {
+  void update(NavigationState state);
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/navigation/NavigationState.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/navigation/NavigationState.java
new file mode 100644
index 0000000000000000000000000000000000000000..4378cd0b6b02a33a7781c2b014637e53ac13e69d
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/navigation/NavigationState.java
@@ -0,0 +1,24 @@
+package edu.ntnu.idatt2003.group6.models.navigation;
+
+import edu.ntnu.idatt2003.group6.controller.navigation.NavigationController;
+
+/**
+ * Enum class for the different states of the view. Used to navigate between different views.
+ *
+ * @version 3.2
+ * @see NavigationModel
+ * @see NavigationObserver
+ * @see NavigationController
+ * @since 3.2
+ */
+public enum NavigationState {
+  SELECT_FILE,
+  EDIT_FILE,
+  SELECT_GAME,
+  SELECT_GAME_FILES,
+  PLAY_GAME,
+  PLAY_JULIA,
+  PLAY_AFFINE,
+  SETTINGS,
+  MENU
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/transformation/AffineTransform2D.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/transformation/AffineTransform2D.java
index 8cdc05a97e5b7d52351930733c2c8ce2d3bdbbde..20e8de7f3b178607fd84d6592bb869c4b50e1304 100644
--- a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/transformation/AffineTransform2D.java
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/transformation/AffineTransform2D.java
@@ -1,5 +1,6 @@
 package edu.ntnu.idatt2003.group6.models.transformation;
 
+import edu.ntnu.idatt2003.group6.models.chaosgame.GameType;
 import edu.ntnu.idatt2003.group6.models.matrix.Matrix2x2;
 import edu.ntnu.idatt2003.group6.models.vector.Vector2D;
 
@@ -7,12 +8,13 @@ import edu.ntnu.idatt2003.group6.models.vector.Vector2D;
  * This class represents an affine transformation in 2D space. It contains a 2x2 matrix and a 2D
  * vector, and methods to transform a 2D vector by the affine transformation.
  *
- * @version 0.1.3
+ * @version 0.3.2
+ * @see Transform2D
+ * @see Matrix2x2
  * @since 0.1.3
  */
-public class AffineTransform2D implements Transform2D {
-  private final Matrix2x2 matrix;
-  private final Vector2D vector;
+public record AffineTransform2D(Matrix2x2 matrix, Vector2D vector) implements Transform2D {
+  private static final GameType gameType = GameType.AFFINE;
 
   /**
    * Constructor for the AffineTransform2D class. Creates a new affine transformation with the given
@@ -22,9 +24,10 @@ public class AffineTransform2D implements Transform2D {
    * @param vector The 2D vector of the affine transformation.
    * @throws IllegalArgumentException If the given matrix or vector are null.
    */
-  public AffineTransform2D(Matrix2x2 matrix, Vector2D vector) {
-    this.matrix = matrix;
-    this.vector = vector;
+  public AffineTransform2D {
+    if (matrix == null || vector == null) {
+      throw new IllegalArgumentException("The matrix or vector cannot be null.");
+    }
   }
 
   /**
@@ -38,12 +41,32 @@ public class AffineTransform2D implements Transform2D {
     return this.matrix.multiply(vector).add(this.vector);
   }
 
-
-  public Matrix2x2 getMatrix() {
+  /**
+   * Returns the matrix of this affine transformation.
+   *
+   * @return The 2x2 matrix of this affine transformation.
+   */
+  @Override
+  public Matrix2x2 matrix() {
     return this.matrix;
   }
 
-  public Vector2D getVector() {
+  /**
+   * Returns the vector of this affine transformation.
+   *
+   * @return The 2D vector of this affine transformation.
+   */
+  @Override
+  public Vector2D vector() {
     return this.vector;
   }
+
+  /**
+   * Returns the game type of this affine transformation.
+   *
+   * @return The game type of this affine transformation.
+   */
+  public GameType gameType() {
+    return gameType;
+  }
 }
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/transformation/JuliaTransform.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/transformation/JuliaTransform.java
index a11cd672e72453ed0966bd147002f56209432bd1..809bedbe0f0d1b151b5204e414d372351bb5f32e 100644
--- a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/transformation/JuliaTransform.java
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/transformation/JuliaTransform.java
@@ -1,5 +1,6 @@
 package edu.ntnu.idatt2003.group6.models.transformation;
 
+import edu.ntnu.idatt2003.group6.models.chaosgame.GameType;
 import edu.ntnu.idatt2003.group6.models.vector.Complex;
 import edu.ntnu.idatt2003.group6.models.vector.Vector2D;
 import edu.ntnu.idatt2003.group6.utils.Utils;
@@ -9,23 +10,28 @@ import edu.ntnu.idatt2003.group6.utils.Utils;
  * and a signature to determine the direction of the transformation, positive or negative
  * and methods to transform a 2D vector by the Julia transformation.
  *
- * @version 0.1.3
+ * @version 0.3.2
  * @since 0.1.3
  */
 public class JuliaTransform implements Transform2D {
   private final Complex point;
   private final int sign;
+  private static final GameType gameType = GameType.JULIA;
 
   /**
    * Constructor for the JuliaTransform class. Creates a new Julia transformation with the given
    * complex number and signature.
    *
    * @param point The complex number of the Julia transformation.
-   * @param sign The signature of the Julia transformation.
+   * @param sign  The signature of the Julia transformation.
    * @throws IllegalArgumentException If the given complex number is null
-   *      or if its components are invalid. Also, if the sign is invalid.
+   *                                  or if its components are invalid.
+   *                                  Also, if the sign is not +-1.
    */
-  public JuliaTransform(Complex point, int sign) {
+  public JuliaTransform(Complex point, int sign) throws IllegalArgumentException {
+    if (sign != 1 && sign != -1) {
+      throw new IllegalArgumentException("The sign must be either 1 or -1.");
+    }
     Utils.verifyInt(sign, "sign");
     this.point = point;
     this.sign = sign;
@@ -35,34 +41,22 @@ public class JuliaTransform implements Transform2D {
     return point;
   }
 
+  public GameType gameType() {
+    return gameType;
+  }
+
   /**
    * Transforms the given vector by this Julia transformation.
    *
    * @param vector The vector to be transformed by this Julia transformation.
    * @return A new vector that is the result of the transformation.
    */
-
   @Override
   public Vector2D transform(Vector2D vector) {
-    // Convert the input vector to a Complex object
-    Complex z = new Complex(vector.getX0(), vector.getX1());
-
-    // Convert the point to a Complex object
-    Complex c = new Complex(point.getX0(), point.getX1());
-
-    // Subtract the complex point from the input complex number
-    Complex subtracted = new Complex(z.getX0() - c.getX0(), z.getX1() - c.getX1());
-
-    // Take the square root of the subtracted complex number
-    Complex result = subtracted.sqrt();
-
-    // Negate the imaginary part if sign is -1
-    if (sign == -1) {
-      result = new Complex(result.getX0(), -result.getX1());
-    }
-
-    // Convert the result back to a Vector2D object
-    return new Vector2D(result.getX0(), result.getX1());
+    Vector2D z = vector.subtract(point);                    // z = z - c
+    Complex complexZ = new Complex(z.getX0(), z.getX1());   // Casting to complex
+    Complex sqrt = complexZ.sqrt();                         // sqrt(z)
+    return new Vector2D(sign * sqrt.getX0(),
+        sign * sqrt.getX1()); // Adjusting imaginary part by sign
   }
-
 }
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/transformation/Transform2D.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/transformation/Transform2D.java
index d57a6db6bcde571265eb2b9de1fa1cb905fcccb5..bb9d8cb7e68fe3975f90e8c4acf8698d95f007b8 100644
--- a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/transformation/Transform2D.java
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/transformation/Transform2D.java
@@ -1,5 +1,6 @@
 package edu.ntnu.idatt2003.group6.models.transformation;
 
+import edu.ntnu.idatt2003.group6.models.chaosgame.GameType;
 import edu.ntnu.idatt2003.group6.models.vector.Vector2D;
 
 /**
@@ -7,6 +8,8 @@ import edu.ntnu.idatt2003.group6.models.vector.Vector2D;
  * It contains an abstract method to transform a 2D vector.
  *
  * @version 0.1.3
+ * @see AffineTransform2D
+ * @see JuliaTransform
  * @since 0.1.3
  */
 public interface Transform2D {
@@ -18,4 +21,11 @@ public interface Transform2D {
    * @return A new vector that is the result of the transformation.
    */
   Vector2D transform(Vector2D vector);
+
+  /**
+   * Returns the type of game that this transformation is used for.
+   *
+   * @return The type of game that this transformation is used for.
+   */
+  GameType gameType();
 }
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/vector/Complex.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/vector/Complex.java
index ece36d3d32c16d6b5600292c2444127fc532b417..0d4eb816d2c2279ef3fd09315cbf907f8f1b565e 100644
--- a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/vector/Complex.java
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/vector/Complex.java
@@ -4,7 +4,8 @@ package edu.ntnu.idatt2003.group6.models.vector;
  * This class represents a complex number in 2D space. It contains the real and imaginary parts of
  * the complex number and methods to perform operations with complex numbers.
  *
- * @version 0.1.2
+ * @version 0.3.2
+ * @see Vector2D
  * @since 0.1.2
  */
 public class Complex extends Vector2D {
@@ -27,10 +28,15 @@ public class Complex extends Vector2D {
    * @return A new complex vector that is the result of the square root.
    */
   public Complex sqrt() {
-    double realPart = Math.sqrt((double) 1 / 2 * (Math.sqrt(Math.pow(this.getX0(), 2)
-        + Math.pow(this.getX1(), 2)) + this.getX0()));
-    double imaginaryPart = -Math.sqrt((double) 1 / 2 * (Math.sqrt(Math.pow(this.getX0(), 2)
-        + Math.pow(this.getX1(), 2)) - this.getX0()));
+    double x = this.getX0();
+    double y = this.getX1();
+    // the core is square root of x^2 + y^2
+    double core = Math.sqrt(x * x + y * y);
+    // square root of 1/2 * (x^2 + y^2 + x)
+    double realPart = Math.sqrt((core + x) / 2);
+    // square root of i * 1/2 * (x^2 + y^2 - x)
+    double imaginaryPart = Math.signum(y) * Math.sqrt((core - x) / 2);
+    // return the new complex number
     return new Complex(realPart, imaginaryPart);
   }
 }
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/vector/Vector2D.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/vector/Vector2D.java
index 75b7c41964109a9cf96b32164ae44359b7e94370..e8f4abdd25fd32c084f4bbbd207c9d041c739e8d 100644
--- a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/vector/Vector2D.java
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/models/vector/Vector2D.java
@@ -1,12 +1,11 @@
 package edu.ntnu.idatt2003.group6.models.vector;
 
-import edu.ntnu.idatt2003.group6.utils.Utils;
-
 /**
  * This class represents a 2D vector. It contains the components of the vector and methods to add,
  * subtract, and multiply the vector by a scalar.
  *
  * @version 0.1.2
+ * @see Complex
  * @since 0.1.2
  */
 public class Vector2D {
@@ -21,8 +20,6 @@ public class Vector2D {
    * @throws IllegalArgumentException If the given components are invalid.
    */
   public Vector2D(double x0, double x1) {
-    Utils.verifyDoubleParameter(x0, "x0");
-    Utils.verifyDoubleParameter(x1, "x1");
     this.x0 = x0;
     this.x1 = x1;
   }
@@ -83,11 +80,12 @@ public class Vector2D {
    * Verifies that the given vector is not null and that its components are valid.
    *
    * @param vector The vector to be verified.
-   * @throws IllegalArgumentException If the vector is null or if its components are invalid.
+   * @throws IllegalArgumentException If the vector is null.
    */
   private void verifyVector2D(Vector2D vector) {
-    Utils.verifyDoubleParameter(vector.getX0(), "x0");
-    Utils.verifyDoubleParameter(vector.getX1(), "x1");
+    if (vector == null) {
+      throw new IllegalArgumentException("The vector can not be null");
+    }
   }
 
 }
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/utils/ChaosGameFileHandler.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/utils/ChaosGameFileHandler.java
index 76ce9b9a1bf455e4ae2184f2a17c8b9ff732197b..616afa9956cc30f326b77f8809ff8ccb03b0dfcb 100644
--- a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/utils/ChaosGameFileHandler.java
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/utils/ChaosGameFileHandler.java
@@ -7,25 +7,26 @@ import edu.ntnu.idatt2003.group6.models.transformation.JuliaTransform;
 import edu.ntnu.idatt2003.group6.models.transformation.Transform2D;
 import edu.ntnu.idatt2003.group6.models.vector.Complex;
 import edu.ntnu.idatt2003.group6.models.vector.Vector2D;
-import java.io.BufferedReader;
 import java.io.FileWriter;
 import java.io.IOException;
-import java.io.PrintWriter;
-import java.io.StringWriter;
 import java.nio.file.Files;
+import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
 
 /**
- * This class contains methods to handle reading and writing ChaosGameDescriptions to and from files.
+ * This class contains methods to handle reading and
+ * writing ChaosGameDescriptions to and from files.
  *
- * @version 0.2.4
+ * @version 0.3.2
  * @since 0.2.4
  */
 public class ChaosGameFileHandler {
-  public ChaosGameFileHandler() {
-  }
+
+  private static final Logger LOGGER = Logger.getLogger(ChaosGameFileHandler.class.getName());
 
   /**
    * Method to write to file.
@@ -33,12 +34,12 @@ public class ChaosGameFileHandler {
    * @param fileName name of file
    * @param content  content to write to file
    */
-  private static void writeToFile(String fileName, String content) {
-
+  static void writeToFile(String fileName, String content) {
     try (FileWriter fileWriter = new FileWriter(fileName)) {
       fileWriter.write(content);
     } catch (IOException e) {
-      //handle exception
+      LOGGER.severe("An error occurred while writing to file: " + e.getMessage());
+      throw new RuntimeException("An error occurred while writing to file: " + e.getMessage());
     }
   }
 
@@ -46,34 +47,33 @@ public class ChaosGameFileHandler {
    * Method to write extra lines to file.
    *
    * @param fileName name of file
-   * @param content  content to be added to file
+   * @param content  content to be added to the file
+   *                 without overwriting the existing content in the file.
+   * @throws RuntimeException if an error occurs while writing to file.
    */
-  private static void writeToFileExtra(String fileName, String content) {
+  static void writeToFileExtra(String fileName, String content) throws RuntimeException {
     try (FileWriter fileWriter = new FileWriter(fileName, true)) {
       fileWriter.write(content);
     } catch (IOException e) {
-      //handle exception
+      LOGGER.severe("An error occurred while writing to file: " + e.getMessage());
+      throw new RuntimeException("An error occurred while writing to file: " + e.getMessage());
     }
   }
 
   /**
-   * Method to read from file.
+   * Method to read from a file.
    *
    * @param fileName name of file
    * @return content of file
+   * @throws RuntimeException if an error occurs while reading from file
    */
-  private static String readFromFile(String fileName) {
-    StringWriter stringWriter = new StringWriter();
-    try (BufferedReader bufferedReader = Files.newBufferedReader(Paths.get(fileName))) {
-      PrintWriter printWriter = new PrintWriter(stringWriter);
-      String line;
-      while ((line = bufferedReader.readLine()) != null) {
-        printWriter.println(line);
-      }
+  static String readFromFile(String fileName) throws RuntimeException {
+    try {
+      return Files.readString(Paths.get(fileName));
     } catch (IOException e) {
-      //handle exception
+      LOGGER.severe("An error occurred while reading from file: " + e.getMessage());
+      throw new RuntimeException("An error occurred while reading from file: " + e.getMessage(), e);
     }
-    return stringWriter.toString();
   }
 
   /**
@@ -81,120 +81,196 @@ public class ChaosGameFileHandler {
    *
    * @param fileName             name of file to write to
    * @param chaosGameDescription the ChaosGameDescription to write to file
+   * @throws RuntimeException if an error occurs while writing to file
    */
   public static void writeChaosGameDescriptionToFile(
-      String fileName, ChaosGameDescription chaosGameDescription) {
+      String fileName, ChaosGameDescription chaosGameDescription) throws RuntimeException {
+    try {
 
-    // Write first line. Type of transformation
-    if (chaosGameDescription.getTransformations().getFirst().getClass() == AffineTransform2D.class) {
-      writeToFile(fileName, "Affine2D                # Type of transform \n");
-    } else if (chaosGameDescription.getTransformations().getFirst().getClass() == JuliaTransform.class) {
-      writeToFile(fileName, "Julia               # Type of transform \n");
-    }
+      /* Write the first line. Type of transformation */
+      if (chaosGameDescription.getTransformations().getFirst().getClass()
+          == AffineTransform2D.class) {
+        writeToFile(fileName, "Affine2D                # Type of transform \n");
+      } else if (chaosGameDescription.getTransformations().getFirst().getClass()
+          == JuliaTransform.class) {
+        writeToFile(fileName, "Julia               # Type of transform \n");
+      }
+
+      /* Write the second line. Coordinates of the lower left corner of the canvas */
+      writeToFileExtra(fileName,
+          chaosGameDescription.getMinCoords().getX0() + ", "
+              + chaosGameDescription.getMinCoords().getX1() + " # Lower left" + "\n");
 
-    // Write second line. coordinates of the lower left corner of the canvas
-    writeToFileExtra(fileName,
-        chaosGameDescription.getMinCoords().getX0() + ", "
-            + chaosGameDescription.getMinCoords().getX1() + " # Lower left" + "\n");
-
-    // Write third line. Coordinates of the upper right corner of the canvas
-    writeToFileExtra(fileName,
-        chaosGameDescription.getMaxCoords().getX0() + ", "
-            + chaosGameDescription.getMaxCoords().getX1() + " # Upper right" + "\n");
-
-    // Write fourth line+. A line for each transformation
-    // With all parameters separated by a comma.
-    List<Transform2D> transformations = chaosGameDescription.getTransformations();
-    for (int i = 0; i < transformations.size(); i++) {
-      if (transformations.get(i) instanceof AffineTransform2D affineTransform2D) {
-        writeToFileExtra(fileName,
-            affineTransform2D.getMatrix().getA00()
-                + ", " + affineTransform2D.getMatrix().getA01()
-                + ", " + affineTransform2D.getMatrix().getA10()
-                + ", " + affineTransform2D.getMatrix().getA11()
-                + ", " + affineTransform2D.getVector().getX0()
-                + ", " + affineTransform2D.getVector().getX1()
-                + " # " + (i + 1) + "nd transform" + "\n");
-      } else if (transformations.get(i) instanceof JuliaTransform juliaTransform) {
-        writeToFileExtra(fileName,
-            juliaTransform.getPoint().getX0() + ", "
-                + juliaTransform.getPoint().getX1() + ", "
-                + " # Real and imaginary part of the constant c");
+      /* Write the third line. The Coordinates in the upper right corner of the canvas */
+      writeToFileExtra(fileName,
+          chaosGameDescription.getMaxCoords().getX0() + ", "
+              + chaosGameDescription.getMaxCoords().getX1() + " # Upper right" + "\n");
+
+      /* Write fourth line++.
+      A line for each transformation With all parameters separated by a comma. */
+      List<Transform2D> transformations = chaosGameDescription.getTransformations();
+      for (int i = 0; i < transformations.size(); i++) {
+        if (transformations.get(i) instanceof AffineTransform2D affineTransform2D) {
+          writeToFileExtra(fileName,
+              affineTransform2D.matrix().a00()
+                  + ", " + affineTransform2D.matrix().a01()
+                  + ", " + affineTransform2D.matrix().a10()
+                  + ", " + affineTransform2D.matrix().a11()
+                  + ", " + affineTransform2D.vector().getX0()
+                  + ", " + affineTransform2D.vector().getX1()
+                  + " # " + (i + 1) + "nd transform" + "\n");
+        } else if (transformations.get(i) instanceof JuliaTransform juliaTransform) {
+          writeToFileExtra(fileName,
+              juliaTransform.getPoint().getX0() + ", "
+                  + juliaTransform.getPoint().getX1() + ", "
+                  + " # Real and imaginary part of the constant c");
+          return;
+        }
       }
+    } catch (Exception e) {
+      LOGGER.severe("An error occurred while writing ChaosGameDescription to file: "
+          + e.getMessage());
+      throw new RuntimeException("An error occurred while writing ChaosGameDescription to file: "
+          + e.getMessage(), e);
     }
   }
 
-  public static ChaosGameDescription readChaosGameDescriptionFromFile(String fileName) {
-    String content = readFromFile(fileName);
-    String[] lines = content.split("\n");
-    String type = lines[0].split("#")[0].trim();
-    String[] lowerLeft = lines[1].split("#")[0].split(",");
-    String[] upperRight = lines[2].split("#")[0].split(",");
-    String[] transformations = new String[lines.length - 3];
-
-    List<Transform2D> transformList = new ArrayList<>();
-
-    for (int i = 3; i < lines.length; i++) {
-      transformations[i - 3] = lines[i].split("#")[0].trim();
-
-      if (type.equals("Affine2D")) {
-        String[] matrix = transformations[i - 3].split(",");
-        double a00 = Double.parseDouble(matrix[0].trim());
-        double a01 = Double.parseDouble(matrix[1].trim());
-        double a10 = Double.parseDouble(matrix[2].trim());
-        double a11 = Double.parseDouble(matrix[3].trim());
-        double x0 = Double.parseDouble(matrix[4].trim());
-        double x1 = Double.parseDouble(matrix[5].trim());
-        Matrix2x2 matrix2x2 = new Matrix2x2(a00, a01, a10, a11);
-        Vector2D vector2D = new Vector2D(x0, x1);
-
-        AffineTransform2D affineTransform2D = new AffineTransform2D(matrix2x2, vector2D);
-        transformList.add(affineTransform2D);
-      } else if (type.equals("Julia")) {
-        String[] point = transformations[i - 3].split(",");
-        double x0 = Double.parseDouble(point[0].trim());
-        double x1 = Double.parseDouble(point[1].trim());
-        Complex complex = new Complex(x0, x1);
-
-        JuliaTransform juliaTransformPos = new JuliaTransform(complex, 1);
-        transformList.add(juliaTransformPos);
-        JuliaTransform juliaTransformNeg = new JuliaTransform(complex, -1);
-        transformList.add(juliaTransformNeg);
+  /**
+   * Method to read a ChaosGameDescription from a file.
+   *
+   * @param fileName name of file to read from
+   * @return ChaosGameDescription read from file
+   * @throws RuntimeException if an error occurs while reading from file
+   */
+  public static ChaosGameDescription readChaosGameDescriptionFromFile(String fileName)
+      throws RuntimeException {
+    try {
+      String content = readFromFile(fileName);
+      String[] lines = content.split("\n");
+
+      String type = lines[0].split("#")[0].trim();
+      Vector2D minCoords = parseVector2D(lines[1]);
+      Vector2D maxCoords = parseVector2D(lines[2]);
+
+      List<Transform2D> transformList = new ArrayList<>();
+      for (int i = 3; i < lines.length; i++) {
+        String transformation = lines[i].split("#")[0].trim();
+        if (type.equals("Affine2D")) {
+          transformList.add(parseAffineTransform2D(transformation));
+        } else if (type.equals("Julia")) {
+          transformList.add(parseJuliaTransform(transformation, 1));
+          transformList.add(parseJuliaTransform(transformation, -1));
+        }
       }
+      return new ChaosGameDescription(transformList, minCoords, maxCoords);
+    } catch (Exception e) {
+      LOGGER.severe("An error occurred while reading ChaosGameDescription from file: "
+          + e.getMessage());
+      throw new RuntimeException("An error occurred while reading ChaosGameDescription from file: "
+          + e.getMessage(), e);
     }
+  }
 
-    Vector2D minCoords = new Vector2D(
-        Double.parseDouble(lowerLeft[0].trim()), Double.parseDouble(lowerLeft[1].trim()));
+  /**
+   * Method to parse a string to a Vector2D object.
+   *
+   * @param line The string to parse.
+   * @return A Vector2D object.
+   */
+  private static Vector2D parseVector2D(String line) {
+    String[] coords = line.split("#")[0].split(",");
+    double x0 = Double.parseDouble(coords[0].trim());
+    double x1 = Double.parseDouble(coords[1].trim());
+    return new Vector2D(x0, x1);
+  }
 
-    Vector2D upperCoords = new Vector2D(
-        Double.parseDouble(upperRight[0].trim()), Double.parseDouble(upperRight[1].trim()));
+  /**
+   * Method to parse a string to an AffineTransform2D object.
+   *
+   * @param transformation The string to parse.
+   * @return An AffineTransform2D object.
+   */
+  private static AffineTransform2D parseAffineTransform2D(String transformation) {
+    String[] params = transformation.split(",");
+    double a00 = Double.parseDouble(params[0].trim());
+    double a01 = Double.parseDouble(params[1].trim());
+    double a10 = Double.parseDouble(params[2].trim());
+    double a11 = Double.parseDouble(params[3].trim());
+    double x0 = Double.parseDouble(params[4].trim());
+    double x1 = Double.parseDouble(params[5].trim());
+    Matrix2x2 matrix = new Matrix2x2(a00, a01, a10, a11);
+    Vector2D vector = new Vector2D(x0, x1);
+    return new AffineTransform2D(matrix, vector);
+  }
 
-    return new ChaosGameDescription(transformList, minCoords, upperCoords);
+  /**
+   * Method to parse a string to a JuliaTransform object.
+   *
+   * @param transformation The string to parse.
+   * @param sign           The sign of the imaginary part of the complex number.
+   * @return A JuliaTransform object.
+   */
+  private static JuliaTransform parseJuliaTransform(String transformation, int sign) {
+    String[] params = transformation.split(",");
+    double x0 = Double.parseDouble(params[0].trim());
+    double x1 = Double.parseDouble(params[1].trim());
+    Complex complex = new Complex(x0, x1);
+    return new JuliaTransform(complex, sign);
   }
 
-  public static List<String> showFiles(String path) {
-    List<String> files = new ArrayList<>();
-    try {
-      Files.walk(Paths.get(path))
+  /**
+   * Method to show files in a directory.
+   *
+   * @param directoryPath The path to the directory.
+   * @return A list of strings with the name of files in the directory.
+   * @throws RuntimeException if an error occurs while showing files.
+   */
+  public static List<String> showFiles(String directoryPath) throws RuntimeException {
+    Path path = Paths.get(directoryPath);
+
+    try (var stream = Files.walk(path)) {
+      return stream
           .filter(Files::isRegularFile)
-          .map(path1 -> path1.toFile().getName())
-          .forEach(files::add);
+          .map(filePath -> filePath.getFileName().toString())
+          .collect(Collectors.toList());
     } catch (IOException e) {
-      e.printStackTrace();
+      LOGGER.severe("An error occurred while showing files: " + e.getMessage());
+      throw new RuntimeException("An error occurred while showing files: " + e.getMessage());
     }
-    return files;
   }
 
-  public static int numberOfFiles(String path) {
-    int count = 0;
-    try {
-      count = (int) Files.walk(Paths.get(path))
+  /**
+   * Method to count the number of files in a directory.
+   *
+   * @param directoryPath The path to the directory.
+   * @return The number of files in the directory.
+   * @throws RuntimeException if an error occurs while counting files.
+   */
+  public static int numberOfFiles(String directoryPath) throws RuntimeException {
+    Path path = Paths.get(directoryPath);
+    try (var stream = Files.walk(path)) {
+      return (int) stream
           .filter(Files::isRegularFile)
-          .map(path1 -> path1.toFile().getName())
           .count();
     } catch (IOException e) {
-      e.printStackTrace();
+      LOGGER.severe("An error occurred while counting files: " + e.getMessage());
+      throw new RuntimeException("An error occurred while counting files: " + e.getMessage());
+    }
+  }
+
+  /**
+   * Method to delete a file from the resource folder.
+   *
+   * @param path The name of the file to be deleted.
+   *             The file must be in the resource folder.
+   * @throws RuntimeException if an error occurs while deleting the file.
+   */
+  public static void deleteFile(String path) throws RuntimeException {
+    try {
+      Files.delete(Paths.get(path));
+    } catch (IOException e) {
+      LOGGER.severe("An error occurred while deleting file: " + e.getMessage());
+      throw new RuntimeException("An error occurred while deleting file: " + e.getMessage());
     }
-    return count;
   }
 }
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/utils/ControllerUtils.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/utils/ControllerUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..52fdce8b00a1ee5e4b4c6cfbe1231f721a992120
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/utils/ControllerUtils.java
@@ -0,0 +1,207 @@
+package edu.ntnu.idatt2003.group6.utils;
+
+import static edu.ntnu.idatt2003.group6.utils.Utils.inputStringToDouble;
+
+import edu.ntnu.idatt2003.group6.models.chaosgame.ChaosGameDescription;
+import edu.ntnu.idatt2003.group6.models.matrix.Matrix2x2;
+import edu.ntnu.idatt2003.group6.models.transformation.AffineTransform2D;
+import edu.ntnu.idatt2003.group6.models.transformation.JuliaTransform;
+import edu.ntnu.idatt2003.group6.models.transformation.Transform2D;
+import edu.ntnu.idatt2003.group6.models.vector.Complex;
+import edu.ntnu.idatt2003.group6.models.vector.Vector2D;
+import edu.ntnu.idatt2003.group6.view.gamecontrols.AffineTransformationControls;
+import edu.ntnu.idatt2003.group6.view.gamecontrols.AttributeControls;
+import edu.ntnu.idatt2003.group6.view.gamecontrols.JuliaTransformationControls;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class contains methods to handle reading and writing ChaosGameDescriptions to and from
+ * files.
+ *
+ * @version 0.3.2
+ * @since 0.3.2
+ * @see ChaosGameDescription
+ * @see AffineTransformationControls
+ * @see JuliaTransformationControls
+ * @see AttributeControls
+ * @see Vector2D
+ * @see Transform2D
+ * @see AffineTransform2D
+ * @see JuliaTransform
+ * @see Complex
+ * @see Matrix2x2
+ * @see Utils
+ */
+public class ControllerUtils {
+
+  /**
+   * Get the common attributes for a chaos game description
+   * and put them in the EditFileFrame.
+   *
+   * @param attributeView The attribute view to get the attributes from.
+   * @param model         The ChaosGameDescription model to get the attributes from.
+   * @throws IllegalArgumentException If the model is null.
+   */
+  public static void setAttributesCommon(AttributeControls attributeView,
+                                         ChaosGameDescription model)
+      throws IllegalArgumentException {
+    try {
+      attributeView.setMinCoordsX0Field(String.valueOf(model.getMinCoords().getX0()));
+      attributeView.setMinCoordsX1Field(String.valueOf(model.getMinCoords().getX1()));
+      attributeView.setMaxCoordsX0Field(String.valueOf(model.getMaxCoords().getX0()));
+      attributeView.setMaxCoordsX1Field(String.valueOf(model.getMaxCoords().getX1()));
+    } catch (Exception e) {
+      throw new IllegalArgumentException("Model is null: ");
+    }
+  }
+
+  /**
+   * Set the attributes for the Julia transformation in the JuliaFrame.
+   *
+   * @param chaosGameDescription The ChaosGameDescription to get the attributes from.
+   * @return The JuliaTransformationControls frame with the attributes' set.
+   * @throws IllegalArgumentException If the ChaosGameDescription is null.
+   */
+  public static JuliaTransformationControls setAttributesJulia(
+      ChaosGameDescription chaosGameDescription) throws IllegalArgumentException {
+    try {
+      JuliaTransformationControls juliaView = new JuliaTransformationControls();
+      JuliaTransform julia = (JuliaTransform) chaosGameDescription.getTransformations().getFirst();
+      juliaView.setImaginaryC(String.valueOf(julia.getPoint().getX1()));
+      juliaView.setRealC(String.valueOf(julia.getPoint().getX0()));
+      return juliaView;
+    } catch (Exception e) {
+      throw new IllegalArgumentException("Attributes could not be set: @" + e.getMessage());
+    }
+  }
+
+  /**
+   * Set the attributes for the Affine transformations in the AffineFrame.
+   *
+   * @param model The ChaosGameDescription to get the attributes from.
+   * @return The AffineTransformationControls frame with the attribute set.
+   * @throws IllegalArgumentException If the ChaosGameDescription is null.
+   */
+  public static List<AffineTransformationControls> setAttributesAffineControlsList(
+      ChaosGameDescription model) throws IllegalArgumentException {
+    try {
+      List<Transform2D> affineTransforms = model.getTransformations();
+      List<AffineTransformationControls> affineViews = new ArrayList<>();
+      affineTransforms.forEach(transform -> {
+        AffineTransform2D affine = (AffineTransform2D) transform;
+        AffineTransformationControls affineView = new AffineTransformationControls();
+        affineView.setTransformationNumber(
+            String.valueOf(affineTransforms.indexOf(transform) + 1));
+        affineView.setA00(String.valueOf(affine.matrix().a00()));
+        affineView.setA01(String.valueOf(affine.matrix().a01()));
+        affineView.setA10(String.valueOf(affine.matrix().a10()));
+        affineView.setA11(String.valueOf(affine.matrix().a11()));
+        affineView.setX0(String.valueOf(affine.vector().getX0()));
+        affineView.setX1(String.valueOf(affine.vector().getX1()));
+        affineViews.add(affineView);
+      });
+      return affineViews;
+    } catch (Exception e) {
+      throw new IllegalArgumentException("View could not be set: @" + e.getMessage());
+    }
+  }
+
+  /**
+   * Get the attributes for a ChaosGameDescription from the EditFileFrame.
+   *
+   * @param affineTransformationControlsList The list of affine transformations to get the
+   *                                         attributes from.
+   * @param minCoords                        The minimum coordinates to get the attributes for.
+   * @param maxCoords                        The maximum coordinates to get the attributes for.
+   * @return The ChaosGameDescription with the found attributes.
+   * @throws IllegalArgumentException If the ChaosGameDescription could not be created.
+   */
+  public static ChaosGameDescription getAttributesAffineControlsList(
+      List<AffineTransformationControls> affineTransformationControlsList,
+      Vector2D minCoords, Vector2D maxCoords) throws IllegalArgumentException {
+    try {
+      List<Transform2D> transforms = new ArrayList<>();
+      affineTransformationControlsList.forEach(affine -> {
+        double a00 = inputStringToDouble(affine.getA00());
+        double a01 = inputStringToDouble(affine.getA01());
+        double a10 = inputStringToDouble(affine.getA10());
+        double a11 = inputStringToDouble(affine.getA11());
+        double x0 = inputStringToDouble(affine.getX0());
+        double x1 = inputStringToDouble(affine.getX1());
+        Matrix2x2 matrix = new Matrix2x2(a00, a01, a10, a11);
+        Vector2D vector = new Vector2D(x0, x1);
+        AffineTransform2D affineTransform = new AffineTransform2D(matrix, vector);
+        transforms.add(affineTransform);
+      });
+      return new ChaosGameDescription(transforms, minCoords, maxCoords);
+    } catch (Exception e) {
+      throw new IllegalArgumentException(
+          "ChaosGameDescription could not be created: @" + e.getMessage());
+    }
+  }
+
+  /**
+   * Get the attributes for a ChaosGameDescription from the JuliaFrame.
+   *
+   * @param juliaTransform The JuliaTransformationControls to get the attributes from.
+   * @param minCoords      The minimum coordinates to get the attributes for.
+   * @param maxCoords      The maximum coordinates to get the attributes for.
+   * @return The ChaosGameDescription with the found attributes.
+   * @throws IllegalArgumentException If the ChaosGameDescription could not be created.
+   */
+  public static ChaosGameDescription getAttributesJuliaControls(
+      JuliaTransformationControls juliaTransform, Vector2D minCoords, Vector2D maxCoords)
+      throws IllegalArgumentException {
+    try {
+      List<Transform2D> transforms = new ArrayList<>();
+      double realC = inputStringToDouble(juliaTransform.getRealC());
+      double imaginaryC = inputStringToDouble(juliaTransform.getImaginaryC());
+      Complex point = new Complex(realC, imaginaryC);
+      JuliaTransform juliaPos = new JuliaTransform(point, 1);
+      JuliaTransform juliaNeg = new JuliaTransform(point, -1);
+      transforms.add(juliaPos);
+      transforms.add(juliaNeg);
+      return new ChaosGameDescription(transforms, minCoords, maxCoords);
+    } catch (Exception e) {
+      throw new IllegalArgumentException(
+          "ChaosGameDescription could not be created: @" + e.getMessage());
+    }
+  }
+
+  /**
+   * Get the minimum coordinates from the AttributeControls.
+   *
+   * @param attributeControls The AttributeControls to get the minimum coordinates from.
+   * @return The minimum coordinates.
+   * @throws IllegalArgumentException If the minimum coordinates could not be found.
+   */
+  public static Vector2D getMinCoordsControls(AttributeControls attributeControls)
+      throws IllegalArgumentException {
+    try {
+      double minCoordsX0 = inputStringToDouble(attributeControls.getMinCoordsX0Field());
+      double minCoordsX1 = inputStringToDouble(attributeControls.getMinCoordsX1Field());
+      return new Vector2D(minCoordsX0, minCoordsX1);
+    } catch (Exception e) {
+      throw new IllegalArgumentException("Could not get min coords: @" + e.getMessage());
+    }
+  }
+
+  /**
+   * Get the maximum coordinates from the AttributeControls.
+   *
+   * @param attributeControls The AttributeControls to get the maximum coordinates from.
+   * @return The maximum coordinates.
+   * @throws IllegalArgumentException If the maximum coordinates could not be found.
+   */
+  public static Vector2D getMaxCoordsControls(AttributeControls attributeControls)
+      throws IllegalArgumentException {
+    try {
+      double maxCoordsX0 = inputStringToDouble(attributeControls.getMaxCoordsX0Field());
+      double maxCoordsX1 = inputStringToDouble(attributeControls.getMaxCoordsX1Field());
+      return new Vector2D(maxCoordsX0, maxCoordsX1);
+    } catch (Exception e) {
+      throw new IllegalArgumentException("Could not get max coords: @" + e.getMessage());
+    }
+  }
+}
\ No newline at end of file
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/utils/Utils.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/utils/Utils.java
index edd3404f069f7d1d215a71ca0cc5a803ac8ca855..7bd920fe3a7328a119310ebb81e10645106dc07f 100644
--- a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/utils/Utils.java
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/utils/Utils.java
@@ -1,7 +1,6 @@
 package edu.ntnu.idatt2003.group6.utils;
 
 
-
 import java.util.List;
 import java.util.Scanner;
 
@@ -15,22 +14,7 @@ import java.util.Scanner;
 public class Utils {
 
   /**
-   * Verifies if the given parameter is a valid double.
-   *
-   * @param parameter     The parameter to be verified.
-   * @param parameterName The name of the parameter to be used in the exception message.
-   * @throws IllegalArgumentException If the given parameter is not a valid double.
-   */
-  public static void verifyDoubleParameter(Double parameter, String parameterName)
-      throws IllegalArgumentException {
-    if (parameter.isInfinite() || parameter.isNaN()) {
-      throw new IllegalArgumentException("The string for the parameter "
-          + parameterName + " was not valid, try to register again");
-    }
-  }
-
-  /**
-   * Verifies if the given parameter is a valid sign, 1 or -1.
+   * Verifies if the given parameter is a valid sign, +-1.
    *
    * @param parameter     The parameter to be verified.
    * @param parameterName The name of the parameter to be used in the exception message.
@@ -59,6 +43,11 @@ public class Utils {
     return in.nextDouble();
   }
 
+  /**
+   * A method to input an integer from the user. Verifies if the input is a valid integer.
+   *
+   * @return The integer input by the user.
+   */
   public static int inputInt() {
     Scanner in = new Scanner(System.in);
     while (!in.hasNextInt()) {
@@ -68,12 +57,20 @@ public class Utils {
     return in.nextInt();
   }
 
+  /**
+   * A method to print a list of strings with a number in front.
+   */
   public static void printListWithNumbers(List<String> list) {
     for (int i = 0; i < list.size(); i++) {
       System.out.println(i + 1 + ". " + list.get(i));
     }
   }
 
+  /**
+   * A method to verify if the user input is y or n.
+   *
+   * @return true if the user input is y, false if the user input is n.
+   */
   public static boolean editYesNo() {
     Scanner in = new Scanner(System.in);
     String choice = in.nextLine();
@@ -82,4 +79,34 @@ public class Utils {
     }
     return choice.equals("y");
   }
+
+  /**
+   * a method to parse a string to an integer.
+   *
+   * @param input the string to be parsed.
+   * @return the integer value of the string, or 0 if the string is not a valid integer.
+   * @throws IllegalArgumentException if the string is not a valid integer.
+   */
+  public static int inputStringToInt(String input) throws IllegalArgumentException {
+    try {
+      return Integer.parseInt(input);
+    } catch (NumberFormatException e) {
+      throw new IllegalArgumentException("The string was not a valid integer");
+    }
+  }
+
+  /**
+   * a method to parse a string to a double.
+   *
+   * @param input the string to be parsed.
+   * @return the double value of the string, or 0 if the string is not a valid double.
+   * @throws IllegalArgumentException if the string is not a valid double.
+   */
+  public static double inputStringToDouble(String input) throws IllegalArgumentException {
+    try {
+      return Double.parseDouble(input);
+    } catch (NullPointerException e) {
+      throw new IllegalArgumentException("The string was not a valid double");
+    }
+  }
 }
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/utils/exceptions/IllegalChaosGameException.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/utils/exceptions/IllegalChaosGameException.java
new file mode 100644
index 0000000000000000000000000000000000000000..69b6864d28d9921d879488bfe23cc0b294729c47
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/utils/exceptions/IllegalChaosGameException.java
@@ -0,0 +1,33 @@
+package edu.ntnu.idatt2003.group6.utils.exceptions;
+
+import edu.ntnu.idatt2003.group6.controller.chaosgame.ChaosGame;
+
+/**
+ * Exception thrown when an illegal operation is performed on a ChaosGame object.
+ *
+ * @version 0.3.2
+ * @see ChaosGame
+ * @see edu.ntnu.idatt2003.group6.utils.ChaosGameFileHandler
+ * @since 0.3.2
+ */
+public class IllegalChaosGameException extends IllegalArgumentException {
+
+  /**
+   * Constructs an IllegalChaosGameException with the specified detail message and cause.
+   *
+   * @param message the detail message
+   * @param cause the cause
+   */
+  public IllegalChaosGameException(String message, Throwable cause) {
+    super(message, cause);
+  }
+
+  /**
+   * Constructs an IllegalChaosGameException with the specified detail message.
+   *
+   * @param message the detail message
+   */
+  public IllegalChaosGameException(String message) {
+    super(message);
+  }
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/ButtonBox.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/ButtonBox.java
deleted file mode 100644
index 588fac14e25d4311989a8e675d175b54f06c5cf0..0000000000000000000000000000000000000000
--- a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/ButtonBox.java
+++ /dev/null
@@ -1,102 +0,0 @@
-package edu.ntnu.idatt2003.group6.view;
-
-import javafx.event.ActionEvent;
-import javafx.event.EventHandler;
-import javafx.geometry.Insets;
-import javafx.scene.control.ToggleGroup;
-import javafx.scene.layout.VBox;
-
-public class ButtonBox extends VBox {
-
-  private static final String MENU_BUTTON_STYLE = "menuButton";
-  private static final String SUB_MENU_BUTTON_STYLE = "subMenuButton";
-
-  private final CustomToggleButton playGameButton;
-  private final CustomToggleButton filesButton;
-  private final CustomToggleButton quitButton;
-  private final CustomToggleButton playSierpinskiButton;
-  private final CustomToggleButton playJuliaButton;
-  private final CustomToggleButton playBarnsleyButton;
-  private final CustomToggleButton playMandelbrotButton;
-
-  private final ToggleGroup menuButtonGroup = new ToggleGroup();
-  private final ToggleGroup subMenuButtonGroup = new ToggleGroup();
-
-  public ButtonBox() {
-    getStyleClass().add("buttonBox");
-
-    playGameButton = new CustomToggleButton("Play Game", MENU_BUTTON_STYLE);
-    filesButton = new CustomToggleButton("Files", MENU_BUTTON_STYLE);
-    quitButton = new CustomToggleButton("Quit", MENU_BUTTON_STYLE);
-
-    playSierpinskiButton = new CustomToggleButton("Sierpinski", SUB_MENU_BUTTON_STYLE);
-    playJuliaButton = new CustomToggleButton("Julia", SUB_MENU_BUTTON_STYLE);
-    playBarnsleyButton = new CustomToggleButton("Barnsley", SUB_MENU_BUTTON_STYLE);
-    playMandelbrotButton = new CustomToggleButton("Mandelbrot", SUB_MENU_BUTTON_STYLE);
-
-    playGameButton.setToggleGroup(menuButtonGroup);
-    filesButton.setToggleGroup(menuButtonGroup);
-    quitButton.setToggleGroup(menuButtonGroup);
-
-    playSierpinskiButton.setToggleGroup(subMenuButtonGroup);
-    playJuliaButton.setToggleGroup(subMenuButtonGroup);
-    playBarnsleyButton.setToggleGroup(subMenuButtonGroup);
-    playMandelbrotButton.setToggleGroup(subMenuButtonGroup);
-
-    menuButtonGroup.selectToggle(null);
-    getChildren().addAll(playGameButton, filesButton, quitButton);
-
-    menuButtonGroup.selectedToggleProperty().addListener((observable, oldValue, newValue) -> {
-      if (newValue == playGameButton) {
-        addSubMenuButtonBox();
-      } else {
-        clearSubMenuButtonBox();
-      }
-    });
-  }
-
-  public void setActionOnButton(String buttonType, EventHandler<ActionEvent> eventHandler) {
-    switch (buttonType) {
-      case "playGame":
-        playGameButton.setOnAction(eventHandler);
-        break;
-      case "files":
-        filesButton.setOnAction(eventHandler);
-        break;
-      case "quit":
-        quitButton.setOnAction(eventHandler);
-        break;
-      case "playSierpinski":
-        playSierpinskiButton.setOnAction(eventHandler);
-        break;
-      case "playJulia":
-        playJuliaButton.setOnAction(eventHandler);
-        break;
-      case "playBarnsley":
-        playBarnsleyButton.setOnAction(eventHandler);
-        break;
-      case "playMandelbrot":
-
-        playMandelbrotButton.setOnAction(eventHandler);
-        break;
-      default:
-        break;
-    }
-  }
-
-  private void addSubMenuButtonBox(){
-    VBox subMenuButtonBox = new VBox();
-
-    subMenuButtonBox.getChildren().addAll(
-        playSierpinskiButton, playJuliaButton, playBarnsleyButton, playMandelbrotButton);
-    subMenuButtonBox.setPadding(new Insets(0, 0, 0, 20));
-
-    getChildren().add(1, subMenuButtonBox);
-  }
-  private void clearSubMenuButtonBox(){
-    if (getChildren().get(1) instanceof VBox) {
-      subMenuButtonGroup.selectToggle(null);
-      getChildren().remove(1);
-    }
-  }
-}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/CommandLineInterface.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/CommandLineInterface.java
index 1434c428f3e9f234a229fa989fdc950f2634fd2d..c35db60fdd1cacd0f389eeb0e32c86c2693e563a 100644
--- a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/CommandLineInterface.java
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/CommandLineInterface.java
@@ -9,7 +9,7 @@ import static edu.ntnu.idatt2003.group6.utils.Utils.inputDouble;
 import static edu.ntnu.idatt2003.group6.utils.Utils.inputInt;
 import static edu.ntnu.idatt2003.group6.utils.Utils.printListWithNumbers;
 
-import edu.ntnu.idatt2003.group6.controller.ChaosGame;
+import edu.ntnu.idatt2003.group6.controller.chaosgame.ChaosGame;
 import edu.ntnu.idatt2003.group6.models.chaosgame.ChaosGameDescription;
 import edu.ntnu.idatt2003.group6.models.matrix.Matrix2x2;
 import edu.ntnu.idatt2003.group6.models.transformation.AffineTransform2D;
@@ -37,6 +37,11 @@ public class CommandLineInterface {
   private static ChaosGame chaosGame;
   private static ChaosGameDescription description;
 
+  /**
+   * Main method to run the Chaos Game as a command line application.
+   *
+   * @param args The command line arguments.
+   */
   public static void main(String[] args) {
     CommandLineInterface commandLineInterface = new CommandLineInterface();
 
@@ -102,7 +107,11 @@ public class CommandLineInterface {
   private void runGame() {
     System.out.println("Enter the number of steps to run the chaos game for: ");
     int steps = inputInt();
-    chaosGame.runSteps(steps);
+    try {
+      chaosGame.runSteps(steps);
+    } catch (Exception e) {
+      System.out.println(" Could not run the game: \n" + e.getMessage());
+    }
   }
 
   /**
@@ -134,16 +143,17 @@ public class CommandLineInterface {
       System.out.println("No file chosen. Returning to main menu.");
     } else {
       description = readChaosGameDescriptionFromFile(file);
-      chaosGame = new ChaosGame(description, 100, 30);
+      chaosGame = new ChaosGame(description, 50, 50);
       System.out.println("Chaos Game Description loaded successfully!");
     }
   }
 
   /**
    * Method to choose a file from the list of files in the descriptions folder.
+   *
    * @return The file path of the chosen file.
    */
-  public String chooseFile(){
+  public String chooseFile() {
     System.out.println(
         "Which file would you like to choose?"
             + "\n0. Back to main menu");
@@ -166,27 +176,31 @@ public class CommandLineInterface {
    * Method to display the canvas of the chaos game.
    */
   private void displayCanvas() {
-    int[][] canvasArray = chaosGame.getCanvas().getCanvasArray();
-    for (int[] row : canvasArray) {
-      for (int pixel : row) {
-        if (pixel == 0) {
-          System.out.print(" ");
-        } else if (pixel == 1) {
-          System.out.print("X");
+    try {
+      int[][] canvasArray = chaosGame.getCanvas().getCanvasArray();
+      for (int[] row : canvasArray) {
+        for (int pixel : row) {
+          if (pixel == 0) {
+            System.out.print(" ");
+          } else if (pixel >= 1) {
+            System.out.print("X");
+          }
         }
+        System.out.println();
       }
-      System.out.println();
+    } catch (Exception e) {
+      System.out.println("Could not print the canvas: \n" + e.getMessage());
     }
   }
 
   /**
    * Method to edit the coordinates of the chaos game.
    */
-  private void editCoordinate(){
+  private void editCoordinate() {
     System.out.println("Current min coordinates: "
-        + description.getMinCoords().getX0() + ", " + description.getMinCoords().getX1() +"\n"
+        + description.getMinCoords().getX0() + ", " + description.getMinCoords().getX1() + "\n"
         + "Current max coordinates: "
-        + description.getMaxCoords().getX0() + ", " + description.getMaxCoords().getX1() +"\n"
+        + description.getMaxCoords().getX0() + ", " + description.getMaxCoords().getX1() + "\n"
         + "Would you like to edit the min and max coordinates? (y/n)");
     if (editYesNo()) {
       System.out.println("Enter the new min coordinates: \n");
@@ -205,18 +219,18 @@ public class CommandLineInterface {
         .filter(transform -> transform instanceof AffineTransform2D)
         .forEach(transform -> {
           AffineTransform2D affineTransforms = (AffineTransform2D) transform;
-          Matrix2x2 matrix = affineTransforms.getMatrix();
-          Vector2D vector = affineTransforms.getVector();
+          Matrix2x2 matrix = affineTransforms.matrix();
+          Vector2D vector = affineTransforms.vector();
 
-          System.out.println("Current matrix: " + matrix.getA00() + ", " + matrix.getA01()
-                + ", " + matrix.getA10() + ", " + matrix.getA11()
+          System.out.println("Current matrix: " + matrix.a00() + ", " + matrix.a01()
+              + ", " + matrix.a10() + ", " + matrix.a11()
               + "\nWould you like to edit the matrix (y/n)");
-          if (editYesNo()){
+          if (editYesNo()) {
             matrix = changeMatrix();
           }
           System.out.println("Current vector: " + vector.getX0() + ", " + vector.getX1()
               + "\nWould you like to edit the vector (y/n)");
-          if (editYesNo()){
+          if (editYesNo()) {
             vector = changeVector2D();
           }
           newAffineTransforms.add(new AffineTransform2D(matrix, vector));
@@ -232,7 +246,7 @@ public class CommandLineInterface {
    */
   private void writeJuliaToFile(String file) {
     System.out.println("Would you like to edit the constant c? (y/n)");
-    if (editYesNo()){
+    if (editYesNo()) {
       List<Transform2D> transforms = new ArrayList<>();
       Complex constant = changeComplex();
       transforms.add(new JuliaTransform(constant, 1));
@@ -245,6 +259,7 @@ public class CommandLineInterface {
 
   /**
    * Method to change the vector2D of the chaos game.
+   *
    * @return The new vector2D.
    */
   private Vector2D changeVector2D() {
@@ -254,23 +269,26 @@ public class CommandLineInterface {
     double x1 = inputDouble();
     return new Vector2D(x0, x1);
   }
+
   /**
    * Method to change the complex number of the chaos game.
+   *
    * @return The new complex number.
    */
   private Complex changeComplex() {
     JuliaTransform descriptionJulia = (JuliaTransform) description.getTransformations().getFirst();
     System.out.println("Enter the real part of the constant c:\n"
-        + "Current real part: "+descriptionJulia.getPoint().getX0());
+        + "Current real part: " + descriptionJulia.getPoint().getX0());
     double x0 = inputDouble();
     System.out.println("Enter the imaginary part of the constant c:\n"
-        + "Current imaginary part: "+descriptionJulia.getPoint().getX0());
+        + "Current imaginary part: " + descriptionJulia.getPoint().getX0());
     double x1 = inputDouble();
     return new Complex(x0, x1);
   }
 
   /**
    * Method to change the matrix of the chaos game.
+   *
    * @return The new matrix.
    */
   private Matrix2x2 changeMatrix() {
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/CustomButton.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/CustomButton.java
deleted file mode 100644
index de793f1b93f39975ba120133864ab68e369930fb..0000000000000000000000000000000000000000
--- a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/CustomButton.java
+++ /dev/null
@@ -1,12 +0,0 @@
-package edu.ntnu.idatt2003.group6.view;
-
-
-import javafx.scene.control.Button;
-
-public class CustomButton extends Button {
-
-    public CustomButton(String text, String styleClass) {
-      super(text);
-      getStyleClass().add(styleClass);
-    }
-}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/CustomToggleButton.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/CustomToggleButton.java
deleted file mode 100644
index fdc87954dd76079e46b990f938ad646dbaa1ab5b..0000000000000000000000000000000000000000
--- a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/CustomToggleButton.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package edu.ntnu.idatt2003.group6.view;
-
-import javafx.scene.control.ToggleButton;
-
-public class CustomToggleButton extends ToggleButton {
-
-    public CustomToggleButton(String text, String styleClass) {
-      super(text);
-      getStyleClass().add(styleClass);
-    }
-}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/HomePage.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/HomePage.java
deleted file mode 100644
index 55b2ee1289eacbd667385d73ac9aa54abaa718be..0000000000000000000000000000000000000000
--- a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/HomePage.java
+++ /dev/null
@@ -1,43 +0,0 @@
-package edu.ntnu.idatt2003.group6.view;
-
-import javafx.event.ActionEvent;
-import javafx.event.EventHandler;
-import javafx.scene.layout.*;
-import javafx.stage.Stage;
-
-public class HomePage extends StackPane {
-
-  private ButtonBox buttonBox;
-  private TransformationFrame transformationFrame;
-
-  public HomePage(Stage stage) {
-    this.prefWidthProperty().bind(stage.widthProperty());
-    this.prefHeightProperty().bind(stage.heightProperty());
-    getStyleClass().add("homePage");
-
-    buttonBox = new ButtonBox();
-    transformationFrame = new TransformationFrame();
-
-
-    BorderPane buttonBoxFrame = new BorderPane();
-    Pane contentFrame = new Pane();
-    buttonBoxFrame.setBottom(buttonBox);
-    contentFrame.getChildren().add(transformationFrame);
-
-    HBox homePageFrame = new HBox();
-    homePageFrame.getChildren().addAll(buttonBoxFrame, contentFrame);
-
-    HBox.setHgrow(buttonBoxFrame, Priority.ALWAYS);
-    HBox.setHgrow(contentFrame, Priority.ALWAYS);
-    buttonBoxFrame.prefWidthProperty().bind(homePageFrame.widthProperty().multiply(0.3));
-    contentFrame.prefWidthProperty().bind(homePageFrame.widthProperty().multiply(0.7));
-
-    this.getChildren().add(homePageFrame);
-  }
-
-
-
-  public void setActionOnButton(String buttonType, EventHandler<ActionEvent> eventHandler) {
-    buttonBox.setActionOnButton(buttonType, eventHandler);
-  }
-}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/TransformationAttributeFrame.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/TransformationAttributeFrame.java
deleted file mode 100644
index f49bf3e3e80e95758d7c6d68e01ce5b246f22f71..0000000000000000000000000000000000000000
--- a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/TransformationAttributeFrame.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package edu.ntnu.idatt2003.group6.view;
-
-import javafx.scene.layout.GridPane;
-
-public class TransformationAttributeFrame extends GridPane {
-  public TransformationAttributeFrame() {
-    super();
-  }
-}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/TransformationDisplay.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/TransformationDisplay.java
deleted file mode 100644
index dd5e038a035c7015da8fead19d82a2da90b1ea4c..0000000000000000000000000000000000000000
--- a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/TransformationDisplay.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package edu.ntnu.idatt2003.group6.view;
-
-import edu.ntnu.idatt2003.group6.controller.ChaosGame;
-import javafx.scene.layout.StackPane;
-
-public class TransformationDisplay extends StackPane {
-
-  public TransformationDisplay() {;
-  }
-
-  public void setTransformationDisplay(ChaosGame chaosGame) {
-    //unused
-  }
-}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/TransformationFrame.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/TransformationFrame.java
deleted file mode 100644
index ef324cf08a78086523b28fd7268da80f3728d282..0000000000000000000000000000000000000000
--- a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/TransformationFrame.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package edu.ntnu.idatt2003.group6.view;
-
-import edu.ntnu.idatt2003.group6.controller.ChaosGame;
-import javafx.scene.layout.GridPane;
-import javafx.scene.layout.StackPane;
-import javafx.scene.layout.VBox;
-
-public class TransformationFrame extends VBox {
-  private TransformationDisplay transformationDisplay;
-  private TransformationAttributeFrame transformationAttributeFrame;
-
-  public TransformationFrame() {
-    transformationDisplay = new TransformationDisplay();
-    transformationAttributeFrame = new TransformationAttributeFrame();
-  }
-
-  public void setTransformationDisplay(ChaosGame chaosGame) {
-    transformationDisplay.setTransformationDisplay(chaosGame);
-  }
-}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/alert/AlertError.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/alert/AlertError.java
new file mode 100644
index 0000000000000000000000000000000000000000..77238e9c0b6416e5f93aa1db97f1c1f16a43d856
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/alert/AlertError.java
@@ -0,0 +1,66 @@
+package edu.ntnu.idatt2003.group6.view.alert;
+
+import edu.ntnu.idatt2003.group6.controller.chaosgame.ChaosGameController;
+import java.util.Objects;
+import javafx.geometry.Insets;
+import javafx.scene.control.Alert;
+import javafx.scene.control.ButtonType;
+import javafx.scene.image.Image;
+import javafx.scene.layout.VBox;
+import javafx.scene.text.Text;
+import javafx.stage.Stage;
+
+/**
+ * A class for creating an error alert.
+ *
+ * @version 0.3.2
+ * @since 0.3.2
+ */
+public class AlertError extends Alert {
+
+  /**
+   * Creates an error alert with the specified message.
+   *
+   * @param message the message to be displayed in the alert
+   */
+  public AlertError(String message, String description) {
+    super(AlertType.ERROR);
+    this.getDialogPane().getStylesheets().add(
+        Objects.requireNonNull(getClass().getResource("/stylesheets/alert.css")).toExternalForm());
+    this.setTitle("Error");
+    setIcon();
+    this.setGraphic(null);
+    this.setHeaderText(null);
+
+    Text text = new Text(message);
+    text.getStyleClass().add("errorText");
+    Text descriptionText = new Text(description);
+    descriptionText.getStyleClass().add("errorDescription");
+
+    VBox content = new VBox();
+    content.getStyleClass().add("vBox");
+    content.setPadding(new Insets(10));
+    content.setSpacing(10);
+    content.getChildren().addAll(text, descriptionText);
+
+    this.getDialogPane().setContent(content);
+
+    this.getDialogPane().lookupButton(ButtonType.OK).getStyleClass().add("positiveButton");
+  }
+
+  /**
+   * Shows the alert.
+   */
+  public void showAlertError() {
+    this.showAndWait();
+  }
+
+  /**
+   * Sets the icon of the alert.
+   */
+  private void setIcon() {
+    ((Stage) this.getDialogPane().getScene().getWindow()).getIcons().add(
+        new Image(Objects.requireNonNull(
+            ChaosGameController.class.getResourceAsStream("/Logo.png"))));
+  }
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/alert/AlertInputFileName.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/alert/AlertInputFileName.java
new file mode 100644
index 0000000000000000000000000000000000000000..f667fecad7a2aadcfb3789941f33a2c15eab7944
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/alert/AlertInputFileName.java
@@ -0,0 +1,76 @@
+package edu.ntnu.idatt2003.group6.view.alert;
+
+import edu.ntnu.idatt2003.group6.controller.chaosgame.ChaosGameController;
+import java.util.Objects;
+import javafx.geometry.Insets;
+import javafx.scene.control.Alert;
+import javafx.scene.control.ButtonType;
+import javafx.scene.control.TextField;
+import javafx.scene.image.Image;
+import javafx.scene.layout.VBox;
+import javafx.scene.text.Text;
+import javafx.stage.Stage;
+
+/**
+ * Alert for inputting a file name.
+ *
+ * @version 0.3.2
+ * @since 0.3.2
+ */
+public class AlertInputFileName extends Alert {
+  private final TextField fileName;
+
+  /**
+   * Constructor for the AlertInputFileName class.
+   */
+  public AlertInputFileName() {
+    super(AlertType.CONFIRMATION);
+    this.getDialogPane().getStylesheets().add(
+        Objects.requireNonNull(getClass().getResource(
+            "/stylesheets/alert.css")).toExternalForm());
+
+    setTitle("Enter file name");
+    setHeaderText(null);
+    setGraphic(null);
+    setIcon();
+
+    VBox content = new VBox();
+    content.setPadding(new Insets(10));
+    content.setSpacing(10);
+    Text text = new Text("Please enter the name of the file you want to save: ");
+    fileName = new TextField();
+    text.getStyleClass().add("informationText");
+    fileName.getStyleClass().add("textField");
+    content.getChildren().addAll(text, fileName);
+    getDialogPane().setContent(content);
+
+    getDialogPane().lookupButton(ButtonType.OK).getStyleClass().add("positiveButton");
+    getDialogPane().lookupButton(ButtonType.CANCEL).getStyleClass().add("negativeButton");
+  }
+
+
+  /**
+   * Returns the file name.
+   *
+   * @return the file name.
+   */
+  public String getFileName() {
+    return fileName.getText();
+  }
+
+  /**
+   * Shows the alert.
+   */
+  public void showAlert() {
+    this.showAndWait();
+  }
+
+  /**
+   * Sets the icon of the alert.
+   */
+  private void setIcon() {
+    ((Stage) this.getDialogPane().getScene().getWindow()).getIcons()
+        .add(new Image(Objects.requireNonNull(
+            ChaosGameController.class.getResourceAsStream("/Logo.png"))));
+  }
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/buttonbox/ButtonBoxControls.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/buttonbox/ButtonBoxControls.java
new file mode 100644
index 0000000000000000000000000000000000000000..4b700549e1b9bc13adc38bd1a5883421577eb7ab
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/buttonbox/ButtonBoxControls.java
@@ -0,0 +1,71 @@
+package edu.ntnu.idatt2003.group6.view.buttonbox;
+
+import javafx.scene.layout.VBox;
+
+/**
+ * A class for creating a VBox with buttons for saving,
+ * loading and running the game and returning to
+ * the menu.
+ *
+ * @version 0.3.2
+ * @see CustomButton
+ * @since 0.3.2
+ */
+public class ButtonBoxControls extends VBox {
+
+  private static final String MENU_BUTTON_STYLE = "menuButton";
+  private final CustomButton saveButton;
+  private final CustomButton runGameButton;
+  private final CustomButton backToMenuButton;
+  private final CustomButton loadParametersButton;
+
+  /**
+   * Constructor for PlayGameButtonBox.
+   * Creates a VBox with text fields for steps, max cords and min cords, and buttons for saving,
+   * loading and running the game and returning to the menu.
+   */
+  public ButtonBoxControls() {
+
+    getStyleClass().add("buttonBox");
+    loadParametersButton = new CustomButton("Load Parameters", MENU_BUTTON_STYLE);
+    saveButton = new CustomButton("Save Game", MENU_BUTTON_STYLE);
+    runGameButton = new CustomButton("Run Game", MENU_BUTTON_STYLE);
+    backToMenuButton = new CustomButton("Back to menu", MENU_BUTTON_STYLE);
+
+    getChildren().addAll(
+        runGameButton, loadParametersButton, saveButton, backToMenuButton);
+
+  }
+
+
+  /**
+   * Returns the save button.
+   *
+   * @return the save button.
+   */
+  public CustomButton getSaveButton() {
+    return saveButton;
+  }
+
+  /**
+   * Returns the run game button.
+   *
+   * @return the run game button.
+   */
+  public CustomButton getRunGameButton() {
+    return runGameButton;
+  }
+
+  /**
+   * Returns the back to menu button.
+   *
+   * @return the back to menu button.
+   */
+  public CustomButton getBackToMenuButton() {
+    return backToMenuButton;
+  }
+
+  public CustomButton getLoadParametersButton() {
+    return loadParametersButton;
+  }
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/buttonbox/ButtonBoxFiles.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/buttonbox/ButtonBoxFiles.java
new file mode 100644
index 0000000000000000000000000000000000000000..a88e79577a34b9b07a5bc2a84a810357f213d911
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/buttonbox/ButtonBoxFiles.java
@@ -0,0 +1,115 @@
+package edu.ntnu.idatt2003.group6.view.buttonbox;
+
+import java.util.List;
+import javafx.scene.control.ToggleGroup;
+import javafx.scene.layout.VBox;
+
+/**
+ * A class for creating a VBox with buttons for editing,
+ * creating and deleting files and returning to the menu.
+ *
+ * @version 0.3.2
+ * @see CustomButton
+ * @see CustomToggleButton
+ * @since 0.3.2
+ */
+public class ButtonBoxFiles extends VBox {
+
+  private static final String MENU_BUTTON_STYLE = "menuButton";
+
+  private final VBox filesButtonsBoxToggle;
+  private final VBox filesButtonsBox;
+
+  private final CustomButton newFileButton;
+  private final CustomButton editFileButton;
+  private final CustomButton deleteFileButton;
+  private final CustomButton backToMenuButton;
+  private final ToggleGroup toggleButtons;
+
+  /**
+   * Constructor for PlayGameButtonBox.
+   * Creates a VBox with text fields for steps, max cords and min cords, and buttons for saving,
+   * loading and running the game and returning to the menu.
+   */
+  public ButtonBoxFiles() {
+
+    toggleButtons = new ToggleGroup();
+    filesButtonsBoxToggle = new VBox();
+    filesButtonsBox = new VBox();
+
+    getStyleClass().add("buttonBox");
+
+    editFileButton = new CustomButton("Edit file", MENU_BUTTON_STYLE);
+    newFileButton = new CustomButton("New file", MENU_BUTTON_STYLE);
+    deleteFileButton = new CustomButton("Delete file", MENU_BUTTON_STYLE);
+    backToMenuButton = new CustomButton("Back to menu", MENU_BUTTON_STYLE);
+
+    VBox menuButtonsBox = new VBox();
+    menuButtonsBox.getChildren().addAll(editFileButton, newFileButton, deleteFileButton,
+        backToMenuButton);
+    setSpacing(20);
+    getChildren().addAll(filesButtonsBoxToggle, menuButtonsBox);
+  }
+
+  public VBox getFilesButtonsBox() {
+    return filesButtonsBox;
+  }
+
+  public List<CustomToggleButton> getFileButtonsToggle() {
+    return filesButtonsBoxToggle.getChildren().stream()
+        .map(e -> (CustomToggleButton) e).toList();
+  }
+
+  public List<CustomButton> getFileButtons() {
+    return filesButtonsBox.getChildren().stream()
+        .map(e -> (CustomButton) e).toList();
+  }
+
+  public void addFileButton(String filename) {
+    addFileButtonToggleGroup(filename);
+    addFileButtonCustom(filename);
+  }
+
+  private void addFileButtonToggleGroup(String filename) {
+    CustomToggleButton button = new CustomToggleButton(filename, MENU_BUTTON_STYLE);
+    filesButtonsBoxToggle.getChildren().add(button);
+    button.setToggleGroup(toggleButtons);
+  }
+
+  private void addFileButtonCustom(String filename) {
+    CustomButton button = new CustomButton(filename, MENU_BUTTON_STYLE);
+    filesButtonsBox.getChildren().add(button);
+  }
+
+
+  public void clearFileButtons() {
+    filesButtonsBoxToggle.getChildren().remove(0, filesButtonsBoxToggle.getChildren().size());
+    filesButtonsBox.getChildren().remove(0, filesButtonsBox.getChildren().size());
+  }
+
+  public ToggleGroup getToggleButtons() {
+    return toggleButtons;
+  }
+
+  /**
+   * Returns the back to menu button.
+   *
+   * @return the back to menu button.
+   */
+  public CustomButton getBackToMenuButton() {
+    return backToMenuButton;
+  }
+
+  public CustomButton getEditFileButton() {
+    return editFileButton;
+  }
+
+  public CustomButton getDeleteFileButton() {
+    return deleteFileButton;
+  }
+
+  public CustomButton getNewFileButton() {
+    return newFileButton;
+  }
+
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/buttonbox/ButtonBoxGames.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/buttonbox/ButtonBoxGames.java
new file mode 100644
index 0000000000000000000000000000000000000000..4d28ccb64f76d2cb9240bf0e1fbf9d6421526002
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/buttonbox/ButtonBoxGames.java
@@ -0,0 +1,72 @@
+package edu.ntnu.idatt2003.group6.view.buttonbox;
+
+import javafx.scene.layout.VBox;
+
+/**
+ * A class for creating a VBox with buttons for selecting and starting a game, and returning to
+ * the menu.
+ *
+ * @version 0.3.2
+ * @see CustomButton
+ * @since 0.1
+ */
+public class ButtonBoxGames extends VBox {
+  private static final String MENU_BUTTON_STYLE = "menuButton";
+
+  private final CustomButton newAffineButton;
+  private final CustomButton newJuliaButton;
+  private final CustomButton juliaButton;
+  private final CustomButton sierpinskiButton;
+  private final CustomButton barnsleyButton;
+  private final CustomButton fileButton;
+  private final CustomButton backtoMenuButton;
+
+  /**
+   * Constructor for PlayGameButtonBox.
+   * Creates a VBox with text fields for steps, max cords and min cords, and buttons for saving,
+   * loading and running the game and returning to the menu.
+   */
+  public ButtonBoxGames() {
+    getStyleClass().add("buttonBox");
+    newAffineButton = new CustomButton("New Affine", MENU_BUTTON_STYLE);
+    newJuliaButton = new CustomButton("New Julia", MENU_BUTTON_STYLE);
+    juliaButton = new CustomButton("Preset Julia Game", MENU_BUTTON_STYLE);
+    sierpinskiButton = new CustomButton("Preset Sierpinski Game", MENU_BUTTON_STYLE);
+    barnsleyButton = new CustomButton("Preset Barnsley Game", MENU_BUTTON_STYLE);
+    fileButton = new CustomButton("Game from file", MENU_BUTTON_STYLE);
+    backtoMenuButton = new CustomButton("Back to menu", MENU_BUTTON_STYLE);
+
+    getChildren().addAll(newAffineButton, newJuliaButton, juliaButton, sierpinskiButton,
+        barnsleyButton,
+        fileButton, backtoMenuButton);
+  }
+
+  public CustomButton getNewAffineButtonButton() {
+    return newAffineButton;
+  }
+
+  public CustomButton getNewJuliaButtonButton() {
+    return newJuliaButton;
+  }
+
+  public CustomButton getJuliaButton() {
+    return juliaButton;
+  }
+
+  public CustomButton getSierpinskiButton() {
+    return sierpinskiButton;
+  }
+
+  public CustomButton getBarnsleyButton() {
+    return barnsleyButton;
+  }
+
+  public CustomButton getFileButton() {
+    return fileButton;
+  }
+
+  public CustomButton getBackToMenuButton() {
+    return backtoMenuButton;
+  }
+}
+
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/buttonbox/ButtonBoxMenu.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/buttonbox/ButtonBoxMenu.java
new file mode 100644
index 0000000000000000000000000000000000000000..348763a02a447ea9c5dde903f17aecfed2232e6f
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/buttonbox/ButtonBoxMenu.java
@@ -0,0 +1,77 @@
+package edu.ntnu.idatt2003.group6.view.buttonbox;
+
+import javafx.scene.layout.VBox;
+
+/**
+ * A class for creating a VBox with buttons for the menu.
+ * The buttons are Play Game, Files, Settings and Quit.
+ * The buttons are styled with the class menuButton.
+ * The VBox is styled with the class buttonBox.
+ * The class extends VBox.
+ *
+ * @version 0.3.2
+ * @see VBox
+ * @see CustomButton
+ * @see CustomButton
+ * @since 0.3.2
+ */
+public class ButtonBoxMenu extends VBox {
+
+  private static final String MENU_BUTTON_STYLE = "menuButton";
+  private final CustomButton playGameButton;
+  private final CustomButton filesButton;
+  private final CustomButton settingsButton;
+  private final CustomButton quitButton;
+
+
+  /**
+   * Constructor for the ButtonBoxMenu class.
+   */
+  public ButtonBoxMenu() {
+    getStyleClass().add("buttonBox");
+
+    playGameButton = new CustomButton("Play Game", MENU_BUTTON_STYLE);
+    filesButton = new CustomButton("Files", MENU_BUTTON_STYLE);
+    settingsButton = new CustomButton("Settings", MENU_BUTTON_STYLE);
+    quitButton = new CustomButton("Quit", MENU_BUTTON_STYLE);
+
+    getChildren().addAll(playGameButton, filesButton, settingsButton, quitButton);
+  }
+
+
+  /**
+   * Method for getting the play Game Button.
+   *
+   * @return the playGameButton
+   */
+  public CustomButton getPlayGameButton() {
+    return playGameButton;
+  }
+
+  /**
+   * Method for getting the file Button.
+   *
+   * @return the filesButton
+   */
+  public CustomButton getFilesButton() {
+    return filesButton;
+  }
+
+  /**
+   * Method for getting the settings Button.
+   *
+   * @return the settingsButton
+   */
+  public CustomButton getSettingsButton() {
+    return settingsButton;
+  }
+
+  /**
+   * Method for getting the quit Button.
+   *
+   * @return the quit Button
+   */
+  public CustomButton getQuitButton() {
+    return quitButton;
+  }
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/buttonbox/ButtonBoxSettings.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/buttonbox/ButtonBoxSettings.java
new file mode 100644
index 0000000000000000000000000000000000000000..f779c0e9c97821d3f824b3cfdb65aec3cced164c
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/buttonbox/ButtonBoxSettings.java
@@ -0,0 +1,39 @@
+package edu.ntnu.idatt2003.group6.view.buttonbox;
+
+import javafx.scene.layout.VBox;
+
+/**
+ * The ButtonBoxSettings class creates a VBox with buttons for the settings menu.
+ * The buttons are for general settings, background settings,
+ * music settings and returning to the menu.
+ *
+ * @version 0.3.2
+ * @since 0.3.2
+ */
+public class ButtonBoxSettings extends VBox {
+
+  private static final String MENU_BUTTON_STYLE = "menuButton";
+  private final CustomButton backToMenuButton;
+
+  /**
+   * Constructor for PlayGameButtonBox.
+   * Creates a VBox with text fields for steps, max cords and min cords, and buttons for saving,
+   * loading and running the game and returning to the menu.
+   */
+  public ButtonBoxSettings() {
+    getStyleClass().add("buttonBox");
+
+    backToMenuButton = new CustomButton("Back to menu", MENU_BUTTON_STYLE);
+
+    getChildren().addAll(backToMenuButton);
+  }
+
+  /**
+   * Returns the back to menu button.
+   *
+   * @return the back to menu button.
+   */
+  public CustomButton getBackToMenuButton() {
+    return backToMenuButton;
+  }
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/buttonbox/CustomButton.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/buttonbox/CustomButton.java
new file mode 100644
index 0000000000000000000000000000000000000000..dcb4e53799b499c789465c1b4982398149092b61
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/buttonbox/CustomButton.java
@@ -0,0 +1,19 @@
+package edu.ntnu.idatt2003.group6.view.buttonbox;
+
+
+import javafx.scene.control.Button;
+
+/**
+ * CustomButton is a class that extends the Button class in JavaFX.
+ * It is used to create buttons with a specific style class.
+ *
+ * @version 0.3.2
+ * @since 0.3.2
+ */
+public class CustomButton extends Button {
+
+  public CustomButton(String text, String styleClass) {
+    super(text);
+    getStyleClass().add(styleClass);
+  }
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/buttonbox/CustomToggleButton.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/buttonbox/CustomToggleButton.java
new file mode 100644
index 0000000000000000000000000000000000000000..cccfda524a07d963c45db5247f64f7004d7c66b4
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/buttonbox/CustomToggleButton.java
@@ -0,0 +1,18 @@
+package edu.ntnu.idatt2003.group6.view.buttonbox;
+
+import javafx.scene.control.ToggleButton;
+
+/**
+ * CustomToggleButton is a class that extends the ToggleButton class in JavaFX.
+ * It is used to create toggle buttons with a specific style class.
+ *
+ * @version 0.3.2
+ * @since 0.3.2
+ */
+public class CustomToggleButton extends ToggleButton {
+
+  public CustomToggleButton(String text, String styleClass) {
+    super(text);
+    getStyleClass().add(styleClass);
+  }
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/frames/EditFileFrame.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/frames/EditFileFrame.java
new file mode 100644
index 0000000000000000000000000000000000000000..5565cf1ff5286a669b79511a0ab8fa24edb38f8a
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/frames/EditFileFrame.java
@@ -0,0 +1,192 @@
+package edu.ntnu.idatt2003.group6.view.frames;
+
+import edu.ntnu.idatt2003.group6.view.gamecontrols.AffineControlsView;
+import edu.ntnu.idatt2003.group6.view.gamecontrols.AffineTransformationControls;
+import edu.ntnu.idatt2003.group6.view.gamecontrols.AttributeControls;
+import edu.ntnu.idatt2003.group6.view.gamecontrols.JuliaTransformationControls;
+import java.util.List;
+import javafx.geometry.Pos;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.VBox;
+import javafx.scene.text.Text;
+
+/**
+ * EditFileFrame is a class that extends the VBox class in JavaFX.
+ * It is used to create a frame for editing files with different attributes.
+ *
+ * @version 0.3.2
+ * @since 0.3.2
+ */
+public class EditFileFrame extends VBox {
+  Label title;
+  TextField fileNameField;
+  AttributeControls transformationControls;
+  JuliaTransformationControls juliaTransformationControls;
+  AffineControlsView affineControlsView;
+  HBox typeButtons;
+  Button juliaTransformButton;
+  Button affineTransformButton;
+  Button saveButton;
+
+  /**
+   * Constructor for EditFileFrame.
+   */
+  public EditFileFrame() {
+    getStylesheets().add("/stylesheets/transformationAttributes.css");
+    setAlignment(Pos.CENTER);
+    title = new Label("Test");
+
+    Text fileName = new Text("File Name:");
+    fileName.getStyleClass().add("attributeNames");
+    fileNameField = new TextField();
+    fileNameField.setPromptText("Enter new file name");
+    fileNameField.getStyleClass().add("textField");
+    HBox fileNameBox = new HBox();
+    fileNameBox.getChildren().addAll(fileName, fileNameField);
+
+    transformationControls = new AttributeControls();
+    transformationControls.removeSteps();
+
+    affineControlsView = new AffineControlsView();
+    juliaTransformButton = new Button("Julia Transformation");
+    affineTransformButton = new Button("Affine Transformation");
+    saveButton = new Button("Save To File");
+
+    typeButtons = new HBox();
+    typeButtons.getChildren().addAll(juliaTransformButton, affineTransformButton);
+    getChildren().addAll(fileNameBox, transformationControls, typeButtons, saveButton);
+  }
+
+
+  /**
+   * Method for clearing the fields in the EditFileFrame.
+   */
+  public void clearFields() {
+    getChildren().remove(2);
+    getChildren().add(2, new Pane());
+    getChildren().remove(3);
+    getChildren().add(3, typeButtons);
+  }
+
+  /**
+   * Method for setting the file name field in the EditFileFrame.
+   *
+   * @param fileNameField The file name to be set.
+   */
+  public void setFileNameField(String fileNameField) {
+    this.fileNameField.setText(fileNameField);
+  }
+
+  /**
+   * Method for setting the transformation controls in the EditFileFrame.
+   *
+   * @param juliaTransformationControls the julia transformation controls to be set.
+   */
+  public void setJuliaTransformControls(JuliaTransformationControls juliaTransformationControls) {
+    this.juliaTransformationControls = juliaTransformationControls;
+    showJuliaAttributes();
+  }
+
+  /**
+   * method to get the name field of the file.
+   *
+   * @return the name of the file.
+   */
+  public String getFileNameField() {
+    return fileNameField.getText();
+  }
+
+  /**
+   * Method to get the common attributes of a transformation.
+   *
+   * @return the common transformation attributes.
+   */
+  public AttributeControls getAttributeControls() {
+    return transformationControls;
+  }
+
+  /**
+   * Method to get the julia transformation controls.
+   *
+   * @return the julia transformation controls.
+   */
+  public JuliaTransformationControls getJuliaTransformationControls() {
+    return juliaTransformationControls;
+  }
+
+  /**
+   * Method to get the affine transformation controls.
+   *
+   * @return the affine transformation controls.
+   */
+  public List<AffineTransformationControls> getAffineTransformControls() {
+    return affineControlsView.getAffineControlsList();
+  }
+
+  /**
+   * Method to get the julia transformation button.
+   *
+   * @return the julia transformation button.
+   */
+  public Button getJuliaTransformButton() {
+    return juliaTransformButton;
+  }
+
+  /**
+   * Method to get the affine transformation button.
+   *
+   * @return the affine transformation button.
+   */
+  public Button getAffineTransformButton() {
+    return affineTransformButton;
+  }
+
+  /**
+   * Method to get the affine controls view.
+   *
+   * @return the affine controls view.
+   */
+  public AffineControlsView getAffineControlsView() {
+    return affineControlsView;
+  }
+
+  /**
+   * Method to get the save button.
+   *
+   * @return the save button.
+   */
+  public Button getSaveButton() {
+    return saveButton;
+  }
+
+  /**
+   * Method to show the common transformation attributes from a file.
+   */
+  public void showFileAttributes() {
+    getChildren().clear();
+    getChildren().addAll(title, fileNameField, transformationControls, typeButtons, saveButton);
+  }
+
+  /**
+   * Method to show the affine transformation attributes from a file.
+   */
+  public void showAffineAttributes() {
+    getChildren().clear();
+    getChildren().addAll(title, fileNameField, transformationControls,
+        affineControlsView.getScrollPaneAffineControls(), saveButton);
+  }
+
+  /**
+   * Method to show the julia transformation attributes from a file.
+   */
+  public void showJuliaAttributes() {
+    getChildren().clear();
+    getChildren().addAll(title, fileNameField, transformationControls,
+        juliaTransformationControls, saveButton);
+  }
+
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/frames/HomePage.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/frames/HomePage.java
new file mode 100644
index 0000000000000000000000000000000000000000..0fb1a483bc9cb17d9512a425c345b79c379f6478
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/frames/HomePage.java
@@ -0,0 +1,277 @@
+package edu.ntnu.idatt2003.group6.view.frames;
+
+
+import edu.ntnu.idatt2003.group6.controller.chaosgame.ChaosGame;
+import edu.ntnu.idatt2003.group6.models.navigation.NavigationObserver;
+import edu.ntnu.idatt2003.group6.models.navigation.NavigationState;
+import edu.ntnu.idatt2003.group6.view.buttonbox.ButtonBoxControls;
+import edu.ntnu.idatt2003.group6.view.buttonbox.ButtonBoxFiles;
+import edu.ntnu.idatt2003.group6.view.buttonbox.ButtonBoxGames;
+import edu.ntnu.idatt2003.group6.view.buttonbox.ButtonBoxMenu;
+import edu.ntnu.idatt2003.group6.view.buttonbox.ButtonBoxSettings;
+import edu.ntnu.idatt2003.group6.view.gamecontrols.AffineControlsView;
+import edu.ntnu.idatt2003.group6.view.gamecontrols.AttributeControls;
+import edu.ntnu.idatt2003.group6.view.gamecontrols.JuliaTransformationControls;
+import java.util.Objects;
+import javafx.scene.image.Image;
+import javafx.scene.image.ImageView;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.Pane;
+import javafx.scene.layout.Priority;
+import javafx.scene.layout.StackPane;
+import javafx.stage.Stage;
+
+
+/**
+ * The HomePage class is the main view of the application.
+ * It contains the menu buttons and the content frame.
+ * The content frame is where the different views are displayed.
+ * The views are controlled by the NavigationState enum.
+ *
+ * @version 0.3.2
+ * @since 0.3.2
+ */
+public class HomePage extends StackPane implements NavigationObserver {
+  private final Pane contentFrame;
+  private final ButtonBoxMenu buttonBoxMenu;
+  private final BorderPane buttonBoxFrame;
+  private final ButtonBoxControls buttonBoxControls;
+  private final ButtonBoxFiles buttonBoxFiles;
+  private final ButtonBoxSettings buttonBoxSettings;
+  private final TransformationFrame transformationFrame;
+  private final ButtonBoxGames buttonBoxSelectGame;
+  private final AttributeControls attributeControls;
+  private JuliaTransformationControls juliaTransformationControls;
+  private final AffineControlsView affineControlsView;
+  private final EditFileFrame editFileFrame;
+  private final SettingsFrame settingsFrame;
+  private final ImageView logo;
+
+  /**
+   * Creates an instance of the HomePage class.
+   *
+   * @param stage The stage to bind the width and height properties to.
+   */
+  public HomePage(Stage stage) {
+
+    buttonBoxMenu = new ButtonBoxMenu();
+    buttonBoxFrame = new BorderPane();
+    contentFrame = new Pane();
+    buttonBoxControls = new ButtonBoxControls();
+    buttonBoxFiles = new ButtonBoxFiles();
+    buttonBoxSettings = new ButtonBoxSettings();
+    transformationFrame = new TransformationFrame();
+    buttonBoxSelectGame = new ButtonBoxGames();
+    editFileFrame = new EditFileFrame();
+    settingsFrame = new SettingsFrame();
+
+    attributeControls = new AttributeControls();
+    affineControlsView = new AffineControlsView();
+    juliaTransformationControls = new JuliaTransformationControls();
+
+    this.prefWidthProperty().bind(stage.widthProperty());
+    this.prefHeightProperty().bind(stage.heightProperty());
+    getStyleClass().add("homePage");
+    Image image = new Image(
+        Objects.requireNonNull(getClass().getResourceAsStream("/Logo.png")));
+
+    logo = new ImageView(image);
+    logo.opacityProperty().setValue(0.5);
+    logo.fitWidthProperty().bind(contentFrame.widthProperty());
+    logo.fitHeightProperty().bind(contentFrame.heightProperty());
+
+    HBox homePageFrame = new HBox();
+    homePageFrame.getChildren().addAll(buttonBoxFrame, contentFrame);
+
+    HBox.setHgrow(buttonBoxFrame, Priority.ALWAYS);
+    HBox.setHgrow(contentFrame, Priority.ALWAYS);
+
+    buttonBoxFrame.prefWidthProperty().bind(homePageFrame.widthProperty().multiply(0.3));
+    buttonBoxFrame.prefHeightProperty().bind(homePageFrame.heightProperty());
+
+    contentFrame.prefWidthProperty().bind(homePageFrame.widthProperty().multiply(0.7));
+    contentFrame.prefHeightProperty().bind(homePageFrame.heightProperty());
+
+
+    transformationFrame.prefWidthProperty().bind(contentFrame.widthProperty());
+    transformationFrame.prefHeightProperty().bind(contentFrame.heightProperty());
+
+    HBox.setHgrow(contentFrame, Priority.ALWAYS);
+    editFileFrame.prefHeightProperty().bind(contentFrame.heightProperty());
+
+    settingsFrame.prefWidthProperty().bind(contentFrame.widthProperty());
+    settingsFrame.prefHeightProperty().bind(contentFrame.heightProperty());
+
+    this.getChildren().add(homePageFrame);
+    getStylesheets().add("/stylesheets/transformationAttributes.css");
+    getStylesheets().add("/stylesheets/buttonBox.css");
+    update(NavigationState.MENU);
+  }
+
+  /**
+   * Gets the buttonBoxMenu.
+   *
+   * @return The buttonBoxMenu.
+   */
+  public ButtonBoxMenu getButtonBoxMenu() {
+    return buttonBoxMenu;
+  }
+
+  /**
+   * Gets the buttonBoxControls.
+   *
+   * @return The buttonBoxControls.
+   */
+  public ButtonBoxControls getButtonBoxControls() {
+    return buttonBoxControls;
+  }
+
+  /**
+   * Gets the buttonBoxFiles.
+   *
+   * @return The buttonBoxFiles.
+   */
+  public ButtonBoxFiles getButtonBoxFiles() {
+    return buttonBoxFiles;
+  }
+
+  /**
+   * Gets the buttonBoxSettings.
+   *
+   * @return The buttonBoxSettings.
+   */
+  public ButtonBoxSettings getButtonBoxSettings() {
+    return buttonBoxSettings;
+  }
+
+  /**
+   * Gets the buttonBoxSelectGame.
+   *
+   * @return The buttonBoxSelectGame.
+   */
+  public ButtonBoxGames getButtonBoxGames() {
+    return buttonBoxSelectGame;
+  }
+
+  /**
+   * Gets the attributeControls.
+   *
+   * @return The attributeControls.
+   */
+  public AttributeControls getAttributeControls() {
+    return attributeControls;
+  }
+
+  /**
+   * Gets the editFileFrame.
+   *
+   * @return The editFileFrame.
+   */
+  public EditFileFrame getEditFileFrame() {
+    return editFileFrame;
+  }
+
+  /**
+   * Gets the settingsFrame.
+   *
+   * @return The settingsFrame.
+   */
+  public SettingsFrame getSettingsFrame() {
+    return settingsFrame;
+  }
+
+  /**
+   * Gets the affineControlsView.
+   *
+   * @return The affineControlsView.
+   */
+  public AffineControlsView getAffineControlsView() {
+    return affineControlsView;
+  }
+
+  /**
+   * Sets the transformation picture in the transformationFrame.
+   *
+   * @param chaosGame The chaosGame to set the transformation picture from.
+   */
+  public void setTransformationPicture(ChaosGame chaosGame) {
+    contentFrame.getChildren().clear();
+    transformationFrame.showTransformationPicture(chaosGame);
+    contentFrame.getChildren().add(transformationFrame);
+  }
+
+  /**
+   * Gets the juliaTransformationControls.
+   *
+   * @return The juliaTransformationControls.
+   */
+  public JuliaTransformationControls getJuliaTransformationControls() {
+    return juliaTransformationControls;
+  }
+
+  /**
+   * Sets the juliaTransformationControls.
+   *
+   * @param juliaTransformationControls The juliaTransformationControls to set.
+   */
+  public void setJuliaTransformationControls(
+      JuliaTransformationControls juliaTransformationControls) {
+    this.juliaTransformationControls = juliaTransformationControls;
+  }
+
+  /**
+   * Updates the view based on the NavigationState.
+   *
+   * @param state The NavigationState to update the view based on.
+   */
+  @Override
+  public void update(NavigationState state) {
+    switch (state) {
+      case MENU:
+        //Clears the contentFrame and buttonBoxFrame and adds the menu buttons to the buttonBoxFrame
+        buttonBoxFrame.getChildren().clear();
+        contentFrame.getChildren().clear();
+        buttonBoxFrame.setBottom(buttonBoxMenu);
+        contentFrame.getChildren().add(logo);
+        break;
+      case SELECT_GAME:
+        buttonBoxFrame.getChildren().clear();
+        buttonBoxFrame.setBottom(buttonBoxSelectGame);
+        break;
+      case SELECT_GAME_FILES:
+        buttonBoxFrame.setCenter(buttonBoxFiles.getFilesButtonsBox());
+        break;
+      case PLAY_AFFINE:
+        contentFrame.getChildren().clear();
+        //Sets the common attributes for the affine transformations
+        buttonBoxFrame.setTop(attributeControls);
+        //Sets the affine transformation controls as a scrollPane
+        buttonBoxFrame.setCenter(affineControlsView.getScrollPaneAffineControls());
+        //Sets the buttons to run and load new transformations
+        buttonBoxFrame.setBottom(buttonBoxControls);
+        break;
+      case PLAY_JULIA:
+        contentFrame.getChildren().clear();
+        buttonBoxFrame.setTop(attributeControls);
+        buttonBoxFrame.setCenter(juliaTransformationControls);
+        buttonBoxFrame.setBottom(buttonBoxControls);
+        break;
+      case SELECT_FILE:
+        buttonBoxFrame.setBottom(buttonBoxFiles);
+        break;
+      case SETTINGS:
+        buttonBoxFrame.setBottom(buttonBoxSettings);
+        contentFrame.getChildren().clear();
+        contentFrame.getChildren().add(settingsFrame);
+        break;
+      case EDIT_FILE:
+        contentFrame.getChildren().clear();
+        contentFrame.getChildren().add(editFileFrame);
+        break;
+
+      default:
+        break;
+    }
+  }
+}
\ No newline at end of file
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/frames/SettingsFrame.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/frames/SettingsFrame.java
new file mode 100644
index 0000000000000000000000000000000000000000..071ff7fc3002e40ac81a4510ef913f1971383f83
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/frames/SettingsFrame.java
@@ -0,0 +1,99 @@
+package edu.ntnu.idatt2003.group6.view.frames;
+
+import edu.ntnu.idatt2003.group6.view.buttonbox.CustomToggleButton;
+import java.util.Objects;
+import javafx.geometry.Pos;
+import javafx.scene.control.Slider;
+import javafx.scene.control.ToggleGroup;
+import javafx.scene.layout.GridPane;
+import javafx.scene.layout.HBox;
+import javafx.scene.layout.StackPane;
+import javafx.scene.text.Text;
+
+/**
+ * The SettingsFrame class creates a StackPane with a toggle group for music settings.
+ *
+ * @version 0.3.2
+ * @since 0.3.2
+ */
+public class SettingsFrame extends StackPane {
+  private final ToggleGroup musicOption;
+  private final CustomToggleButton musicOn;
+  private final CustomToggleButton musicOff;
+  private final Slider volumeSlider;
+
+  /**
+   * Constructor for SettingsFrame.
+   * Creates a StackPane with a toggle group for music settings.
+   */
+  public SettingsFrame() {
+    getStylesheets().add(Objects.requireNonNull(getClass()
+        .getResource("/stylesheets/settings.css")).toExternalForm());
+
+
+
+    musicOption = new ToggleGroup();
+    musicOn = new CustomToggleButton("On", "optionButton");
+    musicOff = new CustomToggleButton("Off", "optionButton");
+    musicOn.setToggleGroup(musicOption);
+    musicOff.setToggleGroup(musicOption);
+
+    volumeSlider = new Slider(0, 0.2, 0.02);
+
+    Text musicText = new Text("Music: ");
+    musicText.getStyleClass().add("text");
+
+    Text volumeText = new Text("Volume: ");
+    volumeText.getStyleClass().add("text");
+
+    HBox buttons = new HBox(musicOn, musicOff);
+    GridPane musicPane = new GridPane();
+    musicPane.add(musicText, 0, 0);
+    musicPane.add(buttons, 1, 0);
+    musicPane.add(volumeText, 0, 1);
+    musicPane.add(volumeSlider, 1, 1);
+
+    setAlignment(Pos.CENTER);
+    getChildren().add(musicPane);
+
+    musicPane.maxHeightProperty().bind(heightProperty().multiply(0.2));
+    musicPane.maxWidthProperty().bind(widthProperty().multiply(0.5));
+    musicPane.minWidthProperty().bind(widthProperty().multiply(0.5));
+  }
+
+  /**
+   * Gets the toggle group for the option buttons.
+   *
+   * @return the toggle group
+   */
+  public ToggleGroup getMusicOption() {
+    return musicOption;
+  }
+
+  /**
+   * Gets the button for turning music on.
+   *
+   * @return the button for turning music on
+   */
+  public CustomToggleButton getMusicOn() {
+    return musicOn;
+  }
+
+  /**
+   * Gets the button for turning music off.
+   *
+   * @return the button for turning music off
+   */
+  public CustomToggleButton getMusicOff() {
+    return musicOff;
+  }
+
+  /**
+   * Gets the volume slider.
+   *
+   * @return the volume slider
+   */
+  public Slider getVolumeSlider() {
+    return volumeSlider;
+  }
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/frames/TransformationFrame.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/frames/TransformationFrame.java
new file mode 100644
index 0000000000000000000000000000000000000000..59b2032968dd340504d1460298d038dac448d7a3
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/frames/TransformationFrame.java
@@ -0,0 +1,100 @@
+package edu.ntnu.idatt2003.group6.view.frames;
+
+import edu.ntnu.idatt2003.group6.controller.chaosgame.ChaosGame;
+import edu.ntnu.idatt2003.group6.models.chaosgame.ChaosCanvas;
+import javafx.geometry.Insets;
+import javafx.scene.image.ImageView;
+import javafx.scene.image.PixelWriter;
+import javafx.scene.image.WritableImage;
+import javafx.scene.layout.Border;
+import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.BorderStroke;
+import javafx.scene.layout.BorderStrokeStyle;
+import javafx.scene.layout.BorderWidths;
+import javafx.scene.layout.CornerRadii;
+import javafx.scene.layout.StackPane;
+import javafx.scene.paint.Color;
+
+/**
+ * This class is a view for displaying the transformation picture of a chaos game.
+ * The transformation picture is a heatmap of the pixels that have been visited by the chaos game.
+ * The more times a pixel has been visited, the more red it will be.
+ * The transformation picture is displayed in a frame with a border.
+ *
+ * @version 0.3.2
+ * @see ChaosGame
+ * @see ChaosCanvas
+ * @since 0.3.2
+ */
+public class TransformationFrame extends StackPane {
+
+  private final BorderPane frame;
+
+  /**
+   * Creates an instance of the TransformationFrame class.
+   */
+  public TransformationFrame() {
+    frame = new BorderPane();
+    setPadding(new Insets(10));
+    frame.setBorder(new Border(new BorderStroke(
+        Color.BLACK, BorderStrokeStyle.SOLID, new CornerRadii(10), new BorderWidths(1))));
+    getChildren().add(frame);
+  }
+
+  /**
+   * Show the transformation picture of a chaos game in the frame.
+   *
+   * @param chaosGame The chaos game to show the transformation picture of.
+   */
+  public void showTransformationPicture(ChaosGame chaosGame) {
+    getChildren().clear();
+    getChildren().add(frame);
+
+    ChaosCanvas canvas = chaosGame.getCanvas();
+    int[][] canvasArray = canvas.getCanvasArray();
+    int width = canvasArray[0].length;
+    int height = canvasArray.length;
+
+    // Find the maximum pixel count
+    int maxPixelCount = 0;
+    for (int[] row : canvasArray) {
+      for (int pixelCount : row) {
+        if (pixelCount > maxPixelCount) {
+          maxPixelCount = pixelCount;
+        }
+      }
+    }
+
+    WritableImage image = new WritableImage(width, height);
+    PixelWriter pixelWriter = image.getPixelWriter();
+
+    for (int y = 0; y < height; y++) {
+      for (int x = 0; x < width; x++) {
+        int pixelCount = canvasArray[y][x];
+        // Map the pixel count to a hue value for the heatmap
+        // If pixelCount is 0, set color to black
+        if (pixelCount == 0) {
+          pixelWriter.setColor(x, y, Color.grayRgb(20));
+        } else {
+          double hue =
+              240 + (120 * (pixelCount / (double) maxPixelCount)); // 240 is blue, 360 is red
+          Color color = Color.hsb(hue, 1.0, 1.0); // saturation and brightness are set to maximum
+          pixelWriter.setColor(x, y, color);
+        }
+      }
+    }
+
+    /* puts the finished image inside a frame */
+    ImageView imageView = new ImageView(image);
+    frame.setCenter(imageView);
+    Insets padding = this.getPadding();
+    imageView.setPreserveRatio(true);
+    imageView.fitWidthProperty().bind(
+        frame.widthProperty().subtract(padding.getLeft() + padding.getRight()));
+    imageView.fitHeightProperty().bind(
+        frame.heightProperty().subtract(padding.getTop() + padding.getBottom()));
+    imageView.setPreserveRatio(true);
+    getChildren().add(imageView);
+  }
+
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/gamecontrols/AffineControlsView.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/gamecontrols/AffineControlsView.java
new file mode 100644
index 0000000000000000000000000000000000000000..068e4697440bb4eb0a3425a7da03173c658ff3ba
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/gamecontrols/AffineControlsView.java
@@ -0,0 +1,123 @@
+package edu.ntnu.idatt2003.group6.view.gamecontrols;
+
+import java.util.ArrayList;
+import java.util.List;
+import javafx.scene.control.Button;
+import javafx.scene.control.ScrollPane;
+import javafx.scene.layout.VBox;
+
+/**
+ * The AffineControlsView class is a view class that creates a scrollable pane containing affine
+ * transformation controls.
+ * The class contains a list of affine transformation controls, and a function to add a new
+ * transformation, a remove transformation button,
+ * a scroll pane, and a VBox to contain the
+ * affine transformation controls.
+ *
+ * @version 0.3.2
+ * @see AffineTransformationControls
+ * @since 0.3.2
+ */
+public class AffineControlsView {
+  private final Button addTransformButton;
+  private final Button removeTransformButton;
+  private final ScrollPane scrollPaneAffineControls;
+  private final VBox affineControlsBox;
+  private ArrayList<AffineTransformationControls> affineControlsList;
+
+
+  /**
+   * Constructor for the AffineControlsView class.
+   */
+  public AffineControlsView() {
+    this.affineControlsList = new ArrayList<>();
+    this.addTransformButton = new Button("Add Transformation");
+    this.removeTransformButton = new Button("Remove Transformation");
+    this.affineControlsBox = new VBox();
+    affineControlsBox.alignmentProperty().setValue(javafx.geometry.Pos.CENTER);
+    affineControlsBox.getChildren().addAll(addTransformButton, removeTransformButton);
+    this.scrollPaneAffineControls = makeScrollPaneAffineControls();
+  }
+
+  /**
+   * Method to get a list of affine transformation controls.
+   *
+   * @return a list of affine transformation controls.
+   */
+  public List<AffineTransformationControls> getAffineControlsList() {
+    return affineControlsList;
+  }
+
+  /**
+   * Method to set a list of affine transformation controls in the view.
+   *
+   * @param affineControlsList a list of affine transformation controls.
+   */
+  public void setAffineControlsList(List<AffineTransformationControls> affineControlsList) {
+    this.affineControlsList = (ArrayList<AffineTransformationControls>) affineControlsList;
+    updateScrollPane();
+  }
+
+  /**
+   * Method to add an affine transformation control to the view.
+   *
+   * @return the button to add an affine transformation control.
+   */
+  public Button getAddTransformButton() {
+    return addTransformButton;
+  }
+
+  /**
+   * Method to get the button to remove an affine transformation control.
+   *
+   * @return the button to remove an affine transformation control.
+   */
+  public Button getRemoveTransformButton() {
+    return removeTransformButton;
+  }
+
+  /**
+   * Method to update the scroll pane containing the affine transformation controls.
+   */
+  private void updateScrollPane() {
+    scrollPaneAffineControls.setContent(makeScrollPaneAffineControls());
+  }
+
+  /**
+   * Method to get the scroll pane containing the affine transformation controls.
+   *
+   * @return the scroll pane containing the affine transformation controls.
+   */
+  public ScrollPane getScrollPaneAffineControls() {
+    return scrollPaneAffineControls;
+  }
+
+  /**
+   * Method to make a scroll pane containing the affine transformation controls.
+   *
+   * @return a scroll pane containing the affine transformation controls.
+   */
+  private ScrollPane makeScrollPaneAffineControls() {
+    ScrollPane scrollPane = new ScrollPane();
+    scrollPane.getStyleClass().add("scrollPane");
+    scrollPane.setFitToWidth(true);
+    scrollPane.hbarPolicyProperty().setValue(ScrollPane.ScrollBarPolicy.NEVER);
+    VBox collector = new VBox();
+    collector.getStyleClass().add("vbox");
+    for (AffineTransformationControls affineTransformationControl : affineControlsList) {
+      collector.getChildren().add(affineTransformationControl);
+    }
+
+    int size = affineControlsList.size();
+    if (size < 2) {
+      removeTransformButton.setDisable(true);
+      removeTransformButton.setVisible(false);
+    } else {
+      removeTransformButton.setDisable(false);
+      removeTransformButton.setVisible(true);
+    }
+    collector.getChildren().add(affineControlsBox);
+    scrollPane.setContent(collector);
+    return scrollPane;
+  }
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/gamecontrols/AffineTransformationControls.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/gamecontrols/AffineTransformationControls.java
new file mode 100644
index 0000000000000000000000000000000000000000..b6401440fed0cbcb1990b2e834b21cec01e7518f
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/gamecontrols/AffineTransformationControls.java
@@ -0,0 +1,199 @@
+package edu.ntnu.idatt2003.group6.view.gamecontrols;
+
+import java.util.List;
+import javafx.scene.Node;
+import javafx.scene.control.Label;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.GridPane;
+import javafx.scene.text.Text;
+
+/**
+ * A class that represents the controls for the affine transformations in the Chaos Game.
+ * The class extends GridPane and contains TextFields for the affine transformation matrix A and
+ * the vector B. The class also contains a Text object for the transformation number and a Label
+ * for error messages.
+ */
+public class AffineTransformationControls extends GridPane {
+
+  private final Text transformationNumber;
+  private final TextField a00;
+  private final TextField a01;
+  private final TextField a10;
+  private final TextField a11;
+  private final TextField x0;
+  private final TextField x1;
+
+  /**
+   * Constructor for the AffineTransformationControls class.
+   * Initializes the TextFields and Labels
+   * for the affine transformation matrix A and the vector B.
+   * Also sets the style classes for the
+   * different nodes.
+   */
+  public AffineTransformationControls() {
+    getStylesheets().add("/stylesheets/transformationAttributes.css");
+    getStyleClass().add("frame");
+
+    transformationNumber = new Text();
+    a00 = new TextField();
+    a01 = new TextField();
+    a10 = new TextField();
+    a11 = new TextField();
+    x0 = new TextField();
+    x1 = new TextField();
+
+    a00.setPromptText("a00");
+    a01.setPromptText("a01");
+    a10.setPromptText("a10");
+    a11.setPromptText("a11");
+    x0.setPromptText("x0");
+    x1.setPromptText("x1");
+
+    add(transformationNumber, 0, 0);
+    Text matrixA = new Text("A:");
+    add(matrixA, 1, 0);
+    add(a00, 2, 0);
+    add(a01, 3, 0);
+    add(a10, 2, 1);
+    add(a11, 3, 1);
+
+    Text vectorB = new Text("B:");
+    add(vectorB, 4, 0);
+    add(x0, 5, 0);
+    add(x1, 5, 1);
+    Label errorLabel = new Label();
+    add(errorLabel, 1, 2);
+
+    setColumnSpan(errorLabel, 5);
+
+    List<Node> children = getChildren();
+    for (Node node : children) {
+      if (node instanceof Text) {
+        if (node == transformationNumber) {
+          node.getStyleClass().add("attributeNumber");
+        } else {
+          node.getStyleClass().add("attributeNames");
+        }
+      } else if (node instanceof TextField) {
+        node.getStyleClass().add("textField");
+      } else if (node instanceof Label) {
+        node.getStyleClass().add("errorLabel");
+      }
+    }
+  }
+
+  /**
+   * Method that sets the transformation number for the transformation.
+   */
+  public void setTransformationNumber(String transformationNumber) {
+    this.transformationNumber.setText(transformationNumber);
+  }
+
+  /**
+   * method to get the string for A00 in the matrix.
+   *
+   * @return the string for A00.
+   */
+  public String getA00() {
+    return a00.getText();
+  }
+
+  /**
+   * method to get the string for A01 in the matrix.
+   *
+   * @return the string for A01
+   */
+  public String getA01() {
+    return a01.getText();
+  }
+
+  /**
+   * method to get the string for A10 in the matrix.
+   *
+   * @return the string for A10.
+   */
+  public String getA10() {
+    return a10.getText();
+  }
+
+  /**
+   * method to get the string for A11 in the matrix.
+   *
+   * @return the string for A11.
+   */
+  public String getA11() {
+    return a11.getText();
+  }
+
+  /**
+   * method to get the string for X0 in the vector.
+   *
+   * @return the string for X0.
+   */
+  public String getX0() {
+    return x0.getText();
+  }
+
+  /**
+   * method to get the string for X1 in the vector.
+   *
+   * @return the string for X1.
+   */
+  public String getX1() {
+    return x1.getText();
+  }
+
+  /**
+   * Method to set the A00 value in the matrix.
+   *
+   * @param a00 the value to set.
+   */
+  public void setA00(String a00) {
+    this.a00.setText(a00);
+  }
+
+  /**
+   * Method to set the A01 value in the matrix.
+   *
+   * @param a01 the value to set.
+   */
+  public void setA01(String a01) {
+    this.a01.setText(a01);
+  }
+
+  /**
+   * Method to set the A10 value in the matrix.
+   *
+   * @param a10 the value to set.
+   */
+  public void setA10(String a10) {
+    this.a10.setText(a10);
+  }
+
+  /**
+   * Method to set the A11 value in the matrix.
+   *
+   * @param a11 the value to set.
+   */
+  public void setA11(String a11) {
+    this.a11.setText(a11);
+  }
+
+  /**
+   * Method to set the X0 value in the vector.
+   *
+   * @param x0 the value to set.
+   */
+  public void setX0(String x0) {
+    this.x0.setText(x0);
+  }
+
+  /**
+   * Method to set the X1 value in the vector.
+   *
+   * @param x1 the value to set.
+   */
+  public void setX1(String x1) {
+    this.x1.setText(x1);
+  }
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/gamecontrols/AttributeControls.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/gamecontrols/AttributeControls.java
new file mode 100644
index 0000000000000000000000000000000000000000..b4bad8a7ada4222edc6b667e469fd2c1335b4869
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/gamecontrols/AttributeControls.java
@@ -0,0 +1,186 @@
+package edu.ntnu.idatt2003.group6.view.gamecontrols;
+
+import edu.ntnu.idatt2003.group6.controller.chaosgame.ChaosGameController;
+import java.util.List;
+import javafx.scene.Node;
+import javafx.scene.control.Label;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.GridPane;
+import javafx.scene.text.Text;
+
+/**
+ * A class that represents the common attributes for the transformations in the Chaos Game.
+ * The class extends GridPane and contains TextFields for the steps and the min and max coordinates.
+ * The class also contains a Text object for the attribute names and a Label for error messages.
+ * The class is used for both the affine and julia transformations.
+ *
+ * @version 0.3.2
+ * @see AffineTransformationControls
+ * @see JuliaTransformationControls
+ * @see ChaosGameController
+ * @see edu.ntnu.idatt2003.group6.view.gamecontrols.JuliaTransformationControls
+ * @see edu.ntnu.idatt2003.group6.view.gamecontrols.AffineTransformationControls
+ * @since 0.3.2
+ */
+public class AttributeControls extends GridPane {
+
+  private final Text steps;
+  private final TextField stepsField;
+  private final TextField minCoordsX0Field;
+  private final TextField minCoordsX1Field;
+  private final TextField maxCoordsX0Field;
+  private final TextField maxCoordsX1Field;
+  private final Label stepsErrorLabel;
+
+  /**
+   * Constructor for the AttributeControls class.
+   * Initializes the TextFields and Labels for the steps and the min and max coordinates.
+   * Also sets the style classes for the different nodes.
+   */
+  public AttributeControls() {
+    getStylesheets().add("/stylesheets/transformationAttributes.css");
+    getStyleClass().add("frame");
+
+    steps = new Text("Steps:");
+    stepsField = new TextField();
+    minCoordsX0Field = new TextField();
+    minCoordsX1Field = new TextField();
+    maxCoordsX0Field = new TextField();
+    maxCoordsX1Field = new TextField();
+
+    stepsField.setPromptText("Enter steps");
+    minCoordsX0Field.setPromptText("0.0");
+    minCoordsX1Field.setPromptText("0.0");
+    maxCoordsX0Field.setPromptText("0.0");
+    maxCoordsX1Field.setPromptText("0.0");
+
+    stepsErrorLabel = new Label();
+
+
+
+    add(steps, 0, 0);
+    add(stepsField, 1, 0);
+    add(stepsErrorLabel, 0, 1);
+
+    Text minCords = new Text("Min Cords:");
+    add(minCords, 0, 2);
+    add(minCoordsX0Field, 1, 2);
+    add(minCoordsX1Field, 2, 2);
+
+    Label minCordsErrorLabel = new Label();
+    add(minCordsErrorLabel, 0, 3);
+
+    Text maxCords = new Text("Max Cords:");
+    add(maxCords, 0, 4);
+    add(maxCoordsX0Field, 1, 4);
+    add(maxCoordsX1Field, 2, 4);
+
+    Label maxCordsErrorLabel = new Label();
+    add(maxCordsErrorLabel, 0, 5);
+
+    setColumnSpan(stepsErrorLabel, 3);
+    setColumnSpan(minCordsErrorLabel, 3);
+    setColumnSpan(maxCordsErrorLabel, 3);
+
+    List<Node> children = getChildren();
+    for (Node node : children) {
+      if (node instanceof Text) {
+        node.getStyleClass().add("attributeNames");
+      } else if (node instanceof TextField) {
+        node.getStyleClass().add("textField");
+      } else if (node instanceof Label) {
+        node.getStyleClass().add("errorLabel");
+      }
+    }
+  }
+
+  /**
+   * Returns the steps TextField.
+   *
+   * @return The steps TextField.
+   */
+  public String getStepsField() {
+    return stepsField.getText();
+  }
+
+  /**
+   * gets the minimum coords for x0.
+   *
+   * @return the minimum coords for x0.
+   */
+  public String getMinCoordsX0Field() {
+    return minCoordsX0Field.getText();
+  }
+
+  /**
+   * gets the minimum coords for x1.
+   *
+   * @return the minimum coords for x1.
+   */
+  public String getMinCoordsX1Field() {
+    return minCoordsX1Field.getText();
+  }
+
+  /**
+   * gets the maximum coords for x0.
+   *
+   * @return the maximum coords for x0.
+   */
+  public String getMaxCoordsX0Field() {
+    return maxCoordsX0Field.getText();
+  }
+
+  /**
+   * gets the maximum coords for x1.
+   *
+   * @return the maximum coords for x1.
+   */
+  public String getMaxCoordsX1Field() {
+    return maxCoordsX1Field.getText();
+  }
+
+  /**
+   * sets the minimum coords for x0.
+   *
+   * @param minCoordsX0 the minimum coords for x0.
+   */
+  public void setMinCoordsX0Field(String minCoordsX0) {
+    minCoordsX0Field.setText(minCoordsX0);
+  }
+
+  /**
+   * sets the minimum coords for x1.
+   *
+   * @param minCoordsX1 the minimum coords for x1.
+   */
+  public void setMinCoordsX1Field(String minCoordsX1) {
+    minCoordsX1Field.setText(minCoordsX1);
+  }
+
+  /**
+   * sets the maximum coords for x0.
+   *
+   * @param maxCoordsX0 the maximum coords for x0.
+   */
+  public void setMaxCoordsX0Field(String maxCoordsX0) {
+    maxCoordsX0Field.setText(maxCoordsX0);
+  }
+
+  /**
+   * sets the maximum coords for x1.
+   *
+   * @param maxCoordsX1 the maximum coords for x1.
+   */
+  public void setMaxCoordsX1Field(String maxCoordsX1) {
+    maxCoordsX1Field.setText(maxCoordsX1);
+  }
+
+  /**
+   * removes the steps from the attribute controls.
+   */
+  public void removeSteps() {
+    getChildren().remove(steps);
+    getChildren().remove(stepsField);
+    getChildren().remove(stepsErrorLabel);
+  }
+}
diff --git a/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/gamecontrols/JuliaTransformationControls.java b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/gamecontrols/JuliaTransformationControls.java
new file mode 100644
index 0000000000000000000000000000000000000000..792ea69806d64e79510b09d167bb0fdf67c98b76
--- /dev/null
+++ b/ChaosGame/src/main/java/edu/ntnu/idatt2003/group6/view/gamecontrols/JuliaTransformationControls.java
@@ -0,0 +1,93 @@
+package edu.ntnu.idatt2003.group6.view.gamecontrols;
+
+import java.util.List;
+import javafx.scene.Node;
+import javafx.scene.control.Label;
+import javafx.scene.control.TextField;
+import javafx.scene.layout.GridPane;
+import javafx.scene.text.Text;
+
+/**
+ * A class that represents the controls for the affine transformations in the Chaos Game.
+ *
+ * @version 0.3.2
+ * @see JuliaTransformationControls
+ */
+public class JuliaTransformationControls extends GridPane {
+
+  private final TextField realC;
+  private final TextField imaginaryC;
+
+  /**
+   * Constructor for the JuliaTransformationControls class.
+   */
+  public JuliaTransformationControls() {
+    getStylesheets().add("/stylesheets/transformationAttributes.css");
+    getStyleClass().add("frame");
+
+    realC = new TextField();
+    imaginaryC = new TextField();
+
+    realC.setPromptText("Real part of c");
+    imaginaryC.setPromptText("Imaginary part of c");
+
+    Text transformationNumber = new Text();
+    add(transformationNumber, 0, 0);
+
+    Text c = new Text("C:");
+    add(c, 1, 0);
+    add(realC, 2, 0);
+    add(imaginaryC, 3, 0);
+
+    List<Node> children = getChildren();
+    for (Node node : children) {
+      if (node instanceof Text) {
+        if (node == transformationNumber) {
+          node.getStyleClass().add("attributeNumber");
+        } else {
+          node.getStyleClass().add("attributeNames");
+        }
+      } else if (node instanceof TextField) {
+        node.getStyleClass().add("textField");
+      } else if (node instanceof Label) {
+        node.getStyleClass().add("errorLabel");
+      }
+    }
+  }
+
+  /**
+   * Returns the real part of the complex number c.
+   *
+   * @return the real part of the complex number c.
+   */
+  public String getRealC() {
+    return realC.getText();
+  }
+
+  /**
+   * Returns the imaginary part of the complex number c.
+   *
+   * @return the imaginary part of the complex number c.
+   */
+  public String getImaginaryC() {
+    return imaginaryC.getText();
+  }
+
+  /**
+   * Sets the real part of the complex number c.
+   *
+   * @param realC the real part of the complex number c.
+   */
+  public void setRealC(String realC) {
+    this.realC.setText(realC);
+  }
+
+  /**
+   * Sets the imaginary part of the complex number c.
+   *
+   * @param imaginaryC the imaginary part of the complex number c.
+   */
+  public void setImaginaryC(String imaginaryC) {
+    this.imaginaryC.setText(imaginaryC);
+  }
+}
diff --git a/ChaosGame/src/main/resources/Logo.png b/ChaosGame/src/main/resources/Logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..21f270726ed3a4ced702aca04dd2ea430bcea161
Binary files /dev/null and b/ChaosGame/src/main/resources/Logo.png differ
diff --git a/ChaosGame/src/main/resources/descriptions/chaosGameDescription.txt b/ChaosGame/src/main/resources/descriptions/chaosGameDescription.txt
deleted file mode 100644
index fb6d7b0f676fa3884a21e166a4b84be05864bd4a..0000000000000000000000000000000000000000
--- a/ChaosGame/src/main/resources/descriptions/chaosGameDescription.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-Affine2D # Type of transformation
-0.0, 0.0 # Lower left
-1.0, 1.0 # Upper right
-0.5, 0.0, 0.0, 0.5, 0.0, 0.0 # 1nd transform
-0.5, 0.0, 0.0, 0.5, 0.25, 0.5 # 2nd transform
-0.5, 0.0, 0.0, 0.5, 0.5, 0.0 # 3nd transform
diff --git a/ChaosGame/src/main/resources/mp3/Legio_Symphonica.mp3 b/ChaosGame/src/main/resources/mp3/Legio_Symphonica.mp3
new file mode 100644
index 0000000000000000000000000000000000000000..3e90123cbc402f2ecda3df299afbe936f878b7c7
Binary files /dev/null and b/ChaosGame/src/main/resources/mp3/Legio_Symphonica.mp3 differ
diff --git a/ChaosGame/src/main/resources/stylesheets/alert.css b/ChaosGame/src/main/resources/stylesheets/alert.css
new file mode 100644
index 0000000000000000000000000000000000000000..346d509a0358f23390a8175d501c68c39d1aa134
--- /dev/null
+++ b/ChaosGame/src/main/resources/stylesheets/alert.css
@@ -0,0 +1,66 @@
+.dialog-pane {
+  -fx-background-color: #181C82;
+  -fx-border-color: #c26d37;
+  -fx-border-radius: 10;
+  -fx-border-width: 2;
+  -fx-background-radius: 10;
+  -fx-padding: 10;
+
+  -fx-pref-height: 200;
+  -fx-pref-width: 400;
+}
+
+.vBox {
+  -fx-background-color: rgba(196, 0, 0, 0.9);
+  -fx-background-radius: 6;
+}
+
+.errorText {
+  -fx-font-size: 16;
+  -fx-font-weight: bold;
+  -fx-fill: #ffffff;
+}
+
+.errorDescription {
+  -fx-font-size: 14;
+  -fx-font-weight: bold;
+  -fx-font-style: italic;
+  -fx-fill: #ffffff;
+}
+
+.informationText {
+  -fx-font-size: 16;
+  -fx-fill: #ffffff;
+}
+
+.dialog-pane .button {
+  -fx-background-radius: 12;
+  -fx-border-radius: 10;
+  -fx-border-width: 2;
+  -fx-text-fill: #ffffff;
+  -fx-font-weight: bold;
+  -fx-pref-height: 40;
+  -fx-pref-width: 100;
+  -fx-font-size: 14;
+  -fx-alignment: center;
+}
+
+.positiveButton {
+  -fx-background-color: #c26d37;
+  -fx-border-color: #0f2465;
+}
+
+.negativeButton {
+  -fx-background-color: #0f2465;
+  -fx-border-color: #c26d37;
+}
+
+.textField {
+  -fx-background-color: #0F2465FF;
+  -fx-text-fill: #ffffff;
+  -fx-prompt-text-fill: #565656;
+  -fx-font-size: 14;
+  -fx-border-color: #c26d37;
+  -fx-border-width: 2;
+  -fx-border-radius: 5;
+}
\ No newline at end of file
diff --git a/ChaosGame/src/main/resources/stylesheets/buttonBox.css b/ChaosGame/src/main/resources/stylesheets/buttonBox.css
new file mode 100644
index 0000000000000000000000000000000000000000..399162aa425ee41ddb79fee8a8220470a9239224
--- /dev/null
+++ b/ChaosGame/src/main/resources/stylesheets/buttonBox.css
@@ -0,0 +1,33 @@
+.buttonBox {
+  -fx-background-color: transparent;
+  -fx-border-width: 0;
+  -fx-padding: 0 40 0 40;
+}
+.menuButton {
+  -fx-font-size: 14;
+  -fx-alignment: center-left;
+}
+.subMenuButton {
+  -fx-font-size: 12;
+  -fx-alignment: center-left;
+}
+.menuButton,
+.subMenuButton {
+  -fx-background-color: radial-gradient(center 50% 50%, radius 100%, #0f2465, transparent);
+  -fx-background-radius: 0;
+  -fx-border-width: 0;
+  -fx-text-fill: #ffffff;
+  -fx-font-weight: bold;
+  -fx-padding: 10 20 10 20;
+  -fx-pref-width: infinity;
+  -fx-pref-height: 40;
+}
+.menuButton:hover,
+.menuButton:pressed,
+.menuButton:selected,
+.subMenuButton:hover,
+.subMenuButton:pressed,
+.subMenuButton:selected {
+  -fx-background-color: linear-gradient(to right, #c26d37 50%, transparent);
+  -fx-text-fill: #ffffff;
+}
diff --git a/ChaosGame/src/main/resources/stylesheets/exitBox.css b/ChaosGame/src/main/resources/stylesheets/exitBox.css
new file mode 100644
index 0000000000000000000000000000000000000000..17a5b36ad9e5e2539ff1858c3578be23a86559b6
--- /dev/null
+++ b/ChaosGame/src/main/resources/stylesheets/exitBox.css
@@ -0,0 +1,17 @@
+.label {
+  -fx-font-size: 20px;
+  -fx-font-weight: bold;
+  -fx-text-fill: #eeeeee;
+}
+
+.text {
+  -fx-font-size: 18px;
+  -fx-font-weight: bold;
+  -fx-text-fill: #eeeeee;
+}
+
+.box {
+  -fx-padding: 0 0 0 10;
+  -fx-background-color: radial-gradient(center 20% 50%, radius 100%, #000000, rgba(2, 2, 2, 0.85));
+  -fx-border-width: 0px;
+}
\ No newline at end of file
diff --git a/ChaosGame/src/main/resources/globals.css b/ChaosGame/src/main/resources/stylesheets/globals.css
similarity index 70%
rename from ChaosGame/src/main/resources/globals.css
rename to ChaosGame/src/main/resources/stylesheets/globals.css
index 9a87450f25ccbcbe79698e0e951588fabf194357..9c917f65c4a4872ebc670d84f820adc864de3ff6 100644
--- a/ChaosGame/src/main/resources/globals.css
+++ b/ChaosGame/src/main/resources/stylesheets/globals.css
@@ -2,26 +2,25 @@
     -fx-background-color: #181C82;
     -fx-border-width: 0;
 }
-
 .buttonBox {
     -fx-background-color: transparent;
     -fx-border-width: 0;
     -fx-padding: 0 40 0 40;
 }
-
-
 .menuButton {
     -fx-font-size: 14;
+    -fx-alignment: center-left;
 }
 .subMenuButton {
     -fx-font-size: 12;
+    -fx-alignment: center-left;
 }
 .menuButton,
 .subMenuButton {
-    -fx-background-color: #a3a9c4;
+    -fx-background-color: radial-gradient(center 50% 50%, radius 100%, #0f2465, transparent);
     -fx-background-radius: 0;
     -fx-border-width: 0;
-    -fx-text-fill: #000000;
+    -fx-text-fill: #ffffff;
     -fx-font-weight: bold;
     -fx-padding: 10 20 10 20;
     -fx-pref-width: infinity;
@@ -33,6 +32,6 @@
 .subMenuButton:hover,
 .subMenuButton:pressed,
 .subMenuButton:selected {
-    -fx-background-color: #3436b0;
+    -fx-background-color: linear-gradient(to right, #c26d37 50%, transparent);
     -fx-text-fill: #ffffff;
 }
diff --git a/ChaosGame/src/main/resources/stylesheets/homePage.css b/ChaosGame/src/main/resources/stylesheets/homePage.css
new file mode 100644
index 0000000000000000000000000000000000000000..8280f274516c64187784daaba04de52a3c135612
--- /dev/null
+++ b/ChaosGame/src/main/resources/stylesheets/homePage.css
@@ -0,0 +1,4 @@
+.homePage {
+  -fx-background-color: #181C82;
+  -fx-border-width: 0;
+}
\ No newline at end of file
diff --git a/ChaosGame/src/main/resources/stylesheets/settings.css b/ChaosGame/src/main/resources/stylesheets/settings.css
new file mode 100644
index 0000000000000000000000000000000000000000..5a1bddfaa0bae4f99d19d0462b0af89fb994456e
--- /dev/null
+++ b/ChaosGame/src/main/resources/stylesheets/settings.css
@@ -0,0 +1,34 @@
+.text {
+  -fx-font-size: 20px;
+  -fx-font-weight: bold;
+  -fx-font-family: italic;
+  -fx-fill: #c4c4c4;
+  -fx-pref-height: 40;
+}
+
+.optionButton {
+  -fx-font-size: 14;
+  -fx-alignment: center-left;
+  -fx-background-color: radial-gradient(center 50% 50%, radius 100%, #0f2465, transparent);
+  -fx-background-radius: 0;
+  -fx-border-width: 0;
+  -fx-text-fill: #ffffff;
+  -fx-font-weight: bold;
+  -fx-padding: 10 20 10 20;
+  -fx-pref-width: 80;
+  -fx-pref-height: 40;
+}
+
+.optionButton:hover,
+.optionButton:selected {
+  -fx-background-color: linear-gradient(to right, #c26d37 50%, transparent);
+  -fx-text-fill: #ffffff;
+}
+
+.slider .track {
+  -fx-background-color: #12165b;
+}
+
+.slider .thumb {
+  -fx-background-color: #c26d37;
+}
\ No newline at end of file
diff --git a/ChaosGame/src/main/resources/stylesheets/transformationAttributes.css b/ChaosGame/src/main/resources/stylesheets/transformationAttributes.css
new file mode 100644
index 0000000000000000000000000000000000000000..efb1757b69f141aab44d2b47a75ea2c88fa9b128
--- /dev/null
+++ b/ChaosGame/src/main/resources/stylesheets/transformationAttributes.css
@@ -0,0 +1,70 @@
+.textField {
+  -fx-background-color: #0F2465FF;
+  -fx-text-fill: #ffffff;
+  -fx-prompt-text-fill: #565656;
+  -fx-font-size: 14;
+  -fx-border-color: #c26d37;
+  -fx-border-width: 2;
+  -fx-border-radius: 5;
+}
+
+.attributeNames {
+  -fx-font-size: 14px;
+  -fx-font-weight: bold;
+  -fx-fill: #cccccc;
+}
+
+.errorLabel {
+  -fx-font-size: 10px;
+  -fx-text-fill: #ff0000;
+}
+
+.attributeNumber {
+  -fx-font-size: 20px;
+  -fx-font-weight: bold;
+  -fx-font-family: italic;
+  -fx-text-fill: #c4c4c4;
+}
+
+.frame {
+  -fx-border-width: 0px;
+  -fx-padding: 20 40 0 40;
+  -fx-hgap: 10;
+  -fx-vgap: 10;
+}
+
+.vbox {
+  -fx-background-color: #181C82;
+}
+
+.scroll-bar,
+.scroll-pane,
+.scroll-pane .viewport {
+  -fx-background-color: #181C82;
+}
+
+.scroll-bar .thumb {
+  -fx-background-color: #c26d37;
+}
+
+.button {
+  -fx-background-color: radial-gradient(center 50% 50%, radius 100%, #0f2465, transparent);
+  -fx-background-radius: 0;
+  -fx-border-width: 0;
+  -fx-text-fill: #ffffff;
+  -fx-font-weight: bold;
+  -fx-padding: 10 20 10 20;
+  -fx-pref-height: 40;
+  -fx-pref-width: 250;
+  -fx-font-size: 12;
+  -fx-alignment: center;
+}
+
+.button:hover,
+.button:pressed,
+.button:selected {
+  -fx-background-color: #c26d37;
+  -fx-text-fill: #ffffff;
+
+
+}
\ No newline at end of file
diff --git a/ChaosGame/src/main/resources/stylesheets/transformationPicture.css b/ChaosGame/src/main/resources/stylesheets/transformationPicture.css
new file mode 100644
index 0000000000000000000000000000000000000000..552c8f351a73d2ac3764fc8780f3c253af4946d2
--- /dev/null
+++ b/ChaosGame/src/main/resources/stylesheets/transformationPicture.css
@@ -0,0 +1,7 @@
+.frame {
+  -fx-border-width: 4;
+  -fx-border-color: #0f2465;
+  -fx-border-radius: 10;
+  -fx-background-radius: 12;
+  -fx-effect: dropshadow(gaussian, rgba(19, 19, 19, 0.8), 10, 2, 10, 6);
+}
\ No newline at end of file
diff --git a/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/controller/ChaosGameTest.java b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/controller/ChaosGameTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..bff4cd721c335c6a3240efaed9a68816436f38eb
--- /dev/null
+++ b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/controller/ChaosGameTest.java
@@ -0,0 +1,155 @@
+package edu.ntnu.idatt2003.group6.controller;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import edu.ntnu.idatt2003.group6.controller.chaosgame.ChaosGame;
+import edu.ntnu.idatt2003.group6.controller.chaosgame.GameState;
+import edu.ntnu.idatt2003.group6.models.chaosgame.ChaosCanvas;
+import edu.ntnu.idatt2003.group6.models.chaosgame.ChaosGameDescription;
+import edu.ntnu.idatt2003.group6.models.chaosgame.ChaosGameDescriptionFactory;
+import edu.ntnu.idatt2003.group6.models.chaosgame.GameType;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+class ChaosGameTest {
+
+  private ChaosGame chaosGame;
+  private ChaosGameDescription chaosGameDescription;
+
+  @BeforeEach
+  void setUp() {
+    chaosGameDescription =
+        ChaosGameDescriptionFactory.createChaosGameDescription(GameType.SIERPINSKI);
+    chaosGame = new ChaosGame(chaosGameDescription, 700, 700);
+  }
+
+  @Nested
+  @DisplayName("Positive tests for ChaosGame")
+  class methodsDoesNotThrowException {
+
+    @Test
+    @DisplayName("ChaosGame constructor creates an instance of ChaosGame without throwing an exception")
+    void chaosGameDoesntThrowOnNewChaosGame() {
+      assertNotNull(chaosGame);
+    }
+
+    @Test
+    @DisplayName("getState method returns the expected value without throwing an exception")
+    void evaluateChaosGameGetState() {
+      chaosGame.runSteps(1);
+      GameState result = chaosGame.getState();
+      assertEquals(GameState.DONE, result);
+    }
+
+    @Test
+    @DisplayName("runSteps method executes without throwing an exception")
+    void runStepsDoesntThrow() {
+      assertDoesNotThrow(() -> chaosGame.runSteps(1));
+    }
+
+    @Test
+    @DisplayName("addObserver method executes without throwing an exception")
+    void addObserverDoesntThrow() {
+      assertDoesNotThrow(() -> chaosGame.addObserver((o) -> {
+      }));
+    }
+
+    @Test
+    @DisplayName("removeObserver method executes without throwing an exception")
+    void removeObserverDoesntThrow() {
+      assertDoesNotThrow(() -> chaosGame.removeObserver((o) -> {
+      }));
+    }
+
+    @Test
+    @DisplayName("ChaosGame constructor throws on null description")
+    void chaosGameThrowsOnNullDescription() {
+      assertThrows(IllegalArgumentException.class, () -> new ChaosGame(null, 700, 700));
+    }
+
+    @Test
+    @DisplayName("ChaosGame constructor throws on invalid width")
+    void chaosGameThrowsOnInvalidWidth() {
+      assertThrows(IllegalArgumentException.class,
+          () -> new ChaosGame(chaosGameDescription, 0, 700));
+    }
+
+    @Test
+    @DisplayName("ChaosGame constructor throws on invalid height")
+    void chaosGameThrowsOnInvalidHeight() {
+      assertThrows(IllegalArgumentException.class,
+          () -> new ChaosGame(chaosGameDescription, 700, 0));
+    }
+
+    @Test
+    @DisplayName("getCanvas method returns the canvas")
+    void evaluateChaosGameGetCanvas() {
+      ChaosCanvas result = chaosGame.getCanvas();
+      assertNotNull(result);
+    }
+
+    @Test
+    @DisplayName("getChaosGameDescription method returns the chaos game description")
+    void evaluateChaosGameGetChaosGameDescription() {
+      ChaosGameDescription result = chaosGame.getChaosGameDescription();
+      assertNotNull(result);
+    }
+
+    @Test
+    @DisplayName("getGameType method returns the game type")
+    void evaluateChaosGameGetGameType() {
+      GameType result = chaosGame.getGameType();
+      assertEquals(GameType.AFFINE, result);
+    }
+
+
+  }
+
+  @Nested
+  @DisplayName("Negative tests for ChaosGame")
+  class methodsThrowsExceptions {
+
+    @Test
+    @DisplayName("ChaosGame constructor throws an exception when description is null")
+    void chaosGameThrowsOnNullDescription() {
+      assertThrows(IllegalArgumentException.class, () -> new ChaosGame(null, 700, 700));
+    }
+
+    @Test
+    @DisplayName("ChaosGame constructor throws an exception when width is less than or equal to 0")
+    void chaosGameThrowsOnInvalidWidth() {
+      assertThrows(IllegalArgumentException.class,
+          () -> new ChaosGame(chaosGameDescription, 0, 700));
+    }
+
+    @Test
+    @DisplayName("ChaosGame constructor throws an exception when height is less than or equal to 0")
+    void chaosGameThrowsOnInvalidHeight() {
+      assertThrows(IllegalArgumentException.class,
+          () -> new ChaosGame(chaosGameDescription, 700, 0));
+    }
+
+    @Test
+    @DisplayName("runSteps method throws an exception when steps is less than 1")
+    void runStepsThrowsOnInvalidSteps() {
+      assertThrows(IllegalArgumentException.class, () -> chaosGame.runSteps(-1));
+    }
+
+    @Test
+    @DisplayName("addObserver method throws an exception when observer is null")
+    void addObserverThrowsOnNullObserver() {
+      assertThrows(IllegalArgumentException.class, () -> chaosGame.addObserver(null));
+    }
+
+    @Test
+    @DisplayName("removeObserver method throws an exception when observer is null")
+    void removeObserverThrowsOnNullObserver() {
+      assertThrows(IllegalArgumentException.class, () -> chaosGame.removeObserver(null));
+    }
+  }
+}
\ No newline at end of file
diff --git a/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosCanvasTest.java b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosCanvasTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..56ab7d5ad7dd732c6eedf76ddfd0696bce4dbf19
--- /dev/null
+++ b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosCanvasTest.java
@@ -0,0 +1,125 @@
+package edu.ntnu.idatt2003.group6.models.chaosgame;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import edu.ntnu.idatt2003.group6.models.matrix.Matrix2x2;
+import edu.ntnu.idatt2003.group6.models.vector.Vector2D;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+class ChaosCanvasTest {
+
+  ChaosCanvas chaosCanvas;
+
+  @BeforeEach
+  public void setUp() {
+    chaosCanvas = new ChaosCanvas(100, 100, new Vector2D(0, 0), new Vector2D(1, 1));
+  }
+
+  @Nested
+  @DisplayName("Positive tests for ChaosCanvas")
+  class methodsDoesNotThrowException {
+    @Test
+    @DisplayName("ChaosCanvas constructor creates an instance of ChaosCanvas " +
+        "without throwing an exception")
+    void chaosCanvasDoesntThrowOnNewChaosCanvas() {
+      try {
+        ChaosCanvas testChaosCanvas =
+            new ChaosCanvas(100, 100, new Vector2D(0, 0), new Vector2D(1, 1));
+        assertNotNull(testChaosCanvas);
+      } catch (IllegalArgumentException e) {
+        fail("The test chaosCanvasDoesntThrowOnNewChaosCanvas failed with the exception " +
+            "message " + e.getMessage());
+      }
+    }
+
+    @Test
+    @DisplayName("getPixel method returns the expected value without throwing an exception")
+    void evaluateChaosCanvasGetPixel() {
+      Vector2D point = new Vector2D(0.5, 0.5);
+      int result = chaosCanvas.getPixel(point);
+      assertEquals(0, result);
+    }
+
+    @Test
+    @DisplayName("putPixel method returns the expected value without throwing an exception")
+    void evaluateChaosCanvasPutPixel() {
+      Vector2D point = new Vector2D(0.5, 0.5);
+      chaosCanvas.putPixel(point);
+      int result = chaosCanvas.getPixel(point);
+      assertEquals(1, result);
+    }
+
+    @Test
+    @DisplayName("getCanvasArray method returns the expected value without throwing an exception")
+    void evaluateChaosCanvasGetCanvasArray() {
+      int[][] result = chaosCanvas.getCanvasArray();
+      assertEquals(100, result.length);
+      assertEquals(100, result[0].length);
+    }
+
+    @Test
+    @DisplayName("clear method returns the expected value without throwing an exception")
+    void evaluateChaosCanvasClear() {
+      chaosCanvas.putPixel(new Vector2D(0.5, 0.5));
+      chaosCanvas.clear();
+      int[][] result = chaosCanvas.getCanvasArray();
+      assertEquals(0, result[50][50]);
+    }
+
+    @Test
+    @DisplayName("getMatrixForIndices method returns the expected value without throwing an exception")
+    void evaluateChaosCanvasGetMatrixForIndices() {
+      try {
+        var method = ChaosCanvas.class.getDeclaredMethod("getMatrixForIndices");
+        method.setAccessible(true);
+        var result = (Matrix2x2) method.invoke(chaosCanvas);
+        assertNotNull(result);
+      } catch (Exception e) {
+        fail("The test evaluateChaosCanvasGetMatrixForIndices failed with the exception " +
+            "message " + e.getMessage());
+      }
+    }
+  }
+
+  @Nested
+  @DisplayName("Negative tests for ChaosCanvas")
+  class methodsThrowsExceptions {
+    @Test
+    @DisplayName("ChaosCanvas constructor throws an exception when width is less than or equal to 0")
+    void chaosCanvasThrowsOnInvalidWidth() {
+      assertThrows(IllegalArgumentException.class, () ->
+          new ChaosCanvas(0, 100, new Vector2D(0, 0), new Vector2D(1, 1)));
+    }
+
+    @Test
+    @DisplayName("ChaosCanvas constructor throws an exception when height is less than or equal to 0")
+    void chaosCanvasThrowsOnInvalidHeight() {
+      assertThrows(IllegalArgumentException.class, () ->
+          new ChaosCanvas(100, 0, new Vector2D(0, 0), new Vector2D(1, 1)));
+    }
+
+    @Test
+    @DisplayName("getPixel method throws an exception when point is out of bounds")
+    void evaluateChaosCanvasGetPixelThrows() {
+      Vector2D point = new Vector2D(2, 2);
+      assertThrows(IllegalArgumentException.class, () ->
+          chaosCanvas.getPixel(point));
+    }
+
+    @Test
+    @DisplayName("putPixel method throws an exception when point is out of bounds")
+    void evaluateChaosCanvasPutPixelThrows() {
+      Vector2D point = new Vector2D(2, 2);
+      assertThrows(IllegalArgumentException.class, () ->
+          chaosCanvas.putPixel(point));
+    }
+  }
+
+
+}
\ No newline at end of file
diff --git a/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosGameDescriptionFactoryTest.java b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosGameDescriptionFactoryTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..146da27f7db1fac8323cb6369fda79edd0627adb
--- /dev/null
+++ b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosGameDescriptionFactoryTest.java
@@ -0,0 +1,107 @@
+package edu.ntnu.idatt2003.group6.models.chaosgame;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+class ChaosGameDescriptionFactoryTest {
+
+
+  @Nested
+  @DisplayName("Positive tests for ChaosGameDescriptionFactory")
+  class methodsDoesNotThrowException {
+    @Test
+    @DisplayName("createChaosGameDescription method creates an instance of Sierpinski " +
+        "without throwing an exception")
+    void createChaosGameDescriptionSierpinskiDoesntThrowOnNewChaosGameDescription() {
+      try {
+        ChaosGameDescription testChaosGameDescription =
+            ChaosGameDescriptionFactory.createChaosGameDescription(GameType.SIERPINSKI);
+        assertNotNull(testChaosGameDescription);
+      } catch (Exception e) {
+        fail(
+            "The test createChaosGameDescriptionDoesntThrowOnNewChaosGameDescription failed" +
+                "with the exception message " + e.getMessage());
+      }
+    }
+
+    @Test
+    @DisplayName("createChaosGameDescription method creates an instance of Barnsley " +
+        "without throwing an exception")
+    void createChaosGameDescriptionBarnsleyDoesntThrowOnNewChaosGameDescription() {
+      try {
+        ChaosGameDescription testChaosGameDescription =
+            ChaosGameDescriptionFactory.createChaosGameDescription(GameType.BARNSLEY);
+        assertNotNull(testChaosGameDescription);
+      } catch (Exception e) {
+        fail(
+            "The test createChaosGameDescriptionBarnsleyDoesntThrowOnNewChaosGameDescription " +
+                "failed with the exception message " + e.getMessage());
+      }
+    }
+
+    @Test
+    @DisplayName("createChaosGameDescription method creates an instance of Julia " +
+        "without throwing an exception")
+    void createChaosGameDescriptionJuliaDoesntThrowOnNewChaosGameDescription() {
+      try {
+        ChaosGameDescription testChaosGameDescription =
+            ChaosGameDescriptionFactory.createChaosGameDescription(GameType.JULIA);
+        assertNotNull(testChaosGameDescription);
+      } catch (Exception e) {
+        fail(
+            "The test createChaosGameDescriptionJuliaDoesntThrowOnNewChaosGameDescription " +
+                "failed with the exception message " + e.getMessage());
+      }
+    }
+
+    @Test
+    @DisplayName("createChaosGameDescription method creates an instance of Julia_New " +
+        "without throwing an exception")
+    void createChaosGameDescriptionJuliaNewDoesntThrowOnNewChaosGameDescription() {
+      try {
+        ChaosGameDescription testChaosGameDescription =
+            ChaosGameDescriptionFactory.createChaosGameDescription(GameType.JULIA_NEW);
+        assertNotNull(testChaosGameDescription);
+      } catch (Exception e) {
+        fail(
+            "The test createChaosGameDescriptionJuliaNewDoesntThrowOnNewChaosGameDescription " +
+                "failed with the exception message " + e.getMessage());
+      }
+    }
+
+    @Test
+    @DisplayName("createChaosGameDescription method creates an instance of Affine_New " +
+        "without throwing an exception")
+    void createChaosGameDescriptionAffineNewDoesntThrowOnNewChaosGameDescription() {
+      try {
+        ChaosGameDescription testChaosGameDescription =
+            ChaosGameDescriptionFactory.createChaosGameDescription(GameType.AFFINE_NEW);
+        assertNotNull(testChaosGameDescription);
+      } catch (Exception e) {
+        fail(
+            "The test createChaosGameDescriptionAffineNewDoesntThrowOnNewChaosGameDescription " +
+                "failed with the exception message " + e.getMessage());
+      }
+    }
+
+    @Test
+    @DisplayName("createChaosGameDescription method throws an exception when gameType is null")
+    void createChaosGameDescriptionThrowsOnNullGameType() {
+      assertThrows(IllegalArgumentException.class, () ->
+          ChaosGameDescriptionFactory.createChaosGameDescription(null));
+    }
+
+    @Test
+    @DisplayName("createChaosGameDescription method throws an exception when gameType is invalid")
+    void createChaosGameDescriptionThrowsOnInvalidGameType() {
+      assertThrows(IllegalArgumentException.class, () ->
+          ChaosGameDescriptionFactory.createChaosGameDescription(GameType.valueOf("INVALID")));
+    }
+
+  }
+}
\ No newline at end of file
diff --git a/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosGameDescriptionTest.java b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosGameDescriptionTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b3ac6277bf7347c82198415247a6ddc83d016353
--- /dev/null
+++ b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/chaosgame/ChaosGameDescriptionTest.java
@@ -0,0 +1,142 @@
+package edu.ntnu.idatt2003.group6.models.chaosgame;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import edu.ntnu.idatt2003.group6.models.matrix.Matrix2x2;
+import edu.ntnu.idatt2003.group6.models.transformation.AffineTransform2D;
+import edu.ntnu.idatt2003.group6.models.transformation.Transform2D;
+import edu.ntnu.idatt2003.group6.models.vector.Vector2D;
+import edu.ntnu.idatt2003.group6.utils.exceptions.IllegalChaosGameException;
+import java.util.Arrays;
+import java.util.List;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+class ChaosGameDescriptionTest {
+
+  ChaosGameDescription chaosGameDescription;
+  List<Transform2D> transformations;
+
+  @BeforeEach
+  public void setUp() {
+    transformations = Arrays.asList(new AffineTransform2D(
+        new Matrix2x2(0.5, 0, 0, 0.5), new Vector2D(0, 0)
+    ), new AffineTransform2D(
+        new Matrix2x2(0.5, 0, 0, 0.5), new Vector2D(0.5, 0)
+    ), new AffineTransform2D(
+        new Matrix2x2(0.5, 0, 0, 0.5), new Vector2D(0.25, 0.5)
+    ));
+    chaosGameDescription =
+        new ChaosGameDescription(transformations, new Vector2D(0, 0), new Vector2D(1, 1));
+  }
+
+  @Nested
+  @DisplayName("Positive tests for ChaosGameDescription")
+  class methodsDoesNotThrowException {
+    @Test
+    @DisplayName("ChaosGameDescription constructor creates an instance of ChaosGameDescription " +
+        "without throwing an exception")
+    void chaosGameDescriptionDoesntThrowOnNewChaosGameDescription() {
+      try {
+        ChaosGameDescription testChaosGameDescription =
+            new ChaosGameDescription(transformations, new Vector2D(0, 0), new Vector2D(1, 1));
+        assertNotNull(testChaosGameDescription);
+      } catch (IllegalChaosGameException e) {
+        fail(
+            "The test chaosGameDescriptionDoesntThrowOnNewChaosGameDescription failed with the exception " +
+                "message " + e.getMessage());
+      }
+    }
+
+    @Test
+    @DisplayName("getTransformations method returns the expected value without throwing an exception")
+    void evaluateChaosGameDescriptionGetTransformations() {
+      List<Transform2D> result = chaosGameDescription.getTransformations();
+      assertEquals(transformations, result);
+    }
+
+    @Test
+    @DisplayName("getMinCoords method returns the expected value without throwing an exception")
+    void evaluateChaosGameDescriptionGetMinCoords() {
+      Vector2D result = chaosGameDescription.getMinCoords();
+      assertEquals(0.0, result.getX0());
+      assertEquals(0.0, result.getX1());
+    }
+
+    @Test
+    @DisplayName("getMaxCoords method returns the expected value without throwing an exception")
+    void evaluateChaosGameDescriptionGetMaxCoords() {
+      Vector2D result = chaosGameDescription.getMaxCoords();
+      assertEquals(1.0, result.getX0());
+      assertEquals(1.0, result.getX1());
+    }
+
+    @Test
+    @DisplayName("setTransformations method sets the transformations correctly")
+    void evaluateChaosGameDescriptionSetTransformations() {
+      List<Transform2D> newTransformations = Arrays.asList(new AffineTransform2D(
+          new Matrix2x2(0.5, 0, 0, 0.5), new Vector2D(0, 0)
+      ), new AffineTransform2D(
+          new Matrix2x2(0.5, 0, 0, 0.5), new Vector2D(0.5, 0)
+      ), new AffineTransform2D(
+          new Matrix2x2(0.5, 0, 0, 0.5), new Vector2D(0.25, 0.5)
+      ));
+      chaosGameDescription.setTransformations(newTransformations);
+      assertEquals(newTransformations, chaosGameDescription.getTransformations());
+    }
+
+    @Test
+    @DisplayName("setMinCoords method sets the minimum coordinates correctly")
+    void evaluateChaosGameDescriptionSetMinCoords() {
+      Vector2D newMinCoords = new Vector2D(0.5, 0.5);
+      chaosGameDescription.setMinCoords(newMinCoords);
+      assertEquals(newMinCoords, chaosGameDescription.getMinCoords());
+    }
+
+    @Test
+    @DisplayName("setMaxCoords method sets the maximum coordinates correctly")
+    void evaluateChaosGameDescriptionSetMaxCoords() {
+      Vector2D newMaxCoords = new Vector2D(1.5, 1.5);
+      chaosGameDescription.setMaxCoords(newMaxCoords);
+      assertEquals(newMaxCoords, chaosGameDescription.getMaxCoords());
+    }
+
+    @Test
+    @DisplayName("getGameType method returns the expected value")
+    void evaluateChaosGameDescriptionGetGameType() {
+      GameType result = chaosGameDescription.getGameType();
+
+      assertEquals(GameType.AFFINE, result);
+    }
+  }
+
+  @Nested
+  @DisplayName("Negative tests for ChaosGameDescription")
+  class MethodsThrowsExceptions {
+    @Test
+    @DisplayName("ChaosGameDescription constructor throws an exception when transformations is null")
+    void chaosGameDescriptionThrowsOnNullTransformations() {
+      assertThrows(IllegalChaosGameException.class, () ->
+          new ChaosGameDescription(null, new Vector2D(0, 0), new Vector2D(1, 1)));
+    }
+
+    @Test
+    @DisplayName("ChaosGameDescription constructor throws an exception when minCoords is null")
+    void chaosGameDescriptionThrowsOnNullMinCoords() {
+      assertThrows(IllegalChaosGameException.class, () ->
+          new ChaosGameDescription(transformations, null, new Vector2D(1, 1)));
+    }
+
+    @Test
+    @DisplayName("ChaosGameDescription constructor throws an exception when maxCoords is null")
+    void chaosGameDescriptionThrowsOnNullMaxCoords() {
+      assertThrows(IllegalChaosGameException.class, () ->
+          new ChaosGameDescription(transformations, new Vector2D(0, 0), null));
+    }
+  }
+}
\ No newline at end of file
diff --git a/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/chaosgame/GameTypeTest.java b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/chaosgame/GameTypeTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..7bb8f6de251cbea57ad988a42cd4e9c5fc61ddd6
--- /dev/null
+++ b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/chaosgame/GameTypeTest.java
@@ -0,0 +1,23 @@
+package edu.ntnu.idatt2003.group6.models.chaosgame;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.Test;
+
+class GameTypeTest {
+
+  @Test
+  void testEnumValues() {
+    // Test that the enum contains the expected number of values
+    assertEquals(6, GameType.values().length);
+
+    // Test that the enum contains the expected values
+    assertEquals(GameType.SIERPINSKI, GameType.valueOf("SIERPINSKI"));
+    assertEquals(GameType.BARNSLEY, GameType.valueOf("BARNSLEY"));
+    assertEquals(GameType.JULIA, GameType.valueOf("JULIA"));
+    assertEquals(GameType.AFFINE, GameType.valueOf("AFFINE"));
+    assertEquals(GameType.JULIA_NEW, GameType.valueOf("JULIA_NEW"));
+    assertEquals(GameType.AFFINE_NEW, GameType.valueOf("AFFINE_NEW"));
+  }
+
+}
\ No newline at end of file
diff --git a/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/files/FileModelTest.java b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/files/FileModelTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..db053d1544c0bf07e07715ee62ac83c0e7409f8e
--- /dev/null
+++ b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/files/FileModelTest.java
@@ -0,0 +1,155 @@
+package edu.ntnu.idatt2003.group6.models.files;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import edu.ntnu.idatt2003.group6.models.chaosgame.ChaosGameDescription;
+import edu.ntnu.idatt2003.group6.models.chaosgame.ChaosGameDescriptionFactory;
+import edu.ntnu.idatt2003.group6.models.chaosgame.GameType;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+//Disabled since maven struggles to run the files, even though they can run locally
+@Disabled
+class FileModelTest {
+
+  private FileModel fileModel;
+  private ChaosGameDescription chaosGameDescription;
+
+  @BeforeEach
+  void setUp() {
+    fileModel = FileModel.getInstance();
+    chaosGameDescription = ChaosGameDescriptionFactory.
+        createChaosGameDescription(GameType.SIERPINSKI);
+  }
+
+
+  @Nested
+  @DisplayName("Positive tests for FileModel")
+  class methodsDoesNotThrowException {
+
+    @Test
+    @DisplayName("getInstance method creates an instance of FileModel without throwing an exception")
+    void getInstanceDoesntThrow() {
+      assertNotNull(fileModel);
+    }
+
+    @Test
+    @DisplayName("getFiles method executes without throwing an exception")
+    void getFilesDoesntThrow() {
+      assertDoesNotThrow(() -> fileModel.getFiles());
+    }
+
+    @Test
+    @DisplayName("addFile method executes without throwing an exception")
+    void addFileDoesntThrow() {
+      assertDoesNotThrow(() -> fileModel.addFile("testFile", chaosGameDescription));
+    }
+
+    @Test
+    @DisplayName("getFile method executes without throwing an exception")
+    void getFileDoesntThrow() {
+      assertDoesNotThrow(() -> fileModel.getFile("testFile"));
+    }
+
+    @Test
+    @DisplayName("removeFile method executes without throwing an exception")
+    void removeFileDoesntThrow() {
+      assertDoesNotThrow(() -> fileModel.removeFile("testFile"));
+    }
+
+    @Test
+    @DisplayName("setState method executes without throwing an exception")
+    void setStateDoesntThrow() {
+      assertDoesNotThrow(() -> fileModel.setState(FileState.FILES_CHANGED));
+    }
+
+    @Test
+    @DisplayName("addObserver method executes without throwing an exception")
+    void addObserverDoesntThrow() {
+      FileObserver observer = state -> {
+        // Do nothing
+      };
+      assertDoesNotThrow(() -> fileModel.addObserver(observer));
+    }
+
+    @Test
+    @DisplayName("removeObserver method executes without throwing an exception")
+    void removeObserverDoesntThrow() {
+      FileObserver observer = state -> {
+        // Do nothing
+      };
+      fileModel.addObserver(observer);
+      assertDoesNotThrow(() -> fileModel.removeObserver(observer));
+    }
+  }
+
+  @Nested
+  @DisplayName("Negative tests for FileModel")
+  class methodsThrowsExceptions {
+
+    @Test
+    @DisplayName("getFiles method throws an exception when file does not exist")
+    void getFilesThrowsOnNonExistingFile() {
+      assertThrows(IllegalArgumentException.class, () -> fileModel.getFile(null));
+    }
+
+    @Test
+    @DisplayName("addFile method throws an exception when fileName is null")
+    void addFileThrowsOnNullFileName() {
+      assertThrows(IllegalArgumentException.class, () -> fileModel.addFile(null, chaosGameDescription));
+    }
+
+    @Test
+    @DisplayName("addFile method throws an exception when chaosGameDescription is null")
+    void addFileThrowsOnNullChaosGameDescription() {
+      assertThrows(IllegalArgumentException.class, () -> fileModel.addFile("testFile", null));
+    }
+
+    @Test
+    @DisplayName("getFile method throws an exception when fileName is null")
+    void getFileThrowsOnNullFileName() {
+      assertThrows(IllegalArgumentException.class, () -> fileModel.getFile(null));
+    }
+
+    @Test
+    @DisplayName("getFile method throws an exception when file does not exist")
+    void getFileThrowsOnNonExistingFile() {
+      assertThrows(IllegalArgumentException.class, () -> fileModel.getFile("nonExistingFile"));
+    }
+
+    @Test
+    @DisplayName("removeFile method throws an exception when fileName is null")
+    void removeFileThrowsOnNullFileName() {
+      assertThrows(IllegalArgumentException.class, () -> fileModel.removeFile(null));
+    }
+
+    @Test
+    @DisplayName("removeFile method throws an exception when file does not exist")
+    void removeFileThrowsOnNonExistingFile() {
+      assertThrows(IllegalArgumentException.class, () -> fileModel.removeFile("nonExistingFile"));
+    }
+
+    @Test
+    @DisplayName("setState method throws an exception when state is null")
+    void setStateThrowsOnNullState() {
+      assertThrows(IllegalArgumentException.class, () -> fileModel.setState(null));
+    }
+
+    @Test
+    @DisplayName("addObserver method throws an exception when observer is null")
+    void addObserverThrowsOnNullObserver() {
+      assertThrows(IllegalArgumentException.class, () -> fileModel.addObserver(null));
+    }
+
+    @Test
+    @DisplayName("removeObserver method throws an exception when observer is null")
+    void removeObserverThrowsOnNullObserver() {
+      assertThrows(IllegalArgumentException.class, () -> fileModel.removeObserver(null));
+    }
+  }
+}
\ No newline at end of file
diff --git a/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/files/FilePathTest.java b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/files/FilePathTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..33fb174ce3517c0f05b35528480e02ea25e72b7d
--- /dev/null
+++ b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/files/FilePathTest.java
@@ -0,0 +1,19 @@
+package edu.ntnu.idatt2003.group6.models.files;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class FilePathTest {
+
+  @Test
+  void testEnumValues() {
+    // Test that the enum contains the expected number of values
+    assertEquals(3, FilePath.values().length);
+    // Test that the enum contains the expected values
+    assertEquals(FilePath.DESCRIPTIONS, FilePath.valueOf("DESCRIPTIONS"));
+    assertEquals(FilePath.IMAGES, FilePath.valueOf("IMAGES"));
+    assertEquals(FilePath.MUSIC, FilePath.valueOf("MUSIC"));
+    assertEquals("src/main/resources/descriptions/", FilePath.DESCRIPTIONS.getPath());
+  }
+}
\ No newline at end of file
diff --git a/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/files/FileStateTest.java b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/files/FileStateTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..88d14ce4bb33dc68939c499592042f6e6435d666
--- /dev/null
+++ b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/files/FileStateTest.java
@@ -0,0 +1,19 @@
+package edu.ntnu.idatt2003.group6.models.files;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class FileStateTest {
+
+  @Test
+  void testEnumValues() {
+    // Test that the enum contains the expected number of values
+    assertEquals(3, FileState.values().length);
+
+    // Test that the enum contains the expected values
+    assertEquals(FileState.FILES_UPDATING, FileState.valueOf("FILES_UPDATING"));
+    assertEquals(FileState.FILES_UNCHANGED, FileState.valueOf("FILES_UNCHANGED"));
+    assertEquals(FileState.FILES_CHANGED, FileState.valueOf("FILES_CHANGED"));
+  }
+}
\ No newline at end of file
diff --git a/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/matrix/Matrix2x2Test.java b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/matrix/Matrix2x2Test.java
index 7e952d40a4d8f7d457350c308cd5c56a038ba933..d3fb777f82ba86b282135fedb7ba6d7b20d57c1e 100644
--- a/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/matrix/Matrix2x2Test.java
+++ b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/matrix/Matrix2x2Test.java
@@ -4,7 +4,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.fail;
 
-import edu.ntnu.idatt2003.group6.models.matrix.Matrix2x2;
 import edu.ntnu.idatt2003.group6.models.vector.Vector2D;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
@@ -23,6 +22,16 @@ public class Matrix2x2Test {
   @Nested
   @DisplayName("Positive tests for Matrix2x2")
   class methodsDoesNotThrowException {
+
+    @Test
+    void testRecordFields() {
+      Matrix2x2 matrix = new Matrix2x2(1, 2, 3, 4);
+      assertEquals(1, matrix.a00());
+      assertEquals(2, matrix.a01());
+      assertEquals(3, matrix.a10());
+      assertEquals(4, matrix.a11());
+    }
+
     @Test
     @DisplayName("Matrix2x2 constructor creates an instance of Matrix2x2 " +
         "without throwing an exception")
@@ -49,17 +58,16 @@ public class Matrix2x2Test {
   @Nested
   @DisplayName("Negative tests for Matrix2x2")
   class methodsThrowsExceptions {
-
     @Test
-    @DisplayName("Matrix2x2 constructor throws an exception when a00 is invalid")
-    void matrix2x2ThrowsOnInvalidA00() {
+    @DisplayName("Matrix2x2 multiply throws an exception when the vector is invalid")
+    void matrix2x2ThrowsOnInvalidVector() {
       try {
-        new Matrix2x2(Double.NaN, 2, 3, 4);
-        fail("The test matrix2x2ThrowsOnInvalidA00 failed");
+        matrix.multiply(null);
+        fail("The test matrix2x2ThrowsOnInvalidVector failed");
       } catch (IllegalArgumentException e) {
-        assertEquals("The string for the parameter a00 was not valid, try to register " +
-            "again", e.getMessage());
+        assertEquals("The given vector cannot be null.", e.getMessage());
       }
     }
+
   }
 }
\ No newline at end of file
diff --git a/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/navigation/NavigationModelTest.java b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/navigation/NavigationModelTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..1cd3a86ec67d6481e3954adf05b9dd19b3842930
--- /dev/null
+++ b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/navigation/NavigationModelTest.java
@@ -0,0 +1,77 @@
+package edu.ntnu.idatt2003.group6.models.navigation;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+class NavigationModelTest {
+
+  private NavigationModel navigationModel;
+
+  @BeforeEach
+  void setUp() {
+    navigationModel = new NavigationModel();
+  }
+
+  @Nested
+  @DisplayName("Positive tests for NavigationModel")
+  class methodsDoesNotThrowException {
+
+    @Test
+    @DisplayName("getState method returns the expected value without throwing an exception")
+    void getStateDoesntThrow() {
+      navigationModel.setState(NavigationState.MENU);
+      assertEquals(NavigationState.MENU, navigationModel.getState());
+    }
+
+    @Test
+    @DisplayName("setState method sets the state correctly without throwing an exception")
+    void setStateDoesntThrow() {
+      navigationModel.setState(NavigationState.SETTINGS);
+      assertEquals(NavigationState.SETTINGS, navigationModel.getState());
+    }
+
+    @Test
+    @DisplayName("addObserver method adds an observer correctly without throwing an exception")
+    void addObserverDoesntThrow() {
+      NavigationObserver observer = state -> {};
+      assertDoesNotThrow(() -> navigationModel.addObserver(observer));
+    }
+
+    @Test
+    @DisplayName("removeObserver method removes an observer correctly without throwing an exception")
+    void removeObserverDoesntThrow() {
+      NavigationObserver observer = state -> {};
+      navigationModel.addObserver(observer);
+      assertDoesNotThrow(() -> navigationModel.removeObserver(observer));
+    }
+  }
+
+  @Nested
+  @DisplayName("Negative tests for NavigationModel")
+  class methodsThrowsExceptions {
+
+    @Test
+    @DisplayName("setState method throws an exception when state is null")
+    void setStateThrowsOnNullState() {
+      assertThrows(IllegalArgumentException.class, () -> navigationModel.setState(null));
+    }
+
+    @Test
+    @DisplayName("addObserver method throws an exception when observer is null")
+    void addObserverThrowsOnNullObserver() {
+      assertThrows(IllegalArgumentException.class, () -> navigationModel.addObserver(null));
+    }
+
+    @Test
+    @DisplayName("removeObserver method throws an exception when observer is null")
+    void removeObserverThrowsOnNullObserver() {
+      assertThrows(IllegalArgumentException.class, () -> navigationModel.removeObserver(null));
+    }
+  }
+}
\ No newline at end of file
diff --git a/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/navigation/NavigationStateTest.java b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/navigation/NavigationStateTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..9ddfe05ad439c00bfe4b286b5f64792596f4a511
--- /dev/null
+++ b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/navigation/NavigationStateTest.java
@@ -0,0 +1,25 @@
+package edu.ntnu.idatt2003.group6.models.navigation;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class NavigationStateTest {
+
+  @Test
+  void testEnumValues() {
+    // Test that the enum contains the expected number of values
+    assertEquals(9, NavigationState.values().length);
+
+    // Test that the enum contains the expected values
+    assertEquals(NavigationState.SELECT_FILE, NavigationState.valueOf("SELECT_FILE"));
+    assertEquals(NavigationState.EDIT_FILE, NavigationState.valueOf("EDIT_FILE"));
+    assertEquals(NavigationState.SELECT_GAME, NavigationState.valueOf("SELECT_GAME"));
+    assertEquals(NavigationState.SELECT_GAME_FILES, NavigationState.valueOf("SELECT_GAME_FILES"));
+    assertEquals(NavigationState.PLAY_GAME, NavigationState.valueOf("PLAY_GAME"));
+    assertEquals(NavigationState.PLAY_JULIA, NavigationState.valueOf("PLAY_JULIA"));
+    assertEquals(NavigationState.PLAY_AFFINE, NavigationState.valueOf("PLAY_AFFINE"));
+    assertEquals(NavigationState.SETTINGS, NavigationState.valueOf("SETTINGS"));
+    assertEquals(NavigationState.MENU, NavigationState.valueOf("MENU"));
+  }
+}
\ No newline at end of file
diff --git a/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/transformation/AffineTransform2DTest.java b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/transformation/AffineTransform2DTest.java
index 85f0230ab2244f2fb3c06a0e51e1341e8fe25ac1..146f32d1ae6eab21c384d7412e0f2ec3cb52c628 100644
--- a/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/transformation/AffineTransform2DTest.java
+++ b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/transformation/AffineTransform2DTest.java
@@ -2,10 +2,11 @@ package edu.ntnu.idatt2003.group6.models.transformation;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.fail;
 
+import edu.ntnu.idatt2003.group6.models.chaosgame.GameType;
 import edu.ntnu.idatt2003.group6.models.matrix.Matrix2x2;
-import edu.ntnu.idatt2003.group6.models.transformation.AffineTransform2D;
 import edu.ntnu.idatt2003.group6.models.vector.Vector2D;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
@@ -16,16 +17,30 @@ public class AffineTransform2DTest {
 
   Matrix2x2 matrix;
   Vector2D vector;
+  AffineTransform2D affineTransform2D;
 
   @BeforeEach
   public void setUp() {
     matrix = new Matrix2x2(1, 2, 3, 4);
     vector = new Vector2D(1, 2);
+    affineTransform2D = new AffineTransform2D(matrix, vector);
   }
 
   @Nested
   @DisplayName("Positive tests for AffineTransform2D")
   class methodsDoesNotThrowException {
+
+    @Test
+    @DisplayName("Record fields are set correctly")
+    void testRecordFields() {
+      Matrix2x2 matrix = new Matrix2x2(1, 2, 3, 4);
+      Vector2D vector = new Vector2D(1, 2);
+      AffineTransform2D transform = new AffineTransform2D(matrix, vector);
+
+      assertEquals(matrix, transform.matrix());
+      assertEquals(vector, transform.vector());
+    }
+
     @Test
     @DisplayName("AffineTransform2D constructor creates an instance of AffineTransform2D " +
         "without throwing an exception")
@@ -40,6 +55,18 @@ public class AffineTransform2DTest {
       }
     }
 
+    @Test
+    @DisplayName("matrix method returns the expected value without throwing an exception")
+    void matrixDoesntThrow() {
+      assertEquals(matrix, affineTransform2D.matrix());
+    }
+
+    @Test
+    @DisplayName("vector method returns the expected value without throwing an exception")
+    void vectorDoesntThrow() {
+      assertEquals(vector, affineTransform2D.vector());
+    }
+
     @Test
     @DisplayName("Transform method returns the expected value without throwing an exception")
     void evaluateAffineTransform2DTransform() {
@@ -47,6 +74,46 @@ public class AffineTransform2DTest {
       assertEquals(6, result.getX0());
       assertEquals(13, result.getX1());
     }
+
+    @Test
+    @DisplayName("gameType method returns the expected value without throwing an exception")
+    void gameTypeDoesntThrow() {
+      assertEquals(GameType.AFFINE, affineTransform2D.gameType());
+    }
+
+    @Test
+    void testToString() {
+      Matrix2x2 matrix = new Matrix2x2(1, 2, 3, 4);
+      Vector2D vector = new Vector2D(1, 2);
+      AffineTransform2D transform = new AffineTransform2D(matrix, vector);
+
+      String expected = "AffineTransform2D[matrix=" + matrix + ", vector=" + vector + "]";
+      assertEquals(expected, transform.toString());
+    }
+
+  }
+
+  @Nested
+  @DisplayName("Negative tests for AffineTransform2D")
+  class methodsThrowsExceptions {
+
+    @Test
+    @DisplayName("AffineTransform2D constructor throws an exception when matrix is null")
+    void affineTransform2DThrowsOnNullMatrix() {
+      assertThrows(IllegalArgumentException.class, () -> new AffineTransform2D(null, vector));
+    }
+
+    @Test
+    @DisplayName("AffineTransform2D constructor throws an exception when vector is null")
+    void affineTransform2DThrowsOnNullVector() {
+      assertThrows(IllegalArgumentException.class, () -> new AffineTransform2D(matrix, null));
+    }
+
+    @Test
+    @DisplayName("transform method throws an exception when vector is null")
+    void transformThrowsOnNullVector() {
+      assertThrows(IllegalArgumentException.class, () -> affineTransform2D.transform(null));
+    }
   }
 
 }
\ No newline at end of file
diff --git a/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/transformation/JuliaTransformTest.java b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/transformation/JuliaTransformTest.java
index 91fdc6d4c0bea3c110a790ef17007175aa3a1ac4..8f37c6d6e6854c67c2b8e1916de4bbf8afcb5257 100644
--- a/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/transformation/JuliaTransformTest.java
+++ b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/transformation/JuliaTransformTest.java
@@ -1,8 +1,10 @@
 package edu.ntnu.idatt2003.group6.models.transformation;
 
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.fail;
 
-import edu.ntnu.idatt2003.group6.models.transformation.JuliaTransform;
+import edu.ntnu.idatt2003.group6.models.chaosgame.GameType;
 import edu.ntnu.idatt2003.group6.models.vector.Complex;
 import edu.ntnu.idatt2003.group6.models.vector.Vector2D;
 import org.junit.jupiter.api.BeforeEach;
@@ -16,13 +18,13 @@ public class JuliaTransformTest {
   int complexInt;
 
   @BeforeEach
-    public void setUp() {
-        complex = new Complex(1, 2);
-        complexInt = 1;
-    }
+  public void setUp() {
+    complex = new Complex(1, 2);
+    complexInt = 1;
+  }
 
-    @Nested
-    @DisplayName("Positive tests for JuliaTransform")
+  @Nested
+  @DisplayName("Positive tests for JuliaTransform")
   public class methodsDoesNotThrowException {
     @Test
     @DisplayName("JuliaTransform constructor creates an instance of JuliaTransform " +
@@ -36,15 +38,16 @@ public class JuliaTransformTest {
             "message " + e.getMessage());
       }
     }
+
     @Test
-      @DisplayName("Transform method returns the expected value without throwing an exception")
-        void evaluateJuliaTransformTransform() {
-            JuliaTransform juliaTransform = new JuliaTransform(complex, complexInt);
-            Vector2D result = new Vector2D(1, 1);
-            juliaTransform.transform(result);
-            assertEquals(1, result.getX0());
-            assertEquals(1, result.getX1());
-        }
+    @DisplayName("Transform method returns the expected value without throwing an exception")
+    void evaluateJuliaTransformTransform() {
+      JuliaTransform juliaTransform = new JuliaTransform(complex, complexInt);
+      Vector2D result = new Vector2D(1, 1);
+      juliaTransform.transform(result);
+      assertEquals(1, result.getX0());
+      assertEquals(1, result.getX1());
+    }
 
     @Test
     @DisplayName("Transform method returns the expected value without throwing an exception")
@@ -56,5 +59,34 @@ public class JuliaTransformTest {
       assertEquals(1, result.getX1());
     }
 
+    @Test
+    @DisplayName("GetPoint method returns the expected value without throwing an exception")
+    void evaluateJuliaTransformGetPoint() {
+      JuliaTransform juliaTransform = new JuliaTransform(complex, complexInt);
+      assertEquals(complex, juliaTransform.getPoint());
+    }
+
+    @Test
+    @DisplayName("GameType method returns the expected value without throwing an exception")
+    void evaluateJuliaTransformGameType() {
+      JuliaTransform juliaTransform = new JuliaTransform(complex, complexInt);
+      assertEquals(GameType.JULIA, juliaTransform.gameType());
+    }
+
+  }
+
+  @Nested
+  @DisplayName("Negative tests for JuliaTransform")
+  public class methodsThrowException {
+    @Test
+    @DisplayName("JuliaTransform constructor throws an exception when the sign is not +-1")
+    void juliaTransformThrowsOnInvalidSign() {
+      try {
+        new JuliaTransform(complex, 0);
+        fail("The test juliaTransformThrowsOnInvalidSign failed");
+      } catch (IllegalArgumentException e) {
+        assertEquals("The sign must be either 1 or -1.", e.getMessage());
+      }
+    }
   }
 }
\ No newline at end of file
diff --git a/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/vector/ComplexTest.java b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/vector/ComplexTest.java
index d7babbf21113d891c573b43ed4ec5a136b01d590..512c3775c1e69c09a42ad9252c72e2ba053fa45e 100644
--- a/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/vector/ComplexTest.java
+++ b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/vector/ComplexTest.java
@@ -36,7 +36,7 @@ public class ComplexTest {
     public void testComplexSqrt() {
       Complex result = complex.sqrt();
       assertEquals(1.272019649514069, result.getX0());
-      assertEquals(-0.7861513777574233, result.getX1());
+      assertEquals(0.7861513777574233, result.getX1());
     }
   }
 }
\ No newline at end of file
diff --git a/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/vector/Vector2DTest.java b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/vector/Vector2DTest.java
index 5eb9dcb15324430c5c0e708b4b22340ce870f330..7ea89a5410d1504663203047d344dab8ad281986 100644
--- a/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/vector/Vector2DTest.java
+++ b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/models/vector/Vector2DTest.java
@@ -4,7 +4,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.fail;
 
-import edu.ntnu.idatt2003.group6.models.vector.Vector2D;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.DisplayName;
 import org.junit.jupiter.api.Nested;
@@ -76,27 +75,14 @@ public class Vector2DTest {
   @Nested
   @DisplayName("Negative tests for Vector2D")
   class methodsThrowsException {
-    @Test
-    @DisplayName("Constructor throws an exception when given invalid input")
-    void Vector2DThrowsOnInvalidInput() {
-      try {
-        new Vector2D(Double.NaN, 2);
-        fail("The test Vector2DThrowsOnInvalidInput failed");
-      } catch (IllegalArgumentException e) {
-        assertEquals("The string for the parameter x0 was not valid, " +
-            "try to register again", e.getMessage());
-      }
-    }
-
     @Test
     @DisplayName("Add method throws an exception when given invalid input")
     void Vector2DAddThrowsOnInvalidInput() {
       try {
-        vector.add(new Vector2D(Double.NaN, 2));
+        vector.add(null);
         fail("The test Vector2DAddThrowsOnInvalidInput failed");
       } catch (IllegalArgumentException e) {
-        assertEquals("The string for the parameter x0 was not valid, " +
-                "try to register again",
+        assertEquals("The vector can not be null",
             e.getMessage());
       }
     }
@@ -105,11 +91,10 @@ public class Vector2DTest {
     @DisplayName("Subtract method throws an exception when given invalid input")
     void Vector2DSubtractThrowsOnInvalidInput() {
       try {
-        vector.subtract(new Vector2D(Double.NaN, 2));
+        vector.subtract(null);
         fail("The test Vector2DSubtractThrowsOnInvalidInput failed");
       } catch (IllegalArgumentException e) {
-        assertEquals("The string for the parameter x0 was not valid, " +
-                "try to register again",
+        assertEquals("The vector can not be null",
             e.getMessage());
       }
     }
diff --git a/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/utils/ChaosGameFileHandlerTest.java b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/utils/ChaosGameFileHandlerTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..857062a3b3c883e98d682f2f93a5bc9c21b4a830
--- /dev/null
+++ b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/utils/ChaosGameFileHandlerTest.java
@@ -0,0 +1,194 @@
+package edu.ntnu.idatt2003.group6.utils;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import edu.ntnu.idatt2003.group6.models.chaosgame.ChaosGameDescription;
+import edu.ntnu.idatt2003.group6.models.chaosgame.ChaosGameDescriptionFactory;
+import edu.ntnu.idatt2003.group6.models.chaosgame.GameType;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+class ChaosGameFileHandlerTest {
+  private ChaosGameDescription chaosGameDescriptionAffine;
+  private ChaosGameDescription chaosGameDescriptionJulia;
+  private String fileName;
+
+  @BeforeEach
+  void setUp() {
+    chaosGameDescriptionAffine =
+        ChaosGameDescriptionFactory.createChaosGameDescription(GameType.SIERPINSKI);
+    chaosGameDescriptionJulia =
+        ChaosGameDescriptionFactory.createChaosGameDescription(GameType.JULIA);
+    fileName = "testFile";
+  }
+
+  @Nested
+  @DisplayName("Positive tests for ChaosGameFileHandler")
+  class methodsDoesNotThrowException {
+
+    @Test
+    @DisplayName("writeChaosGameDescriptionToFile method writes to file without throwing an exception")
+    void writeChaosGameDescriptionAffineToFileDoesntThrow() {
+      assertDoesNotThrow(() -> ChaosGameFileHandler.writeChaosGameDescriptionToFile(
+          fileName, chaosGameDescriptionAffine));
+    }
+
+    @Test
+    @DisplayName("readChaosGameDescriptionFromFile method reads from file without throwing an exception")
+    void readChaosGameDescriptionAffineFromFileDoesntThrow() {
+      assertDoesNotThrow(() -> ChaosGameFileHandler.readChaosGameDescriptionFromFile(fileName));
+    }
+
+    @Test
+    @DisplayName("writeChaosGameDescriptionToFile method writes a ChaosGameDescriptionJulia to file without throwing an exception")
+    void writeChaosGameDescriptionJuliaToFileDoesntThrow() {
+      assertDoesNotThrow(() -> ChaosGameFileHandler.writeChaosGameDescriptionToFile(fileName,
+          chaosGameDescriptionJulia));
+    }
+
+    @Test
+    @DisplayName("readChaosGameDescriptionFromFile method reads a ChaosGameDescriptionJulia from file without throwing an exception")
+    void readChaosGameDescriptionJuliaFromFileDoesntThrow() {
+      ChaosGameFileHandler.writeChaosGameDescriptionToFile(fileName, chaosGameDescriptionJulia);
+      assertDoesNotThrow(() -> ChaosGameFileHandler.readChaosGameDescriptionFromFile(fileName));
+    }
+
+    @Test
+    @DisplayName("readChaosGameDescriptionFromFile method reads a ChaosGameDescriptionJulia from file correctly")
+    void readChaosGameDescriptionFromFileCorrectly() {
+      ChaosGameFileHandler.writeChaosGameDescriptionToFile(fileName, chaosGameDescriptionJulia);
+      ChaosGameDescription readChaosGameDescriptionJulia =
+          ChaosGameFileHandler.readChaosGameDescriptionFromFile(fileName);
+      assertEquals(chaosGameDescriptionJulia.getTransformations().getFirst().gameType(),
+          readChaosGameDescriptionJulia.getTransformations().getFirst().gameType());
+      assertEquals(chaosGameDescriptionJulia.getMinCoords().getX0(),
+          readChaosGameDescriptionJulia.getMinCoords().getX0());
+      assertEquals(chaosGameDescriptionJulia.getMinCoords().getX1(),
+          readChaosGameDescriptionJulia.getMinCoords().getX1());
+      assertEquals(chaosGameDescriptionJulia.getMaxCoords().getX0(),
+          readChaosGameDescriptionJulia.getMaxCoords().getX0());
+      assertEquals(chaosGameDescriptionJulia.getMaxCoords().getX1(),
+          readChaosGameDescriptionJulia.getMaxCoords().getX1());
+      assertEquals(GameType.JULIA, readChaosGameDescriptionJulia.getGameType());
+    }
+
+    @Test
+    @DisplayName("showFiles method shows files without throwing an exception")
+    void showFilesDoesntThrow() {
+      assertDoesNotThrow(() -> ChaosGameFileHandler.showFiles("."));
+    }
+
+    @Test
+    @DisplayName("numberOfFiles method counts files without throwing an exception")
+    void numberOfFilesDoesntThrow() {
+      assertDoesNotThrow(() -> ChaosGameFileHandler.numberOfFiles("."));
+    }
+
+    @Test
+    @DisplayName("deleteFile method deletes file without throwing an exception")
+    void deleteFileDoesntThrow() {
+      assertDoesNotThrow(() -> ChaosGameFileHandler.deleteFile(fileName));
+    }
+  }
+
+  @Nested
+  @DisplayName("Negative tests for ChaosGameFileHandler")
+  class methodsThrowsExceptions {
+
+    @Test
+    @DisplayName("writeChaosGameDescriptionToFile method throws an exception when fileName is null")
+    void writeChaosGameDescriptionToFileThrowsOnNullFileName() {
+      assertThrows(RuntimeException.class,
+          () -> ChaosGameFileHandler.writeChaosGameDescriptionToFile(
+              null, chaosGameDescriptionAffine));
+    }
+
+    @Test
+    @DisplayName("writeChaosGameDescriptionToFile method throws an exception when chaosGameDescription is null")
+    void writeChaosGameDescriptionToFileThrowsOnNullChaosGameDescription() {
+      assertThrows(RuntimeException.class,
+          () -> ChaosGameFileHandler.writeChaosGameDescriptionToFile(
+              fileName, null));
+    }
+
+    @Test
+    @DisplayName("readChaosGameDescriptionFromFile method throws an exception when fileName is null")
+    void readChaosGameDescriptionFromFileThrowsOnNullFileName() {
+      assertThrows(RuntimeException.class,
+          () -> ChaosGameFileHandler.readChaosGameDescriptionFromFile(null));
+    }
+
+    @Test
+    @DisplayName("showFiles method throws an exception when directoryPath is null")
+    void showFilesThrowsOnNullDirectoryPath() {
+      assertThrows(RuntimeException.class, () -> ChaosGameFileHandler.showFiles(null));
+    }
+
+    @Test
+    @DisplayName("numberOfFiles method throws an exception when directoryPath is null")
+    void numberOfFilesThrowsOnNullDirectoryPath() {
+      assertThrows(RuntimeException.class, () -> ChaosGameFileHandler.numberOfFiles(null));
+    }
+
+    @Test
+    @DisplayName("deleteFile method throws an exception when path is null")
+    void deleteFileThrowsOnNullPath() {
+      assertThrows(RuntimeException.class, () -> ChaosGameFileHandler.deleteFile(null));
+    }
+
+    @TempDir
+    Path tempDir;
+
+    @Test
+    void testReadFromFileIOException() {
+      assertThrows(RuntimeException.class,
+          () -> ChaosGameFileHandler.readFromFile(null));
+    }
+
+    @Test
+    void testWriteToFileExtraIOException() {
+      assertThrows(RuntimeException.class,
+          () -> ChaosGameFileHandler.writeToFileExtra(null, "content"));
+    }
+
+    @Test
+    void testWriteToFileIOException() {
+      assertThrows(RuntimeException.class,
+          () -> ChaosGameFileHandler.writeToFile(null, "content"));
+    }
+
+    @Test
+    void testShowFilesIOException() {
+      assertThrows(RuntimeException.class,
+          () -> ChaosGameFileHandler.showFiles("nonexistentdirectory"));
+    }
+
+    @Test
+    void testNumberOfFilesIOException() {
+      assertThrows(RuntimeException.class,
+          () -> ChaosGameFileHandler.numberOfFiles("nonexistentdirectory"));
+    }
+
+    @Test
+    void testDeleteFileIOException() {
+      assertThrows(RuntimeException.class,
+          () -> ChaosGameFileHandler.deleteFile(null));
+    }
+
+    @Test
+    void testDeleteFileSuccess() throws IOException {
+      Path file = Files.createFile(tempDir.resolve("testfile.txt"));
+      assertDoesNotThrow(() -> ChaosGameFileHandler.deleteFile(file.toString()));
+      assertFalse(Files.exists(file));
+    }
+  }
+}
\ No newline at end of file
diff --git a/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/utils/UtilsTest.java b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/utils/UtilsTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..7b329be9279e5be15f2a1115dd5d68937418bfc7
--- /dev/null
+++ b/ChaosGame/src/test/java/edu/ntnu/idatt2003/group6/utils/UtilsTest.java
@@ -0,0 +1,82 @@
+package edu.ntnu.idatt2003.group6.utils;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Nested;
+import org.junit.jupiter.api.Test;
+
+class UtilsTest {
+
+  @Nested
+  @DisplayName("Positive tests for Utils")
+  class utilsDoesNotThrowException {
+
+    @Test
+    @DisplayName("verifyInt method does not throw an exception when given a positive integer")
+    void verifyIntDoesNotThrowOnPositiveInt() {
+      assertDoesNotThrow(() -> Utils.verifyInt(1, "test"));
+    }
+
+    @Test
+    @DisplayName("verifyInt method does not throw an exception when given a negative integer")
+    void verifyIntDoesNotThrowOnNegativeInt() {
+      assertDoesNotThrow(() -> Utils.verifyInt(-1, "test"));
+    }
+
+    @Test
+    @DisplayName("verifyInt method throws an exception when given 0")
+    void verifyIntThrowsOnZero() {
+      assertThrows(IllegalArgumentException.class, () -> Utils.verifyInt(0, "test"));
+    }
+
+    @Test
+    @DisplayName("inputStringToInt method returns the expected value without throwing an exception")
+    void inputStringToIntReturnsExpectedValue() {
+      assertEquals(10, Utils.inputStringToInt("10"));
+    }
+
+    @Test
+    @DisplayName("inputStringToInt method throws an exception when given a non-integer string")
+    void inputStringToIntThrowsOnNonIntegerString() {
+      assertThrows(IllegalArgumentException.class, () -> Utils.inputStringToInt("test"));
+    }
+
+    @Test
+    @DisplayName("inputStringToDouble method returns the expected value without throwing an exception")
+    void inputStringToDoubleReturnsExpectedValue() {
+      assertEquals(10.5, Utils.inputStringToDouble("10.5"));
+    }
+
+    @Test
+    @DisplayName("inputStringToDouble method throws an exception when given a non-double string")
+    void inputStringToDoubleThrowsOnNonDoubleString() {
+      assertThrows(IllegalArgumentException.class, () -> Utils.inputStringToDouble("test"));
+    }
+  }
+
+  @Nested
+  @DisplayName("Negative tests for Utils")
+  class utilsThrowsException {
+
+    @Test
+    @DisplayName("verifyInt method throws an exception when given a null string")
+    void verifyIntThrowsOnNullString() {
+      assertThrows(IllegalArgumentException.class, () -> Utils.verifyInt(0, "test"));
+    }
+
+    @Test
+    @DisplayName("inputStringToInt method throws an exception when given a null string")
+    void inputStringToIntThrowsOnNullString() {
+      assertThrows(IllegalArgumentException.class, () -> Utils.inputStringToInt(null));
+    }
+
+    @Test
+    @DisplayName("inputStringToDouble method throws an exception when given a null string")
+    void inputStringToDoubleThrowsOnNullString() {
+      assertThrows(IllegalArgumentException.class, () -> Utils.inputStringToDouble(null));
+    }
+  }
+}
\ No newline at end of file