diff --git a/src/main/java/org/example/chaosgame/MainApp.java b/src/main/java/org/example/chaosgame/MainApp.java
index 20aa139361ea37500a14d55484af4cda2bd8e583..91e6367280a7385c54c81832968e74c2e347d4e8 100644
--- a/src/main/java/org/example/chaosgame/MainApp.java
+++ b/src/main/java/org/example/chaosgame/MainApp.java
@@ -6,10 +6,7 @@ import javafx.scene.control.Button;
 import javafx.scene.layout.BorderPane;
 import javafx.scene.layout.HBox;
 import javafx.stage.Stage;
-import org.example.chaosgame.controller.MainController;
-import org.example.chaosgame.model.chaos.ChaosGame;
 import org.example.chaosgame.model.chaos.ChaosGameDescription;
-import org.example.chaosgame.model.chaos.ChaosGameDescriptionFactory;
 import org.example.chaosgame.model.chaos.ChaosGameFileHandler;
 import org.example.chaosgame.view.ChaosPage;
 import org.example.chaosgame.view.ExplorePage;
diff --git a/src/main/java/org/example/chaosgame/controller/MainController.java b/src/main/java/org/example/chaosgame/controller/ChaosGameController.java
similarity index 55%
rename from src/main/java/org/example/chaosgame/controller/MainController.java
rename to src/main/java/org/example/chaosgame/controller/ChaosGameController.java
index fe97afa8003b8bfe103da46b29dd8e84e26a189d..e47d5e13030dddd4b1030db77b4440a072ba1fb6 100644
--- a/src/main/java/org/example/chaosgame/controller/MainController.java
+++ b/src/main/java/org/example/chaosgame/controller/ChaosGameController.java
@@ -1,22 +1,23 @@
 package org.example.chaosgame.controller;
 
-import javafx.scene.layout.StackPane;
 import org.example.chaosgame.model.chaos.ChaosGame;
 import org.example.chaosgame.view.ChaosPage;
 
