diff --git a/android/gradle.properties b/android/gradle.properties
index f7613f2f8c445194bd8345c26effa0131dfe211e..dfa6ea859d8324f76d1b0eccc01621db70e41cde 100644
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,5 +1,5 @@
 org.gradle.jvmargs=-Xmx1536M
 android.useAndroidX=true
 android.enableJetifier=true
-app.versionName=0.1.40
-app.versionCode=64
+app.versionName=0.2.0
+app.versionCode=65
diff --git a/assets/menu/game-pick-image.png b/assets/menu/game-pick-image.png
deleted file mode 100644
index 4f98fea428136e093ec5ed41310bc18ad6bda71a..0000000000000000000000000000000000000000
Binary files a/assets/menu/game-pick-image.png and /dev/null differ
diff --git a/assets/menu/game-pick-word.png b/assets/menu/game-pick-word.png
deleted file mode 100644
index 0625f5ac0e3428e5c5959f0e66eebc7fced794da..0000000000000000000000000000000000000000
Binary files a/assets/menu/game-pick-word.png and /dev/null differ
diff --git a/assets/placeholder.png b/assets/placeholder.png
deleted file mode 100644
index 9c9e7153c4ac87b54574b24a2cef2d27678c6cd7..0000000000000000000000000000000000000000
Binary files a/assets/placeholder.png and /dev/null differ
diff --git a/assets/translations/en.json b/assets/translations/en.json
index 7a959c85f39256092adb9e8b230109e61283fb63..bee067fabfa853ccf17fe49031ee56c06a778293 100644
--- a/assets/translations/en.json
+++ b/assets/translations/en.json
@@ -1,14 +1,12 @@
 {
   "app_name": "Word guess",
 
-  "bottom_nav_home": "Game",
-  "bottom_nav_settings": "Settings",
-  "bottom_nav_about": "About",
-
   "settings_title": "Settings",
   "settings_label_theme": "Theme mode",
 
   "about_title": "About",
   "about_content": "Word guess game.",
-  "about_version": "Version: {version}"
+  "about_version": "Version: {version}",
+
+  "": ""
 }
diff --git a/assets/translations/fr.json b/assets/translations/fr.json
index de1e73a173d57d55b362a6a9c92c6d5c88e4cd77..51afd63375a5f83f8579342d6886dbaa186a196e 100644
--- a/assets/translations/fr.json
+++ b/assets/translations/fr.json
@@ -1,14 +1,12 @@
 {
   "app_name": "Trouve le mot",
 
-  "bottom_nav_home": "Jeu",
-  "bottom_nav_settings": "Réglages",
-  "bottom_nav_about": "Infos",
-
   "settings_title": "Réglages",
   "settings_label_theme": "Thème de couleurs",
 
   "about_title": "Informations",
   "about_content": "Trouve le mot.",
-  "about_version": "Version : {version}"
+  "about_version": "Version : {version}",
+
+  "": ""
 }
diff --git a/assets/ui/button_back.png b/assets/ui/button_back.png
new file mode 100644
index 0000000000000000000000000000000000000000..cc48ffb1dbb653d9a996f139dfbe02969724bfa5
Binary files /dev/null and b/assets/ui/button_back.png differ
diff --git a/assets/ui/button_delete_saved_game.png b/assets/ui/button_delete_saved_game.png
new file mode 100644
index 0000000000000000000000000000000000000000..5e4f217689b11e444b7163557d7e5d68f3bbfe7d
Binary files /dev/null and b/assets/ui/button_delete_saved_game.png differ
diff --git a/assets/ui/button_resume_game.png b/assets/ui/button_resume_game.png
new file mode 100644
index 0000000000000000000000000000000000000000..b2ea0a02d05e42377eb551a4b51428b511a32f5d
Binary files /dev/null and b/assets/ui/button_resume_game.png differ
diff --git a/assets/ui/button_start.png b/assets/ui/button_start.png
new file mode 100644
index 0000000000000000000000000000000000000000..6845e2f5c21598ab61f1684d2075aeec0334bf23
Binary files /dev/null and b/assets/ui/button_start.png differ
diff --git a/assets/ui/game_fail.png b/assets/ui/game_fail.png
new file mode 100644
index 0000000000000000000000000000000000000000..93f2801f9d6bb2ce508e1293cd64d6ff2e9970ec
Binary files /dev/null and b/assets/ui/game_fail.png differ
diff --git a/assets/ui/game_win.png b/assets/ui/game_win.png
new file mode 100644
index 0000000000000000000000000000000000000000..876334279c1711b349a62131a33607eecf924eb6
Binary files /dev/null and b/assets/ui/game_win.png differ
diff --git a/assets/ui/placeholder.png b/assets/ui/placeholder.png
new file mode 100644
index 0000000000000000000000000000000000000000..814df31be6ddc4275ebe4490c79365578dbef1f0
Binary files /dev/null and b/assets/ui/placeholder.png differ
diff --git a/assets/ui/type_pick-image.png b/assets/ui/type_pick-image.png
new file mode 100644
index 0000000000000000000000000000000000000000..216e7d24926beb60c9806f5404a313cb62778ffb
Binary files /dev/null and b/assets/ui/type_pick-image.png differ
diff --git a/assets/ui/type_pick-word.png b/assets/ui/type_pick-word.png
new file mode 100644
index 0000000000000000000000000000000000000000..8c816e62f246aa7fc2762cae52090547b74cb1c2
Binary files /dev/null and b/assets/ui/type_pick-word.png differ
diff --git a/fastlane/metadata/android/en-US/changelogs/65.txt b/fastlane/metadata/android/en-US/changelogs/65.txt
new file mode 100644
index 0000000000000000000000000000000000000000..d4afd512e55b3fd8ffbfd795adb9b00832e5aaef
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/65.txt
@@ -0,0 +1 @@
+Improve/normalize game architecture.
diff --git a/fastlane/metadata/android/fr-FR/changelogs/65.txt b/fastlane/metadata/android/fr-FR/changelogs/65.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6a9871a5eb8eb3c6e9106520f1cbf1f39f9e5ef7
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/65.txt
@@ -0,0 +1 @@
+Amélioration/normalisation de l'architecture du jeu.
diff --git a/images/build_images.sh b/images/build_images.sh
deleted file mode 100755
index c9639849e52cc4c8306171828fe670f147eb63f3..0000000000000000000000000000000000000000
--- a/images/build_images.sh
+++ /dev/null
@@ -1,67 +0,0 @@
-#! /bin/bash
-
-# Check dependencies
-command -v inkscape >/dev/null 2>&1 || { echo >&2 "I require inkscape but it's not installed. Aborting."; exit 1; }
-command -v scour >/dev/null 2>&1 || { echo >&2 "I require scour but it's not installed. Aborting."; exit 1; }
-command -v optipng >/dev/null 2>&1 || { echo >&2 "I require optipng but it's not installed. Aborting."; exit 1; }
-command -v convert >/dev/null 2>&1 || { echo >&2 "I require convert (imagemagick) but it's not installed. Aborting."; exit 1; }
-
-CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
-BASE_DIR="$(dirname "${CURRENT_DIR}")"
-
-CONVERT_OPTIONS="-alpha off +dither -colors 256 -depth 4"
-OPTIPNG_OPTIONS="-preserve -quiet -o7"
-
-# optimize svg
-function optimize_svg() {
-  SOURCE="$1"
-
-  cp ${SOURCE} ${SOURCE}.tmp
-  scour \
-      --remove-descriptive-elements \
-      --enable-id-stripping \
-      --enable-viewboxing \
-      --enable-comment-stripping \
-      --nindent=4 \
-      -i ${SOURCE}.tmp \
-      -o ${SOURCE}
-  rm ${SOURCE}.tmp
-}
-
-# build image
-function build_image() {
-  SOURCE="$1"
-  TARGET_PNG="$2"
-  IMAGE_WIDTH="$3"
-  IMAGE_HEIGHT="$4"
-
-  inkscape \
-      --export-width=${IMAGE_WIDTH} \
-      --export-height=${IMAGE_HEIGHT} \
-      --export-filename=${TARGET_PNG} \
-      ${SOURCE}
-}
-
-# optimize image
-function optimize_image() {
-  IMAGE_FILE="$1"
-
-  convert "${IMAGE_FILE}" ${CONVERT_OPTIONS} "${IMAGE_FILE}"
-  optipng ${OPTIPNG_OPTIONS} ${IMAGE_FILE}
-}
-
-# build menu image
-function build_menu_image() {
-  IMAGE_NAME="$1"
-
-  INPUT_SVG="${CURRENT_DIR}/menu/${IMAGE_NAME}.svg"
-  OUTPUT_PNG="${BASE_DIR}/assets/menu/${IMAGE_NAME}.png"
-
-  optimize_svg "${INPUT_SVG}"
-  build_image "${INPUT_SVG}" "${OUTPUT_PNG}" 640 640
-  optimize_image "${OUTPUT_PNG}"
-}
-
-
-build_menu_image "game-pick-image"
-build_menu_image "game-pick-word"
diff --git a/lib/config/default_game_settings.dart b/lib/config/default_game_settings.dart
new file mode 100644
index 0000000000000000000000000000000000000000..f6ae267b5da3b0be46ecb25da461df11ebddf274
--- /dev/null
+++ b/lib/config/default_game_settings.dart
@@ -0,0 +1,52 @@
+import 'package:wordguessing/utils/tools.dart';      
+
+class DefaultGameSettings {
+  // available game parameters codes
+  static const String parameterCodeGameType = 'type';
+  static const String parameterCodeLangValue = 'lang';
+  static const List<String> availableParameters = [
+    parameterCodeGameType,
+    parameterCodeLangValue,
+  ];
+
+  // game type: available values
+  static const String gameTypeValuePickWord = 'pick-word';
+  static const String gameTypeValuePickImage = 'pick-image';
+  static const List<String> allowedGameTypeValues = [
+    gameTypeValuePickWord,
+    gameTypeValuePickImage,
+  ];
+  // game type: default value
+  static const String defaultGameTypeValue = gameTypeValuePickWord;
+
+  // lang: available values
+  static const String langValueFr = 'fr';
+  static const String langValueEn = 'en';
+  static const List<String> allowedLangValues = [
+    langValueFr,
+    langValueEn,
+  ];
+  // lang: default value
+  static const String defaultLangValue = langValueFr;
+
+  // available values from parameter code
+  static List<String> getAvailableValues(String parameterCode) {
+    switch (parameterCode) {
+      case parameterCodeGameType:
+        return DefaultGameSettings.allowedGameTypeValues;
+      case parameterCodeLangValue:
+        return DefaultGameSettings.allowedLangValues;
+    }
+
+    printlog('Did not find any available value for game parameter "$parameterCode".');
+    return [];
+  }
+
+  // parameters displayed with assets (instead of painter)
+  static List<String> displayedWithAssets = [
+    parameterCodeGameType,
+  ];
+
+  static const int itemsCount = 4;
+  static const int recentWordsCount = 20;
+}
diff --git a/lib/config/default_global_settings.dart b/lib/config/default_global_settings.dart
new file mode 100644
index 0000000000000000000000000000000000000000..2b98f69b6fc166bd72410cb1e30bdb8f2bdfe36c
--- /dev/null
+++ b/lib/config/default_global_settings.dart
@@ -0,0 +1,33 @@
+import 'package:wordguessing/utils/tools.dart';      
+
+class DefaultGlobalSettings {
+  // available global parameters codes
+  static const String parameterCodeSkin = 'skin';
+  static const List<String> availableParameters = [
+    parameterCodeSkin,
+  ];
+
+  // skin: available values
+  static const String skinValueDefault = 'default';
+  static const List<String> allowedSkinValues = [
+    skinValueDefault,
+  ];
+  // skin: default value
+  static const String defaultSkinValue = skinValueDefault;
+
+  // available values from parameter code
+  static List<String> getAvailableValues(String parameterCode) {
+    switch (parameterCode) {
+      case parameterCodeSkin:
+        return DefaultGlobalSettings.allowedSkinValues;
+    }
+
+    printlog('Did not find any available value for global parameter "$parameterCode".');
+    return [];
+  }
+
+  // parameters displayed with assets (instead of painter)
+  static List<String> displayedWithAssets = [
+    //
+  ];
+}
diff --git a/lib/config/menu.dart b/lib/config/menu.dart
index 13081ea3b21b0c581d8dec4088186de0a98e3683..3d55d36f5ba813bc482957b2589dd3cf5c73423b 100644
--- a/lib/config/menu.dart
+++ b/lib/config/menu.dart
@@ -1,53 +1,51 @@
-import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
 import 'package:unicons/unicons.dart';
 
