diff --git a/tetrecs/src/main/java/uk/ac/soton/comp1206/event/ScoreUpdatedListener.java b/tetrecs/src/main/java/uk/ac/soton/comp1206/event/ScoreUpdatedListener.java
new file mode 100644
index 0000000000000000000000000000000000000000..c88cfdb38c9fd55ad276d24847e757aba98bafda
--- /dev/null
+++ b/tetrecs/src/main/java/uk/ac/soton/comp1206/event/ScoreUpdatedListener.java
@@ -0,0 +1,5 @@
+package uk.ac.soton.comp1206.event;
+
+public interface ScoreUpdatedListener {
+  void updateHighScore();
+}
diff --git a/tetrecs/src/main/java/uk/ac/soton/comp1206/game/Game.java b/tetrecs/src/main/java/uk/ac/soton/comp1206/game/Game.java
index b8751b677ec55ba14f1ac2530e3a3e9dd816a914..68ab9a82ba4991acb6089294d09ca3612531496b 100644
--- a/tetrecs/src/main/java/uk/ac/soton/comp1206/game/Game.java
+++ b/tetrecs/src/main/java/uk/ac/soton/comp1206/game/Game.java
@@ -7,10 +7,7 @@ import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import uk.ac.soton.comp1206.component.GameBlock;
 import uk.ac.soton.comp1206.component.GameBlockCoordinate;
-import uk.ac.soton.comp1206.event.GameLoopListener;
-import uk.ac.soton.comp1206.event.GameOverListener;
-import uk.ac.soton.comp1206.event.LineClearedListener;
-import uk.ac.soton.comp1206.event.NextPieceListener;
+import uk.ac.soton.comp1206.event.*;
 import uk.ac.soton.comp1206.utility.Multimedia;
 
 import java.util.*;