-public class MainController implements Observer{
+public class ChaosGameController implements Observer{
   private final ChaosGame chaosGame;
-  private final ChaosPage chaosPage;
+//  private final ChaosPage chaosPage;
 
 
-  public MainController(ChaosGame chaosGame) {
+
+
+  public ChaosGameController(ChaosGame chaosGame) {
     this.chaosGame = chaosGame;
-    this.chaosPage = new ChaosPage();
     chaosGame.registerObserver(this);
   }
 
   @Override
   public void update() {
-    chaosPage.updateCanvas();
+//    chaosPage.updateCanvas();
+    System.out.println("ChaosGameController.update");
   }
 }
diff --git a/src/main/java/org/example/chaosgame/controller/ChaosGameSubject.java b/src/main/java/org/example/chaosgame/controller/Subject.java
similarity index 81%
rename from src/main/java/org/example/chaosgame/controller/ChaosGameSubject.java
rename to src/main/java/org/example/chaosgame/controller/Subject.java
index 36dd8621aa6f29fd57d63cb449a8be2e7b8af86d..79bd695fb2aefa71f338b147ce255ce8be548985 100644
--- a/src/main/java/org/example/chaosgame/controller/ChaosGameSubject.java
+++ b/src/main/java/org/example/chaosgame/controller/Subject.java
@@ -1,6 +1,6 @@
 package org.example.chaosgame.controller;
 
-public interface ChaosGameSubject {
+public interface Subject {
   void registerObserver(Observer observer);
   void removeObserver(Observer observer);
   void notifyObservers();
diff --git a/src/main/java/org/example/chaosgame/model/chaos/ChaosGame.java b/src/main/java/org/example/chaosgame/model/chaos/ChaosGame.java
index 88ec0ecbffc6eadb086322dcbfb0d982502bc35e..19101023bdabacdb662f49c42459a9dc025ba611 100644
--- a/src/main/java/org/example/chaosgame/model/chaos/ChaosGame.java
+++ b/src/main/java/org/example/chaosgame/model/chaos/ChaosGame.java
@@ -4,7 +4,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Random;
 
-import org.example.chaosgame.controller.ChaosGameSubject;
+import org.example.chaosgame.controller.Subject;
 import org.example.chaosgame.controller.Observer;
 import org.example.chaosgame.model.linalg.Vector2D;
 
@@ -17,7 +17,7 @@ import org.example.chaosgame.model.linalg.Vector2D;
  * The new point is then drawn on the canvas.
  * This process is repeated a selected amount of steps.
  */
-public class ChaosGame implements ChaosGameSubject {
+public class ChaosGame implements Subject {
   private final ChaosCanvas canvas;
 
   private final ChaosGameDescription description;
diff --git a/src/main/java/org/example/chaosgame/model/chaos/ChaosGameDescription.java b/src/main/java/org/example/chaosgame/model/chaos/ChaosGameDescription.java
index ca773de82ee80d0c4e3a3ec3bffcbf7c0da89381..107dd439fea917d3f43903891a8b95a516cf3e5c 100644
--- a/src/main/java/org/example/chaosgame/model/chaos/ChaosGameDescription.java
+++ b/src/main/java/org/example/chaosgame/model/chaos/ChaosGameDescription.java
@@ -11,8 +11,8 @@ import org.example.chaosgame.model.transformations.Transform2D;
  * and a list of transformations to apply to the points.
  */
 public class ChaosGameDescription {
-  private final Vector2D minCoords;
-  private final Vector2D maxCoords;
+  private Vector2D minCoords;
+  private Vector2D maxCoords;
   private final List<Transform2D> transforms;
 
   private final List<Integer> probabilities;
@@ -50,6 +50,13 @@ public class ChaosGameDescription {
     return maxCoords;
   }
 
+  public void setMinCoords(Vector2D minCoords) {
+    this.minCoords = minCoords;
+  }
+  public void setMaxCoords(Vector2D maxCoords) {
+    this.maxCoords = maxCoords;
+  }
+
   public List<Transform2D> getTransforms() {
     return transforms;
   }
diff --git a/src/main/java/org/example/chaosgame/model/chaos/ExploreGame.java b/src/main/java/org/example/chaosgame/model/chaos/ExploreGame.java
index b0d356ac0b8de24f28c2a2f3ce69c7df893a3e26..1803a8012e248a74ec3dd02aecafbfd558ef1462 100644
--- a/src/main/java/org/example/chaosgame/model/chaos/ExploreGame.java
+++ b/src/main/java/org/example/chaosgame/model/chaos/ExploreGame.java
@@ -53,23 +53,7 @@ public class ExploreGame{
 
       }
     });
-//    for (int y = 0; y < canvas.getHeight(); y++) {
-//      for (int x = 0; x < canvas.getWidth(); x++) {
-//        int iter = 0;
-//        currentPoint = canvas.transformIndicesToCoords(x, y);
-//        Vector2D tempPoint = currentPoint;
-//        while (iter < MAX_ITER && tempPoint.lengthSQ() < 4){
-//          tempPoint = description.getTransforms().getFirst().transform(tempPoint);
-//          iter++;
-//        }
-//        double abs = Math.sqrt(tempPoint.lengthSQ());
-//        double smooth = iter - Math.log(Math.log(abs)) / Math.log(2);
-//
-//        canvas.putPixel(x, y, smooth);
-//
-//      }
-//
-//    }
+
     long end = System.currentTimeMillis();
     System.out.println("Time taken: " + (end - start) + "ms");
   }
diff --git a/src/main/java/org/example/chaosgame/view/ChaosPage.java b/src/main/java/org/example/chaosgame/view/ChaosPage.java
index 658dfd3e14c814da3219d96fffa31a48f7127172..3fdcf472af1274e02635c4aed526c2e2fef23ee7 100644
--- a/src/main/java/org/example/chaosgame/view/ChaosPage.java
+++ b/src/main/java/org/example/chaosgame/view/ChaosPage.java
@@ -12,28 +12,34 @@ import javafx.scene.input.MouseEvent;
 import javafx.scene.layout.StackPane;
 import javafx.scene.layout.VBox;
 import javafx.scene.paint.Color;
-import org.example.chaosgame.model.chaos.ChaosCanvas;
-import org.example.chaosgame.model.chaos.ChaosGame;
-import org.example.chaosgame.model.chaos.ChaosGameDescriptionFactory;
+import org.example.chaosgame.controller.ChaosGameController;
+import org.example.chaosgame.model.chaos.*;
 import org.example.chaosgame.model.linalg.Complex;
+import java.io.File;
+import java.io.IOException;
+import javafx.stage.FileChooser;
+import java.io.BufferedReader;
+import java.io.FileReader;
 
 public class ChaosPage {
+  ChaosGameController chaosGameController;
   private final StackPane chaosContent;
   private ChaosGame chaosGame;
   private ChaosCanvas chaosCanvas;
   private Complex c = new Complex(-0.70176, -0.3842);
   private final Button runStepsButton = new Button("Run Steps");
-  private final Canvas canvas;
-  private final GraphicsContext gc;
+  private final Canvas canvas = new Canvas(1200, 800);
+  private final GraphicsContext gc ;
   private final Label errorLabel = new Label("Invalid input. Please enter a valid number.");
   private final VBox runStepsBox = new VBox();
 
   public ChaosPage() {
+
     chaosContent = new StackPane();
+    gc = canvas.getGraphicsContext2D();
     updateChaosGame("Julia");
     chaosCanvas = chaosGame.getCanvas();
-    canvas = new Canvas(chaosCanvas.getWidth(), chaosCanvas.getHeight());
-    gc = canvas.getGraphicsContext2D();
+
 
 
     TextField stepsField = new TextField();
@@ -54,9 +60,9 @@ public class ChaosPage {
       } else {
         updateChaosGame(selectedGame);
       }
-      gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
       updateCanvas();
     });
+
     runStepsButton.setOnAction(e5 -> {
               if (!stepsField.getText().isEmpty()) {
                 try {
@@ -71,7 +77,25 @@ public class ChaosPage {
               }
             });
 
-    runStepsBox.getChildren().addAll(contextMenu,stepsField, runStepsButton);
+
+Button openFileButton = new Button("Open File");
+openFileButton.setOnAction(e -> {
+    FileChooser fileChooser = new FileChooser();
+    fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("TXT files (*.txt)", "*.txt"));
+    File selectedFile = fileChooser.showOpenDialog(null);
+
+    if (selectedFile != null) {
+        try {
+          ChaosGameFileHandler fileHandler = new ChaosGameFileHandler();
+          ChaosGameDescription description = fileHandler.readFromFile(selectedFile.getAbsolutePath());
+          updateChaosGame(description);
+        } catch (IOException ex) {
+            ex.printStackTrace();
+        }
+    }
+});
+
+    runStepsBox.getChildren().addAll(contextMenu,stepsField, runStepsButton, openFileButton);
     runStepsBox.setSpacing(10);
     runStepsBox.setPadding(new Insets(10));
     runStepsBox.setAlignment(Pos.CENTER_RIGHT);
@@ -113,6 +137,14 @@ public class ChaosPage {
 
   private void updateChaosGame(String chaosGameType) {
     chaosGame = new ChaosGame(ChaosGameDescriptionFactory.get(chaosGameType, c), 1200, 800);
+    chaosGameController = new ChaosGameController(chaosGame);
+    chaosCanvas = chaosGame.getCanvas();
+    gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
+  }
+  private void updateChaosGame(ChaosGameDescription description){
+    chaosGame = new ChaosGame(description, 1200, 800);
+    chaosGameController = new ChaosGameController(chaosGame);
     chaosCanvas = chaosGame.getCanvas();
+    gc.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
   }
 }
diff --git a/src/main/java/org/example/chaosgame/view/ExplorePage.java b/src/main/java/org/example/chaosgame/view/ExplorePage.java
index e5483593a439f0af5e165e2955439a4baa2ce20f..3aae4b46684b97979d13b53dc3f527c5f80554ee 100644
--- a/src/main/java/org/example/chaosgame/view/ExplorePage.java
+++ b/src/main/java/org/example/chaosgame/view/ExplorePage.java
@@ -1,5 +1,7 @@
 package org.example.chaosgame.view;
 
+import javafx.animation.AnimationTimer;
+import javafx.application.Platform;
 import javafx.geometry.Pos;
 import javafx.scene.canvas.Canvas;
 import javafx.scene.canvas.GraphicsContext;
@@ -27,6 +29,9 @@ public class ExplorePage {
   private Complex c = new Complex(-0.835, 0.2321);
   private final Canvas canvas;
   private final GraphicsContext gc;
+  private Vector2D dragStart;
+  private Vector2D dragStartTemp;
+
   private final List<Transform2D> trans = List.of(
                   new ExploreJulia(c)
           );
@@ -42,6 +47,7 @@ public class ExplorePage {
 
   private WritableImage offScreenImage;
   private PixelWriter pixelWriter;
+  private Vector2D dragDistance;
 
 
   public ExplorePage() {
@@ -71,27 +77,55 @@ public class ExplorePage {
 
 
     zoomInButton.setOnMousePressed(event -> {
-      double scaleFactor = 1.05;
-      Vector2D newMinCoords = description.getMinCoords().scale(1 / scaleFactor);
-      Vector2D newMaxCoords = description.getMaxCoords().scale(1 / scaleFactor);
-        description = new ChaosGameDescription(newMinCoords, newMaxCoords, trans);
-        exploreGame = new ExploreGame(description, 1200, 800);
-//
-        exploreGame.exploreFractals();
-        updateCanvas();
+      AnimationTimer zoomInTimer = new AnimationTimer() {
+        @Override
+        public void handle(long now) {
+          double scaleFactor = 1.05;
+          Vector2D canvasCenter = new Vector2D(canvas.getWidth() / 2, canvas.getHeight() / 2);
+          Vector2D fractalCenter = chaosCanvas.transformIndicesToCoords((int)canvasCenter.getX(), (int)canvasCenter.getY());
+          Vector2D newMinCoords = fractalCenter.subtract(fractalCenter.subtract(description.getMinCoords()).scale(1 / scaleFactor));
+          Vector2D newMaxCoords = fractalCenter.add(description.getMaxCoords().subtract(fractalCenter).scale(1 / scaleFactor));
+          description = new ChaosGameDescription(newMinCoords, newMaxCoords, trans);
+          exploreGame = new ExploreGame(description, 1200, 800);
+          exploreGame.exploreFractals();
+          updateCanvas();
+        }
+      };
+      zoomInTimer.start();
+      zoomInButton.setUserData(zoomInTimer); // Store the timer in the button's user data
+    });
 
+    zoomInButton.setOnMouseReleased(event -> {
+      AnimationTimer zoomInTimer = (AnimationTimer) zoomInButton.getUserData();
+      if (zoomInTimer != null) {
+        zoomInTimer.stop();
+      }
     });
 
-    zoomOutButton.setOnAction(event -> {
-      double scaleFactor = 1 / 1.05;
-      Vector2D newMinCoords = description.getMinCoords().scale(1 / scaleFactor);
-      Vector2D newMaxCoords = description.getMaxCoords().scale(1 / scaleFactor);
+    zoomOutButton.setOnMousePressed(event -> {
+      AnimationTimer zoomOutTimer = new AnimationTimer() {
+        @Override
+        public void handle(long now) {
+          double scaleFactor = 1.0 / 1.05;
+          Vector2D canvasCenter = new Vector2D(canvas.getWidth() / 2, canvas.getHeight() / 2);
+          Vector2D fractalCenter = chaosCanvas.transformIndicesToCoords((int)canvasCenter.getX(), (int)canvasCenter.getY());
+          Vector2D newMinCoords = fractalCenter.subtract(fractalCenter.subtract(description.getMinCoords()).scale(1 / scaleFactor));
+          Vector2D newMaxCoords = fractalCenter.add(description.getMaxCoords().subtract(fractalCenter).scale(1 / scaleFactor));
           description = new ChaosGameDescription(newMinCoords, newMaxCoords, trans);
           exploreGame = new ExploreGame(description, 1200, 800);
-//          chaosCanvas = exploreGame.getCanvas();
           exploreGame.exploreFractals();
           updateCanvas();
+        }
+      };
+      zoomOutTimer.start();
+      zoomOutButton.setUserData(zoomOutTimer); // Store the timer in the button's user data
+    });
 
+    zoomOutButton.setOnMouseReleased(event -> {
+      AnimationTimer zoomOutTimer = (AnimationTimer) zoomOutButton.getUserData();
+      if (zoomOutTimer != null) {
+        zoomOutTimer.stop();
+      }
     });
 
 
@@ -102,35 +136,94 @@ public class ExplorePage {
 
     exploreContent.getChildren().addAll(canvas, buttons);
 
+    Platform.runLater(() -> {
+      buttons.setLayoutX(canvas.getWidth() - buttons.getWidth());
+      buttons.setLayoutY(0);
+    });
+
     exploreContent.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> {
       try {
+        dragStart = new Vector2D(event.getX(), event.getY());
+
         double mouseX = event.getX() - canvas.getLayoutX();
         double mouseY = event.getY() - canvas.getLayoutY();
-        initialMousePosition = new Vector2D(mouseX, canvas.getHeight() - mouseY);
+        dragStartTemp = new Vector2D(mouseX, canvas.getHeight() - mouseY);
+//        initialMousePosition = new Vector2D(mouseX, canvas.getHeight() - mouseY);
       } catch (Exception e) {
         e.printStackTrace();
     }
 });
 
 exploreContent.addEventFilter(MouseEvent.MOUSE_DRAGGED, event -> {
-    Vector2D currentMousePosition = new Vector2D(event.getX(),canvas.getHeight() - event.getY());
-    Vector2D dragDistance = currentMousePosition.subtract(initialMousePosition);
+//    Vector2D currentMousePosition = new Vector2D(event.getX(),canvas.getHeight() - event.getY());
+//    Vector2D dragDistance = currentMousePosition.subtract(initialMousePosition);
+//
+//    // Adjust the drag distance based on the zoom level
+//// Convert the drag distance from canvas coordinates to fractal coordinates
+//  Vector2D fractalRange = description.getMaxCoords().subtract(description.getMinCoords());
+//  Vector2D adjustedDragDistance = dragDistance.multiply(fractalRange).divide(new Vector2D(canvas.getWidth(), canvas.getHeight()));
+//
+//    Vector2D newMinCoords = description.getMinCoords().subtract(adjustedDragDistance);
+//    Vector2D newMaxCoords = description.getMaxCoords().subtract(adjustedDragDistance);
+//    description.setMinCoords(newMinCoords);
+//    description.setMaxCoords(newMaxCoords);
+//    exploreGame = new ExploreGame(description, 1200, 800);
+//    exploreGame.exploreFractals();
+//    updateCanvas();
+//
+//    initialMousePosition = currentMousePosition;
+
+  Vector2D dragEnd = new Vector2D(event.getX(), event.getY());
+  dragDistance = dragEnd.subtract(dragStart);
+
+  canvas.setTranslateX(canvas.getTranslateX() + dragDistance.getX());
+  canvas.setTranslateY(canvas.getTranslateY() + dragDistance.getY());
+
+  dragStart = dragEnd;
+
 
-    // Adjust the drag distance based on the zoom level
-// Convert the drag distance from canvas coordinates to fractal coordinates
-  Vector2D fractalRange = description.getMaxCoords().subtract(description.getMinCoords());
-  Vector2D adjustedDragDistance = dragDistance.multiply(fractalRange).divide(new Vector2D(canvas.getWidth(), canvas.getHeight()));
 
+
+});
+
+    exploreContent.setOnMouseReleased(event -> {
+      dragDistance = new Vector2D(event.getX(), canvas.getHeight() - event.getY()).subtract(dragStartTemp);
+//       Reset the position where the drag started
+      Vector2D fractalRange = description.getMaxCoords().subtract(description.getMinCoords());
+      System.out.println("drag distance: " + dragDistance.getX() + ", " + dragDistance.getY());
+    Vector2D adjustedDragDistance = dragDistance.multiply(fractalRange).divide(new Vector2D(canvas.getWidth(), canvas.getHeight()));
+      System.out.println("Adjusted drag distance: " + adjustedDragDistance.getX() + ", " + adjustedDragDistance.getY());
     Vector2D newMinCoords = description.getMinCoords().subtract(adjustedDragDistance);
     Vector2D newMaxCoords = description.getMaxCoords().subtract(adjustedDragDistance);
-
-    description = new ChaosGameDescription(newMinCoords, newMaxCoords, trans);
+    description.setMinCoords(newMinCoords);
+    description.setMaxCoords(newMaxCoords);
     exploreGame = new ExploreGame(description, 1200, 800);
     exploreGame.exploreFractals();
     updateCanvas();
+      System.out.println("Mouse released");
 
-    initialMousePosition = currentMousePosition;
-});
+      dragStart = null;
+      canvas.setTranslateX(0);
+      canvas.setTranslateY(0);
+    });
+
+//exploreContent.addEventFilter(MouseEvent.MOUSE_RELEASED, event -> {
+//    Vector2D currentMousePosition = new Vector2D(event.getX(), canvas.getHeight() - event.getY());
+//    Vector2D dragDistance = currentMousePosition.subtract(initialMousePosition);
+//
+//    // Adjust the drag distance based on the zoom level
+//    Vector2D fractalRange = description.getMaxCoords().subtract(description.getMinCoords());
+//    Vector2D adjustedDragDistance = dragDistance.multiply(fractalRange).divide(new Vector2D(canvas.getWidth(), canvas.getHeight()));
+//
+//    Vector2D newMinCoords = description.getMinCoords().subtract(adjustedDragDistance);
+//    Vector2D newMaxCoords = description.getMaxCoords().subtract(adjustedDragDistance);
+//
+//    description.setMinCoords(newMinCoords);
+//    description.setMaxCoords(newMaxCoords);
+//    exploreGame.setDescription(description);
+//    exploreGame.exploreFractals();
+//    updateCanvas();
+//  });
   }
 
   public StackPane getExploreContent() {
@@ -152,9 +245,10 @@ exploreContent.addEventFilter(MouseEvent.MOUSE_DRAGGED, event -> {
     for (int i = 0; i < chaosCanvas.getHeight(); i++) {
       for (int j = 0; j < chaosCanvas.getWidth(); j++) {
         double color = Math.min(canvasArray[i][j] * 3, 255);
-        if (color > 0 && color < 255) {
-          pixelWriter.setColor(j, i, Color.rgb((int) color, (int) color, (int) color));
-        }
+//        if (color >= 0 && color <= 255) {
+          pixelWriter.setColor(j, i, Color.rgb((int) color, 0, 0));
+//        }
+
       }
     }