-import 'package:wordguessing/ui/screens/about_page.dart';
-import 'package:wordguessing/ui/screens/game_page.dart';
-import 'package:wordguessing/ui/screens/settings_page.dart';
+import 'package:wordguessing/ui/screens/page_about.dart';
+import 'package:wordguessing/ui/screens/page_game.dart';
+import 'package:wordguessing/ui/screens/page_settings.dart';
 
 class MenuItem {
-  final String code;
   final Icon icon;
   final Widget page;
 
   const MenuItem({
-    required this.code,
     required this.icon,
     required this.page,
   });
 }
 
 class Menu {
-  static List<MenuItem> items = [
-    const MenuItem(
-      code: 'bottom_nav_home',
-      icon: Icon(UniconsLine.home),
-      page: GamePage(),
-    ),
-    const MenuItem(
-      code: 'bottom_nav_settings',
-      icon: Icon(UniconsLine.setting),
-      page: SettingsPage(),
-    ),
-    const MenuItem(
-      code: 'bottom_nav_about',
-      icon: Icon(UniconsLine.info_circle),
-      page: AboutPage(),
-    ),
-  ];
+  static const indexGame = 0;
+  static const menuItemGame = MenuItem(
+    icon: Icon(UniconsLine.home),
+    page: PageGame(),
+  );
 
-  static Widget getPageWidget(int pageIndex) {
-    return Menu.items.elementAt(pageIndex).page;
+  static const indexSettings = 1;
+  static const menuItemSettings = MenuItem(
+    icon: Icon(UniconsLine.setting),
+    page: PageSettings(),
+  );
+
+  static const indexAbout = 2;
+  static const menuItemAbout = MenuItem(
+    icon: Icon(UniconsLine.info_circle),
+    page: PageAbout(),
+  );
+
+  static Map<int, MenuItem> items = {
+    indexGame: menuItemGame,
+    indexSettings: menuItemSettings,
+    indexAbout: menuItemAbout,
+  };
+
+  static bool isIndexAllowed(int pageIndex) {
+    return items.keys.contains(pageIndex);
   }
 
-  static List<BottomNavigationBarItem> getMenuItems() {
-    return Menu.items
-        .map((MenuItem item) => BottomNavigationBarItem(
-              icon: item.icon,
-              label: tr(item.code),
-            ))
-        .toList();
+  static Widget getPageWidget(int pageIndex) {
+    return items[pageIndex]?.page ?? menuItemGame.page;
   }
 
   static int itemsCount = Menu.items.length;
diff --git a/lib/config/theme.dart b/lib/config/theme.dart
index be390348c7868e7c63387df13e13c46de43f8a23..74f532fd5abf693979118609564d29167e902009 100644
--- a/lib/config/theme.dart
+++ b/lib/config/theme.dart
@@ -39,11 +39,9 @@ final ColorScheme lightColorScheme = ColorScheme.light(
   secondary: primarySwatch.shade500,
   onSecondary: Colors.white,
   error: errorColor,
-  background: textSwatch.shade200,
-  onBackground: textSwatch.shade500,
   onSurface: textSwatch.shade500,
   surface: textSwatch.shade50,
-  surfaceVariant: Colors.white,
+  surfaceContainerHighest: Colors.white,
   shadow: textSwatch.shade900.withOpacity(.1),
 );
 
@@ -52,11 +50,9 @@ final ColorScheme darkColorScheme = ColorScheme.dark(
   secondary: primarySwatch.shade500,
   onSecondary: Colors.white,
   error: errorColor,
-  background: const Color(0xFF171724),
-  onBackground: textSwatch.shade400,
   onSurface: textSwatch.shade300,
   surface: const Color(0xFF262630),
-  surfaceVariant: const Color(0xFF282832),
+  surfaceContainerHighest: const Color(0xFF282832),
   shadow: textSwatch.shade900.withOpacity(.2),
 );
 
@@ -192,5 +188,3 @@ final ThemeData darkTheme = lightTheme.copyWith(
     ),
   ),
 );
-
-final ThemeData appTheme = darkTheme;
diff --git a/lib/cubit/game_cubit.dart b/lib/cubit/game_cubit.dart
new file mode 100644
index 0000000000000000000000000000000000000000..bd4ccf1393b22e97ff5f4b5a7ff66a3b70aaa3df
--- /dev/null
+++ b/lib/cubit/game_cubit.dart
@@ -0,0 +1,113 @@
+import 'package:equatable/equatable.dart';
+import 'package:flutter/material.dart';
+import 'package:hydrated_bloc/hydrated_bloc.dart';
+
+import 'package:wordguessing/models/game/game.dart';
+import 'package:wordguessing/models/settings/settings_game.dart';
+import 'package:wordguessing/models/settings/settings_global.dart';
+
+part 'game_state.dart';
+
+class GameCubit extends HydratedCubit<GameState> {
+  GameCubit()
+      : super(GameState(
+          currentGame: Game.createEmpty(),
+        ));
+
+  void updateState(Game game) {
+    emit(GameState(
+      currentGame: game,
+    ));
+  }
+
+  void refresh() {
+    final Game game = Game(
+      // Settings
+      gameSettings: state.currentGame.gameSettings,
+      globalSettings: state.currentGame.globalSettings,
+      // State
+      isRunning: state.currentGame.isRunning,
+      isStarted: state.currentGame.isStarted,
+      isFinished: state.currentGame.isFinished,
+      animationInProgress: state.currentGame.animationInProgress,
+      // Base data
+      word: state.currentGame.word,
+      otherWords: state.currentGame.otherWords,
+      images: state.currentGame.images,
+      // Game data
+      recentWordsKeys: state.currentGame.recentWordsKeys,
+      questionsCount: state.currentGame.questionsCount,
+      goodAnswers: state.currentGame.goodAnswers,
+      wrongAnswers: state.currentGame.wrongAnswers,
+    );
+    // game.dump();
+
+    updateState(game);
+  }
+
+  void startNewGame({
+    required GameSettings gameSettings,
+    required GlobalSettings globalSettings,
+  }) {
+    final Game newGame = Game.createNew(
+      // Settings
+      gameSettings: gameSettings,
+      globalSettings: globalSettings,
+    );
+
+    updateState(newGame);
+    nextWord();
+
+    newGame.dump();
+
+    updateState(newGame);
+    refresh();
+  }
+
+  void quitGame() {
+    state.currentGame.isRunning = false;
+    refresh();
+  }
+
+  void resumeSavedGame() {
+    state.currentGame.isRunning = true;
+    refresh();
+  }
+
+  void deleteSavedGame() {
+    state.currentGame.isRunning = false;
+    state.currentGame.isFinished = true;
+    refresh();
+  }
+
+  void nextWord() {
+    state.currentGame.pickNewWord();
+    refresh();
+  }
+
+  void checkWord(word) {
+    if (state.currentGame.word.key == word.key) {
+      state.currentGame.goodAnswers++;
+      nextWord();
+    } else {
+      state.currentGame.wrongAnswers++;
+    }
+    refresh();
+  }
+
+  @override
+  GameState? fromJson(Map<String, dynamic> json) {
+    final Game currentGame = json['currentGame'] as Game;
+
+    return GameState(
+      currentGame: currentGame,
+    );
+  }
+
+  @override
+  Map<String, dynamic>? toJson(GameState state) {
+    return <String, dynamic>{
+      'currentGame': state.currentGame.toJson(),
+    };
+  }
+}
diff --git a/lib/cubit/game_state.dart b/lib/cubit/game_state.dart
new file mode 100644
index 0000000000000000000000000000000000000000..00e211668c3269255926939324355792abd61c41
--- /dev/null
+++ b/lib/cubit/game_state.dart
@@ -0,0 +1,15 @@
+part of 'game_cubit.dart';
+
+@immutable
+class GameState extends Equatable {
+  const GameState({
+    required this.currentGame,
+  });
+
+  final Game currentGame;
+
+  @override
+  List<dynamic> get props => <dynamic>[
+        currentGame,
+      ];
+}
diff --git a/lib/cubit/bottom_nav_cubit.dart b/lib/cubit/nav_cubit.dart
similarity index 51%
rename from lib/cubit/bottom_nav_cubit.dart
rename to lib/cubit/nav_cubit.dart
index 96d5a6948ba1212c462227ef08403039b55e266d..889605d765c462238201538baf27ce4c929d2cc0 100644
--- a/lib/cubit/bottom_nav_cubit.dart
+++ b/lib/cubit/nav_cubit.dart
@@ -2,26 +2,32 @@ import 'package:hydrated_bloc/hydrated_bloc.dart';
 
 import 'package:wordguessing/config/menu.dart';
 
-class BottomNavCubit extends HydratedCubit<int> {
-  BottomNavCubit() : super(0);
+class NavCubit extends HydratedCubit<int> {
+  NavCubit() : super(0);
 
   void updateIndex(int index) {
-    if (isIndexAllowed(index)) {
+    if (Menu.isIndexAllowed(index)) {
       emit(index);
     } else {
-      goToHomePage();
+      goToGamePage();
     }
   }
 
-  bool isIndexAllowed(int index) {
-    return (index >= 0) && (index < Menu.itemsCount);
+  void goToGamePage() {
+    emit(Menu.indexGame);
   }
 
-  void goToHomePage() => emit(0);
+  void goToSettingsPage() {
+    emit(Menu.indexSettings);
+  }
+
+  void goToAboutPage() {
+    emit(Menu.indexAbout);
+  }
 
   @override
   int fromJson(Map<String, dynamic> json) {
-    return 0;
+    return Menu.indexGame;
   }
 
   @override
diff --git a/lib/cubit/settings_game_cubit.dart b/lib/cubit/settings_game_cubit.dart
new file mode 100644
index 0000000000000000000000000000000000000000..d7d021010b5ae44542d23387045000eb2c7c9be0
--- /dev/null
+++ b/lib/cubit/settings_game_cubit.dart
@@ -0,0 +1,72 @@
+import 'package:equatable/equatable.dart';
+import 'package:flutter/material.dart';
+import 'package:hydrated_bloc/hydrated_bloc.dart';
+
+import 'package:wordguessing/config/default_game_settings.dart';
+import 'package:wordguessing/models/settings/settings_game.dart';
+
+part 'settings_game_state.dart';
+
+class GameSettingsCubit extends HydratedCubit<GameSettingsState> {
+  GameSettingsCubit() : super(GameSettingsState(settings: GameSettings.createDefault()));
+
+  void setValues({
+    String? gameType,
+    String? lang,
+  }) {
+    emit(
+      GameSettingsState(
+        settings: GameSettings(
+          gameType: gameType ?? state.settings.gameType,
+          lang: lang ?? state.settings.lang,
+        ),
+      ),
+    );
+  }
+
+  String getParameterValue(String code) {
+    switch (code) {
+      case DefaultGameSettings.parameterCodeGameType:
+        return GameSettings.getGameTypeValueFromUnsafe(state.settings.gameType);
+      case DefaultGameSettings.parameterCodeLangValue:
+        return GameSettings.getLangValueFromUnsafe(state.settings.lang);
+    }
+
+    return '';
+  }
+
+  void setParameterValue(String code, String value) {
+    final String gameType = code == DefaultGameSettings.parameterCodeGameType
+        ? value
+        : getParameterValue(DefaultGameSettings.parameterCodeGameType);
+    final String lang = code == DefaultGameSettings.parameterCodeLangValue
+        ? value
+        : getParameterValue(DefaultGameSettings.parameterCodeLangValue);
+
+    setValues(
+      gameType: gameType,
+      lang: lang,
+    );
+  }
+
+  @override
+  GameSettingsState? fromJson(Map<String, dynamic> json) {
+    final String gameType = json[DefaultGameSettings.parameterCodeGameType] as String;
+    final String lang = json[DefaultGameSettings.parameterCodeLangValue] as String;
+
+    return GameSettingsState(
+      settings: GameSettings(
+        gameType: gameType,
+        lang: lang,
+      ),
+    );
+  }
+
+  @override
+  Map<String, dynamic>? toJson(GameSettingsState state) {
+    return <String, dynamic>{
+      DefaultGameSettings.parameterCodeGameType: state.settings.gameType,
+      DefaultGameSettings.parameterCodeLangValue: state.settings.lang,
+    };
+  }
+}
diff --git a/lib/cubit/settings_game_state.dart b/lib/cubit/settings_game_state.dart
new file mode 100644
index 0000000000000000000000000000000000000000..5acd85b44ba541e1c5e9c26af1c4be26a385b9ed
--- /dev/null
+++ b/lib/cubit/settings_game_state.dart
@@ -0,0 +1,15 @@
+part of 'settings_game_cubit.dart';
+
+@immutable
+class GameSettingsState extends Equatable {
+  const GameSettingsState({
+    required this.settings,
+  });
+
+  final GameSettings settings;
+
+  @override
+  List<dynamic> get props => <dynamic>[
+        settings,
+      ];
+}
diff --git a/lib/cubit/settings_global_cubit.dart b/lib/cubit/settings_global_cubit.dart
new file mode 100644
index 0000000000000000000000000000000000000000..9b3f66099e68097a9d905b838626157fa676bc4e
--- /dev/null
+++ b/lib/cubit/settings_global_cubit.dart
@@ -0,0 +1,60 @@
+import 'package:equatable/equatable.dart';
+import 'package:flutter/material.dart';
+import 'package:hydrated_bloc/hydrated_bloc.dart';
+
+import 'package:wordguessing/config/default_global_settings.dart';
+import 'package:wordguessing/models/settings/settings_global.dart';
+
+part 'settings_global_state.dart';
+
+class GlobalSettingsCubit extends HydratedCubit<GlobalSettingsState> {
+  GlobalSettingsCubit() : super(GlobalSettingsState(settings: GlobalSettings.createDefault()));
+
+  void setValues({
+    String? skin,
+  }) {
+    emit(
+      GlobalSettingsState(
+        settings: GlobalSettings(
+          skin: skin ?? state.settings.skin,
+        ),
+      ),
+    );
+  }
+
+  String getParameterValue(String code) {
+    switch (code) {
+      case DefaultGlobalSettings.parameterCodeSkin:
+        return GlobalSettings.getSkinValueFromUnsafe(state.settings.skin);
+    }
+    return '';
+  }
+
+  void setParameterValue(String code, String value) {
+    final String skin = (code == DefaultGlobalSettings.parameterCodeSkin)
+        ? value
+        : getParameterValue(DefaultGlobalSettings.parameterCodeSkin);
+
+    setValues(
+      skin: skin,
+    );
+  }
+
+  @override
+  GlobalSettingsState? fromJson(Map<String, dynamic> json) {
+    final String skin = json[DefaultGlobalSettings.parameterCodeSkin] as String;
+
+    return GlobalSettingsState(
+      settings: GlobalSettings(
+        skin: skin,
+      ),
+    );
+  }
+
+  @override
+  Map<String, dynamic>? toJson(GlobalSettingsState state) {
+    return <String, dynamic>{
+      DefaultGlobalSettings.parameterCodeSkin: state.settings.skin,
+    };
+  }
+}
diff --git a/lib/cubit/settings_global_state.dart b/lib/cubit/settings_global_state.dart
new file mode 100644
index 0000000000000000000000000000000000000000..ebcddd700f252257223ca8e16c85202b04f3ff24
--- /dev/null
+++ b/lib/cubit/settings_global_state.dart
@@ -0,0 +1,15 @@
+part of 'settings_global_cubit.dart';
+
+@immutable
+class GlobalSettingsState extends Equatable {
+  const GlobalSettingsState({
+    required this.settings,
+  });
+
+  final GlobalSettings settings;
+
+  @override
+  List<dynamic> get props => <dynamic>[
+        settings,
+      ];
+}
diff --git a/lib/data/fetch_data_helper.dart b/lib/data/fetch_data_helper.dart
index 848f8240f2399568a09f6684213370b6cc827bf3..7e27529b88b668563ce3920f5801756fa4cf1b3b 100644
--- a/lib/data/fetch_data_helper.dart
+++ b/lib/data/fetch_data_helper.dart
@@ -1,5 +1,5 @@
 import 'package:wordguessing/data/game_data.dart';
-import 'package:wordguessing/models/word.dart';
+import 'package:wordguessing/models/data/word.dart';
 import 'package:wordguessing/utils/tools.dart';
 
 class FetchDataHelper {
@@ -38,7 +38,7 @@ class FetchDataHelper {
     }
   }
 
-  List<Word> getWords(String lang, int count) {
+  List<Word> getWords({required String lang, required int count}) {
     if (_words.isEmpty || lang != _lang) {
       init(lang);
     }
diff --git a/lib/main.dart b/lib/main.dart
index 5dac5d3c52ce806d2155eae497dcae8f22810553..3a627ad614efa29a41b00535e1957f66f3fcc275 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -2,20 +2,23 @@ import 'dart:io';
 
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:hive/hive.dart';
 import 'package:hydrated_bloc/hydrated_bloc.dart';
 import 'package:path_provider/path_provider.dart';
-import 'package:provider/provider.dart';
 
+import 'package:wordguessing/config/default_game_settings.dart';
 import 'package:wordguessing/config/theme.dart';
-import 'package:wordguessing/cubit/bottom_nav_cubit.dart';
+import 'package:wordguessing/cubit/game_cubit.dart';
+import 'package:wordguessing/cubit/nav_cubit.dart';
+import 'package:wordguessing/cubit/settings_game_cubit.dart';
+import 'package:wordguessing/cubit/settings_global_cubit.dart';
 import 'package:wordguessing/cubit/theme_cubit.dart';
-import 'package:wordguessing/provider/data.dart';
 import 'package:wordguessing/ui/skeleton.dart';
 
 void main() async {
-  /// Initialize packages
+  // Initialize packages
   WidgetsFlutterBinding.ensureInitialized();
   await EasyLocalization.ensureInitialized();
   final Directory tmpDir = await getTemporaryDirectory();
@@ -24,18 +27,17 @@ void main() async {
     storageDirectory: tmpDir,
   );
 
-  runApp(
-    EasyLocalization(
-      path: 'assets/translations',
-      supportedLocales: const <Locale>[
-        Locale('en'),
-        Locale('fr'),
-      ],
-      fallbackLocale: const Locale('en'),
-      useFallbackTranslations: true,
-      child: const MyApp(),
-    ),
-  );
+  SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
+      .then((value) => runApp(EasyLocalization(
+            path: 'assets/translations',
+            supportedLocales: const <Locale>[
+              Locale('en'),
+              Locale('fr'),
+            ],
+            fallbackLocale: const Locale('en'),
+            useFallbackTranslations: true,
+            child: const MyApp(),
+          )));
 }
 
 class MyApp extends StatelessWidget {
@@ -43,36 +45,62 @@ class MyApp extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
+    final List<String> assets = getImagesAssets();
+    for (String asset in assets) {
+      precacheImage(AssetImage(asset), context);
+    }
+
     return MultiBlocProvider(
       providers: [
-        BlocProvider<BottomNavCubit>(create: (context) => BottomNavCubit()),
+        BlocProvider<NavCubit>(create: (context) => NavCubit()),
         BlocProvider<ThemeCubit>(create: (context) => ThemeCubit()),
+        BlocProvider<GameCubit>(create: (context) => GameCubit()),
+        BlocProvider<GlobalSettingsCubit>(create: (context) => GlobalSettingsCubit()),
+        BlocProvider<GameSettingsCubit>(create: (context) => GameSettingsCubit()),
       ],
       child: BlocBuilder<ThemeCubit, ThemeModeState>(
-          builder: (BuildContext context, ThemeModeState state) {
-        return ChangeNotifierProvider(
-          create: (BuildContext context) => Data(),
-          child: Consumer<Data>(
-            builder: (context, data, child) {
-              return MaterialApp(
-                title: 'Jeux de mots et lettres',
-                home: const SkeletonScreen(),
+        builder: (BuildContext context, ThemeModeState state) {
+          return MaterialApp(
+            title: 'Jeux de mots et lettres',
+            home: const SkeletonScreen(),
 
-                // Theme stuff
-                theme: lightTheme,
-                darkTheme: darkTheme,
-                themeMode: state.themeMode,
+            // Theme stuff
+            theme: lightTheme,
+            darkTheme: darkTheme,
+            themeMode: state.themeMode,
 
-                // Localization stuff
-                localizationsDelegates: context.localizationDelegates,
-                supportedLocales: context.supportedLocales,
-                locale: context.locale,
-                debugShowCheckedModeBanner: false,
-              );
-            },
-          ),
-        );
-      }),
+            // Localization stuff
+            localizationsDelegates: context.localizationDelegates,
+            supportedLocales: context.supportedLocales,
+            locale: context.locale,
+            debugShowCheckedModeBanner: false,
+          );
+        },
+      ),
     );
   }
+
+  List<String> getImagesAssets() {
+    final List<String> assets = [];
+
+    final List<String> gameImages = [
+      'button_back',
+      'button_delete_saved_game',
+      'button_resume_game',
+      'button_start',
+      'game_fail',
+      'game_win',
+      'placeholder',
+    ];
+
+    for (String gameType in DefaultGameSettings.allowedGameTypeValues) {
+      gameImages.add('${DefaultGameSettings.parameterCodeGameType}_$gameType');
+    }
+
+    for (String image in gameImages) {
+      assets.add('assets/ui/$image.png');
+    }
+
+    return assets;
+  }
 }
diff --git a/lib/models/word.dart b/lib/models/data/word.dart
similarity index 53%
rename from lib/models/word.dart
rename to lib/models/data/word.dart
index bd5dfc3c448102e563fb358f5e94ad8700adf45a..f6b29e955dc367fe2163d114b36bbbda03cff6fd 100644
--- a/lib/models/word.dart
+++ b/lib/models/data/word.dart
@@ -9,16 +9,24 @@ class Word {
     required this.images,
   });
 
-  Map<String, dynamic> toJson() {
-    return {
-      'key': key,
-      'text': text,
-      'images': images.toString(),
-    };
+  factory Word.createEmpty() {
+    return const Word(
+      key: '',
+      text: '',
+      images: [],
+    );
   }
 
   @override
   String toString() {
-    return toJson().toString();
+    return '$Word(${toJson()})';
+  }
+
+  Map<String, dynamic>? toJson() {
+    return <String, dynamic>{
+      'key': key,
+      'text': text,
+      'images': images,
+    };
   }
 }
diff --git a/lib/models/game/game.dart b/lib/models/game/game.dart
new file mode 100644
index 0000000000000000000000000000000000000000..7ea682d127904ffdc13775537db49ab60ffb483c
--- /dev/null
+++ b/lib/models/game/game.dart
@@ -0,0 +1,219 @@
+import 'package:wordguessing/config/default_game_settings.dart';
+import 'package:wordguessing/data/fetch_data_helper.dart';
+import 'package:wordguessing/models/data/word.dart';
+import 'package:wordguessing/models/settings/settings_game.dart';
+import 'package:wordguessing/models/settings/settings_global.dart';
+import 'package:wordguessing/utils/tools.dart';
+
+class Game {
+  Game({
+    // Settings
+    required this.gameSettings,
+    required this.globalSettings,
+
+    // State
+    this.isRunning = false,
+    this.isStarted = false,
+    this.isFinished = false,
+    this.animationInProgress = false,
+
+    // Base data
+    required this.word,
+    required this.otherWords,
+    required this.images,
+
+    // Game data
+    this.recentWordsKeys = const [],
+    this.questionsCount = 0,
+    this.goodAnswers = 0,
+    this.wrongAnswers = 0,
+  });
+
+  // Settings
+  final GameSettings gameSettings;
+  final GlobalSettings globalSettings;
+
+  // State
+  bool isRunning;
+  bool isStarted;
+  bool isFinished;
+  bool animationInProgress;
+
+  // Base data
+  Word word;
+  List<Word> otherWords;
+  List<Word> images;
+
+  // Game data
+  List<String> recentWordsKeys;
+  int questionsCount;
+  int goodAnswers;
+  int wrongAnswers;
+
+  factory Game.createEmpty() {
+    return Game(
+      // Settings
+      gameSettings: GameSettings.createDefault(),
+      globalSettings: GlobalSettings.createDefault(),
+      // Base data
+      word: Word.createEmpty(),
+      otherWords: [],
+      images: [],
+      // Game data
+      recentWordsKeys: [],
+    );
+  }
+
+  factory Game.createNew({
+    GameSettings? gameSettings,
+    GlobalSettings? globalSettings,
+  }) {
+    final GameSettings newGameSettings = gameSettings ?? GameSettings.createDefault();
+    final GlobalSettings newGlobalSettings = globalSettings ?? GlobalSettings.createDefault();
+
+    return Game(
+      // Settings
+      gameSettings: newGameSettings,
+      globalSettings: newGlobalSettings,
+      // State
+      isRunning: true,
+      // Base data
+      word: Word.createEmpty(),
+      otherWords: [],
+      images: [],
+      // Game data
+      recentWordsKeys: [],
+    );
+  }
+
+  bool get canBeResumed => isStarted && !isFinished;
+
+  bool get gameWon => isRunning && isStarted && isFinished;
+
+  void updateWord(Word newWord) {
+    word = newWord;
+    if (newWord.key != '') {
+      recentWordsKeys.insert(0, newWord.key);
+      recentWordsKeys = recentWordsKeys.take(DefaultGameSettings.recentWordsCount).toList();
+    }
+  }
+
+  void pickNewWord() {
+    switch (gameSettings.gameType) {
+      case DefaultGameSettings.gameTypeValuePickImage:
+        pickDataForGamePickImage();
+        break;
+      case DefaultGameSettings.gameTypeValuePickWord:
+        pickDataForGamePickWord();
+        break;
+      default:
+    }
+
+    questionsCount++;
+  }
+
+  bool isRecentlyPicked(String key) {
+    return recentWordsKeys.contains(key);
+  }
+
+  void pickDataForGamePickImage() {
+    Word word;
+
+    int attempts = 0;
+    do {
+      final List<Word> words = FetchDataHelper().getWords(
+        lang: gameSettings.lang,
+        count: DefaultGameSettings.itemsCount,
+      );
+
+      word = words.take(1).toList()[0];
+
+      if ((words.length == DefaultGameSettings.itemsCount) && !isRecentlyPicked(word.key)) {
+        updateWord(word);
+
+        final List<Word> pickedImages = [];
+        for (var element in words) {
+          pickedImages.add(element);
+        }
+
+        images = pickedImages;
+      }
+
+      attempts++;
+    } while (word != word && attempts < 10);
+  }
+
+  void pickDataForGamePickWord() {
+    Word word;
+
+    int attempts = 0;
+    do {
+      final List<Word> words = FetchDataHelper().getWords(
+        lang: gameSettings.lang,
+        count: DefaultGameSettings.itemsCount,
+      );
+
+      word = words.take(1).toList()[0];
+
+      if ((words.length >= DefaultGameSettings.itemsCount) && !isRecentlyPicked(word.key)) {
+        updateWord(word);
+        otherWords = words.skip(1).toList();
+        images = [word];
+      }
+
+      attempts++;
+    } while (word != word && attempts < 10);
+  }
+
+  void dump() {
+    printlog('');
+    printlog('## Current game dump:');
+    printlog('');
+    printlog('$Game:');
+    printlog('  Settings');
+    gameSettings.dump();
+    globalSettings.dump();
+    printlog('  State');
+    printlog('    isRunning: $isRunning');
+    printlog('    isStarted: $isStarted');
+    printlog('    isFinished: $isFinished');
+    printlog('    animationInProgress: $animationInProgress');
+    printlog('  Base data');
+    printlog('    word: $word');
+    printlog('    otherWords: $otherWords');
+    printlog('    images: $images');
+    printlog('  Game data');
+    printlog('    recentWordsKeys: $recentWordsKeys');
+    printlog('    questionsCount: $questionsCount');
+    printlog('    goodAnswers: $goodAnswers');
+    printlog('    wrongAnswers: $wrongAnswers');
+    printlog('');
+  }
+
+  @override
+  String toString() {
+    return '$Game(${toJson()})';
+  }
+
+  Map<String, dynamic>? toJson() {
+    return <String, dynamic>{
+      // Settings
+      'gameSettings': gameSettings.toJson(),
+      'globalSettings': globalSettings.toJson(),
+      // State
+      'isRunning': isRunning,
+      'isStarted': isStarted,
+      'isFinished': isFinished,
+      'animationInProgress': animationInProgress,
+      // Base data
+      'word': word.toJson(),
+      'otherWords': otherWords,
+      'images': images,
+      // Game data
+      'recentWordsKeys': recentWordsKeys,
+      'questionsCount': questionsCount,
+      'goodAnswers': goodAnswers,
+      'wrongAnswers': wrongAnswers,
+    };
+  }
+}
diff --git a/lib/models/settings/settings_game.dart b/lib/models/settings/settings_game.dart
new file mode 100644
index 0000000000000000000000000000000000000000..09272f47cdcfddeed9b532630d0f08bf2908536a
--- /dev/null
+++ b/lib/models/settings/settings_game.dart
@@ -0,0 +1,54 @@
+import 'package:wordguessing/config/default_game_settings.dart';
+import 'package:wordguessing/utils/tools.dart';
+
+class GameSettings {
+  final String gameType;
+  final String lang;
+
+  GameSettings({
+    required this.gameType,
+    required this.lang,
+  });
+
+  static String getGameTypeValueFromUnsafe(String gameType) {
+    if (DefaultGameSettings.allowedGameTypeValues.contains(gameType)) {
+      return gameType;
+    }
+
+    return DefaultGameSettings.defaultGameTypeValue;
+  }
+
+  static String getLangValueFromUnsafe(String lang) {
+    if (DefaultGameSettings.allowedLangValues.contains(lang)) {
+      return lang;
+    }
+
+    return DefaultGameSettings.defaultLangValue;
+  }
+
+  factory GameSettings.createDefault() {
+    return GameSettings(
+      gameType: DefaultGameSettings.defaultGameTypeValue,
+      lang: DefaultGameSettings.defaultLangValue,
+    );
+  }
+
+  void dump() {
+    printlog('$GameSettings:');
+    printlog('  ${DefaultGameSettings.parameterCodeGameType}: $gameType');
+    printlog('  ${DefaultGameSettings.parameterCodeLangValue}: $lang');
+    printlog('');
+  }
+
+  @override
+  String toString() {
+    return '$GameSettings(${toJson()})';
+  }
+
+  Map<String, dynamic>? toJson() {
+    return <String, dynamic>{
+      DefaultGameSettings.parameterCodeGameType: gameType,
+      DefaultGameSettings.parameterCodeLangValue: lang,
+    };
+  }
+}
diff --git a/lib/models/settings/settings_global.dart b/lib/models/settings/settings_global.dart
new file mode 100644
index 0000000000000000000000000000000000000000..3072b1fbfd8c910e290c84c37feab6242b7bfbaa
--- /dev/null
+++ b/lib/models/settings/settings_global.dart
@@ -0,0 +1,41 @@
+import 'package:wordguessing/config/default_global_settings.dart';
+import 'package:wordguessing/utils/tools.dart';
+
+class GlobalSettings {
+  String skin;
+
+  GlobalSettings({
+    required this.skin,
+  });
+
+  static String getSkinValueFromUnsafe(String skin) {
+    if (DefaultGlobalSettings.allowedSkinValues.contains(skin)) {
+      return skin;
+    }
+
+    return DefaultGlobalSettings.defaultSkinValue;
+  }
+
+  factory GlobalSettings.createDefault() {
+    return GlobalSettings(
+      skin: DefaultGlobalSettings.defaultSkinValue,
+    );
+  }
+
+  void dump() {
+    printlog('$GlobalSettings:');
+    printlog('  ${DefaultGlobalSettings.parameterCodeSkin}: $skin');
+    printlog('');
+  }
+
+  @override
+  String toString() {
+    return '$GlobalSettings(${toJson()})';
+  }
+
+  Map<String, dynamic>? toJson() {
+    return <String, dynamic>{
+      DefaultGlobalSettings.parameterCodeSkin: skin,
+    };
+  }
+}
diff --git a/lib/provider/data.dart b/lib/provider/data.dart
deleted file mode 100644
index 476ed718cdc77abe927802975ba9890cc9ff62a7..0000000000000000000000000000000000000000
--- a/lib/provider/data.dart
+++ /dev/null
@@ -1,105 +0,0 @@
-import 'package:flutter/foundation.dart';
-
-import 'package:wordguessing/models/word.dart';
-
-enum GameType { pickWord, pickImage }
-
-class Data extends ChangeNotifier {
-  GameType? _gameType;
-
-  // Language
-  String _lang = '';
-
-  // randomization
-  Word? _word;
-  List<Word> _otherWords = [];
-  List<Word> _images = [];
-  final int _recentWordsCount = 20;
-  List<String> _recentWordsKeys = [];
-
-  // game data
-  int _questionsCount = 0;
-  int _goodAnswers = 0;
-  int _wrongAnswers = 0;
-
-  GameType? get gameType => _gameType;
-
-  void updateGameType(GameType gameType) {
-    _gameType = gameType;
-    notifyListeners();
-  }
-
-  void resetGameType() {
-    _gameType = null;
-    notifyListeners();
-  }
-
-  String get lang => _lang;
-
-  void updateLang(String value) {
-    _lang = value;
-    notifyListeners();
-  }
-
-  Word? get word => _word;
-
-  void updateWord(Word? newWord) {
-    _word = newWord;
-    if ((newWord != null) && (newWord.key != '')) {
-      _recentWordsKeys.insert(0, newWord.key);
-      _recentWordsKeys = _recentWordsKeys.take(_recentWordsCount).toList();
-    }
-    notifyListeners();
-  }
-
-  bool isRecentlyPicked(String word) {
-    return _recentWordsKeys.contains(word);
-  }
-
-  List<Word> get otherWords => _otherWords;
-
-  void updateOtherWords(List<Word> words) {
-    _otherWords = words;
-    notifyListeners();
-  }
-
-  List<Word> get images => _images;
-
-  void updateImages(List<Word> images) {
-    _images = images;
-    notifyListeners();
-  }
-
-  void resetGame() {
-    resetGameType();
-    updateLang('');
-    updateQuestionsCount(0);
-    updateGoodAnswers(0);
-    updateWrongAnswers(0);
-    updateWord(null);
-    updateOtherWords([]);
-    updateImages([]);
-    notifyListeners();
-  }
-
-  int get questionsCount => _questionsCount;
-
-  void updateQuestionsCount(int value) {
-    _questionsCount = value;
-    notifyListeners();
-  }
-
-  int get goodAnswers => _goodAnswers;
-
-  void updateGoodAnswers(int value) {
-    _goodAnswers = value;
-    notifyListeners();
-  }
-
-  int get wrongAnswers => _wrongAnswers;
-
-  void updateWrongAnswers(int value) {
-    _wrongAnswers = value;
-    notifyListeners();
-  }
-}
diff --git a/lib/ui/game/game_end.dart b/lib/ui/game/game_end.dart
new file mode 100644
index 0000000000000000000000000000000000000000..f760ccf5ec901b0fce95c33378004ef401c01ab2
--- /dev/null
+++ b/lib/ui/game/game_end.dart
@@ -0,0 +1,52 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:wordguessing/cubit/game_cubit.dart';
+import 'package:wordguessing/models/game/game.dart';
+import 'package:wordguessing/ui/widgets/actions/button_game_quit.dart';
+
+class GameEndWidget extends StatelessWidget {
+  const GameEndWidget({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return BlocBuilder<GameCubit, GameState>(
+      builder: (BuildContext context, GameState gameState) {
+        final Game currentGame = gameState.currentGame;
+
+        final Image decorationImage = Image(
+          image: AssetImage(
+              currentGame.gameWon ? 'assets/ui/game_win.png' : 'assets/ui/game_fail.png'),
+          fit: BoxFit.fill,
+        );
+
+        return Container(
+          margin: const EdgeInsets.all(2),
+          padding: const EdgeInsets.all(2),
+          child: Table(
+            defaultColumnWidth: const IntrinsicColumnWidth(),
+            children: [
+              TableRow(
+                children: [
+                  Column(
+                    children: [decorationImage],
+                  ),
+                  Column(
+                    children: [
+                      currentGame.animationInProgress == true
+                          ? decorationImage
+                          : const QuitGameButton()
+                    ],
+                  ),
+                  Column(
+                    children: [decorationImage],
+                  ),
+                ],
+              ),
+            ],
+          ),
+        );
+      },
+    );
+  }
+}
diff --git a/lib/ui/game/game_top.dart b/lib/ui/game/game_top.dart
new file mode 100644
index 0000000000000000000000000000000000000000..480f5c760751067cc0e3ee8e997620634ada7ef8
--- /dev/null
+++ b/lib/ui/game/game_top.dart
@@ -0,0 +1,12 @@
+import 'package:flutter/material.dart';
+
+import 'package:wordguessing/ui/widgets/game/score_bar.dart';
+
+class GameTopWidget extends StatelessWidget {
+  const GameTopWidget({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return const ScoreBarWidget();
+  }
+}
diff --git a/lib/ui/games/abstract_game.dart b/lib/ui/games/abstract_game.dart
deleted file mode 100644
index 84b45fea06b7002bd172d0961f5706dd02470aab..0000000000000000000000000000000000000000
--- a/lib/ui/games/abstract_game.dart
+++ /dev/null
@@ -1,163 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:provider/provider.dart';
-
-import 'package:wordguessing/provider/data.dart';
-
-class GameAbstract extends StatelessWidget {
-  const GameAbstract({super.key});
-
-  final int countWords = 4;
-
-  void startGame(Data myProvider, String lang) {
-    myProvider.updateLang(lang);
-    nextWord(myProvider);
-  }
-
-  void nextWord(Data myProvider) {
-    pickData(myProvider);
-    myProvider.updateQuestionsCount(myProvider.questionsCount + 1);
-  }
-
-  void pickData(Data myProvider) {}
-
-  void checkWord(Data myProvider, word) {
-    if (myProvider.word?.key == word.key) {
-      myProvider.updateGoodAnswers(myProvider.goodAnswers + 1);
-      nextWord(myProvider);
-    } else {
-      myProvider.updateWrongAnswers(myProvider.wrongAnswers + 1);
-    }
-  }
-
-  Widget buildScoreItemContainer(String text, Color blockColor) {
-    // Darken block color to get border color
-    const double amount = 0.2;
-    final hsl = HSLColor.fromColor(blockColor);
-    final hslDark = hsl.withLightness((hsl.lightness - amount).clamp(0.0, 1.0));
-    final Color borderColor = hslDark.toColor();
-
-    return Container(
-      margin: const EdgeInsets.symmetric(horizontal: 15),
-      padding: const EdgeInsets.all(5),
-      decoration: BoxDecoration(
-        color: blockColor,
-        borderRadius: BorderRadius.circular(4),
-        border: Border.all(
-          color: borderColor,
-          width: 4,
-        ),
-      ),
-      child: Text(
-        text,
-        style: const TextStyle(
-          fontSize: 25,
-          fontWeight: FontWeight.w600,
-          color: Colors.black,
-        ),
-      ),
-    );
-  }
-
-  String getGoodAnswersString(Data myProvider) {
-    final int count = myProvider.questionsCount - 1;
-    return '👍 ${myProvider.goodAnswers}/$count';
-  }
-
-  String getWrongAnswersString(Data myProvider) {
-    final int count = myProvider.questionsCount - 1;
-    return '🚩 ${myProvider.wrongAnswers}/$count';
-  }
-
-  Widget buildScoreContainer(Data myProvider) {
-    return Container(
-      padding: const EdgeInsets.all(5),
-      child: Row(
-        mainAxisSize: MainAxisSize.min,
-        mainAxisAlignment: MainAxisAlignment.center,
-        children: [
-          buildScoreItemContainer(
-            getGoodAnswersString(myProvider),
-            Colors.green,
-          ),
-          const SizedBox(width: 20),
-          buildScoreItemContainer(
-            getWrongAnswersString(myProvider),
-            Colors.orange,
-          ),
-        ],
-      ),
-    );
-  }
-
-  Widget buildStartGameBlock(Data myProvider) {
-    return Column(
-      mainAxisSize: MainAxisSize.min,
-      mainAxisAlignment: MainAxisAlignment.center,
-      children: [
-        ElevatedButton(
-          style: ElevatedButton.styleFrom(
-            foregroundColor: Colors.teal,
-            backgroundColor: Colors.teal,
-            padding: const EdgeInsets.all(35),
-          ),
-          child: const Text(
-            "🇫🇷",
-            style: TextStyle(
-              fontSize: 60,
-              color: Colors.black,
-            ),
-          ),
-          onPressed: () => startGame(myProvider, 'fr'),
-        ),
-        const SizedBox(height: 15),
-        ElevatedButton(
-          style: ElevatedButton.styleFrom(
-            foregroundColor: Colors.teal,
-            backgroundColor: Colors.teal,
-            padding: const EdgeInsets.all(35),
-          ),
-          child: const Text(
-            "🇬🇧",
-            style: TextStyle(
-              fontSize: 60,
-              color: Colors.black,
-            ),
-          ),
-          onPressed: () => startGame(myProvider, 'en'),
-        ),
-      ],
-    );
-  }
-
-  List<Widget> buildPageContent(Data myProvider) {
-    return <Widget>[];
-  }
-
-  Widget buildPage(BuildContext context) {
-    final Data myProvider = Provider.of<Data>(context);
-
-    return SizedBox.expand(
-      child: FittedBox(
-        fit: BoxFit.contain,
-        alignment: Alignment.center,
-        child: SizedBox(
-          height: (MediaQuery.of(context).size.height),
-          width: (MediaQuery.of(context).size.width),
-          child: Center(
-            child: Column(
-              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
-              crossAxisAlignment: CrossAxisAlignment.center,
-              mainAxisSize: MainAxisSize.max,
-              children: buildPageContent(myProvider),
-            ),
-          ),
-        ),
-      ),
-    );
-  }
-
-  @override
-  Widget build(BuildContext context) {
-    return buildPage(context);
-  }
-}
diff --git a/lib/ui/games/game_pick_image.dart b/lib/ui/games/game_pick_image.dart
deleted file mode 100644
index d6530fedf2135302714699817da9fa3d130435b5..0000000000000000000000000000000000000000
--- a/lib/ui/games/game_pick_image.dart
+++ /dev/null
@@ -1,142 +0,0 @@
-import 'package:flutter/material.dart';
-
-import 'package:wordguessing/data/fetch_data_helper.dart';
-import 'package:wordguessing/models/word.dart';
-import 'package:wordguessing/provider/data.dart';
-import 'package:wordguessing/ui/games/abstract_game.dart';
-
-class GamePickImagePage extends GameAbstract {
-  const GamePickImagePage({super.key});
-
-  @override
-  pickData(Data myProvider) {
-    Word word;
-
-    int attempts = 0;
-    do {
-      final List<Word> words = FetchDataHelper().getWords(myProvider.lang, countWords);
-
-      word = words.take(1).toList()[0];
-
-      if ((words.length == countWords) && !myProvider.isRecentlyPicked(word.key)) {
-        myProvider.updateWord(word);
-
-        final List<Word> images = [];
-        for (var element in words) {
-          images.add(element);
-        }
-
-        myProvider.updateImages(images);
-      }
-
-      attempts++;
-    } while (myProvider.word != word && attempts < 10);
-  }
-
-  Widget buildImageContainer(Data myProvider, Word word) {
-    const double imageSize = 130;
-
-    String imageAsset = 'assets/placeholder.png';
-    if ((word.images.isNotEmpty)) {
-      imageAsset = 'assets/images/${word.images[0]}';
-    }
-
-    return TextButton(
-      child: Container(
-        decoration: BoxDecoration(
-          borderRadius: BorderRadius.circular(8),
-          border: Border.all(
-            color: Colors.blue.shade200,
-            width: 8,
-          ),
-        ),
-        margin: const EdgeInsets.all(2),
-        child: Image(
-          image: AssetImage(imageAsset),
-          width: imageSize,
-          height: imageSize,
-          fit: BoxFit.fill,
-        ),
-      ),
-      onPressed: () {
-        checkWord(myProvider, word);
-      },
-    );
-  }
-
-  Widget buildImageItemsBlock(Data myProvider) {
-    final List<Word> images = myProvider.images;
-
-    if (images.length != countWords) {
-      return const SizedBox.shrink();
-    }
-
-    images.sort((a, b) => a.key.compareTo(b.key));
-
-    return Column(
-      mainAxisSize: MainAxisSize.min,
-      mainAxisAlignment: MainAxisAlignment.center,
-      children: [
-        Row(
-          mainAxisSize: MainAxisSize.min,
-          mainAxisAlignment: MainAxisAlignment.center,
-          children: [
-            buildImageContainer(myProvider, images[0]),
-            buildImageContainer(myProvider, images[1]),
-          ],
-        ),
-        Row(
-          mainAxisSize: MainAxisSize.min,
-          mainAxisAlignment: MainAxisAlignment.center,
-          children: [
-            buildImageContainer(myProvider, images[2]),
-            buildImageContainer(myProvider, images[3]),
-          ],
-        )
-      ],
-    );
-  }
-
-  Widget buildTextItemBlock(Data myProvider) {
-    final Word? word = myProvider.word;
-
-    if (word == null) {
-      return const SizedBox.shrink();
-    }
-
-    return Container(
-      decoration: BoxDecoration(
-        color: Colors.blue.shade800,
-        borderRadius: BorderRadius.circular(6),
-        border: Border.all(
-          color: Colors.white,
-          width: 6,
-        ),
-      ),
-      child: Padding(
-        padding: const EdgeInsets.all(12),
-        child: Text(
-          word.text,
-          style: const TextStyle(
-            fontSize: 30,
-            fontWeight: FontWeight.w600,
-            color: Colors.white,
-          ),
-        ),
-      ),
-    );
-  }
-
-  @override
-  List<Widget> buildPageContent(Data myProvider) {
-    return <Widget>[
-      buildTextItemBlock(myProvider),
-      const SizedBox(height: 2),
-      ((myProvider.word == null) || (myProvider.word?.key == ''))
-          ? buildStartGameBlock(myProvider)
-          : buildScoreContainer(myProvider),
-      const SizedBox(height: 2),
-      buildImageItemsBlock(myProvider),
-    ];
-  }
-}
diff --git a/lib/ui/games/game_pick_word.dart b/lib/ui/games/game_pick_word.dart
deleted file mode 100644
index 6d68235c7195d41cf2c1fb1db4451f83007c12ea..0000000000000000000000000000000000000000
--- a/lib/ui/games/game_pick_word.dart
+++ /dev/null
@@ -1,170 +0,0 @@
-import 'package:flutter/material.dart';
-
-import 'package:wordguessing/data/fetch_data_helper.dart';
-import 'package:wordguessing/models/word.dart';
-import 'package:wordguessing/provider/data.dart';
-import 'package:wordguessing/ui/games/abstract_game.dart';
-
-class GamePickWordPage extends GameAbstract {
-  const GamePickWordPage({super.key});
-
-  @override
-  void pickData(Data myProvider) {
-    Word word;
-
-    int attempts = 0;
-    do {
-      final List<Word> words = FetchDataHelper().getWords(myProvider.lang, countWords);
-
-      word = words.take(1).toList()[0];
-
-      if ((words.length >= countWords) && !myProvider.isRecentlyPicked(word.key)) {
-        myProvider.updateWord(word);
-        myProvider.updateOtherWords(words.skip(1).toList());
-        myProvider.updateImages([word]);
-      }
-
-      attempts++;
-    } while (myProvider.word != word && attempts < 10);
-  }
-
-  Widget buildImageContainer(String image) {
-    const double imageSize = 130;
-
-    String imageAsset = 'assets/placeholder.png';
-    if (image != '') {
-      imageAsset = 'assets/images/$image';
-    }
-
-    return Container(
-      margin: const EdgeInsets.all(2),
-      decoration: BoxDecoration(
-        borderRadius: BorderRadius.circular(8),
-        border: Border.all(
-          color: Colors.blue.shade200,
-          width: 8,
-        ),
-      ),
-      child: Image(
-        image: AssetImage(imageAsset),
-        width: imageSize,
-        height: imageSize,
-        fit: BoxFit.fill,
-      ),
-    );
-  }
-
-  Widget buildImageItemsBlock(Word? currentWord) {
-    return Column(
-      mainAxisSize: MainAxisSize.min,
-      mainAxisAlignment: MainAxisAlignment.center,
-      children: [
-        Row(
-          mainAxisSize: MainAxisSize.min,
-          mainAxisAlignment: MainAxisAlignment.center,
-          children: [
-            buildImageContainer(currentWord?.images[0] ?? ''),
-            buildImageContainer(currentWord?.images[1] ?? ''),
-          ],
-        ),
-        Row(
-          mainAxisSize: MainAxisSize.min,
-          mainAxisAlignment: MainAxisAlignment.center,
-          children: [
-            buildImageContainer(currentWord?.images[2] ?? ''),
-            buildImageContainer(currentWord?.images[3] ?? ''),
-          ],
-        )
-      ],
-    );
-  }
-
-  Widget buildTextContainer(Data myProvider, Word word) {
-    return Container(
-      margin: const EdgeInsets.all(2),
-      decoration: BoxDecoration(
-        color: Colors.blue[800],
-        borderRadius: BorderRadius.circular(6),
-        border: Border.all(
-          color: Colors.white,
-          width: 6,
-        ),
-      ),
-      child: TextButton(
-        style: TextButton.styleFrom(
-          padding: const EdgeInsets.all(15),
-        ),
-        child: Text(
-          word.text,
-          style: const TextStyle(
-            fontSize: 20,
-            fontWeight: FontWeight.w600,
-            color: Colors.white,
-          ),
-        ),
-        onPressed: () {
-          checkWord(myProvider, word);
-        },
-      ),
-    );
-  }
-
-  Widget buildTextItemsBlock(Data myProvider) {
-    Word? word = myProvider.word;
-    List<Word> otherWords = myProvider.otherWords;
-
-    if ((word == null) || (otherWords.length != (countWords - 1))) {
-      return const Column();
-    }
-
-    List<Word> words = [
-      word,
-      otherWords[0],
-      otherWords[1],
-      otherWords[2],
-    ];
-
-    words.sort((a, b) => a.key.compareTo(b.key));
-
-    return Column(
-      mainAxisSize: MainAxisSize.min,
-      mainAxisAlignment: MainAxisAlignment.center,
-      children: [
-        Row(
-          mainAxisSize: MainAxisSize.min,
-          mainAxisAlignment: MainAxisAlignment.center,
-          children: [
-            buildTextContainer(myProvider, words[0]),
-            const SizedBox(width: 10),
-            buildTextContainer(myProvider, words[1]),
-          ],
-        ),
-        const SizedBox(height: 5),
-        Row(
-          mainAxisSize: MainAxisSize.min,
-          mainAxisAlignment: MainAxisAlignment.center,
-          children: [
-            buildTextContainer(myProvider, words[2]),
-            const SizedBox(width: 10),
-            buildTextContainer(myProvider, words[3]),
-          ],
-        )
-      ],
-    );
-  }
-
-  @override
-  List<Widget> buildPageContent(Data myProvider) {
-    return <Widget>[
-      (myProvider.images.isNotEmpty)
-          ? buildImageItemsBlock(myProvider.images[0])
-          : const SizedBox.shrink(),
-      const SizedBox(height: 2),
-      ((myProvider.word == null) || (myProvider.word?.key == ''))
-          ? buildStartGameBlock(myProvider)
-          : buildScoreContainer(myProvider),
-      const SizedBox(height: 2),
-      buildTextItemsBlock(myProvider),
-    ];
-  }
-}
diff --git a/lib/ui/games/game_selector.dart b/lib/ui/games/game_selector.dart
deleted file mode 100644
index 882d9521f02c8d42368f1b51d34456b50465ff6a..0000000000000000000000000000000000000000
--- a/lib/ui/games/game_selector.dart
+++ /dev/null
@@ -1,64 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:provider/provider.dart';
-
-import 'package:wordguessing/provider/data.dart';
-
-class GameSelector extends StatelessWidget {
-  const GameSelector({super.key});
-
-  @override
-  Widget build(BuildContext context) {
-    final Data myProvider = Provider.of<Data>(context);
-
-    Widget buildMenuItemContainer(String code, Color color) {
-      const double imageSize = 150;
-
-      final String imageAsset = 'assets/menu/$code.png';
-
-      return Container(
-        margin: const EdgeInsets.all(2),
-        decoration: BoxDecoration(
-          borderRadius: BorderRadius.circular(8),
-          border: Border.all(
-            color: color,
-            width: 12,
-          ),
-        ),
-        child: GestureDetector(
-          child: Image(
-            image: AssetImage(imageAsset),
-            width: imageSize,
-            height: imageSize,
-            fit: BoxFit.fill,
-          ),
-          onTap: () {
-            myProvider.resetGame();
-            switch (code) {
-              case 'game-pick-word':
-                myProvider.updateGameType(GameType.pickWord);
-                break;
-              case 'game-pick-image':
-                myProvider.updateGameType(GameType.pickImage);
-                break;
-              default:
-            }
-          },
-        ),
-      );
-    }
-
-    Widget content = Center(
-      child: Column(
-        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
-        crossAxisAlignment: CrossAxisAlignment.center,
-        mainAxisSize: MainAxisSize.max,
-        children: <Widget>[
-          buildMenuItemContainer('game-pick-word', Colors.pink),
-          buildMenuItemContainer('game-pick-image', Colors.yellow),
-        ],
-      ),
-    );
-
-    return content;
-  }
-}
diff --git a/lib/ui/helpers/app_titles.dart b/lib/ui/helpers/app_titles.dart
new file mode 100644
index 0000000000000000000000000000000000000000..b98107b12fabc3114ebfbec994166b588abcf1ad
--- /dev/null
+++ b/lib/ui/helpers/app_titles.dart
@@ -0,0 +1,32 @@
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+
+class AppHeader extends StatelessWidget {
+  const AppHeader({super.key, required this.text});
+
+  final String text;
+
+  @override
+  Widget build(BuildContext context) {
+    return Text(
+      tr(text),
+      textAlign: TextAlign.start,
+      style: Theme.of(context).textTheme.headlineMedium!.apply(fontWeightDelta: 2),
+    );
+  }
+}
+
+class AppTitle extends StatelessWidget {
+  const AppTitle({super.key, required this.text});
+
+  final String text;
+
+  @override
+  Widget build(BuildContext context) {
+    return Text(
+      tr(text),
+      textAlign: TextAlign.start,
+      style: Theme.of(context).textTheme.titleLarge!.apply(fontWeightDelta: 2),
+    );
+  }
+}
diff --git a/lib/ui/helpers/outlined_text_widget.dart b/lib/ui/helpers/outlined_text_widget.dart
new file mode 100644
index 0000000000000000000000000000000000000000..bcc628aff9437c9e448df828c763a2e6c1a565d5
--- /dev/null
+++ b/lib/ui/helpers/outlined_text_widget.dart
@@ -0,0 +1,51 @@
+import 'package:flutter/material.dart';
+
+import 'package:wordguessing/utils/color_extensions.dart';
+
+class OutlinedText extends StatelessWidget {
+  const OutlinedText({
+    super.key,
+    required this.text,
+    required this.fontSize,
+    required this.textColor,
+    this.outlineColor,
+  });
+
+  final String text;
+  final double fontSize;
+  final Color textColor;
+  final Color? outlineColor;
+
+  @override
+  Widget build(BuildContext context) {
+    final double delta = fontSize / 30;
+
+    return Text(
+      text,
+      style: TextStyle(
+        inherit: true,
+        fontSize: fontSize,
+        fontWeight: FontWeight.w600,
+        color: textColor,
+        shadows: [
+          Shadow(
+            offset: Offset(-delta, -delta),
+            color: outlineColor ?? textColor.darken(),
+          ),
+          Shadow(
+            offset: Offset(delta, -delta),
+            color: outlineColor ?? textColor.darken(),
+          ),
+          Shadow(
+            offset: Offset(delta, delta),
+            color: outlineColor ?? textColor.darken(),
+          ),
+          Shadow(
+            offset: Offset(-delta, delta),
+            color: outlineColor ?? textColor.darken(),
+          ),
+        ],
+      ),
+    );
+  }
+}
diff --git a/lib/ui/layouts/game_layout.dart b/lib/ui/layouts/game_layout.dart
new file mode 100644
index 0000000000000000000000000000000000000000..e4db92c4e0e71c32e8c60ceeb2fe0b3d538a7b97
--- /dev/null
+++ b/lib/ui/layouts/game_layout.dart
@@ -0,0 +1,37 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:wordguessing/cubit/game_cubit.dart';
+import 'package:wordguessing/models/game/game.dart';
+import 'package:wordguessing/ui/game/game_end.dart';
+import 'package:wordguessing/ui/game/game_top.dart';
+import 'package:wordguessing/ui/widgets/game/game_board.dart';
+
+class GameLayout extends StatelessWidget {
+  const GameLayout({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return BlocBuilder<GameCubit, GameState>(
+      builder: (BuildContext context, GameState gameState) {
+        final Game currentGame = gameState.currentGame;
+
+        return Container(
+          alignment: AlignmentDirectional.topCenter,
+          padding: const EdgeInsets.all(4),
+          child: Column(
+            mainAxisAlignment: MainAxisAlignment.start,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              const GameTopWidget(),
+              const SizedBox(height: 8),
+              const GameBoardWidget(),
+              const Expanded(child: SizedBox.shrink()),
+              currentGame.isFinished ? const GameEndWidget() : const SizedBox.shrink(),
+            ],
+          ),
+        );
+      },
+    );
+  }
+}
diff --git a/lib/ui/layouts/parameters_layout.dart b/lib/ui/layouts/parameters_layout.dart
new file mode 100644
index 0000000000000000000000000000000000000000..ff114f36908b371bdd9be1721a844c2be3f6764d
--- /dev/null
+++ b/lib/ui/layouts/parameters_layout.dart
@@ -0,0 +1,154 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:wordguessing/config/default_game_settings.dart';
+import 'package:wordguessing/config/default_global_settings.dart';
+import 'package:wordguessing/cubit/settings_game_cubit.dart';
+import 'package:wordguessing/cubit/settings_global_cubit.dart';
+import 'package:wordguessing/ui/parameters/parameter_image.dart';
+import 'package:wordguessing/ui/parameters/parameter_painter.dart';
+import 'package:wordguessing/ui/widgets/actions/button_delete_saved_game.dart';
+import 'package:wordguessing/ui/widgets/actions/button_game_start_new.dart';
+import 'package:wordguessing/ui/widgets/actions/button_resume_saved_game.dart';
+
+class ParametersLayout extends StatelessWidget {
+  const ParametersLayout({super.key, required this.canResume});
+
+  final bool canResume;
+
+  final double separatorHeight = 8.0;
+
+  @override
+  Widget build(BuildContext context) {
+    final List<Widget> lines = [];
+
+    // Game settings
+    for (String code in DefaultGameSettings.availableParameters) {
+      lines.add(Row(
+        mainAxisAlignment: MainAxisAlignment.spaceBetween,
+        children: buildParametersLine(
+          code: code,
+          isGlobal: false,
+        ),
+      ));
+
+      lines.add(SizedBox(height: separatorHeight));
+    }
+
+    lines.add(SizedBox(height: separatorHeight));
+
+    if (canResume == false) {
+      // Start new game
+      lines.add(const Expanded(
+        child: StartNewGameButton(),
+      ));
+    } else {
+      // Resume game
+      lines.add(const Expanded(
+        child: ResumeSavedGameButton(),
+      ));
+      // Delete saved game
+      lines.add(SizedBox.square(
+        dimension: MediaQuery.of(context).size.width / 4,
+        child: const DeleteSavedGameButton(),
+      ));
+    }
+
+    lines.add(SizedBox(height: separatorHeight));
+
+    // Global settings
+    for (String code in DefaultGlobalSettings.availableParameters) {
+      lines.add(Row(
+        mainAxisAlignment: MainAxisAlignment.spaceBetween,
+        children: buildParametersLine(
+          code: code,
+          isGlobal: true,
+        ),
+      ));
+
+      lines.add(SizedBox(height: separatorHeight));
+    }
+
+    return Column(
+      children: lines,
+    );
+  }
+
+  List<Widget> buildParametersLine({
+    required String code,
+    required bool isGlobal,
+  }) {
+    final List<Widget> parameterButtons = [];
+
+    final List<String> availableValues = isGlobal
+        ? DefaultGlobalSettings.getAvailableValues(code)
+        : DefaultGameSettings.getAvailableValues(code);
+
+    if (availableValues.length <= 1) {
+      return [];
+    }
+
+    for (String value in availableValues) {
+      final Widget parameterButton = BlocBuilder<GameSettingsCubit, GameSettingsState>(
+        builder: (BuildContext context, GameSettingsState gameSettingsState) {
+          return BlocBuilder<GlobalSettingsCubit, GlobalSettingsState>(
+            builder: (BuildContext context, GlobalSettingsState globalSettingsState) {
+              final GameSettingsCubit gameSettingsCubit =
+                  BlocProvider.of<GameSettingsCubit>(context);
+              final GlobalSettingsCubit globalSettingsCubit =
+                  BlocProvider.of<GlobalSettingsCubit>(context);
+
+              final String currentValue = isGlobal
+                  ? globalSettingsCubit.getParameterValue(code)
+                  : gameSettingsCubit.getParameterValue(code);
+
+              final bool isActive = (value == currentValue);
+
+              final double displayWidth = MediaQuery.of(context).size.width;
+              final double itemWidth = displayWidth / availableValues.length - 26;
+
+              final bool displayedWithAssets =
+                  DefaultGlobalSettings.displayedWithAssets.contains(code) ||
+                      DefaultGameSettings.displayedWithAssets.contains(code);
+
+              return TextButton(
+                child: Container(
+                  child: displayedWithAssets
+                      ? SizedBox.square(
+                          dimension: itemWidth,
+                          child: ParameterImage(
+                            code: code,
+                            value: value,
+                            isSelected: isActive,
+                          ),
+                        )
+                      : CustomPaint(
+                          size: Size(itemWidth, itemWidth),
+                          willChange: false,
+                          painter: ParameterPainter(
+                            code: code,
+                            value: value,
+                            isSelected: isActive,
+                            gameSettings: gameSettingsState.settings,
+                            globalSettings: globalSettingsState.settings,
+                          ),
+                          isComplex: true,
+                        ),
+                ),
+                onPressed: () {
+                  isGlobal
+                      ? globalSettingsCubit.setParameterValue(code, value)
+                      : gameSettingsCubit.setParameterValue(code, value);
+                },
+              );
+            },
+          );
+        },
+      );
+
+      parameterButtons.add(parameterButton);
+    }
+
+    return parameterButtons;
+  }
+}
diff --git a/lib/ui/parameters/parameter_image.dart b/lib/ui/parameters/parameter_image.dart
new file mode 100644
index 0000000000000000000000000000000000000000..fc4b576f85b01158b74548400d11a4d027c57fbe
--- /dev/null
+++ b/lib/ui/parameters/parameter_image.dart
@@ -0,0 +1,38 @@
+import 'package:flutter/material.dart';
+
+class ParameterImage extends StatelessWidget {
+  const ParameterImage({
+    super.key,
+    required this.code,
+    required this.value,
+    required this.isSelected,
+  });
+
+  final String code;
+  final String value;
+  final bool isSelected;
+
+  static const Color buttonBackgroundColor = Colors.white;
+  static const Color buttonBorderColorActive = Colors.blue;
+  static const Color buttonBorderColorInactive = Colors.white;
+  static const double buttonBorderWidth = 8.0;
+  static const double buttonBorderRadius = 8.0;
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      decoration: BoxDecoration(
+        color: buttonBackgroundColor,
+        borderRadius: BorderRadius.circular(buttonBorderRadius),
+        border: Border.all(
+          color: isSelected ? buttonBorderColorActive : buttonBorderColorInactive,
+          width: buttonBorderWidth,
+        ),
+      ),
+      child: Image(
+        image: AssetImage('assets/ui/${code}_$value.png'),
+        fit: BoxFit.fill,
+      ),
+    );
+  }
+}
diff --git a/lib/ui/parameters/parameter_painter.dart b/lib/ui/parameters/parameter_painter.dart
new file mode 100644
index 0000000000000000000000000000000000000000..9fe8daed2b2b33dff467d21e9cdf4404ae3167db
--- /dev/null
+++ b/lib/ui/parameters/parameter_painter.dart
@@ -0,0 +1,148 @@
+import 'dart:math';
+
+import 'package:flutter/material.dart';
+
+import 'package:wordguessing/config/default_game_settings.dart';
+import 'package:wordguessing/models/settings/settings_game.dart';
+import 'package:wordguessing/models/settings/settings_global.dart';
+import 'package:wordguessing/utils/tools.dart';
+
+class ParameterPainter extends CustomPainter {
+  const ParameterPainter({
+    required this.code,
+    required this.value,
+    required this.isSelected,
+    required this.gameSettings,
+    required this.globalSettings,
+  });
+
+  final String code;
+  final String value;
+  final bool isSelected;
+  final GameSettings gameSettings;
+  final GlobalSettings globalSettings;
+
+  @override
+  void paint(Canvas canvas, Size size) {
+    // force square
+    final double canvasSize = min(size.width, size.height);
+
+    const Color borderColorEnabled = Colors.blue;
+    const Color borderColorDisabled = Colors.white;
+
+    // "enabled/disabled" border
+    final paint = Paint();
+    paint.style = PaintingStyle.stroke;
+    paint.color = isSelected ? borderColorEnabled : borderColorDisabled;
+    paint.strokeJoin = StrokeJoin.round;
+    paint.strokeWidth = 10;
+    canvas.drawRect(
+        Rect.fromPoints(const Offset(0, 0), Offset(canvasSize, canvasSize)), paint);
+
+    // content
+    switch (code) {
+      case DefaultGameSettings.parameterCodeLangValue:
+        paintLangParameterItem(value, canvas, canvasSize);
+        break;
+      default:
+        printlog('Unknown parameter: $code/$value');
+        paintUnknownParameterItem(value, canvas, canvasSize);
+    }
+  }
+
+  @override
+  bool shouldRepaint(CustomPainter oldDelegate) {
+    return false;
+  }
+
+  // "unknown" parameter -> simple block with text
+  void paintUnknownParameterItem(
+    final String value,
+    final Canvas canvas,
+    final double size,
+  ) {
+    final paint = Paint();
+    paint.strokeJoin = StrokeJoin.round;
+    paint.strokeWidth = 3;
+
+    paint.color = Colors.grey;
+    paint.style = PaintingStyle.fill;
+    canvas.drawRect(Rect.fromPoints(const Offset(0, 0), Offset(size, size)), paint);
+
+    final textSpan = TextSpan(
+      text: '?\n$value',
+      style: const TextStyle(
+        color: Colors.black,
+        fontSize: 18,
+        fontWeight: FontWeight.bold,
+      ),
+    );
+    final textPainter = TextPainter(
+      text: textSpan,
+      textDirection: TextDirection.ltr,
+      textAlign: TextAlign.center,
+    );
+    textPainter.layout();
+    textPainter.paint(
+      canvas,
+      Offset(
+        (size - textPainter.width) * 0.5,
+        (size - textPainter.height) * 0.5,
+      ),
+    );
+  }
+
+  void paintLangParameterItem(
+    final String value,
+    final Canvas canvas,
+    final double size,
+  ) {
+    Color backgroundColor = Colors.grey;
+    String text = '';
+
+    switch (value) {
+      case DefaultGameSettings.langValueFr:
+        text = '🇫🇷';
+        backgroundColor = Colors.teal;
+        break;
+      case DefaultGameSettings.langValueEn:
+        text = '🇬🇧';
+        backgroundColor = Colors.teal;
+        break;
+      default:
+        printlog('Wrong value for lang parameter value: $value');
+    }
+
+    final paint = Paint();
+    paint.strokeJoin = StrokeJoin.round;
+    paint.strokeWidth = 3;
+
+    // Colored background
+    paint.color = backgroundColor;
+    paint.style = PaintingStyle.fill;
+    canvas.drawRect(Rect.fromPoints(const Offset(0, 0), Offset(size, size)), paint);
+
+    // centered text value
+    final textSpan = TextSpan(
+      text: text,
+      style: TextStyle(
+        color: Colors.black,
+        fontSize: size / 2.6,
+        fontWeight: FontWeight.bold,
+      ),
+    );
+    final textPainter = TextPainter(
+      text: textSpan,
+      textDirection: TextDirection.ltr,
+      textAlign: TextAlign.center,
+    );
+    textPainter.layout();
+    textPainter.paint(
+      canvas,
+      Offset(
+        (size - textPainter.width) * 0.5,
+        (size - textPainter.height) * 0.5,
+      ),
+    );
+  }
+}
diff --git a/lib/ui/screens/game_page.dart b/lib/ui/screens/game_page.dart
deleted file mode 100644
index df3c84376e9d37a3040d09e0665f19d3abca2165..0000000000000000000000000000000000000000
--- a/lib/ui/screens/game_page.dart
+++ /dev/null
@@ -1,25 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:provider/provider.dart';
-
-import 'package:wordguessing/provider/data.dart';
-import 'package:wordguessing/ui/games/game_pick_image.dart';
-import 'package:wordguessing/ui/games/game_pick_word.dart';
-import 'package:wordguessing/ui/games/game_selector.dart';
-
-class GamePage extends StatelessWidget {
-  const GamePage({super.key});
-
-  @override
-  Widget build(BuildContext context) {
-    final Data myProvider = Provider.of<Data>(context);
-
-    switch (myProvider.gameType) {
-      case GameType.pickImage:
-        return const GamePickImagePage();
-      case GameType.pickWord:
-        return const GamePickWordPage();
-      default:
-        return const GameSelector();
-    }
-  }
-}
diff --git a/lib/ui/screens/about_page.dart b/lib/ui/screens/page_about.dart
similarity index 86%
rename from lib/ui/screens/about_page.dart
rename to lib/ui/screens/page_about.dart
index 05d19322774be26931233ecd40beb1adffe27b55..9ea18e98836e10870e541327731974eac5ea7172 100644
--- a/lib/ui/screens/about_page.dart
+++ b/lib/ui/screens/page_about.dart
@@ -2,10 +2,10 @@ import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
 import 'package:package_info_plus/package_info_plus.dart';
 
-import 'package:wordguessing/ui/widgets/header_app.dart';
+import 'package:wordguessing/ui/helpers/app_titles.dart';
 
-class AboutPage extends StatelessWidget {
-  const AboutPage({super.key});
+class PageAbout extends StatelessWidget {
+  const PageAbout({super.key});
 
   @override
   Widget build(BuildContext context) {
@@ -17,7 +17,7 @@ class AboutPage extends StatelessWidget {
         mainAxisSize: MainAxisSize.max,
         children: <Widget>[
           const SizedBox(height: 8),
-          const AppHeader(text: 'about_title'),
+          const AppTitle(text: 'about_title'),
           const Text('about_content').tr(),
           FutureBuilder<PackageInfo>(
             future: PackageInfo.fromPlatform(),
diff --git a/lib/ui/screens/page_game.dart b/lib/ui/screens/page_game.dart
new file mode 100644
index 0000000000000000000000000000000000000000..402d3c0a7a4186483154dc8d655deab11ef8931e
--- /dev/null
+++ b/lib/ui/screens/page_game.dart
@@ -0,0 +1,24 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:wordguessing/cubit/game_cubit.dart';
+import 'package:wordguessing/models/game/game.dart';
+import 'package:wordguessing/ui/layouts/game_layout.dart';
+import 'package:wordguessing/ui/layouts/parameters_layout.dart';
+
+class PageGame extends StatelessWidget {
+  const PageGame({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return BlocBuilder<GameCubit, GameState>(
+      builder: (BuildContext context, GameState gameState) {
+        final Game currentGame = gameState.currentGame;
+
+        return currentGame.isRunning
+            ? const GameLayout()
+            : ParametersLayout(canResume: currentGame.canBeResumed);
+      },
+    );
+  }
+}
diff --git a/lib/ui/screens/settings_page.dart b/lib/ui/screens/page_settings.dart
similarity index 65%
rename from lib/ui/screens/settings_page.dart
rename to lib/ui/screens/page_settings.dart
index df50c147d84f6b0b8358bdc18fc6898cadefc1fb..a72773940501e2a7fae3324ff4894fdd4ce88efc 100644
--- a/lib/ui/screens/settings_page.dart
+++ b/lib/ui/screens/page_settings.dart
@@ -1,10 +1,10 @@
 import 'package:flutter/material.dart';
 
-import 'package:wordguessing/ui/widgets/header_app.dart';
-import 'package:wordguessing/ui/widgets/settings/settings_form.dart';
+import 'package:wordguessing/ui/helpers/app_titles.dart';
+import 'package:wordguessing/ui/settings/settings_form.dart';
 
-class SettingsPage extends StatelessWidget {
-  const SettingsPage({super.key});
+class PageSettings extends StatelessWidget {
+  const PageSettings({super.key});
 
   @override
   Widget build(BuildContext context) {
@@ -16,7 +16,7 @@ class SettingsPage extends StatelessWidget {
         mainAxisSize: MainAxisSize.max,
         children: <Widget>[
           SizedBox(height: 8),
-          AppHeader(text: 'settings_title'),
+          AppTitle(text: 'settings_title'),
           SizedBox(height: 8),
           SettingsForm(),
         ],
diff --git a/lib/ui/widgets/settings/settings_form.dart b/lib/ui/settings/settings_form.dart
similarity index 96%
rename from lib/ui/widgets/settings/settings_form.dart
rename to lib/ui/settings/settings_form.dart
index cb59277121264dace76f59d41290687c575f3a4f..bb30d8d437ff7968f32669f312a7875a0bc85ac2 100644
--- a/lib/ui/widgets/settings/settings_form.dart
+++ b/lib/ui/settings/settings_form.dart
@@ -2,7 +2,7 @@ import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
 import 'package:unicons/unicons.dart';
 
-import 'package:wordguessing/ui/widgets/settings/theme_card.dart';
+import 'package:wordguessing/ui/settings/theme_card.dart';
 
 class SettingsForm extends StatefulWidget {
   const SettingsForm({super.key});
diff --git a/lib/ui/widgets/settings/theme_card.dart b/lib/ui/settings/theme_card.dart
similarity index 100%
rename from lib/ui/widgets/settings/theme_card.dart
rename to lib/ui/settings/theme_card.dart
diff --git a/lib/ui/skeleton.dart b/lib/ui/skeleton.dart
index bc0a8a0bffaf7382bcf8473fd6ecfd12aff9b37a..f3f33c41559decac392bd0a9a4ec097823adbed4 100644
--- a/lib/ui/skeleton.dart
+++ b/lib/ui/skeleton.dart
@@ -1,49 +1,34 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
-import 'package:flutter_swipe/flutter_swipe.dart';
-import 'package:provider/provider.dart';
 
 import 'package:wordguessing/config/menu.dart';
-import 'package:wordguessing/cubit/bottom_nav_cubit.dart';
-import 'package:wordguessing/provider/data.dart';
-import 'package:wordguessing/ui/widgets/app_bar.dart';
-import 'package:wordguessing/ui/widgets/bottom_nav_bar.dart';
+import 'package:wordguessing/cubit/nav_cubit.dart';
+import 'package:wordguessing/ui/widgets/global_app_bar.dart';
 
-class SkeletonScreen extends StatefulWidget {
+class SkeletonScreen extends StatelessWidget {
   const SkeletonScreen({super.key});
 
-  @override
-  State<SkeletonScreen> createState() => _SkeletonScreenState();
-}
-
-class _SkeletonScreenState extends State<SkeletonScreen> {
   @override
   Widget build(BuildContext context) {
-    final Data myProvider = Provider.of<Data>(context);
-
     return Scaffold(
+      appBar: const GlobalAppBar(),
       extendBodyBehindAppBar: false,
-      appBar: StandardAppBar(myProvider: myProvider),
-      body: Swiper(
-        itemCount: Menu.itemsCount,
-        itemBuilder: (BuildContext context, int index) {
-          return Menu.getPageWidget(index);
-        },
-        pagination: SwiperPagination(
-          margin: const EdgeInsets.all(0),
-          builder: SwiperCustomPagination(
-            builder: (BuildContext context, SwiperPluginConfig config) {
-              return BottomNavBar(swipeController: config.controller);
-            },
-          ),
+      body: Material(
+        color: Theme.of(context).colorScheme.surface,
+        child: BlocBuilder<NavCubit, int>(
+          builder: (BuildContext context, int pageIndex) {
+            return Padding(
+              padding: const EdgeInsets.only(
+                top: 8,
+                left: 2,
+                right: 2,
+              ),
+              child: Menu.getPageWidget(pageIndex),
+            );
+          },
         ),
-        onIndexChanged: (newPageIndex) {
-          BlocProvider.of<BottomNavCubit>(context).updateIndex(newPageIndex);
-        },
-        outer: true,
-        loop: false,
       ),
-      backgroundColor: Theme.of(context).colorScheme.background,
+      backgroundColor: Theme.of(context).colorScheme.surface,
     );
   }
 }
diff --git a/lib/ui/widgets/actions/button_delete_saved_game.dart b/lib/ui/widgets/actions/button_delete_saved_game.dart
new file mode 100644
index 0000000000000000000000000000000000000000..0bf51b1734d40d31bec6ee6b3c05660b3d916b78
--- /dev/null
+++ b/lib/ui/widgets/actions/button_delete_saved_game.dart
@@ -0,0 +1,21 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:wordguessing/cubit/game_cubit.dart';
+
+class DeleteSavedGameButton extends StatelessWidget {
+  const DeleteSavedGameButton({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return TextButton(
+      child: const Image(
+        image: AssetImage('assets/ui/button_delete_saved_game.png'),
+        fit: BoxFit.fill,
+      ),
+      onPressed: () {
+        BlocProvider.of<GameCubit>(context).deleteSavedGame();
+      },
+    );
+  }
+}
diff --git a/lib/ui/widgets/actions/button_game_quit.dart b/lib/ui/widgets/actions/button_game_quit.dart
new file mode 100644
index 0000000000000000000000000000000000000000..db54a2b3ed81c05ab53d990f98d853848a86766a
--- /dev/null
+++ b/lib/ui/widgets/actions/button_game_quit.dart
@@ -0,0 +1,21 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:wordguessing/cubit/game_cubit.dart';
+
+class QuitGameButton extends StatelessWidget {
+  const QuitGameButton({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return TextButton(
+      child: const Image(
+        image: AssetImage('assets/ui/button_back.png'),
+        fit: BoxFit.fill,
+      ),
+      onPressed: () {
+        BlocProvider.of<GameCubit>(context).quitGame();
+      },
+    );
+  }
+}
diff --git a/lib/ui/widgets/actions/button_game_start_new.dart b/lib/ui/widgets/actions/button_game_start_new.dart
new file mode 100644
index 0000000000000000000000000000000000000000..dede701ccd80bc41b5cc3e14154694836cceb50f
--- /dev/null
+++ b/lib/ui/widgets/actions/button_game_start_new.dart
@@ -0,0 +1,34 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:wordguessing/cubit/game_cubit.dart';
+import 'package:wordguessing/cubit/settings_game_cubit.dart';
+import 'package:wordguessing/cubit/settings_global_cubit.dart';
+
+class StartNewGameButton extends StatelessWidget {
+  const StartNewGameButton({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return BlocBuilder<GameSettingsCubit, GameSettingsState>(
+      builder: (BuildContext context, GameSettingsState gameSettingsState) {
+        return BlocBuilder<GlobalSettingsCubit, GlobalSettingsState>(
+          builder: (BuildContext context, GlobalSettingsState globalSettingsState) {
+            return TextButton(
+              child: const Image(
+                image: AssetImage('assets/ui/button_start.png'),
+                fit: BoxFit.fill,
+              ),
+              onPressed: () {
+                BlocProvider.of<GameCubit>(context).startNewGame(
+                  gameSettings: gameSettingsState.settings,
+                  globalSettings: globalSettingsState.settings,
+                );
+              },
+            );
+          },
+        );
+      },
+    );
+  }
+}
diff --git a/lib/ui/widgets/actions/button_resume_saved_game.dart b/lib/ui/widgets/actions/button_resume_saved_game.dart
new file mode 100644
index 0000000000000000000000000000000000000000..4e26624a12339a7da2eaf8f801f667d068c049b8
--- /dev/null
+++ b/lib/ui/widgets/actions/button_resume_saved_game.dart
@@ -0,0 +1,21 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:wordguessing/cubit/game_cubit.dart';
+
+class ResumeSavedGameButton extends StatelessWidget {
+  const ResumeSavedGameButton({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return TextButton(
+      child: const Image(
+        image: AssetImage('assets/ui/button_resume_game.png'),
+        fit: BoxFit.fill,
+      ),
+      onPressed: () {
+        BlocProvider.of<GameCubit>(context).resumeSavedGame();
+      },
+    );
+  }
+}
diff --git a/lib/ui/widgets/app_bar.dart b/lib/ui/widgets/app_bar.dart
deleted file mode 100644
index 73038ecffd02c00b457707a647a0b9b57ebdaa3f..0000000000000000000000000000000000000000
--- a/lib/ui/widgets/app_bar.dart
+++ /dev/null
@@ -1,32 +0,0 @@
-import 'package:flutter/material.dart';
-
-import 'package:wordguessing/provider/data.dart';
-import 'package:wordguessing/ui/widgets/header_app.dart';
-
-class StandardAppBar extends StatelessWidget implements PreferredSizeWidget {
-  const StandardAppBar({super.key, required this.myProvider});
-
-  final Data myProvider;
-
-  @override
-  Widget build(BuildContext context) {
-    final List<Widget> menuActions = [];
-
-    if (myProvider.gameType != null) {
-      menuActions.add(
-        IconButton(
-          icon: const Icon(Icons.loop),
-          onPressed: () => myProvider.resetGame(),
-        ),
-      );
-    }
-
-    return AppBar(
-      title: const AppHeader(text: 'app_name'),
-      actions: menuActions,
-    );
-  }
-
-  @override
-  Size get preferredSize => const Size.fromHeight(50);
-}
diff --git a/lib/ui/widgets/bottom_nav_bar.dart b/lib/ui/widgets/bottom_nav_bar.dart
deleted file mode 100644
index 4e1d708cac14eb145f0934a92f552782d72ca978..0000000000000000000000000000000000000000
--- a/lib/ui/widgets/bottom_nav_bar.dart
+++ /dev/null
@@ -1,40 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:flutter_bloc/flutter_bloc.dart';
-import 'package:flutter_swipe/flutter_swipe.dart';
-
-import 'package:wordguessing/config/menu.dart';
-import 'package:wordguessing/cubit/bottom_nav_cubit.dart';
-
-class BottomNavBar extends StatelessWidget {
-  const BottomNavBar({super.key, required this.swipeController});
-
-  final SwiperController swipeController;
-
-  @override
-  Widget build(BuildContext context) {
-    return Card(
-      margin: const EdgeInsets.all(0),
-      elevation: 4,
-      shadowColor: Theme.of(context).colorScheme.shadow,
-      color: Theme.of(context).colorScheme.surfaceVariant,
-      shape: const ContinuousRectangleBorder(),
-      child: BlocBuilder<BottomNavCubit, int>(
-        builder: (BuildContext context, int state) {
-          return BottomNavigationBar(
-            currentIndex: state,
-            onTap: (int index) {
-              context.read<BottomNavCubit>().updateIndex(index);
-              swipeController.move(index);
-            },
-            type: BottomNavigationBarType.fixed,
-            elevation: 0,
-            backgroundColor: Colors.transparent,
-            selectedItemColor: Theme.of(context).colorScheme.primary,
-            unselectedItemColor: Theme.of(context).textTheme.bodySmall!.color,
-            items: Menu.getMenuItems(),
-          );
-        },
-      ),
-    );
-  }
-}
diff --git a/lib/ui/widgets/game/game_board.dart b/lib/ui/widgets/game/game_board.dart
new file mode 100644
index 0000000000000000000000000000000000000000..45ae0e82c7cd2a5fa848afbc940341a3aef0e69d
--- /dev/null
+++ b/lib/ui/widgets/game/game_board.dart
@@ -0,0 +1,32 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:wordguessing/config/default_game_settings.dart';
+import 'package:wordguessing/cubit/game_cubit.dart';
+import 'package:wordguessing/models/game/game.dart';
+import 'package:wordguessing/ui/widgets/game/game_pick_image.dart';
+import 'package:wordguessing/ui/widgets/game/game_pick_word.dart';
+
+class GameBoardWidget extends StatelessWidget {
+  const GameBoardWidget({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return Center(
+      child: BlocBuilder<GameCubit, GameState>(
+        builder: (BuildContext context, GameState gameState) {
+          final Game currentGame = gameState.currentGame;
+
+          switch (currentGame.gameSettings.gameType) {
+            case DefaultGameSettings.gameTypeValuePickImage:
+              return const GamePickImagePage();
+            case DefaultGameSettings.gameTypeValuePickWord:
+              return const GamePickWordPage();
+            default:
+              return const SizedBox.shrink();
+          }
+        },
+      ),
+    );
+  }
+}
diff --git a/lib/ui/widgets/game/game_pick_image.dart b/lib/ui/widgets/game/game_pick_image.dart
new file mode 100644
index 0000000000000000000000000000000000000000..d15b284c7f94593f5fdae736ef669f75503aba50
--- /dev/null
+++ b/lib/ui/widgets/game/game_pick_image.dart
@@ -0,0 +1,22 @@
+import 'package:flutter/material.dart';
+
+import 'package:wordguessing/ui/widgets/game/pick_image_game_items.dart';
+import 'package:wordguessing/ui/widgets/game/pick_image_game_word.dart';
+
+class GamePickImagePage extends StatelessWidget {
+  const GamePickImagePage({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return const Column(
+      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+      crossAxisAlignment: CrossAxisAlignment.center,
+      mainAxisSize: MainAxisSize.max,
+      children: [
+        PickImageGameWordContainer(),
+        SizedBox(height: 8),
+        PickImageGameItemsContainer(),
+      ],
+    );
+  }
+}
diff --git a/lib/ui/widgets/game/game_pick_word.dart b/lib/ui/widgets/game/game_pick_word.dart
new file mode 100644
index 0000000000000000000000000000000000000000..fc22b7b581d47b20151fc606c3a2950a064fb118
--- /dev/null
+++ b/lib/ui/widgets/game/game_pick_word.dart
@@ -0,0 +1,22 @@
+import 'package:flutter/material.dart';
+
+import 'package:wordguessing/ui/widgets/game/pick_word_game_image_items.dart';
+import 'package:wordguessing/ui/widgets/game/pick_word_game_word_items.dart';
+
+class GamePickWordPage extends StatelessWidget {
+  const GamePickWordPage({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return const Column(
+      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+      crossAxisAlignment: CrossAxisAlignment.center,
+      mainAxisSize: MainAxisSize.max,
+      children: [
+        PickWordGameImageItemsContainer(),
+        SizedBox(height: 8),
+        PickWordGameWordItemsContainer(),
+      ],
+    );
+  }
+}
diff --git a/lib/ui/widgets/game/pick_image_game_image.dart b/lib/ui/widgets/game/pick_image_game_image.dart
new file mode 100644
index 0000000000000000000000000000000000000000..dbf46fe7f2429e8d8b19d48776647c5c98923ce9
--- /dev/null
+++ b/lib/ui/widgets/game/pick_image_game_image.dart
@@ -0,0 +1,43 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:wordguessing/cubit/game_cubit.dart';
+import 'package:wordguessing/models/data/word.dart';
+
+class PickImageGameImageContainer extends StatelessWidget {
+  const PickImageGameImageContainer({super.key, required this.word});
+
+  final Word word;
+
+  @override
+  Widget build(BuildContext context) {
+    const double imageSize = 130;
+
+    String imageAsset = 'assets/ui/placeholder.png';
+    if ((word.images.isNotEmpty)) {
+      imageAsset = 'assets/images/${word.images[0]}';
+    }
+
+    return TextButton(
+      child: Container(
+        decoration: BoxDecoration(
+          borderRadius: BorderRadius.circular(8),
+          border: Border.all(
+            color: Colors.blue.shade200,
+            width: 8,
+          ),
+        ),
+        margin: const EdgeInsets.all(2),
+        child: Image(
+          image: AssetImage(imageAsset),
+          width: imageSize,
+          height: imageSize,
+          fit: BoxFit.fill,
+        ),
+      ),
+      onPressed: () {
+        BlocProvider.of<GameCubit>(context).checkWord(word);
+      },
+    );
+  }
+}
diff --git a/lib/ui/widgets/game/pick_image_game_items.dart b/lib/ui/widgets/game/pick_image_game_items.dart
new file mode 100644
index 0000000000000000000000000000000000000000..4ff8245649d178ef33300bb055850148124b0058
--- /dev/null
+++ b/lib/ui/widgets/game/pick_image_game_items.dart
@@ -0,0 +1,51 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:wordguessing/config/default_game_settings.dart';
+import 'package:wordguessing/cubit/game_cubit.dart';
+import 'package:wordguessing/models/data/word.dart';
+import 'package:wordguessing/models/game/game.dart';
+import 'package:wordguessing/ui/widgets/game/pick_image_game_image.dart';
+
+class PickImageGameItemsContainer extends StatelessWidget {
+  const PickImageGameItemsContainer({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return BlocBuilder<GameCubit, GameState>(
+      builder: (BuildContext context, GameState gameState) {
+        final Game currentGame = gameState.currentGame;
+        final List<Word> images = currentGame.images;
+
+        if (images.length != DefaultGameSettings.itemsCount) {
+          return const SizedBox.shrink();
+        }
+
+        images.sort((a, b) => a.key.compareTo(b.key));
+
+        return Column(
+          mainAxisSize: MainAxisSize.min,
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: [
+            Row(
+              mainAxisSize: MainAxisSize.min,
+              mainAxisAlignment: MainAxisAlignment.center,
+              children: [
+                PickImageGameImageContainer(word: images[0]),
+                PickImageGameImageContainer(word: images[1]),
+              ],
+            ),
+            Row(
+              mainAxisSize: MainAxisSize.min,
+              mainAxisAlignment: MainAxisAlignment.center,
+              children: [
+                PickImageGameImageContainer(word: images[2]),
+                PickImageGameImageContainer(word: images[3]),
+              ],
+            )
+          ],
+        );
+      },
+    );
+  }
+}
diff --git a/lib/ui/widgets/game/pick_image_game_word.dart b/lib/ui/widgets/game/pick_image_game_word.dart
new file mode 100644
index 0000000000000000000000000000000000000000..efc1aab1d9d451521baffad5b0398e580d24b173
--- /dev/null
+++ b/lib/ui/widgets/game/pick_image_game_word.dart
@@ -0,0 +1,40 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:wordguessing/cubit/game_cubit.dart';
+import 'package:wordguessing/models/game/game.dart';
+
+class PickImageGameWordContainer extends StatelessWidget {
+  const PickImageGameWordContainer({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return BlocBuilder<GameCubit, GameState>(
+      builder: (BuildContext context, GameState gameState) {
+        final Game currentGame = gameState.currentGame;
+
+        return Container(
+          decoration: BoxDecoration(
+            color: Colors.blue.shade800,
+            borderRadius: BorderRadius.circular(6),
+            border: Border.all(
+              color: Colors.white,
+              width: 6,
+            ),
+          ),
+          child: Padding(
+            padding: const EdgeInsets.all(12),
+            child: Text(
+              currentGame.word.text,
+              style: const TextStyle(
+                fontSize: 30,
+                fontWeight: FontWeight.w600,
+                color: Colors.white,
+              ),
+            ),
+          ),
+        );
+      },
+    );
+  }
+}
diff --git a/lib/ui/widgets/game/pick_word_game_image.dart b/lib/ui/widgets/game/pick_word_game_image.dart
new file mode 100644
index 0000000000000000000000000000000000000000..705450c37d087f6e4df655d39ce1f9c364bfc00e
--- /dev/null
+++ b/lib/ui/widgets/game/pick_word_game_image.dart
@@ -0,0 +1,35 @@
+import 'package:flutter/material.dart';
+
+
+class PickWordGameImageContainer extends StatelessWidget {
+  const PickWordGameImageContainer({super.key, required this.image});
+
+  final String image;
+
+  @override
+  Widget build(BuildContext context) {
+    const double imageSize = 130;
+
+    String imageAsset = 'assets/ui/placeholder.png';
+    if (image != '') {
+      imageAsset = 'assets/images/$image';
+    }
+
+    return Container(
+      margin: const EdgeInsets.all(2),
+      decoration: BoxDecoration(
+        borderRadius: BorderRadius.circular(8),
+        border: Border.all(
+          color: Colors.blue.shade200,
+          width: 8,
+        ),
+      ),
+      child: Image(
+        image: AssetImage(imageAsset),
+        width: imageSize,
+        height: imageSize,
+        fit: BoxFit.fill,
+      ),
+    );
+  }
+}
diff --git a/lib/ui/widgets/game/pick_word_game_image_items.dart b/lib/ui/widgets/game/pick_word_game_image_items.dart
new file mode 100644
index 0000000000000000000000000000000000000000..c0e91cfc0938f594060649707e880b99fa3ddb69
--- /dev/null
+++ b/lib/ui/widgets/game/pick_word_game_image_items.dart
@@ -0,0 +1,49 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:wordguessing/cubit/game_cubit.dart';
+import 'package:wordguessing/models/data/word.dart';
+import 'package:wordguessing/models/game/game.dart';
+import 'package:wordguessing/ui/widgets/game/pick_word_game_image.dart';
+
+class PickWordGameImageItemsContainer extends StatelessWidget {
+  const PickWordGameImageItemsContainer({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return BlocBuilder<GameCubit, GameState>(
+      builder: (BuildContext context, GameState gameState) {
+        final Game currentGame = gameState.currentGame;
+
+        if (currentGame.images.isEmpty) {
+          return const SizedBox.shrink();
+        }
+
+        final Word word = currentGame.images[0];
+
+        return Column(
+          mainAxisSize: MainAxisSize.min,
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: [
+            Row(
+              mainAxisSize: MainAxisSize.min,
+              mainAxisAlignment: MainAxisAlignment.center,
+              children: [
+                PickWordGameImageContainer(image: word.images[0]),
+                PickWordGameImageContainer(image: word.images[1]),
+              ],
+            ),
+            Row(
+              mainAxisSize: MainAxisSize.min,
+              mainAxisAlignment: MainAxisAlignment.center,
+              children: [
+                PickWordGameImageContainer(image: word.images[2]),
+                PickWordGameImageContainer(image: word.images[3]),
+              ],
+            )
+          ],
+        );
+      },
+    );
+  }
+}
diff --git a/lib/ui/widgets/game/pick_word_game_word.dart b/lib/ui/widgets/game/pick_word_game_word.dart
new file mode 100644
index 0000000000000000000000000000000000000000..1a2ad03987fcd4811b527d6326e504ad304d80c1
--- /dev/null
+++ b/lib/ui/widgets/game/pick_word_game_word.dart
@@ -0,0 +1,42 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:wordguessing/cubit/game_cubit.dart';
+import 'package:wordguessing/models/data/word.dart';
+
+class PickWordGameWordContainer extends StatelessWidget {
+  const PickWordGameWordContainer({super.key, required this.word});
+
+  final Word word;
+
+  @override
+  Widget build(BuildContext context) {
+    return Container(
+      margin: const EdgeInsets.all(2),
+      decoration: BoxDecoration(
+        color: Colors.blue[800],
+        borderRadius: BorderRadius.circular(6),
+        border: Border.all(
+          color: Colors.white,
+          width: 6,
+        ),
+      ),
+      child: TextButton(
+        style: TextButton.styleFrom(
+          padding: const EdgeInsets.all(15),
+        ),
+        child: Text(
+          word.text,
+          style: const TextStyle(
+            fontSize: 20,
+            fontWeight: FontWeight.w600,
+            color: Colors.white,
+          ),
+        ),
+        onPressed: () {
+          BlocProvider.of<GameCubit>(context).checkWord(word);
+        },
+      ),
+    );
+  }
+}
diff --git a/lib/ui/widgets/game/pick_word_game_word_items.dart b/lib/ui/widgets/game/pick_word_game_word_items.dart
new file mode 100644
index 0000000000000000000000000000000000000000..8cc00278b20796ad9bd53b9881e368e705467de9
--- /dev/null
+++ b/lib/ui/widgets/game/pick_word_game_word_items.dart
@@ -0,0 +1,63 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:wordguessing/config/default_game_settings.dart';
+import 'package:wordguessing/cubit/game_cubit.dart';
+import 'package:wordguessing/models/data/word.dart';
+import 'package:wordguessing/models/game/game.dart';
+import 'package:wordguessing/ui/widgets/game/pick_word_game_word.dart';
+
+class PickWordGameWordItemsContainer extends StatelessWidget {
+  const PickWordGameWordItemsContainer({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return BlocBuilder<GameCubit, GameState>(
+      builder: (BuildContext context, GameState gameState) {
+        final Game currentGame = gameState.currentGame;
+
+        Word? word = currentGame.word;
+        List<Word> otherWords = currentGame.otherWords;
+
+        if (otherWords.length != (DefaultGameSettings.itemsCount - 1)) {
+          return const Column();
+        }
+
+        List<Word> words = [
+          word,
+          otherWords[0],
+          otherWords[1],
+          otherWords[2],
+        ];
+
+        words.sort((a, b) => a.key.compareTo(b.key));
+
+        return Column(
+          mainAxisSize: MainAxisSize.min,
+          mainAxisAlignment: MainAxisAlignment.center,
+          children: [
+            Row(
+              mainAxisSize: MainAxisSize.min,
+              mainAxisAlignment: MainAxisAlignment.center,
+              children: [
+                PickWordGameWordContainer(word: words[0]),
+                const SizedBox(width: 10),
+                PickWordGameWordContainer(word: words[1]),
+              ],
+            ),
+            const SizedBox(height: 5),
+            Row(
+              mainAxisSize: MainAxisSize.min,
+              mainAxisAlignment: MainAxisAlignment.center,
+              children: [
+                PickWordGameWordContainer(word: words[2]),
+                const SizedBox(width: 10),
+                PickWordGameWordContainer(word: words[3]),
+              ],
+            )
+          ],
+        );
+      },
+    );
+  }
+}
diff --git a/lib/ui/widgets/game/score_bar.dart b/lib/ui/widgets/game/score_bar.dart
new file mode 100644
index 0000000000000000000000000000000000000000..f194767d6b46d03c178223603391c407fb04c6fc
--- /dev/null
+++ b/lib/ui/widgets/game/score_bar.dart
@@ -0,0 +1,43 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:wordguessing/cubit/game_cubit.dart';
+import 'package:wordguessing/models/game/game.dart';
+import 'package:wordguessing/ui/widgets/indicators/score_indicator.dart';
+
+class ScoreBarWidget extends StatelessWidget {
+  const ScoreBarWidget({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return BlocBuilder<GameCubit, GameState>(
+      builder: (BuildContext context, GameState gameState) {
+        final Game currentGame = gameState.currentGame;
+
+        final int count = currentGame.questionsCount - 1;
+
+        final String goodAnswersString = '👍 ${currentGame.goodAnswers}/$count';
+        final String wrongAnswersString = '🚩 ${currentGame.wrongAnswers}/$count';
+
+        return Container(
+          padding: const EdgeInsets.all(5),
+          child: Row(
+            mainAxisSize: MainAxisSize.min,
+            mainAxisAlignment: MainAxisAlignment.center,
+            children: [
+              ScoreIndicator(
+                text: goodAnswersString,
+                blockColor: Colors.green,
+              ),
+              const SizedBox(width: 20),
+              ScoreIndicator(
+                text: wrongAnswersString,
+                blockColor: Colors.orange,
+              ),
+            ],
+          ),
+        );
+      },
+    );
+  }
+}
diff --git a/lib/ui/widgets/global_app_bar.dart b/lib/ui/widgets/global_app_bar.dart
new file mode 100644
index 0000000000000000000000000000000000000000..540f87eeb8d54a47a4be17539dee60b213df0cb6
--- /dev/null
+++ b/lib/ui/widgets/global_app_bar.dart
@@ -0,0 +1,83 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:wordguessing/config/menu.dart';
+import 'package:wordguessing/cubit/game_cubit.dart';
+import 'package:wordguessing/cubit/nav_cubit.dart';
+import 'package:wordguessing/models/game/game.dart';
+import 'package:wordguessing/ui/helpers/app_titles.dart';
+
+class GlobalAppBar extends StatelessWidget implements PreferredSizeWidget {
+  const GlobalAppBar({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return BlocBuilder<GameCubit, GameState>(
+      builder: (BuildContext context, GameState gameState) {
+        return BlocBuilder<NavCubit, int>(
+          builder: (BuildContext context, int pageIndex) {
+            final Game currentGame = gameState.currentGame;
+
+            final List<Widget> menuActions = [];
+
+            if (currentGame.isRunning && !currentGame.isFinished) {
+              menuActions.add(TextButton(
+                child: const Image(
+                  image: AssetImage('assets/ui/button_back.png'),
+                  fit: BoxFit.fill,
+                ),
+                onPressed: () {},
+                onLongPress: () {
+                  BlocProvider.of<GameCubit>(context).quitGame();
+                },
+              ));
+            } else {
+              if (pageIndex == Menu.indexGame) {
+                // go to Settings page
+                menuActions.add(ElevatedButton(
+                  onPressed: () {
+                    context.read<NavCubit>().goToSettingsPage();
+                  },
+                  style: ElevatedButton.styleFrom(
+                    shape: const CircleBorder(),
+                  ),
+                  child: Menu.menuItemSettings.icon,
+                ));
+
+                // go to About page
+                menuActions.add(ElevatedButton(
+                  onPressed: () {
+                    context.read<NavCubit>().goToAboutPage();
+                  },
+                  style: ElevatedButton.styleFrom(
+                    shape: const CircleBorder(),
+                  ),
+                  child: Menu.menuItemAbout.icon,
+                ));
+              } else {
+                // back to Home page
+                menuActions.add(ElevatedButton(
+                  onPressed: () {
+                    context.read<NavCubit>().goToGamePage();
+                  },
+                  style: ElevatedButton.styleFrom(
+                    shape: const CircleBorder(),
+                  ),
+                  child: Menu.menuItemGame.icon,
+                ));
+              }
+            }
+
+            return AppBar(
+              title: const AppHeader(text: 'app_name'),
+              actions: menuActions,
+            );
+          },
+        );
+      },
+    );
+  }
+
+  @override
+  Size get preferredSize => const Size.fromHeight(50);
+}
diff --git a/lib/ui/widgets/header_app.dart b/lib/ui/widgets/header_app.dart
deleted file mode 100644
index bf54b77375fbd0260f876f2885d0572b71715383..0000000000000000000000000000000000000000
--- a/lib/ui/widgets/header_app.dart
+++ /dev/null
@@ -1,23 +0,0 @@
-import 'package:easy_localization/easy_localization.dart';
-import 'package:flutter/material.dart';
-
-class AppHeader extends StatelessWidget {
-  const AppHeader({super.key, required this.text});
-
-  final String text;
-
-  @override
-  Widget build(BuildContext context) {
-    return Row(
-      mainAxisAlignment: MainAxisAlignment.start,
-      crossAxisAlignment: CrossAxisAlignment.start,
-      children: [
-        Text(
-          tr(text),
-          textAlign: TextAlign.start,
-          style: Theme.of(context).textTheme.headlineMedium!.apply(fontWeightDelta: 2),
-        ),
-      ],
-    );
-  }
-}
diff --git a/lib/ui/widgets/indicators/score_indicator.dart b/lib/ui/widgets/indicators/score_indicator.dart
new file mode 100644
index 0000000000000000000000000000000000000000..b6e4ecd132d9356ff8797946b02a0f40f342dfed
--- /dev/null
+++ b/lib/ui/widgets/indicators/score_indicator.dart
@@ -0,0 +1,40 @@
+import 'package:flutter/material.dart';
+
+import 'package:wordguessing/utils/color_extensions.dart';
+
+class ScoreIndicator extends StatelessWidget {
+  const ScoreIndicator({
+    super.key,
+    required this.text,
+    required this.blockColor,
+  });
+
+  final String text;
+  final Color blockColor;
+
+  @override
+  Widget build(BuildContext context) {
+    final Color borderColor = blockColor.darken();
+
+    return Container(
+      margin: const EdgeInsets.symmetric(horizontal: 15),
+      padding: const EdgeInsets.all(5),
+      decoration: BoxDecoration(
+        color: blockColor,
+        borderRadius: BorderRadius.circular(4),
+        border: Border.all(
+          color: borderColor,
+          width: 4,
+        ),
+      ),
+      child: Text(
+        text,
+        style: const TextStyle(
+          fontSize: 25,
+          fontWeight: FontWeight.w600,
+          color: Colors.black,
+        ),
+      ),
+    );
+  }
+}
diff --git a/lib/utils/color_extensions.dart b/lib/utils/color_extensions.dart
new file mode 100644
index 0000000000000000000000000000000000000000..4e55e338f0d3ed98b233d1ef887b7b3e17e29d97
--- /dev/null
+++ b/lib/utils/color_extensions.dart
@@ -0,0 +1,33 @@
+import 'dart:ui';
+
+extension ColorExtension on Color {
+  Color darken([int percent = 40]) {
+    assert(1 <= percent && percent <= 100);
+    final value = 1 - percent / 100;
+    return Color.fromARGB(
+      alpha,
+      (red * value).round(),
+      (green * value).round(),
+      (blue * value).round(),
+    );
+  }
+
+  Color lighten([int percent = 40]) {
+    assert(1 <= percent && percent <= 100);
+    final value = percent / 100;
+    return Color.fromARGB(
+      alpha,
+      (red + ((255 - red) * value)).round(),
+      (green + ((255 - green) * value)).round(),
+      (blue + ((255 - blue) * value)).round(),
+    );
+  }
+
+  Color avg(Color other) {
+    final red = (this.red + other.red) ~/ 2;
+    final green = (this.green + other.green) ~/ 2;
+    final blue = (this.blue + other.blue) ~/ 2;
+    final alpha = (this.alpha + other.alpha) ~/ 2;
+    return Color.fromARGB(alpha, red, green, blue);
+  }
+}
diff --git a/pubspec.lock b/pubspec.lock
index e9215a535c1e4d7b9a106294c437f72a288dd913..e0ab96ebb656b1260018d45af586d9ec14ba4a7e 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -61,10 +61,10 @@ packages:
     dependency: "direct main"
     description:
       name: easy_localization
-      sha256: "432698c31a488dd64c56d4759f20d04844baba5e9e4f2cb1abb9676257918b17"
+      sha256: fa59bcdbbb911a764aa6acf96bbb6fa7a5cf8234354fc45ec1a43a0349ef0201
       url: "https://pub.dev"
     source: hosted
-    version: "3.0.6"
+    version: "3.0.7"
   easy_logger:
     dependency: transitive
     description:
@@ -106,31 +106,23 @@ packages:
     dependency: "direct main"
     description:
       name: flutter_bloc
-      sha256: f0ecf6e6eb955193ca60af2d5ca39565a86b8a142452c5b24d96fb477428f4d2
+      sha256: b594505eac31a0518bdcb4b5b79573b8d9117b193cc80cc12e17d639b10aa27a
       url: "https://pub.dev"
     source: hosted
-    version: "8.1.5"
+    version: "8.1.6"
   flutter_lints:
     dependency: "direct dev"
     description:
       name: flutter_lints
-      sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1"
+      sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c"
       url: "https://pub.dev"
     source: hosted
-    version: "3.0.2"
+    version: "4.0.0"
   flutter_localizations:
     dependency: transitive
     description: flutter
     source: sdk
     version: "0.0.0"
-  flutter_swipe:
-    dependency: "direct main"
-    description:
-      name: flutter_swipe
-      sha256: dc6541bac3a0545ce15a3fa15913f6250532062960bf6b0ad4562d02f14a8545
-      url: "https://pub.dev"
-    source: hosted
-    version: "1.0.1"
   flutter_web_plugins:
     dependency: transitive
     description: flutter
@@ -172,18 +164,18 @@ packages:
     dependency: transitive
     description:
       name: intl
-      sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
+      sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf
       url: "https://pub.dev"
     source: hosted
-    version: "0.18.1"
+    version: "0.19.0"
   lints:
     dependency: transitive
     description:
       name: lints
-      sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290
+      sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235"
       url: "https://pub.dev"
     source: hosted
-    version: "3.0.0"
+    version: "4.0.0"
   material_color_utilities:
     dependency: transitive
     description:
@@ -196,10 +188,10 @@ packages:
     dependency: transitive
     description:
       name: meta
-      sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04
+      sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
       url: "https://pub.dev"
     source: hosted
-    version: "1.11.0"
+    version: "1.12.0"
   nested:
     dependency: transitive
     description:
@@ -225,7 +217,7 @@ packages:
     source: hosted
     version: "3.0.0"
   path:
-    dependency: "direct main"
+    dependency: transitive
     description:
       name: path
       sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
@@ -244,18 +236,18 @@ packages:
     dependency: transitive
     description:
       name: path_provider_android
-      sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d
+      sha256: "9c96da072b421e98183f9ea7464898428e764bc0ce5567f27ec8693442e72514"
       url: "https://pub.dev"
     source: hosted
-    version: "2.2.4"
+    version: "2.2.5"
   path_provider_foundation:
     dependency: transitive
     description:
       name: path_provider_foundation
-      sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f"
+      sha256: f234384a3fdd67f989b4d54a5d73ca2a6c422fa55ae694381ae0f4375cd1ea16
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.2"
+    version: "2.4.0"
   path_provider_linux:
     dependency: transitive
     description:
@@ -284,10 +276,10 @@ packages:
     dependency: transitive
     description:
       name: platform
-      sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
+      sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65"
       url: "https://pub.dev"
     source: hosted
-    version: "3.1.4"
+    version: "3.1.5"
   plugin_platform_interface:
     dependency: transitive
     description:
@@ -297,7 +289,7 @@ packages:
     source: hosted
     version: "2.1.8"
   provider:
-    dependency: "direct main"
+    dependency: transitive
     description:
       name: provider
       sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
@@ -316,18 +308,18 @@ packages:
     dependency: transitive
     description:
       name: shared_preferences_android
-      sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2"
+      sha256: "93d0ec9dd902d85f326068e6a899487d1f65ffcd5798721a95330b26c8131577"
       url: "https://pub.dev"
     source: hosted
-    version: "2.2.2"
+    version: "2.2.3"
   shared_preferences_foundation:
     dependency: transitive
     description:
       name: shared_preferences_foundation
-      sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c"
+      sha256: "0a8a893bf4fd1152f93fec03a415d11c27c74454d96e2318a7ac38dd18683ab7"
       url: "https://pub.dev"
     source: hosted
-    version: "2.3.5"
+    version: "2.4.0"
   shared_preferences_linux:
     dependency: transitive
     description:
@@ -433,10 +425,10 @@ packages:
     dependency: transitive
     description:
       name: win32
-      sha256: "0eaf06e3446824099858367950a813472af675116bf63f008a4c2a75ae13e9cb"
+      sha256: a79dbe579cb51ecd6d30b17e0cae4e0ea15e2c0e66f69ad4198f22a6789e94f4
       url: "https://pub.dev"
     source: hosted
-    version: "5.5.0"
+    version: "5.5.1"
   xdg_directories:
     dependency: transitive
     description:
@@ -446,5 +438,5 @@ packages:
     source: hosted
     version: "1.0.4"
 sdks:
-  dart: ">=3.3.0 <4.0.0"
-  flutter: ">=3.19.0"
+  dart: ">=3.4.0 <4.0.0"
+  flutter: ">=3.22.0"
diff --git a/pubspec.yaml b/pubspec.yaml
index d93b5e6e43a1788a671e11fe1160cc3f0eecf5dc..749d20f0dff6f74571043563b650c6c42013ca0c 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -2,7 +2,8 @@ name: wordguessing
 description: A wordguessing game application.
 
 publish_to: "none"
-version: 0.1.40+64
+
+version: 0.2.0+65
 
 environment:
   sdk: "^3.0.0"
@@ -11,27 +12,27 @@ dependencies:
   flutter:
     sdk: flutter
 
+  # base
   easy_localization: ^3.0.1
   equatable: ^2.0.5
   flutter_bloc: ^8.1.1
-  flutter_swipe: ^1.0.1
   hive: ^2.2.3
   hydrated_bloc: ^9.0.0
   package_info_plus: ^8.0.0
-  path: ^1.9.0
   path_provider: ^2.0.11
-  provider: ^6.0.5
   unicons: ^2.1.1
 
+  # specific
+  # (none)
+
 dev_dependencies:
-  flutter_lints: ^3.0.1
+  flutter_lints: ^4.0.0
 
 flutter:
   uses-material-design: true
   assets:
     - assets/images/
-    - assets/menu/
-    - assets/placeholder.png
+    - assets/ui/
     - assets/translations/
 
   fonts:
@@ -45,3 +46,4 @@ flutter:
           weight: 400
         - asset: assets/fonts/Nunito-Light.ttf
           weight: 300
+
diff --git a/icons/build_application_icons.sh b/resources/app/build_application_resources.sh
similarity index 98%
rename from icons/build_application_icons.sh
rename to resources/app/build_application_resources.sh
index 27dbe2647fe4e6d562fbd99451716d1b7d448570..6d67b8f4f9eca701d1aed7331ef41dfb0bd44f20 100755
--- a/icons/build_application_icons.sh
+++ b/resources/app/build_application_resources.sh
@@ -6,7 +6,7 @@ command -v scour >/dev/null 2>&1 || { echo >&2 "I require scour but it's not ins
 command -v optipng >/dev/null 2>&1 || { echo >&2 "I require optipng but it's not installed. Aborting."; exit 1; }
 
 CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
-BASE_DIR="$(dirname "${CURRENT_DIR}")"
+BASE_DIR="$(dirname "$(dirname "${CURRENT_DIR}")")"
 
 SOURCE_ICON="${CURRENT_DIR}/icon.svg"
 SOURCE_FASTLANE="${CURRENT_DIR}/featureGraphic.svg"
diff --git a/icons/featureGraphic.svg b/resources/app/featureGraphic.svg
similarity index 100%
rename from icons/featureGraphic.svg
rename to resources/app/featureGraphic.svg
diff --git a/icons/icon.svg b/resources/app/icon.svg
similarity index 100%
rename from icons/icon.svg
rename to resources/app/icon.svg
diff --git a/resources/build_resources.sh b/resources/build_resources.sh
new file mode 100755
index 0000000000000000000000000000000000000000..774953c5b885aae73f710aaa9d8b55a0d8dcc2c0
--- /dev/null
+++ b/resources/build_resources.sh
@@ -0,0 +1,6 @@
+#! /bin/bash
+
+CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
+
+${CURRENT_DIR}/app/build_application_resources.sh
+${CURRENT_DIR}/ui/build_ui_resources.sh
diff --git a/scripts/.gitignore b/resources/data/.gitignore
similarity index 100%
rename from scripts/.gitignore
rename to resources/data/.gitignore
diff --git a/scripts/01_download_images.sh b/resources/data/01_download_images.sh
similarity index 100%
rename from scripts/01_download_images.sh
rename to resources/data/01_download_images.sh
diff --git a/scripts/02_prepare_images.sh b/resources/data/02_prepare_images.sh
similarity index 100%
rename from scripts/02_prepare_images.sh
rename to resources/data/02_prepare_images.sh
diff --git a/scripts/03_optimize_images.sh b/resources/data/03_optimize_images.sh
similarity index 100%
rename from scripts/03_optimize_images.sh
rename to resources/data/03_optimize_images.sh
diff --git a/scripts/04_build_images_board.sh b/resources/data/04_build_images_board.sh
similarity index 100%
rename from scripts/04_build_images_board.sh
rename to resources/data/04_build_images_board.sh
diff --git a/scripts/05_build_assets_list.sh b/resources/data/05_build_assets_list.sh
similarity index 100%
rename from scripts/05_build_assets_list.sh
rename to resources/data/05_build_assets_list.sh
diff --git a/scripts/words.csv b/resources/data/words.csv
similarity index 100%
rename from scripts/words.csv
rename to resources/data/words.csv
diff --git a/scripts/words.json b/resources/data/words.json
similarity index 100%
rename from scripts/words.json
rename to resources/data/words.json
diff --git a/resources/ui/build_ui_resources.sh b/resources/ui/build_ui_resources.sh
new file mode 100755
index 0000000000000000000000000000000000000000..4f365ede7d83140ce6309a3083580f2662b30990
--- /dev/null
+++ b/resources/ui/build_ui_resources.sh
@@ -0,0 +1,110 @@
+#! /bin/bash
+
+# Check dependencies
+command -v inkscape >/dev/null 2>&1 || { echo >&2 "I require inkscape but it's not installed. Aborting."; exit 1; }
+command -v scour >/dev/null 2>&1 || { echo >&2 "I require scour but it's not installed. Aborting."; exit 1; }
+command -v optipng >/dev/null 2>&1 || { echo >&2 "I require optipng but it's not installed. Aborting."; exit 1; }
+
+CURRENT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
+BASE_DIR="$(dirname "$(dirname "${CURRENT_DIR}")")"
+ASSETS_DIR="${BASE_DIR}/assets"
+
+OPTIPNG_OPTIONS="-preserve -quiet -o7"
+ICON_SIZE=192
+
+#######################################################
+
+# Game images (svg files found in `images` folder)
+AVAILABLE_GAME_IMAGES=""
+if [ -d "${CURRENT_DIR}/images" ]; then
+  AVAILABLE_GAME_IMAGES="$(find "${CURRENT_DIR}/images" -type f -name "*.svg" | awk -F/ '{print $NF}' | cut -d"." -f1 | sort)"
+fi
+
+# Skins (subfolders found in `skins` folder)
+AVAILABLE_SKINS=""
+if [ -d "${CURRENT_DIR}/skins" ]; then
+  AVAILABLE_SKINS="$(find "${CURRENT_DIR}/skins" -mindepth 1 -type d | awk -F/ '{print $NF}')"
+fi
+
+# Images per skin (svg files found recursively in `skins` folder and subfolders)
+SKIN_IMAGES=""
+if [ -d "${CURRENT_DIR}/skins" ]; then
+  SKIN_IMAGES="$(find "${CURRENT_DIR}/skins" -type f -name "*.svg" | awk -F/ '{print $NF}' | cut -d"." -f1 | sort | uniq)"
+fi
+
+#######################################################
+
+# optimize svg
+function optimize_svg() {
+  SOURCE="$1"
+
+  cp ${SOURCE} ${SOURCE}.tmp
+  scour \
+      --remove-descriptive-elements \
+      --enable-id-stripping \
+      --enable-viewboxing \
+      --enable-comment-stripping \
+      --nindent=4 \
+      --quiet \
+      -i ${SOURCE}.tmp \
+      -o ${SOURCE}
+  rm ${SOURCE}.tmp
+}
+
+# build icons
+function build_image() {
+  SOURCE="$1"
+  TARGET="$2"
+
+  echo "Building ${TARGET}"
+
+  if [ ! -f "${SOURCE}" ]; then
+    echo "Missing file: ${SOURCE}"
+    exit 1
+  fi
+
+  optimize_svg "${SOURCE}"
+
+  mkdir -p "$(dirname "${TARGET}")"
+
+  inkscape \
+      --export-width=${ICON_SIZE} \
+      --export-height=${ICON_SIZE} \
+      --export-filename=${TARGET} \
+      "${SOURCE}"
+
+  optipng ${OPTIPNG_OPTIONS} "${TARGET}"
+}
+
+function build_image_for_skin() {
+  SKIN_CODE="$1"
+
+  # skin images
+  for SKIN_IMAGE in ${SKIN_IMAGES}
+  do
+    build_image ${CURRENT_DIR}/skins/${SKIN_CODE}/${SKIN_IMAGE}.svg ${ASSETS_DIR}/skins/${SKIN_CODE}_${SKIN_IMAGE}.png
+  done
+}
+
+#######################################################
+
+# Delete existing generated images
+if [ -d "${ASSETS_DIR}/ui" ]; then
+  find ${ASSETS_DIR}/ui -type f -name "*.png" -delete
+fi
+if [ -d "${ASSETS_DIR}/skins" ]; then
+  find ${ASSETS_DIR}/skins -type f -name "*.png" -delete
+fi
+
+# build game images
+for GAME_IMAGE in ${AVAILABLE_GAME_IMAGES}
+do
+  build_image ${CURRENT_DIR}/images/${GAME_IMAGE}.svg ${ASSETS_DIR}/ui/${GAME_IMAGE}.png
+done
+
+# build skins images
+for SKIN in ${AVAILABLE_SKINS}
+do
+  build_image_for_skin "${SKIN}"
+done
+
diff --git a/resources/ui/images/button_back.svg b/resources/ui/images/button_back.svg
new file mode 100644
index 0000000000000000000000000000000000000000..2622a578dba53ce582afabfc587c2a85a1fb6eaa
--- /dev/null
+++ b/resources/ui/images/button_back.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 93.665 93.676" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect x=".44662" y=".89101" width="92.772" height="91.894" ry="11.689" fill="#e41578" stroke="#fff" stroke-width=".238"/><path d="m59.387 71.362c1.1248 1.1302 4.0012 1.1302 4.0012 0v-45.921c0-1.1316-2.8832-1.1316-4.0121 0l-37.693 20.918c-1.1289 1.1248-1.1479 2.9551-0.02171 4.084z" fill="#fefeff" stroke="#930e4e" stroke-linecap="round" stroke-linejoin="round" stroke-width="8.257"/><path d="m57.857 68.048c0.96243 0.96706 3.4236 0.96706 3.4236 0v-39.292c0-0.96825-2.467-0.96825-3.4329 0l-32.252 17.898c-0.96594 0.96243-0.9822 2.5285-0.01858 3.4945z" fill="#fefeff" stroke="#feffff" stroke-linecap="round" stroke-linejoin="round" stroke-width="4.314"/></svg>
diff --git a/resources/ui/images/button_delete_saved_game.svg b/resources/ui/images/button_delete_saved_game.svg
new file mode 100644
index 0000000000000000000000000000000000000000..ac7eefef476f761903fe781b8c86d0c94323550a
--- /dev/null
+++ b/resources/ui/images/button_delete_saved_game.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 93.665 93.676" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect x=".44662" y=".89101" width="92.772" height="91.894" ry="11.689" fill="#ee7d49" stroke="#fff" stroke-width=".238"/><path d="m61.07 35.601-1.7399 27.837c-0.13442 2.1535-1.9205 3.8312-4.0781 3.8312h-16.84c-2.1576 0-3.9437-1.6777-4.0781-3.8312l-1.7399-27.837h-2.6176c-0.84621 0-1.5323-0.68613-1.5323-1.5323 0-0.84655 0.68613-1.5323 1.5323-1.5323h33.711c0.84621 0 1.5323 0.68578 1.5323 1.5323 0 0.84621-0.68613 1.5323-1.5323 1.5323zm-3.2617 0h-21.953l1.4715 26.674c0.05985 1.0829 0.95531 1.9305 2.0403 1.9305h14.929c1.085 0 1.9804-0.84757 2.0403-1.9305zm-10.977 3.0647c0.78977 0 1.4301 0.6403 1.4301 1.4301v19.614c0 0.78977-0.6403 1.4301-1.4301 1.4301s-1.4301-0.6403-1.4301-1.4301v-19.614c0-0.78977 0.6403-1.4301 1.4301-1.4301zm-6.1293 0c0.80004 0 1.4588 0.62935 1.495 1.4286l0.89647 19.719c0.03182 0.70016-0.50998 1.2933-1.2101 1.3255-0.01915 7.02e-4 -0.03831 1e-3 -0.05781 1e-3 -0.74462 0-1.3596-0.58215-1.4003-1.3261l-1.0757-19.719c-0.0407-0.74701 0.53188-1.3852 1.2786-1.4259 0.02462-0.0014 0.04926-2e-3 0.07388-2e-3zm12.259 0c0.74804 0 1.3541 0.60609 1.3541 1.3541 0 0.02462-3.28e-4 0.04926-0.0017 0.07388l-1.0703 19.618c-0.04379 0.80106-0.70597 1.4281-1.5081 1.4281-0.74804 0-1.3541-0.60609-1.3541-1.3541 0-0.02462 3.49e-4 -0.04925 0.0017-0.07388l1.0703-19.618c0.04379-0.80106 0.70597-1.4281 1.5081-1.4281zm-10.216-12.259h8.1728c2.2567 0 4.086 1.8293 4.086 4.086v2.0433h-16.344v-2.0433c0-2.2567 1.8293-4.086 4.086-4.086zm0.20453 3.0647c-0.67725 0-1.2259 0.54863-1.2259 1.2259v1.8388h10.215v-1.8388c0-0.67725-0.54863-1.2259-1.2259-1.2259z" fill="#fff" fill-rule="evenodd" stroke="#bd4812" stroke-width=".75383"/></svg>
diff --git a/resources/ui/images/button_resume_game.svg b/resources/ui/images/button_resume_game.svg
new file mode 100644
index 0000000000000000000000000000000000000000..6ad8b64202d0e70f898c16c520e756fe8a934add
--- /dev/null
+++ b/resources/ui/images/button_resume_game.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 93.665 93.676" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect x=".44662" y=".89101" width="92.772" height="91.894" ry="11.689" fill="#49a1ee" stroke="#fff" stroke-width=".238"/><path d="m39.211 31.236c-0.84086-0.84489-2.9911-0.84489-2.9911 0v34.329c0 0.84594 2.1554 0.84594 2.9993 0l28.178-15.637c0.84392-0.84086 0.85812-2.2091 0.01623-3.053z" fill="#fefeff" stroke="#105ca1" stroke-linecap="round" stroke-linejoin="round" stroke-width="6.1726"/><path d="m40.355 33.714c-0.71948-0.72294-2.5594-0.72294-2.5594 0v29.373c0 0.72383 1.8442 0.72383 2.5663 0l24.11-13.38c0.7221-0.71948 0.73426-1.8902 0.01389-2.6124z" fill="#fefeff" stroke="#feffff" stroke-linecap="round" stroke-linejoin="round" stroke-width="3.225"/><path d="m28.369 66.919v-37.591" fill="#105ca2" stroke="#105ca2" stroke-linecap="round" stroke-width="4.0337"/></svg>
diff --git a/resources/ui/images/button_start.svg b/resources/ui/images/button_start.svg
new file mode 100644
index 0000000000000000000000000000000000000000..e9d49d2172b9a0305db82779971e3c1e12f34a70
--- /dev/null
+++ b/resources/ui/images/button_start.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 93.665 93.676" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect x=".44662" y=".89101" width="92.772" height="91.894" ry="11.689" fill="#49a1ee" stroke="#fff" stroke-width=".238"/><path d="m34.852 25.44c-1.1248-1.1302-4.0012-1.1302-4.0012 0v45.921c0 1.1316 2.8832 1.1316 4.0121 0l37.693-20.918c1.1289-1.1248 1.1479-2.9551 0.02171-4.084z" fill="#fefeff" stroke="#105ca1" stroke-linecap="round" stroke-linejoin="round" stroke-width="8.257"/><path d="m36.382 28.754c-0.96243-0.96706-3.4236-0.96706-3.4236 0v39.292c0 0.96825 2.467 0.96825 3.4329 0l32.252-17.898c0.96594-0.96243 0.9822-2.5285 0.01858-3.4945z" fill="#fefeff" stroke="#feffff" stroke-linecap="round" stroke-linejoin="round" stroke-width="4.314"/></svg>
diff --git a/resources/ui/images/game_fail.svg b/resources/ui/images/game_fail.svg
new file mode 100644
index 0000000000000000000000000000000000000000..2922fd7adc2bd2e813836c728f095376c73d4143
--- /dev/null
+++ b/resources/ui/images/game_fail.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 93.665 93.676" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><rect x=".44662" y=".89101" width="92.772" height="91.894" ry="11.689" fill="#d11717" stroke="#fff" stroke-width=".238"/><path d="m71.624 59.304c3.5089 3.5089 3.5089 9.0561 0 12.565-1.6976 1.6976-3.9623 2.6034-6.2261 2.6034s-4.5275-0.90569-6.2261-2.6034l-12.452-12.452-12.452 12.452c-1.6976 1.6976-3.9623 2.6034-6.2261 2.6034s-4.5275-0.90569-6.2261-2.6034c-3.5089-3.5089-3.5089-9.0561 0-12.565l12.452-12.452-12.452-12.452c-3.5089-3.5089-3.5089-9.0561 0-12.565s9.0561-3.5089 12.565 0l12.452 12.452 12.452-12.452c3.5089-3.5089 9.0561-3.5089 12.565 0s3.5089 9.0561 0 12.565l-12.452 12.452z" fill="#e7e7e7" stroke-width=".20213"/></svg>
diff --git a/resources/ui/images/game_win.svg b/resources/ui/images/game_win.svg
new file mode 100644
index 0000000000000000000000000000000000000000..fe20923864d0c5d39168eced03038b65106a596b
--- /dev/null
+++ b/resources/ui/images/game_win.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 93.665 93.676" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"><g transform="matrix(.17604 0 0 .17604 7.9341 1.7716)"><path d="m101.92 496.35c-1.8555 0-3.7109-0.69532-5.1484-2.0898-2.9297-2.8438-3-7.5234-0.15234-10.453l9.1875-9.4648c2.8438-2.9297 7.5234-3 10.453-0.15625s3 7.5234 0.15625 10.453l-9.1914 9.4648c-1.4492 1.4961-3.375 2.2461-5.3047 2.2461z" fill="#ff4e61"/><path d="m201.65 133.26c-1.8516 0-3.7109-0.69531-5.1445-2.0898-2.9297-2.8438-3-7.5234-0.15625-10.449l9.1914-9.4688c2.8438-2.9297 7.5195-3 10.449-0.15625s3 7.5234 0.15625 10.453l-9.1914 9.4688c-1.4492 1.4922-3.375 2.2422-5.3047 2.2422z" fill="#ff4e61"/><path d="m413.8 100.39c-1.8555 0-3.7109-0.69141-5.1484-2.0859-2.9297-2.8438-3-7.5234-0.15625-10.453l9.1914-9.4688c2.8438-2.9258 7.5234-2.9961 10.453-0.15234 2.9297 2.8398 3 7.5234 0.15625 10.449l-9.1914 9.4688c-1.4492 1.4922-3.375 2.2422-5.3047 2.2422z" fill="#5c73bc"/><path d="m413.8 463.77c-1.8555 0-3.7109-0.69532-5.1484-2.0859-2.9297-2.8438-3-7.5234-0.15625-10.453l9.1914-9.4688c2.8438-2.9258 7.5234-3 10.453-0.15625s3 7.5234 0.15625 10.453l-9.1914 9.4688c-1.4492 1.4922-3.375 2.2422-5.3047 2.2422z" fill="#fa0"/><path d="m63.07 112.91c-1.8516 0-3.7109-0.69141-5.1445-2.0859-2.9297-2.8438-3-7.5234-0.15625-10.453l9.1914-9.4687c2.8438-2.9258 7.5234-2.9961 10.453-0.15234 2.9258 2.8438 2.9961 7.5234 0.15234 10.449l-9.1914 9.4688c-1.4492 1.4922-3.375 2.2422-5.3047 2.2422z" fill="#fa0"/><path d="m12.309 278.82c-1.8516 0-3.7109-0.69141-5.1445-2.0859-2.9297-2.8438-3-7.5234-0.15625-10.453l9.1875-9.4688c2.8438-2.9297 7.5234-3 10.453-0.15625 2.9297 2.8438 3 7.5234 0.15625 10.453l-9.1914 9.4688c-1.4453 1.4922-3.375 2.2422-5.3047 2.2422z" fill="#2dc471"/><path d="m216.29 278.49-23.996 12.996c-6.2226 3.3711-13.496-2.0742-12.309-9.2148l4.582-27.523c0.47266-2.8359-0.4375-5.7266-2.4375-7.7344l-19.414-19.496c-5.0352-5.0547-2.2578-13.863 4.7031-14.906l26.824-4.0156c2.7656-0.41407 5.1524-2.1992 6.3867-4.7812l12-25.043c3.1133-6.4922 12.102-6.4922 15.215 0l11.996 25.043c1.2383 2.582 3.625 4.3672 6.3867 4.7812l26.828 4.0156c6.957 1.043 9.7344 9.8516 4.6992 14.906l-19.41 19.496c-2 2.0078-2.9141 4.8984-2.4414 7.7344l4.582 27.523c1.1914 7.1406-6.082 12.586-12.305 9.2148l-23.996-12.996c-2.4727-1.3398-5.4258-1.3398-7.8945 0z" fill="#ffd02f"/><path d="m220.24 512c-4.082 0-7.3906-3.3086-7.3906-7.3906v-115.59c0-4.082 3.3086-7.3945 7.3906-7.3945s7.3906 3.3125 7.3906 7.3945v115.59c0 4.082-3.3086 7.3906-7.3906 7.3906z" fill="#5c73bc"/><path d="m220.3 357.42h-0.11328c-4.082 0-7.3945-3.3125-7.3945-7.3945s3.3086-7.3906 7.3945-7.3906h0.11328c4.082 0 7.3906 3.3086 7.3906 7.3906s-3.3086 7.3945-7.3906 7.3945z" fill="#5c73bc"/><path d="m220.3 332h-0.14838c-4.082-0.0156-7.375-3.3398-7.3594-7.4219 0.0195-4.0742 3.3242-7.3594 7.3906-7.3594h0.14848c4.082 0.0156 7.375 3.3398 7.3594 7.4219-0.0156 4.0703-3.3242 7.3594-7.3906 7.3594z" fill="#fa0"/><path d="m87.234 230.89c-1.9297 0-3.8555-0.75-5.3047-2.2422l-79.34-81.738c-2.8438-2.9297-2.7773-7.6094 0.15234-10.449 2.9297-2.8438 7.6094-2.7734 10.453 0.15235l79.344 81.738c2.8438 2.9258 2.7734 7.6094-0.15625 10.449-1.4375 1.3945-3.293 2.0898-5.1484 2.0898z" fill="#ff4e61"/><path d="m113.95 258.5c-1.8633 0-3.7266-0.69922-5.1641-2.1055-2.9219-2.8516-2.9766-7.5312-0.125-10.453l0.082-0.082c2.8516-2.918 7.5312-2.9766 10.453-0.12109 2.9219 2.8516 2.9766 7.5312 0.12109 10.453l-0.0781 0.082c-1.4492 1.4805-3.3672 2.2266-5.2891 2.2266z" fill="#fa0"/><path d="m131.4 276.48c-1.8555 0-3.7109-0.69531-5.1484-2.0898-2.9258-2.8438-2.9961-7.5234-0.15235-10.449l0.0781-0.0859c2.8476-2.9297 7.5273-2.9961 10.453-0.15235 2.9297 2.8438 3 7.5234 0.15625 10.453l-0.082 0.082c-1.4492 1.4922-3.375 2.2422-5.3047 2.2422z" fill="#5c73bc"/><path d="m353.24 227.99c-1.8555 0-3.7109-0.69141-5.1445-2.0859-2.9297-2.8438-3-7.5234-0.15625-10.453l79.34-81.734c2.8438-2.9297 7.5234-3 10.453-0.15625 2.9297 2.8438 3 7.5234 0.15625 10.453l-79.344 81.734c-1.4492 1.4922-3.375 2.2422-5.3047 2.2422z" fill="#fa0"/><path d="m326.52 255.6c-1.9141 0-3.8242-0.73828-5.2695-2.2109l-0.082-0.082c-2.8633-2.9141-2.8203-7.5938 0.0899-10.453 2.9141-2.8633 7.5938-2.8203 10.453 0.0898l0.082 0.082c2.8594 2.9141 2.8203 7.5938-0.0937 10.453-1.4375 1.4141-3.3086 2.1211-5.1797 2.1211z" fill="#ff4e61"/><path d="m309.07 273.58c-1.9297 0-3.8555-0.75-5.3047-2.2422l-0.082-0.082c-2.8398-2.9297-2.7734-7.6094 0.15625-10.453s7.6094-2.7734 10.453 0.15234l0.082 0.082c2.8398 2.9297 2.7734 7.6094-0.15625 10.453-1.4375 1.3945-3.293 2.0898-5.1484 2.0898z" fill="#fa0"/><path d="m300.65 116.69c-1.2422 0-2.5-0.3125-3.6523-0.97266-3.5469-2.0234-4.7812-6.5391-2.7578-10.082l56.863-99.652c2.0234-3.543 6.5352-4.7773 10.082-2.7539 3.5469 2.0234 4.7812 6.5391 2.7578 10.082l-56.863 99.652c-1.3633 2.3867-3.8594 3.7266-6.4297 3.7266z" fill="#62d38f"/><path d="m281.52 150.33c-1.293 0-2.5977-0.33593-3.7891-1.0469l-0.0976-0.0586c-3.5-2.0938-4.6445-6.6328-2.5469-10.137 2.0938-3.5078 6.6328-4.6445 10.137-2.5508l0.0977 0.0586c3.5039 2.0938 4.6445 6.6328 2.5508 10.137-1.3867 2.3164-3.8359 3.5976-6.3516 3.5976z" fill="#fa0"/><path d="m269.02 172.25c-1.3008 0-2.6172-0.34375-3.8086-1.0625l-0.0977-0.0586c-3.4961-2.1094-4.6211-6.6523-2.5156-10.148 2.1094-3.4961 6.6523-4.6172 10.148-2.5117l0.0976 0.0586c3.4961 2.1094 4.6211 6.6523 2.5117 10.148-1.3867 2.3008-3.832 3.5742-6.3359 3.5742z" fill="#2dc471"/><path d="m139.96 116.69c-2.5703 0-5.0664-1.3398-6.4297-3.7305l-56.863-99.648c-2.0234-3.5469-0.78906-8.0586 2.7539-10.082 3.5469-2.0234 8.0625-0.79297 10.086 2.7539l56.863 99.648c2.0234 3.5469 0.78906 8.0625-2.7539 10.086-1.1562 0.66016-2.4141 0.97266-3.6562 0.97266z" fill="#5c73bc"/><path d="m159.09 150.33c-2.5078 0-4.957-1.2773-6.3438-3.582-2.1016-3.5-0.96875-8.043 2.5273-10.145l0.10157-0.0586c3.5-2.1016 8.0391-0.97266 10.141 2.5273 2.1055 3.5 0.97266 8.0391-2.5273 10.145l-0.0977 0.0586c-1.1914 0.71484-2.5039 1.0547-3.8008 1.0547z" fill="#ff4e61"/><path d="m171.6 172.25c-2.5 0-4.9375-1.2656-6.3281-3.5625-2.1172-3.4922-1-8.0352 2.4883-10.152l0.0977-0.0586c3.4961-2.1133 8.0391-1 10.156 2.4922 2.1133 3.4922 1 8.0352-2.4922 10.152l-0.0977 0.0586c-1.1992 0.72656-2.5195 1.0703-3.8242 1.0703z" fill="#fa0"/><path d="m402.14 357.28-15.523 11.602c-4.0234 3.0117-9.6523-0.043-9.5234-5.1641l0.5039-19.75c0.0508-2.0352-0.87109-3.9648-2.4688-5.1641l-15.508-11.621c-4.0234-3.0156-2.9453-9.4726 1.8242-10.93l18.391-5.6094c1.8906-0.57812 3.3906-2.082 4-4.0156l5.9375-18.785c1.5391-4.875 7.8359-5.8125 10.652-1.5898l10.863 16.285c1.1211 1.6758 2.9688 2.6797 4.9414 2.6797l19.18 0.0117c4.9766 4e-3 7.7891 5.8828 4.7578 9.9492l-11.676 15.672c-1.2031 1.6172-1.5586 3.7383-0.94922 5.6719l5.918 18.797c1.5312 4.875-3.0273 9.4453-7.7148 7.7344l-18.078-6.5977c-1.8594-0.67969-3.9258-0.37109-5.5273 0.82422z" fill="#ffd02f"/><path d="m261.51 512c-4.082 0-7.3906-3.3086-7.3906-7.3906 0-57.23 22.832-95.922 41.984-118.3 20.828-24.332 41.613-35.023 42.488-35.469 3.6406-1.8477 8.0898-0.39063 9.9336 3.2539 1.8438 3.6367 0.39453 8.0781-3.2422 9.9297-0.3125 0.16016-19.5 10.164-38.367 32.395-25.227 29.719-38.016 66.121-38.016 108.2 0 4.082-3.3086 7.3906-7.3906 7.3906z" fill="#ff4e61"/><path d="m102.86 397.35 11.766 15.605c3.0547 4.0469 9.2852 2.7305 10.547-2.2266l4.8633-19.113c0.5-1.9648 1.9102-3.5547 3.7695-4.2461l18.039-6.707c4.6797-1.7383 5.3906-8.25 1.207-11.016l-16.141-10.672c-1.6602-1.1016-2.6914-2.9726-2.7578-5.0039l-0.61719-19.75c-0.15625-5.1211-5.9492-7.832-9.7969-4.5859l-14.84 12.516c-1.5312 1.2891-3.5781 1.7227-5.4726 1.1562l-18.422-5.5c-4.7773-1.4258-9.0703 3.4102-7.2617 8.1836l6.9688 18.41c0.71875 1.8945 0.48438 4.0352-0.625 5.7188l-10.77 16.348c-2.793 4.2422 0.34375 9.9375 5.3125 9.6445l19.145-1.1406c1.9727-0.11719 3.875 0.77343 5.0859 2.3789z" fill="#ffd02f"/><path d="m179.02 512c-4.082 0-7.3906-3.3086-7.3906-7.3906 0-30.059-6.6797-57.559-19.852-81.734-1.9531-3.5859-0.62891-8.0742 2.957-10.027 3.5859-1.9531 8.0742-0.62891 10.027 2.9531 14.363 26.375 21.648 56.254 21.648 88.809 0 4.082-3.3086 7.3906-7.3906 7.3906z" fill="#fa0"/><path d="m268.93 55.898c0-11.285-8.8828-20.434-19.836-20.434-10.957 0-19.836 9.1484-19.836 20.434 0 11.285 8.8789 20.438 19.836 20.438 10.953 0 19.836-9.1523 19.836-20.438z" fill="#ffd02f"/><path d="m373.08 446.81c0-11.285-8.8789-20.434-19.832-20.434-10.957 0-19.836 9.1484-19.836 20.434s8.8789 20.434 19.836 20.434c10.953 0 19.832-9.1484 19.832-20.434z" fill="#5c73bc"/><path d="m44.129 450.86c0-9.0508-7.1211-16.387-15.91-16.387-8.7852 0-15.906 7.3359-15.906 16.387 0 9.0547 7.1211 16.391 15.906 16.391 8.7891 0 15.91-7.3359 15.91-16.391z" fill="#62d38f"/><path d="m88.172 288.35c0-9.0508-7.1211-16.387-15.91-16.387-8.7852 0-15.906 7.3359-15.906 16.387s7.1211 16.391 15.906 16.391c8.7891 0 15.91-7.3398 15.91-16.391z" fill="#5c73bc"/><g fill="#ff4e61"><path d="m210.84 16.391c0-9.0547-7.1211-16.391-15.906-16.391-8.7891 0-15.91 7.3359-15.91 16.391 0 9.0508 7.1211 16.387 15.91 16.387 8.7852 0 15.906-7.3359 15.906-16.387z"/><path d="m365.23 152.88c0-9.0508-7.125-16.391-15.91-16.391-8.7852 0-15.91 7.3398-15.91 16.391s7.125 16.387 15.91 16.387c8.7852 0 15.91-7.3359 15.91-16.387z"/><path d="m139.96 32.746c-1.8555 0-3.7109-0.69141-5.1484-2.0898-2.9297-2.8438-3-7.5195-0.15625-10.449l9.1914-9.4688c2.8438-2.9297 7.5234-3 10.449-0.15625 2.9297 2.8438 3 7.5234 0.15625 10.453l-9.1875 9.4688c-1.4492 1.4922-3.3789 2.2422-5.3047 2.2422z"/></g></g></svg>
diff --git a/resources/ui/images/placeholder.svg b/resources/ui/images/placeholder.svg
new file mode 100644
index 0000000000000000000000000000000000000000..23ace81fbb82a8409cc0710c0f7bddd6381f7256
--- /dev/null
+++ b/resources/ui/images/placeholder.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg enable-background="new 0 0 100 100" version="1.1" viewBox="0 0 102 102" xml:space="preserve" xmlns="http://www.w3.org/2000/svg"/>
diff --git a/images/menu/game-pick-image.svg b/resources/ui/images/type_pick-image.svg
similarity index 100%
rename from images/menu/game-pick-image.svg
rename to resources/ui/images/type_pick-image.svg
diff --git a/images/menu/game-pick-word.svg b/resources/ui/images/type_pick-word.svg
similarity index 100%
rename from images/menu/game-pick-word.svg
rename to resources/ui/images/type_pick-word.svg
diff --git a/scripts/cache/.gitkeep b/scripts/cache/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/scripts/cache/download/.gitkeep b/scripts/cache/download/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/scripts/cache/optimized/.gitkeep b/scripts/cache/optimized/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/scripts/cache/selected/.gitkeep b/scripts/cache/selected/.gitkeep
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000