@@ -50,6 +47,7 @@ public class Game {
   protected LineClearedListener lineClearedListener = null;
   protected GameOverListener gameOverListener = null;
   protected GameLoopListener gameLoopListener = null;
+  protected ScoreUpdatedListener scoreUpdatedListener = null;
 
   protected Timer timer;
 
@@ -327,6 +325,10 @@ public class Game {
     this.gameLoopListener = listener;
   }
 
+  public void setScoreUpdatedListener(ScoreUpdatedListener listener) {
+    this.scoreUpdatedListener = listener;
+  }
+
   public void rotatePiece(int rotations) {
     this.currentPiece.rotate(rotations);
   }
@@ -354,6 +356,10 @@ public class Game {
   public void setScore(int score) {
     logger.info("Score is now " + score);
     this.score.set(score);
+
+    if (this.scoreUpdatedListener != null) {
+      scoreUpdatedListener.updateHighScore();
+    }
   }
 
   public void setLevel(int level) {
diff --git a/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/ChallengeScene.java b/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/ChallengeScene.java
index a0f2afa6a0041bd78a8b6798bb67bbfbe86049a1..7ebc981c6eb4f216cdc20daa67c2c76244a5f178 100644
--- a/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/ChallengeScene.java
+++ b/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/ChallengeScene.java
@@ -1,12 +1,17 @@
 package uk.ac.soton.comp1206.scene;
 
 import javafx.application.Platform;
+import javafx.beans.Observable;
+import javafx.beans.property.IntegerProperty;
+import javafx.beans.property.SimpleIntegerProperty;
+import javafx.beans.value.ObservableValue;
 import javafx.geometry.Pos;
 import javafx.scene.input.KeyCode;
 import javafx.scene.input.KeyEvent;
 import javafx.scene.layout.*;
 import javafx.scene.text.Text;
 
+import javafx.util.Pair;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
@@ -17,6 +22,7 @@ import uk.ac.soton.comp1206.ui.GamePane;
 import uk.ac.soton.comp1206.ui.GameWindow;
 import uk.ac.soton.comp1206.utility.Multimedia;
 
+import java.util.ArrayList;
 import java.util.HashSet;
 
 /**
@@ -35,6 +41,8 @@ public class ChallengeScene extends BaseScene {
   private int keyBoardPosX = 0;
   private int keyBoardPosY = 0;
 
+  private IntegerProperty hiscore = new SimpleIntegerProperty(0);
+
   /**
    * Create a new Single Player challenge scene
    *
@@ -54,9 +62,12 @@ public class ChallengeScene extends BaseScene {
     Multimedia.playBackgroundMusic("game_start.wav", false);
     Multimedia.getBackgroundPlayer().setOnEndOfMedia(() -> Multimedia.playBackgroundMusic("game.wav", true));
 
+    this.hiscore.set(getHighScore());
+
     this.game.setNextPieceListener(this::nextPiece);
     this.game.setLineClearedListener(this::lineCleared);
     this.game.setGameLoopListener(this::gameTimer);
+    this.game.setScoreUpdatedListener(this::updateHiScore);
 
     this.scene.setOnKeyPressed(this::keyHandler);
 
@@ -70,6 +81,13 @@ public class ChallengeScene extends BaseScene {
     game.start();
   }
 
+  private void updateHiScore() {
+    if (this.hiscore.get() < this.game.getScore().get()) {
+      logger.info("Updating Highscore");
+      this.hiscore.set(this.game.getScore().get());
+    }
+  }
+
   private void keyHandler(KeyEvent e) {
     this.board.setHover(this.board.getBlock(keyBoardPosX, keyBoardPosY), false);
     if (e.getCode().equals(KeyCode.ESCAPE)) {
@@ -189,7 +207,8 @@ public class ChallengeScene extends BaseScene {
     hiScoreTitle.getStyleClass().add("heading");
     gameInfo.getChildren().add(hiScoreTitle);
 
-    var hiScoreVal = new Text("10000");
+    var hiScoreVal = new Text();
+    hiScoreVal.textProperty().bind(this.hiscore.asString());
     hiScoreVal.getStyleClass().add("hiscore");
     gameInfo.getChildren().add(hiScoreVal);
 
@@ -279,6 +298,11 @@ public class ChallengeScene extends BaseScene {
     }
   }
 
+  private int getHighScore() {
+    ArrayList<Pair<String, Integer>> localScores = ScoresScene.loadScores();
+    return localScores.get(0).getValue();
+  }
+
   /**
    * Setup the game object and model
    */
diff --git a/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/MenuScene.java b/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/MenuScene.java
index cee420bb45199f12656323a30cca3f909b09d91b..cf60f59754cced920e054e8289b630f1ddee83b9 100644
--- a/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/MenuScene.java
+++ b/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/MenuScene.java
@@ -76,12 +76,7 @@ public class MenuScene extends BaseScene {
 
     Text exitLabel = new Text("Exit");
     exitLabel.getStyleClass().add("menuItem");
-    exitLabel.setOnMouseClicked(new EventHandler<MouseEvent>() {
-      @Override
-      public void handle(MouseEvent mouseEvent) {
-        App.getInstance().shutdown();
-      }
-    });
+    exitLabel.setOnMouseClicked(e -> shutDown());
     menuButtons.getChildren().add(exitLabel);
 
     menuButtons.setAlignment(Pos.CENTER);
@@ -100,7 +95,8 @@ public class MenuScene extends BaseScene {
    */
   @Override
   public void initialise() {
-    Multimedia.playBackgroundMusic("menu.mp3", true);
+    Multimedia.playBackgroundMusic("menumusic.mp3", true);
+    this.scene.setOnKeyPressed(e -> shutDown());
   }
 
   /**
@@ -116,4 +112,8 @@ public class MenuScene extends BaseScene {
     gameWindow.displayInstructions();
   }
 
+  private void shutDown() {
+    App.getInstance().shutdown();
+  }
+
 }
diff --git a/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/ScoresScene.java b/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/ScoresScene.java
index 8f0eab47b67f9a6ac84abc74e97b625420f73bb9..f3c2c357ccb516c98df76d6b1bf784ad19082841 100644
--- a/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/ScoresScene.java
+++ b/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/ScoresScene.java
@@ -1,23 +1,47 @@
 package uk.ac.soton.comp1206.scene;
 
+import javafx.application.Platform;
+import javafx.beans.property.BooleanProperty;
+import javafx.beans.property.SimpleBooleanProperty;
+import javafx.beans.property.SimpleListProperty;
+import javafx.beans.value.ObservableValue;
+import javafx.collections.FXCollections;
+import javafx.collections.ObservableList;
 import javafx.geometry.Pos;
+import javafx.scene.control.Button;
+import javafx.scene.control.TextField;
 import javafx.scene.image.ImageView;
 import javafx.scene.input.KeyCode;
-import javafx.scene.input.KeyEvent;
 import javafx.scene.layout.BorderPane;
+import javafx.scene.layout.HBox;
 import javafx.scene.layout.StackPane;
 import javafx.scene.layout.VBox;
 import javafx.scene.text.Text;
+import javafx.util.Pair;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import uk.ac.soton.comp1206.game.Game;
 import uk.ac.soton.comp1206.ui.GamePane;
 import uk.ac.soton.comp1206.ui.GameWindow;
+import uk.ac.soton.comp1206.ui.ScoresList;
 import uk.ac.soton.comp1206.utility.Multimedia;
 
+import java.io.*;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
 public class ScoresScene extends BaseScene{
   private static final Logger logger = LogManager.getLogger(ScoresScene.class);
 
+  private final Game game;
+
+  private ObservableList<Pair<String, Integer>> localScores;
+  private Pair<String, Integer> gameScore;
+
+  private VBox widgets;
+  private ScoresList localList;
+
   /**
    * Create a new scene, passing in the GameWindow the scene will be displayed in
    *
@@ -25,13 +49,15 @@ public class ScoresScene extends BaseScene{
    */
   public ScoresScene(GameWindow gameWindow, Game game) {
     super(gameWindow);
-
+    this.game = game;
     logger.info("Creating Scores Scene");
   }
 
   @Override
   public void initialise() {
-    this.scene.setOnKeyPressed(this::escapeToMenu);
+    this.scene.setOnKeyPressed(e -> {
+      if (e.getCode().equals(KeyCode.ESCAPE)) escapeToMenu();
+    });
     Multimedia.playSound("explode.wav");
     Multimedia.playBackgroundMusic("end.wav", false);
     Multimedia.getBackgroundPlayer().setOnEndOfMedia(this.gameWindow::startMenu);
@@ -43,6 +69,8 @@ public class ScoresScene extends BaseScene{
 
     root = new GamePane(gameWindow.getWidth(), gameWindow.getHeight());
 
+    this.localScores = FXCollections.observableArrayList(this.loadScores());
+
     StackPane instructionsPane = new StackPane();
     instructionsPane.setMaxWidth(gameWindow.getWidth());
     instructionsPane.setMaxHeight(gameWindow.getHeight());
@@ -52,31 +80,153 @@ public class ScoresScene extends BaseScene{
     BorderPane mainPane = new BorderPane();
     instructionsPane.getChildren().add(mainPane);
 
-    VBox widgets = new VBox();
+    widgets = new VBox();
 
     ImageView title = new ImageView(getClass().getResource("/images/TetrECS.png").toExternalForm());
     title.setPreserveRatio(true);
-    title.setFitWidth(this.gameWindow.getWidth() / 1.25);
+    title.setFitWidth(this.gameWindow.getWidth() / 1.75);
     widgets.getChildren().add(title);
 
     Text gameOver = new Text("Game Over");
     gameOver.getStyleClass().add("bigtitle");
     widgets.getChildren().add(gameOver);
 
-    Text hiScorestitle = new Text("High Scores");
-    hiScorestitle.getStyleClass().add("title");
-    widgets.getChildren().add(hiScorestitle);
+    localList = new ScoresList("Local Scores");
+
+    checkHiScore();
+
+    HBox scoreLists = new HBox();
+    widgets.getChildren().add(scoreLists);
+
+    scoreLists.getChildren().add(localList);
+
+    Text onlineScoresTitle = new Text("Online Scores");
+    onlineScoresTitle.getStyleClass().add("heading");
+    scoreLists.getChildren().add(onlineScoresTitle);
+
+    scoreLists.setAlignment(Pos.CENTER);
+    scoreLists.setSpacing(100);
 
     widgets.setAlignment(Pos.CENTER);
     widgets.setSpacing(20);
 
     mainPane.setCenter(widgets);
+
+  }
+
+  public void checkHiScore() {
+    boolean isHiScore = false;
+    int score = this.game.getScore().get();
+
+    for (Pair<String, Integer> nameScore : this.localScores) {
+      if (nameScore.getValue() < score) {
+        isHiScore = true;
+        break;
+      }
+    }
+
+    if (isHiScore) {
+      logger.info("User has got a high score");
+
+      Text hiScoreTitle = new Text("You've got a new High Score!");
+      hiScoreTitle.getStyleClass().add("title");
+      widgets.getChildren().add(hiScoreTitle);
+
+      TextField usernameEntry = new TextField();
+      usernameEntry.setPromptText("Enter username");
+      usernameEntry.requestFocus();
+      widgets.getChildren().add(usernameEntry);
+
+      Button submitBtn = new Button("Submit");
+      widgets.getChildren().add(submitBtn);
+
+      submitBtn.setOnAction(e -> {
+        this.localScores.add(new Pair<>(usernameEntry.getText(), score));
+
+        this.widgets.getChildren().remove(usernameEntry);
+        this.widgets.getChildren().remove(submitBtn);
+
+        this.writeScores((List<Pair<String, Integer>>) localScores);
+
+        this.localScores.sort(new Comparator<Pair<String, Integer>>() {
+          @Override
+          public int compare(Pair<String, Integer> l1, Pair<String, Integer> l2) {
+            if (l1.getValue() > l2.getValue()) {
+              return -1;
+            } else if (l1.getValue().equals(l2.getValue())) {
+              return 0;
+            } else {
+              return 1;
+            }
+          }
+        });
+        localList.getScores().bind(new SimpleListProperty<>(this.localScores));
+        localList.reveal();
+        Multimedia.playSound("pling.wav");
+      });
+    } else {
+      logger.info("User does not have a high score");
+      Text hiScoreTitle = new Text("High Scores");
+      hiScoreTitle.getStyleClass().add("title");
+      widgets.getChildren().add(hiScoreTitle);
+
+      localList.getScores().bind(new SimpleListProperty<>(this.localScores));
+      localList.reveal();
+    }
   }
 
-  private void escapeToMenu(KeyEvent e) {
-    if (e.getCode().equals(KeyCode.ESCAPE)) {
-      Multimedia.stopSound();
-      this.gameWindow.startMenu();
+  public static ArrayList<Pair<String, Integer>> loadScores() {
+    logger.info("Loading scores from file");
+    ArrayList<Pair<String, Integer>> localScores = new ArrayList<>();
+    try{
+      BufferedReader br = new BufferedReader(new FileReader("localscores.txt"));
+
+      String line = br.readLine();
+      while(line != null) {
+        String[] values = line.split(":");
+        localScores.add(new Pair<>(values[0], Integer.parseInt(values[1])));
+        line = br.readLine();
+      }
+      br.close();
+
+    } catch(IOException e) {
+      logger.info("Error reading file: " + e.getMessage());
     }
+
+    localScores.sort(new Comparator<Pair<String, Integer>>() {
+      @Override
+      public int compare(Pair<String, Integer> l1, Pair<String, Integer> l2) {
+        if (l1.getValue() > l2.getValue()) {
+          return -1;
+        } else if (l1.getValue().equals(l2.getValue())) {
+          return 0;
+        } else {
+          return 1;
+        }
+      }
+    });
+
+    return localScores;
+  }
+
+  public void writeScores(List<Pair<String, Integer>> nameScores) {
+    logger.info("Writing scores to text file");
+
+    try {
+      BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream("localscores.txt")));
+
+      for (Pair<String, Integer> nameScore : nameScores) {
+        bw.write(nameScore.getKey() + ":" + nameScore.getValue());
+        bw.newLine();
+      }
+      bw.close();
+    } catch (Exception e) {
+      logger.info("Error writing to file: " + e.getMessage());
+    }
+  }
+
+  private void escapeToMenu() {
+    Multimedia.stopSound();
+    this.gameWindow.startMenu();
   }
 }
diff --git a/tetrecs/src/main/java/uk/ac/soton/comp1206/ui/ScoresList.java b/tetrecs/src/main/java/uk/ac/soton/comp1206/ui/ScoresList.java
new file mode 100644
index 0000000000000000000000000000000000000000..af28a6ac90c94a01d2e593d090ea73ce1acff15c
--- /dev/null
+++ b/tetrecs/src/main/java/uk/ac/soton/comp1206/ui/ScoresList.java
@@ -0,0 +1,91 @@
+package uk.ac.soton.comp1206.ui;
+
+import javafx.animation.Animation;
+import javafx.animation.FadeTransition;
+import javafx.animation.SequentialTransition;
+import javafx.animation.Transition;
+import javafx.beans.property.ListProperty;
+import javafx.beans.property.SimpleListProperty;
+import javafx.collections.ListChangeListener;
+import javafx.geometry.Pos;
+import javafx.scene.layout.VBox;
+import javafx.scene.text.Text;
+import javafx.scene.text.TextAlignment;
+import javafx.util.Duration;
+import javafx.util.Pair;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import uk.ac.soton.comp1206.component.GameBlock;
+
+import java.util.ArrayList;
+
+
+public class ScoresList extends VBox {
+  private static final Logger logger = LogManager.getLogger(ScoresList.class);
+
+  public final SimpleListProperty<Pair<String, Integer>> scores = new SimpleListProperty();
+
+  private ArrayList<Text> nameScores = new ArrayList<>();
+
+  private String listName;
+
+  public ScoresList(String listName) {
+    setVisible(false);
+
+    getStyleClass().add("scorelist");
+
+    this.listName = listName;
+
+    setSpacing(5);
+    setAlignment(Pos.CENTER);
+
+    this.scores.addListener((ListChangeListener<? super Pair<String, Integer>>) e -> updateList());
+  }
+
+  public void updateList() {
+    logger.info("Updating score list");
+
+    nameScores.clear();
+    getChildren().clear();
+
+    Text title = new Text(listName);
+    title.getStyleClass().add("heading");
+    getChildren().add(title);
+
+    int i = 0;
+    for (Pair<String, Integer> score : scores) {
+      i++;
+      if (i > 10) {
+        break;
+      }
+
+      Text nameScore = new Text(score.getKey() + ": " + score.getValue());
+      nameScore.setTextAlignment(TextAlignment.CENTER);
+      nameScore.setFill(GameBlock.COLOURS[i]);
+
+      nameScores.add(nameScore);
+      getChildren().add(nameScore);
+    }
+
+  }
+
+  public void reveal() {
+    logger.info("Playing reveal animations");
+
+    setVisible(true);
+    SequentialTransition sq = new SequentialTransition();
+
+    for (Text nameScore : nameScores) {
+      FadeTransition ft = new FadeTransition(Duration.millis(250), nameScore);
+      ft.setFromValue(0);
+      ft.setToValue(1);
+      sq.getChildren().add(ft);
+    }
+
+    sq.play();
+  }
+
+  public ListProperty<Pair<String, Integer>> getScores() {
+    return this.scores;
+  }
+}
diff --git a/tetrecs/src/main/resources/style/game.css b/tetrecs/src/main/resources/style/game.css
index df6fa61442ab1589ac24570a3cd468d9301a6e33..9eee303a2c77680d1a7eb381db628d104aa5544c 100644
--- a/tetrecs/src/main/resources/style/game.css
+++ b/tetrecs/src/main/resources/style/game.css
@@ -114,7 +114,7 @@
 }
 
 .scorelist {
-    -fx-font-size: 20px;
+    -fx-font-size: 18px;
     -fx-font-family: 'Orbitron';
 }
 
diff --git a/tetrecs/target/classes/module-info.class b/tetrecs/target/classes/module-info.class
index b6eb5d5dc3206e20460f1afbfd5d3d22095a88f2..861f46b22632e03297e81eb1e4ffa1c4d743d09d 100644
Binary files a/tetrecs/target/classes/module-info.class and b/tetrecs/target/classes/module-info.class differ
diff --git a/tetrecs/target/classes/style/game.css b/tetrecs/target/classes/style/game.css
index df6fa61442ab1589ac24570a3cd468d9301a6e33..9eee303a2c77680d1a7eb381db628d104aa5544c 100644
--- a/tetrecs/target/classes/style/game.css
+++ b/tetrecs/target/classes/style/game.css
@@ -114,7 +114,7 @@
 }
 
 .scorelist {
-    -fx-font-size: 20px;
+    -fx-font-size: 18px;
     -fx-font-family: 'Orbitron';
 }
 
diff --git a/tetrecs/target/classes/uk/ac/soton/comp1206/game/Game.class b/tetrecs/target/classes/uk/ac/soton/comp1206/game/Game.class
index 97e05b42bbb29b8c097703f72b56f60458245a6a..f240a5fb067647a6e97467e55deccf97ca0b1c87 100644
Binary files a/tetrecs/target/classes/uk/ac/soton/comp1206/game/Game.class and b/tetrecs/target/classes/uk/ac/soton/comp1206/game/Game.class differ
diff --git a/tetrecs/target/classes/uk/ac/soton/comp1206/scene/ChallengeScene.class b/tetrecs/target/classes/uk/ac/soton/comp1206/scene/ChallengeScene.class
index c376e054ce27bc4038ee3abe557de47110c82a4b..190abd750f56f6ec1d22c4f9aeec33d970d691b1 100644
Binary files a/tetrecs/target/classes/uk/ac/soton/comp1206/scene/ChallengeScene.class and b/tetrecs/target/classes/uk/ac/soton/comp1206/scene/ChallengeScene.class differ
diff --git a/tetrecs/target/classes/uk/ac/soton/comp1206/scene/MenuScene.class b/tetrecs/target/classes/uk/ac/soton/comp1206/scene/MenuScene.class
index 6fa262bd093cd2c01b74abc8920c2ac3a1ac22ec..5a5424bebb75fe9dda472b832ce79f17ba0d6c4e 100644
Binary files a/tetrecs/target/classes/uk/ac/soton/comp1206/scene/MenuScene.class and b/tetrecs/target/classes/uk/ac/soton/comp1206/scene/MenuScene.class differ