diff --git a/.vscode/settings.json b/.vscode/settings.json
index a7b04eea3c..aa7768f142 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -65,6 +65,7 @@
         "stdexcept": "cpp",
         "streambuf": "cpp",
         "cinttypes": "cpp",
-        "typeinfo": "cpp"
+        "typeinfo": "cpp",
+        "list": "cpp"
     }
 }
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e2b69b8b02..759c05a2c3 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -384,6 +384,7 @@ list(APPEND SOURCE_FILES
         displayapp/screens/ApplicationList.cpp
         displayapp/screens/Notifications.cpp
         displayapp/screens/Twos.cpp
+        displayapp/screens/Adder.cpp
         displayapp/screens/HeartRate.cpp
         displayapp/screens/FlashLight.cpp
         displayapp/screens/List.cpp
diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp
index 6671ac9e51..5a15eca4f8 100644
--- a/src/displayapp/DisplayApp.cpp
+++ b/src/displayapp/DisplayApp.cpp
@@ -23,6 +23,7 @@
 #include "displayapp/screens/SystemInfo.h"
 #include "displayapp/screens/Tile.h"
 #include "displayapp/screens/Twos.h"
+#include "displayapp/screens/Adder.h"
 #include "displayapp/screens/FlashLight.h"
 #include "displayapp/screens/BatteryInfo.h"
 #include "displayapp/screens/Steps.h"
diff --git a/src/displayapp/UserApps.h b/src/displayapp/UserApps.h
index 67bbfa7d41..2e158e8bf5 100644
--- a/src/displayapp/UserApps.h
+++ b/src/displayapp/UserApps.h
@@ -6,6 +6,7 @@
 #include "displayapp/screens/Dice.h"
 #include "displayapp/screens/Timer.h"
 #include "displayapp/screens/Twos.h"
+#include "displayapp/screens/Adder.h"
 #include "displayapp/screens/Tile.h"
 #include "displayapp/screens/ApplicationList.h"
 #include "displayapp/screens/WatchFaceDigital.h"
diff --git a/src/displayapp/apps/Apps.h.in b/src/displayapp/apps/Apps.h.in
index 2104a267c0..03baf42c14 100644
--- a/src/displayapp/apps/Apps.h.in
+++ b/src/displayapp/apps/Apps.h.in
@@ -21,6 +21,7 @@ namespace Pinetime {
       Paint,
       Paddle,
       Twos,
+      Adder,
       HeartRate,
       Navigation,
       StopWatch,
diff --git a/src/displayapp/apps/CMakeLists.txt b/src/displayapp/apps/CMakeLists.txt
index d78587609e..70fe4a85cd 100644
--- a/src/displayapp/apps/CMakeLists.txt
+++ b/src/displayapp/apps/CMakeLists.txt
@@ -10,6 +10,7 @@ else ()
     set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Paint")
     set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Paddle")
     set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Twos")
+    set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Adder")
     set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Dice")
     set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Metronome")
     set(DEFAULT_USER_APP_TYPES "${DEFAULT_USER_APP_TYPES}, Apps::Navigation")
diff --git a/src/displayapp/screens/Adder.cpp b/src/displayapp/screens/Adder.cpp
new file mode 100644
index 0000000000..9f633e587b
--- /dev/null
+++ b/src/displayapp/screens/Adder.cpp
@@ -0,0 +1,340 @@
+#include "displayapp/DisplayApp.h"
+#include "displayapp/screens/Adder.h"
+#include <cstdlib>   // For std::rand
+#include <algorithm> // For std::max
+
+using namespace Pinetime::Applications::Screens;
+
+Adder::Adder(Pinetime::Components::LittleVgl& lvgl, Controllers::FS& fs) : lvgl(lvgl), filesystem(fs) {
+  InitializeGame();
+}
+
+Adder::~Adder() {
+  CleanUp();
+}
+
+void Adder::InitializeGame() {
+  LoadGame();
+
+  tileBuffer = new lv_color_t[TileSize * TileSize];
+  std::fill(tileBuffer, tileBuffer + TileSize * TileSize, LV_COLOR_WHITE);
+
+  displayHeight = LV_VER_RES;
+  displayWidth = LV_HOR_RES;
+
+  fieldHeight = displayHeight / TileSize - 2;
+  fieldWidth = displayWidth / TileSize - 1;
+  fieldOffsetHorizontal = (displayWidth - fieldWidth * TileSize) / 2;
+  fieldOffsetVertical = (displayHeight - fieldHeight * TileSize) / 2 + (TileSize + 0.5) / 2;
+
+  fieldSize = fieldWidth * fieldHeight;
+  field = new AdderField[fieldSize];
+
+  InitializeBody();
+  CreateLevel();
+
+  refreshTask = lv_task_create(
+    [](lv_task_t* task) {
+      auto* adder = static_cast<Adder*>(task->user_data);
+      adder->Refresh();
+    },
+    AdderDelayInterval,
+    LV_TASK_PRIO_MID,
+    this);
+
+  appReady = false;
+  vTaskDelay(20);
+}
+
+void Adder::CleanUp() {
+  delete[] field;
+  delete[] tileBuffer;
+  if (refreshTask) {
+    lv_task_del(refreshTask);
+  }
+  lv_obj_clean(lv_scr_act());
+}
+
+void Adder::LoadGame() {
+  lfs_file file;
+
+  if (filesystem.FileOpen(&file, GameSavePath, LFS_O_RDONLY) == LFS_ERR_OK) {
+    filesystem.FileRead(&file, reinterpret_cast<uint8_t*>(&data), sizeof(AdderSave));
+    filesystem.FileClose(&file);
+
+    if (data.Version != AdderVersion) {
+      data = AdderSave();
+    } else {
+      highScore = std::max(data.HighScore, highScore);
+    }
+  } else {
+    data = AdderSave();
+    filesystem.DirCreate("/games");
+    filesystem.DirCreate("/games/adder");
+    SaveGame();
+  }
+}
+
+void Adder::SaveGame() {
+  lfs_file file;
+
+  if (filesystem.FileOpen(&file, GameSavePath, LFS_O_WRONLY | LFS_O_CREAT) == LFS_ERR_OK) {
+    filesystem.FileWrite(&file, reinterpret_cast<uint8_t*>(&data), sizeof(AdderSave));
+    filesystem.FileClose(&file);
+  }
+}
+
+void Adder::ResetGame() {
+  GameOver();
+  appReady = false;
+  highScore = std::max(highScore, static_cast<unsigned int>(adderBody.size() - 2));
+  data.HighScore = highScore;
+  SaveGame();
+
+  CreateLevel();
+  InitializeBody();
+  UpdateScore(0);
+  FullRedraw();
+}
+
+void Adder::InitializeBody() {
+  adderBody.clear();
+
+  unsigned int startPosition = (fieldHeight / 2) * fieldWidth + fieldWidth / 2 + 2;
+  adderBody = {startPosition, startPosition - 1};
+
+  currentDirection = 1; // Start moving to the right
+  prevDirection = currentDirection;
+}
+
+void Adder::CreateLevel() {
+  for (unsigned int i = 0; i < fieldSize; ++i) {
+    unsigned int x = i % fieldWidth;
+    unsigned int y = i / fieldWidth;
+    if (y == 0 || y == fieldHeight - 1 || x == 0 || x == fieldWidth - 1) {
+      field[i] = AdderField::SOLID;
+    } else {
+      field[i] = AdderField::BLANK;
+    }
+  }
+}
+
+void Adder::CreateFood() {
+  blanks.clear();
+  for (unsigned int i = 0; i < fieldSize; ++i) {
+    if (field[i] == AdderField::BLANK) {
+      blanks.push_back(i);
+    }
+  }
+
+  if (!blanks.empty()) {
+    unsigned int randomIndex = std::rand() % blanks.size();
+    field[blanks[randomIndex]] = AdderField::FOOD;
+    UpdateSingleTile(blanks[randomIndex] % fieldWidth, blanks[randomIndex] / fieldWidth, LV_COLOR_GREEN);
+  }
+}
+
+bool Adder::OnTouchEvent(Pinetime::Applications::TouchEvents event) {
+  switch (event) {
+    case TouchEvents::SwipeLeft:
+      currentDirection = -1;
+      break;
+    case TouchEvents::SwipeUp:
+      currentDirection = -fieldWidth;
+      break;
+    case TouchEvents::SwipeDown:
+      currentDirection = fieldWidth;
+      break;
+    case TouchEvents::SwipeRight:
+      currentDirection = 1;
+      break;
+    case TouchEvents::LongTap:
+      FullRedraw();
+    default:
+      break;
+  }
+
+  // Prevent the adder from directly reversing direction
+  if (prevDirection == -currentDirection) {
+    currentDirection = -currentDirection;
+  }
+
+  // Update previous direction if it differs
+  if (currentDirection != prevDirection) {
+    prevDirection = currentDirection;
+  }
+
+  return true; // Return true to indicate the touch event was handled
+}
+
+void Adder::UpdatePosition() {
+  unsigned int newHead = adderBody.front() + currentDirection;
+  Adder::MoveConsequence result = CheckMove();
+
+  switch (result) {
+    case Adder::MoveConsequence::DEATH:
+      ResetGame();
+      return;
+
+    case Adder::MoveConsequence::EAT:
+      adderBody.push_front(newHead);
+      CreateFood();
+      UpdateScore(adderBody.size() - 2);
+      break;
+
+    case Adder::MoveConsequence::MOVE:
+      adderBody.pop_back();
+      adderBody.push_front(newHead);
+      break;
+  }
+
+  field[adderBody.front()] = AdderField::BODY;
+  field[adderBody.back()] = AdderField::BLANK;
+}
+
+Adder::MoveConsequence Adder::CheckMove() const {
+  unsigned int newHead = adderBody.front() + currentDirection;
+  if (newHead >= fieldSize) {
+    return Adder::MoveConsequence::DEATH;
+  }
+
+  switch (field[newHead]) {
+    case AdderField::BLANK:
+      return Adder::MoveConsequence::MOVE;
+    case AdderField::FOOD:
+      return Adder::MoveConsequence::EAT;
+    default:
+      return Adder::MoveConsequence::DEATH;
+  }
+}
+
+void Adder::Refresh() {
+  if (!appReady) {
+    FullRedraw();
+    CreateFood();
+    vTaskDelay(1); // Required to let the OS draw the tile completely
+    UpdateScore(0);
+    vTaskDelay(1); // Required to let the OS draw the tile completely
+    appReady = true;
+  } else {
+    UpdatePosition();
+    UpdateSingleTile(adderBody.front() % fieldWidth, adderBody.front() / fieldWidth, LV_COLOR_YELLOW);
+    vTaskDelay(1); // Required to let the OS draw the tile completely
+    UpdateSingleTile(adderBody.back() % fieldWidth, adderBody.back() / fieldWidth, LV_COLOR_BLACK);
+    vTaskDelay(1); // Required to let the OS draw the tile completely
+  }
+}
+
+void Adder::FullRedraw() {
+  for (unsigned int x = 0; x < fieldWidth; ++x) {
+    for (unsigned int y = 0; y < fieldHeight; ++y) {
+      lv_color_t color;
+      switch (field[y * fieldWidth + x]) {
+        case AdderField::BODY:
+          color = LV_COLOR_YELLOW;
+          break;
+        case AdderField::SOLID:
+          color = LV_COLOR_WHITE;
+          break;
+        case AdderField::FOOD:
+          color = LV_COLOR_GREEN;
+          break;
+        default:
+          color = LV_COLOR_BLACK;
+          break;
+      }
+      UpdateSingleTile(x, y, color);
+      vTaskDelay(1); // Required to let the OS draw the tile completely
+    }
+  }
+}
+
+void Adder::UpdateSingleTile(unsigned int x, unsigned int y, lv_color_t color) {
+  std::fill(tileBuffer, tileBuffer + TileSize * TileSize, color);
+  lv_area_t area {.x1 = static_cast<lv_coord_t>(x * TileSize + fieldOffsetHorizontal),
+                  .y1 = static_cast<lv_coord_t>(y * TileSize + fieldOffsetVertical),
+                  .x2 = static_cast<lv_coord_t>(x * TileSize + fieldOffsetHorizontal + TileSize - 1),
+                  .y2 = static_cast<lv_coord_t>(y * TileSize + fieldOffsetVertical + TileSize - 1)};
+
+  lvgl.FlushDisplay(&area, tileBuffer);
+}
+
+void Adder::GameOver() {
+  unsigned int digits[] = {7, 0, 5, 3}; // Digits forming the "GAME OVER" display
+
+  // Determine offset based on field dimensions
+  unsigned int offset = fieldOffsetHorizontal > fieldOffsetVertical ? fieldOffsetHorizontal : fieldOffsetVertical;
+
+  // Render "GAME OVER" animation
+  for (unsigned int r = 3 * offset; r < displayWidth - 4 * offset; r += 16) {
+    for (unsigned int i = 0; i < 4; i++) {
+      for (unsigned int j = 0; j < 64; j++) {
+        // Map font bits into the display buffer
+        digitBuffer[63 - j] = (DigitFont[digits[i]][j / 8] & 1 << j % 8)
+                                ? LV_COLOR_WHITE
+                                : LV_COLOR_BLACK; // Bitmagic to rotate the Digits to look like Letters
+      }
+
+      lv_area_t area;
+      area.x1 = r + 8 * i;
+      area.y1 = r;
+      area.x2 = area.x1 + 7;
+      area.y2 = area.y1 + 7;
+
+      lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::None);
+      lvgl.FlushDisplay(&area, digitBuffer);
+      vTaskDelay(1); // Required to let the OS draw the tile completely
+    }
+  }
+}
+
+void Adder::UpdateScore(unsigned int score) {
+  // Extract individual digits of the score
+  unsigned int digits[] = {0, score % 10, (score % 100 - score % 10) / 10, (score - score % 100) / 100};
+
+  // Render the score
+  for (unsigned int i = 0; i < 4; i++) {
+    for (unsigned int j = 0; j < 64; j++) {
+      // Map font bits into the display buffer (using bit manipulation)
+      digitBuffer[j] = (DigitFont[digits[i]][j / 8] & (1 << (j % 8))) ? LV_COLOR_WHITE : LV_COLOR_BLACK;
+    }
+
+    lv_area_t area;
+    area.x1 = displayWidth - 16 - 8 * i; // Adjust X to display digits
+    area.y1 = 4;                         // Y-offset for Score
+    area.x2 = area.x1 + 7;
+    area.y2 = area.y1 + 7;
+
+    lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::None);
+    lvgl.FlushDisplay(&area, digitBuffer);
+    vTaskDelay(20); // Small delay to allow display refresh
+  }
+
+  // Update the high score if necessary
+  unsigned int highScoreToWrite = (highScore > score) ? highScore : score;
+  unsigned int highScoreDigits[] = {0,
+                                    highScoreToWrite % 10,
+                                    (highScoreToWrite % 100 - highScoreToWrite % 10) / 10,
+                                    (highScoreToWrite - highScoreToWrite % 100) / 100};
+
+  // Render the high score
+  for (unsigned int i = 0; i < 4; i++) {
+    for (unsigned int j = 0; j < 64; j++) {
+      // Map font bits into the display buffer
+      digitBuffer[j] = (DigitFont[highScoreDigits[i]][j / 8] & (1 << (j % 8))) ? LV_COLOR_WHITE : LV_COLOR_BLACK;
+    }
+
+    lv_area_t area;
+    area.x1 = 40 - 8 * i; // Adjust X to display digits
+    area.y1 = 4;          // Y-offset for High Score
+    area.x2 = area.x1 + 7;
+    area.y2 = area.y1 + 7;
+
+    lvgl.SetFullRefresh(Components::LittleVgl::FullRefreshDirections::None);
+    lvgl.FlushDisplay(&area, digitBuffer);
+    vTaskDelay(20); // Small delay to allow display refresh
+  }
+
+  // Save the high score if it has changed
+  highScore = highScoreToWrite;
+}
diff --git a/src/displayapp/screens/Adder.h b/src/displayapp/screens/Adder.h
new file mode 100644
index 0000000000..d96c6953f7
--- /dev/null
+++ b/src/displayapp/screens/Adder.h
@@ -0,0 +1,118 @@
+#pragma once
+
+#include "displayapp/apps/Apps.h"
+#include "displayapp/Controllers.h"
+#include "displayapp/screens/Screen.h"
+#include <lvgl/lvgl.h>
+#include "components/fs/FS.h"
+#include <list>
+#include <vector>
+
+namespace Pinetime {
+  namespace Applications {
+    namespace Screens {
+
+      // Save file version
+      constexpr unsigned int AdderVersion = 1;
+
+      struct AdderSave {
+        unsigned int Level {0};
+        unsigned int HighScore {0};
+        unsigned int Version {AdderVersion};
+      };
+
+      enum class AdderField { UNDEFINED, BLANK, SOLID, BODY, FOOD };
+
+      class Adder : public Screen {
+
+      public:
+        Adder(Pinetime::Components::LittleVgl& lvgl, Pinetime::Controllers::FS& fs);
+        ~Adder() override;
+
+        enum class MoveConsequence { DEATH, EAT, MOVE };
+
+        // Overridden functions
+        void Refresh() override;
+        bool OnTouchEvent(Pinetime::Applications::TouchEvents event) override;
+
+      private:
+        static constexpr const char* GameSavePath = "/games/adder/adder.sav";
+        static constexpr unsigned int TileSize = 9;
+        static constexpr unsigned int AdderDelayInterval = 200;
+
+        Pinetime::Components::LittleVgl& lvgl;
+        Controllers::FS& filesystem;
+
+        AdderSave data; // Game save data
+        AdderField* field {nullptr};
+
+        lv_task_t* refreshTask {nullptr};
+        lv_color_t* tileBuffer {nullptr};
+        lv_color_t digitBuffer[64];
+
+        unsigned int displayHeight {0};
+        unsigned int displayWidth {0};
+        unsigned int fieldWidth {0};
+        unsigned int fieldHeight {0};
+        unsigned int fieldSize {0};
+        unsigned int highScore {2};
+
+        unsigned int fieldOffsetHorizontal {0};
+        unsigned int fieldOffsetVertical {0};
+
+        std::list<unsigned int> adderBody;
+        std::vector<unsigned int> blanks;
+
+        int prevDirection {0};
+        int currentDirection {1};
+
+        bool appReady {false};
+
+        // Methods
+        void InitializeGame();
+        void LoadGame();
+        void SaveGame();
+        void ResetGame();
+
+        void InitializeBody();
+        void CreateFood();
+        void CreateLevel();
+
+        void UpdatePosition();
+        void FullRedraw();
+        void UpdateSingleTile(unsigned int fieldX, unsigned int fieldY, lv_color_t color);
+        void UpdateScore(unsigned int score);
+        void GameOver();
+        void CleanUp();
+
+        MoveConsequence CheckMove() const;
+
+        static constexpr const char DigitFont[10][8] = {
+          // Font for digits 0-9
+          {0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // 0
+          {0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // 1
+          {0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // 2
+          {0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // 3
+          {0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // 4
+          {0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // 5
+          {0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // 6
+          {0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // 7
+          {0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // 8
+          {0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}  // 9
+        };
+      };
+    } // namespace Screens
+
+    // Application Traits
+    template <>
+    struct AppTraits<Apps::Adder> {
+      static constexpr Apps app = Apps::Adder;
+      static constexpr const char* icon = "S";
+
+      static Screens::Screen* Create(AppControllers& controllers) {
+        return new Screens::Adder(controllers.lvgl, controllers.filesystem);
+      }
+    };
+
+  } // namespace Applications
+} // namespace Pinetime