diff --git a/android/app/build.gradle b/android/app/build.gradle
index 92dfdf95cca2b5d45bc09ff6fa27da0762ec3e1d..300b8347137fac66851a5f61f9a0e5d08109a59b 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -37,7 +37,7 @@ if (keystorePropertiesFile.exists()) {
 }
 
 android {
-    compileSdkVersion 33
+    compileSdkVersion 34
     namespace "org.benoitharrault.sortgame"
 
     defaultConfig {
diff --git a/android/gradle.properties b/android/gradle.properties
index cd2d833ca96b3d1ada4a39df51dc5f5ee67665b7..30298b3b3f04073678e48519b8c043edba635df8 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.0.17
-app.versionCode=17
+app.versionName=0.0.18
+app.versionCode=18
diff --git a/assets/files/data.json b/assets/files/data.json
deleted file mode 100644
index 0a37920d3c39be20abe6ba1159c8e111d992abce..0000000000000000000000000000000000000000
--- a/assets/files/data.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-  data: []
-}
diff --git a/assets/fonts/Nunito-Bold.ttf b/assets/fonts/Nunito-Bold.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..6519feb781449ebe0015cbc74dfd9e13110fbba9
Binary files /dev/null and b/assets/fonts/Nunito-Bold.ttf differ
diff --git a/assets/fonts/Nunito-Light.ttf b/assets/fonts/Nunito-Light.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..8a0736c41cd6c2a1225d356bf274de1d0afc3497
Binary files /dev/null and b/assets/fonts/Nunito-Light.ttf differ
diff --git a/assets/fonts/Nunito-Medium.ttf b/assets/fonts/Nunito-Medium.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..88fccdc0638b6f5d6ac49d9d269dc3d518618ad1
Binary files /dev/null and b/assets/fonts/Nunito-Medium.ttf differ
diff --git a/assets/fonts/Nunito-Regular.ttf b/assets/fonts/Nunito-Regular.ttf
new file mode 100644
index 0000000000000000000000000000000000000000..e7b8375a896ef0cd8e06730a78c84532b377e784
Binary files /dev/null and b/assets/fonts/Nunito-Regular.ttf differ
diff --git a/assets/icons/button_back.png b/assets/icons/button_back.png
new file mode 100644
index 0000000000000000000000000000000000000000..cc48ffb1dbb653d9a996f139dfbe02969724bfa5
Binary files /dev/null and b/assets/icons/button_back.png differ
diff --git a/assets/icons/button_start.png b/assets/icons/button_start.png
new file mode 100644
index 0000000000000000000000000000000000000000..6845e2f5c21598ab61f1684d2075aeec0334bf23
Binary files /dev/null and b/assets/icons/button_start.png differ
diff --git a/assets/icons/placeholder.png b/assets/icons/placeholder.png
new file mode 100644
index 0000000000000000000000000000000000000000..814df31be6ddc4275ebe4490c79365578dbef1f0
Binary files /dev/null and b/assets/icons/placeholder.png differ
diff --git a/assets/translations/en.json b/assets/translations/en.json
new file mode 100644
index 0000000000000000000000000000000000000000..5f4285607dd81c5e4a64c24734cb40530e4ac12d
--- /dev/null
+++ b/assets/translations/en.json
@@ -0,0 +1,3 @@
+{
+  "app_name": "SortGame"
+}
diff --git a/assets/translations/fr.json b/assets/translations/fr.json
new file mode 100644
index 0000000000000000000000000000000000000000..5f4285607dd81c5e4a64c24734cb40530e4ac12d
--- /dev/null
+++ b/assets/translations/fr.json
@@ -0,0 +1,3 @@
+{
+  "app_name": "SortGame"
+}
diff --git a/fastlane/metadata/android/en-US/changelogs/18.txt b/fastlane/metadata/android/en-US/changelogs/18.txt
new file mode 100644
index 0000000000000000000000000000000000000000..c4767c31cd60be21ad424c3e0b8357a7a045e229
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/18.txt
@@ -0,0 +1 @@
+Add minimal playable game.
diff --git a/fastlane/metadata/android/fr-FR/changelogs/18.txt b/fastlane/metadata/android/fr-FR/changelogs/18.txt
new file mode 100644
index 0000000000000000000000000000000000000000..fa0c74f6946c75534baca4f6411a9e3a690c3dfe
--- /dev/null
+++ b/fastlane/metadata/android/fr-FR/changelogs/18.txt
@@ -0,0 +1 @@
+Ajout du jeu minimal.
diff --git a/icons/build_game_icons.sh b/icons/build_game_icons.sh
index 218080d1eb12952690ba1e182a468f6e3cf03d65..7368dc4543ff5b92568d683f3d0fb144364bbe04 100755
--- a/icons/build_game_icons.sh
+++ b/icons/build_game_icons.sh
@@ -16,10 +16,9 @@ ICON_SIZE=192
 
 # Game images
 AVAILABLE_GAME_IMAGES="
-"
-
-# Settings images
-AVAILABLES_GAME_SETTINGS="
+  button_back
+  button_start
+  placeholder
 "
 
 #######################################################
@@ -64,19 +63,6 @@ function build_icon() {
   optipng ${OPTIPNG_OPTIONS} ${TARGET}
 }
 
-function build_settings_icons() {
-  INPUT_STRING="$1"
-
-  SETTING_NAME="$(echo "${INPUT_STRING}" | cut -d":" -f1)"
-  SETTING_VALUES="$(echo "${INPUT_STRING}" | cut -d":" -f2 | tr "," " ")"
-
-  for SETTING_VALUE in ${SETTING_VALUES}
-  do
-    SETTING_CODE="${SETTING_NAME}_${SETTING_VALUE}"
-    build_icon ${CURRENT_DIR}/${SETTING_CODE}.svg ${ASSETS_DIR}/icons/${SETTING_CODE}.png
-  done
-}
-
 #######################################################
 
 # Create output folders
@@ -90,9 +76,3 @@ for GAME_IMAGE in ${AVAILABLE_GAME_IMAGES}
 do
   build_icon ${CURRENT_DIR}/${GAME_IMAGE}.svg ${ASSETS_DIR}/icons/${GAME_IMAGE}.png
 done
-
-# build settings images
-for GAME_SETTING in ${AVAILABLES_GAME_SETTINGS}
-do
-  build_settings_icons "${GAME_SETTING}"
-done
diff --git a/icons/build_icons.sh b/icons/build_icons.sh
deleted file mode 100755
index fefc393e2f601cd671938068d23247d6bfb1682b..0000000000000000000000000000000000000000
--- a/icons/build_icons.sh
+++ /dev/null
@@ -1,48 +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}")"
-
-SOURCE="${CURRENT_DIR}/icon.svg"
-OPTIPNG_OPTIONS="-preserve -quiet -o7"
-
-# optimize svg
-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 icons
-function build_icon() {
-  ICON_SIZE="$1"
-  TARGET="$2"
-
-  TARGET_PNG="${TARGET}.png"
-
-  inkscape \
-      --export-width=${ICON_SIZE} \
-      --export-height=${ICON_SIZE} \
-      --export-filename=${TARGET_PNG} \
-      ${SOURCE}
-
-  optipng ${OPTIPNG_OPTIONS} ${TARGET_PNG}
-}
-
-
-build_icon  72 ${BASE_DIR}/android/app/src/main/res/mipmap-hdpi/ic_launcher
-build_icon  48 ${BASE_DIR}/android/app/src/main/res/mipmap-mdpi/ic_launcher
-build_icon  96 ${BASE_DIR}/android/app/src/main/res/mipmap-xhdpi/ic_launcher
-build_icon 144 ${BASE_DIR}/android/app/src/main/res/mipmap-xxhdpi/ic_launcher
-build_icon 192 ${BASE_DIR}/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher
diff --git a/icons/button_back.svg b/icons/button_back.svg
new file mode 100644
index 0000000000000000000000000000000000000000..2622a578dba53ce582afabfc587c2a85a1fb6eaa
--- /dev/null
+++ b/icons/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/icons/button_start.svg b/icons/button_start.svg
new file mode 100644
index 0000000000000000000000000000000000000000..e9d49d2172b9a0305db82779971e3c1e12f34a70
--- /dev/null
+++ b/icons/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/icons/placeholder.svg b/icons/placeholder.svg
new file mode 100644
index 0000000000000000000000000000000000000000..23ace81fbb82a8409cc0710c0f7bddd6381f7256
--- /dev/null
+++ b/icons/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/lib/config/default_game_settings.dart b/lib/config/default_game_settings.dart
new file mode 100644
index 0000000000000000000000000000000000000000..c4486031cf4e7ed40d95822ce17ee826fe84e4b2
--- /dev/null
+++ b/lib/config/default_game_settings.dart
@@ -0,0 +1,30 @@
+import 'package:sortgame/utils/tools.dart';
+
+class DefaultGameSettings {
+  static const List<String> availableParameters = [
+    'itemsCount',
+  ];
+
+  static const int itemsCountValueLow = 5;
+  static const int itemsCountValueMedium = 10;
+  static const int itemsCountValueHigh = 15;
+  static const int itemsCountValueVeryHigh = 20;
+
+  static const int defaultItemsCountValue = itemsCountValueMedium;
+  static const List<int> allowedItemsCountValues = [
+    itemsCountValueLow,
+    itemsCountValueMedium,
+    itemsCountValueHigh,
+    itemsCountValueVeryHigh,
+  ];
+
+  static List<int> getAvailableValues(String parameterCode) {
+    switch (parameterCode) {
+      case 'itemsCount':
+        return DefaultGameSettings.allowedItemsCountValues;
+    }
+
+    printlog('Did not find any available value for game parameter "$parameterCode".');
+    return [];
+  }
+}
diff --git a/lib/config/default_global_settings.dart b/lib/config/default_global_settings.dart
new file mode 100644
index 0000000000000000000000000000000000000000..8b0d15cae4ca4f0dbaa902ac35fdd0c865b91e5a
--- /dev/null
+++ b/lib/config/default_global_settings.dart
@@ -0,0 +1,10 @@
+import 'package:sortgame/utils/tools.dart';
+
+class DefaultGlobalSettings {
+  static const List<String> availableParameters = [];
+
+  static List<int> getAvailableValues(String parameterCode) {
+    printlog('Did not find any available value for global parameter "$parameterCode".');
+    return [];
+  }
+}
diff --git a/lib/config/theme.dart b/lib/config/theme.dart
new file mode 100644
index 0000000000000000000000000000000000000000..be390348c7868e7c63387df13e13c46de43f8a23
--- /dev/null
+++ b/lib/config/theme.dart
@@ -0,0 +1,196 @@
+import 'package:flutter/material.dart';
+
+/// Colors from Tailwind CSS (v3.0) - June 2022
+///
+/// https://tailwindcss.com/docs/customizing-colors
+
+const int _primaryColor = 0xFF6366F1;
+const MaterialColor primarySwatch = MaterialColor(_primaryColor, <int, Color>{
+  50: Color(0xFFEEF2FF), // indigo-50
+  100: Color(0xFFE0E7FF), // indigo-100
+  200: Color(0xFFC7D2FE), // indigo-200
+  300: Color(0xFFA5B4FC), // indigo-300
+  400: Color(0xFF818CF8), // indigo-400
+  500: Color(_primaryColor), // indigo-500
+  600: Color(0xFF4F46E5), // indigo-600
+  700: Color(0xFF4338CA), // indigo-700
+  800: Color(0xFF3730A3), // indigo-800
+  900: Color(0xFF312E81), // indigo-900
+});
+
+const int _textColor = 0xFF64748B;
+const MaterialColor textSwatch = MaterialColor(_textColor, <int, Color>{
+  50: Color(0xFFF8FAFC), // slate-50
+  100: Color(0xFFF1F5F9), // slate-100
+  200: Color(0xFFE2E8F0), // slate-200
+  300: Color(0xFFCBD5E1), // slate-300
+  400: Color(0xFF94A3B8), // slate-400
+  500: Color(_textColor), // slate-500
+  600: Color(0xFF475569), // slate-600
+  700: Color(0xFF334155), // slate-700
+  800: Color(0xFF1E293B), // slate-800
+  900: Color(0xFF0F172A), // slate-900
+});
+
+const Color errorColor = Color(0xFFDC2626); // red-600
+
+final ColorScheme lightColorScheme = ColorScheme.light(
+  primary: primarySwatch.shade500,
+  secondary: primarySwatch.shade500,
+  onSecondary: Colors.white,
+  error: errorColor,
+  background: textSwatch.shade200,
+  onBackground: textSwatch.shade500,
+  onSurface: textSwatch.shade500,
+  surface: textSwatch.shade50,
+  surfaceVariant: Colors.white,
+  shadow: textSwatch.shade900.withOpacity(.1),
+);
+
+final ColorScheme darkColorScheme = ColorScheme.dark(
+  primary: primarySwatch.shade500,
+  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),
+  shadow: textSwatch.shade900.withOpacity(.2),
+);
+
+final ThemeData lightTheme = ThemeData(
+  colorScheme: lightColorScheme,
+  fontFamily: 'Nunito',
+  textTheme: TextTheme(
+    displayLarge: TextStyle(
+      color: textSwatch.shade700,
+      fontFamily: 'Nunito',
+    ),
+    displayMedium: TextStyle(
+      color: textSwatch.shade600,
+      fontFamily: 'Nunito',
+    ),
+    displaySmall: TextStyle(
+      color: textSwatch.shade500,
+      fontFamily: 'Nunito',
+    ),
+    headlineLarge: TextStyle(
+      color: textSwatch.shade700,
+      fontFamily: 'Nunito',
+    ),
+    headlineMedium: TextStyle(
+      color: textSwatch.shade600,
+      fontFamily: 'Nunito',
+    ),
+    headlineSmall: TextStyle(
+      color: textSwatch.shade500,
+      fontFamily: 'Nunito',
+    ),
+    titleLarge: TextStyle(
+      color: textSwatch.shade700,
+      fontFamily: 'Nunito',
+    ),
+    titleMedium: TextStyle(
+      color: textSwatch.shade600,
+      fontFamily: 'Nunito',
+    ),
+    titleSmall: TextStyle(
+      color: textSwatch.shade500,
+      fontFamily: 'Nunito',
+    ),
+    bodyLarge: TextStyle(
+      color: textSwatch.shade700,
+      fontFamily: 'Nunito',
+    ),
+    bodyMedium: TextStyle(
+      color: textSwatch.shade600,
+      fontFamily: 'Nunito',
+    ),
+    bodySmall: TextStyle(
+      color: textSwatch.shade500,
+      fontFamily: 'Nunito',
+    ),
+    labelLarge: TextStyle(
+      color: textSwatch.shade700,
+      fontFamily: 'Nunito',
+    ),
+    labelMedium: TextStyle(
+      color: textSwatch.shade600,
+      fontFamily: 'Nunito',
+    ),
+    labelSmall: TextStyle(
+      color: textSwatch.shade500,
+      fontFamily: 'Nunito',
+    ),
+  ),
+);
+
+final ThemeData darkTheme = lightTheme.copyWith(
+  colorScheme: darkColorScheme,
+  textTheme: TextTheme(
+    displayLarge: TextStyle(
+      color: textSwatch.shade200,
+      fontFamily: 'Nunito',
+    ),
+    displayMedium: TextStyle(
+      color: textSwatch.shade300,
+      fontFamily: 'Nunito',
+    ),
+    displaySmall: TextStyle(
+      color: textSwatch.shade400,
+      fontFamily: 'Nunito',
+    ),
+    headlineLarge: TextStyle(
+      color: textSwatch.shade200,
+      fontFamily: 'Nunito',
+    ),
+    headlineMedium: TextStyle(
+      color: textSwatch.shade300,
+      fontFamily: 'Nunito',
+    ),
+    headlineSmall: TextStyle(
+      color: textSwatch.shade400,
+      fontFamily: 'Nunito',
+    ),
+    titleLarge: TextStyle(
+      color: textSwatch.shade200,
+      fontFamily: 'Nunito',
+    ),
+    titleMedium: TextStyle(
+      color: textSwatch.shade300,
+      fontFamily: 'Nunito',
+    ),
+    titleSmall: TextStyle(
+      color: textSwatch.shade400,
+      fontFamily: 'Nunito',
+    ),
+    bodyLarge: TextStyle(
+      color: textSwatch.shade200,
+      fontFamily: 'Nunito',
+    ),
+    bodyMedium: TextStyle(
+      color: textSwatch.shade300,
+      fontFamily: 'Nunito',
+    ),
+    bodySmall: TextStyle(
+      color: textSwatch.shade400,
+      fontFamily: 'Nunito',
+    ),
+    labelLarge: TextStyle(
+      color: textSwatch.shade200,
+      fontFamily: 'Nunito',
+    ),
+    labelMedium: TextStyle(
+      color: textSwatch.shade300,
+      fontFamily: 'Nunito',
+    ),
+    labelSmall: TextStyle(
+      color: textSwatch.shade400,
+      fontFamily: 'Nunito',
+    ),
+  ),
+);
+
+final ThemeData appTheme = darkTheme;
diff --git a/lib/cubit/game_cubit.dart b/lib/cubit/game_cubit.dart
new file mode 100644
index 0000000000000000000000000000000000000000..8a2551c889ff95a9c6ae8d42389f6b1fc9a931df
--- /dev/null
+++ b/lib/cubit/game_cubit.dart
@@ -0,0 +1,87 @@
+import 'package:equatable/equatable.dart';
+import 'package:flutter/material.dart';
+import 'package:hydrated_bloc/hydrated_bloc.dart';
+
+import 'package:sortgame/models/game.dart';
+import 'package:sortgame/models/settings_game.dart';
+import 'package:sortgame/models/settings_global.dart';
+
+part 'game_state.dart';
+
+class GameCubit extends HydratedCubit<GameState> {
+  GameCubit()
+      : super(GameState(
+          currentGame: Game.createNull(),
+        ));
+
+  void updateState(Game game) {
+    emit(GameState(
+      currentGame: game,
+    ));
+  }
+
+  void refresh() {
+    final Game game = Game(
+      items: state.currentGame.items,
+      gameSettings: state.currentGame.gameSettings,
+      globalSettings: state.currentGame.globalSettings,
+      isRunning: state.currentGame.isRunning,
+      isFinished: state.currentGame.isFinished,
+      position: state.currentGame.position,
+      score: state.currentGame.score,
+    );
+    game.dump();
+
+    updateState(game);
+  }
+
+  void quitGame() {
+    state.currentGame.updateGameIsRunning(false);
+    refresh();
+  }
+
+  void increasePosition() {
+    if (state.currentGame.position < state.currentGame.items.length) {
+      state.currentGame.increasePosition();
+    } else {
+      state.currentGame.updateGameIsFinished(true);
+    }
+    refresh();
+  }
+
+  void increaseScore(int increment) {
+    state.currentGame.increaseScore(increment);
+    refresh();
+  }
+
+  void startNewGame({
+    required GameSettings gameSettings,
+    required GlobalSettings globalSettings,
+  }) {
+    Game newGame = Game.createNew(
+      gameSettings: gameSettings,
+      globalSettings: globalSettings,
+    );
+
+    newGame.dump();
+
+    updateState(newGame);
+    refresh();
+  }
+
+  @override
+  GameState? fromJson(Map<String, dynamic> json) {
+    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..3fd161a0915313722b7a15c55c7cf538a7e3b6e1
--- /dev/null
+++ b/lib/cubit/game_state.dart
@@ -0,0 +1,19 @@
+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,
+      ];
+
+  Map<String, dynamic> get values => <String, dynamic>{
+        'currentGame': currentGame,
+      };
+}
diff --git a/lib/cubit/settings_game_cubit.dart b/lib/cubit/settings_game_cubit.dart
new file mode 100644
index 0000000000000000000000000000000000000000..a2c04ea96f915f709c25b31942c277bb742ade54
--- /dev/null
+++ b/lib/cubit/settings_game_cubit.dart
@@ -0,0 +1,61 @@
+import 'package:equatable/equatable.dart';
+import 'package:flutter/material.dart';
+import 'package:hydrated_bloc/hydrated_bloc.dart';
+
+import 'package:sortgame/models/settings_game.dart';
+import 'package:sortgame/utils/tools.dart';
+
+part 'settings_game_state.dart';
+
+class GameSettingsCubit extends HydratedCubit<GameSettingsState> {
+  GameSettingsCubit() : super(GameSettingsState(settings: GameSettings.createDefault()));
+
+  void setValues({
+    int? itemsCount,
+  }) {
+    emit(
+      GameSettingsState(
+        settings: GameSettings(
+          itemsCount: itemsCount ?? state.settings.itemsCount,
+        ),
+      ),
+    );
+  }
+
+  int getParameterValue(String code) {
+    switch (code) {
+      case 'itemsCount':
+        return GameSettings.getItemsCountValueFromUnsafe(state.settings.itemsCount);
+    }
+    return 0;
+  }
+
+  void setParameterValue(String code, int value) {
+    printlog('GameSettingsCubit.setParameterValue');
+    printlog('code: $code  / value: $value');
+
+    int itemsCount = code == 'itemsCount' ? value : getParameterValue('itemsCount');
+
+    setValues(
+      itemsCount: itemsCount,
+    );
+  }
+
+  @override
+  GameSettingsState? fromJson(Map<String, dynamic> json) {
+    int itemsCount = json['itemsCount'] as int;
+
+    return GameSettingsState(
+      settings: GameSettings(
+        itemsCount: itemsCount,
+      ),
+    );
+  }
+
+  @override
+  Map<String, dynamic>? toJson(GameSettingsState state) {
+    return <String, dynamic>{
+      'itemsCount': state.settings.itemsCount,
+    };
+  }
+}
diff --git a/lib/cubit/settings_game_state.dart b/lib/cubit/settings_game_state.dart
new file mode 100644
index 0000000000000000000000000000000000000000..b773dc69be12673b158e880e2d7e6e7bec465506
--- /dev/null
+++ b/lib/cubit/settings_game_state.dart
@@ -0,0 +1,19 @@
+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,
+      ];
+
+  Map<String, dynamic> get values => <String, dynamic>{
+        'settings': settings,
+      };
+}
diff --git a/lib/cubit/settings_global_cubit.dart b/lib/cubit/settings_global_cubit.dart
new file mode 100644
index 0000000000000000000000000000000000000000..36b4b20ed5e0c18f5509e0214986fecb86df4d3a
--- /dev/null
+++ b/lib/cubit/settings_global_cubit.dart
@@ -0,0 +1,44 @@
+import 'package:equatable/equatable.dart';
+import 'package:flutter/material.dart';
+import 'package:hydrated_bloc/hydrated_bloc.dart';
+
+import 'package:sortgame/models/settings_global.dart';
+import 'package:sortgame/utils/tools.dart';
+
+part 'settings_global_state.dart';
+
+class GlobalSettingsCubit extends HydratedCubit<GlobalSettingsState> {
+  GlobalSettingsCubit() : super(GlobalSettingsState(settings: GlobalSettings.createDefault()));
+
+  void setValues() {
+    emit(
+      GlobalSettingsState(
+        settings: GlobalSettings(),
+      ),
+    );
+  }
+
+  int getParameterValue(String code) {
+    switch (code) {}
+    return 0;
+  }
+
+  void setParameterValue(String code, int value) {
+    printlog('GlobalSettingsCubit.setParameterValue');
+    printlog('code: $code  / value: $value');
+
+    setValues();
+  }
+
+  @override
+  GlobalSettingsState? fromJson(Map<String, dynamic> json) {
+    return GlobalSettingsState(
+      settings: GlobalSettings(),
+    );
+  }
+
+  @override
+  Map<String, dynamic>? toJson(GlobalSettingsState state) {
+    return <String, dynamic>{};
+  }
+}
diff --git a/lib/cubit/settings_global_state.dart b/lib/cubit/settings_global_state.dart
new file mode 100644
index 0000000000000000000000000000000000000000..4e4fbdf707b4e805f2092d0ca6a68a2de1c957c6
--- /dev/null
+++ b/lib/cubit/settings_global_state.dart
@@ -0,0 +1,19 @@
+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,
+      ];
+
+  Map<String, dynamic> get values => <String, dynamic>{
+        'settings': settings,
+      };
+}
diff --git a/lib/data/fetch_data_helper.dart b/lib/data/fetch_data_helper.dart
new file mode 100644
index 0000000000000000000000000000000000000000..2b5148c194338d497a9b2ef79d10ecddf0d0395f
--- /dev/null
+++ b/lib/data/fetch_data_helper.dart
@@ -0,0 +1,75 @@
+import 'package:sortgame/data/game_data.dart';
+import 'package:sortgame/models/data/category.dart';
+import 'package:sortgame/models/data/game_item.dart';
+import 'package:sortgame/models/data/item.dart';
+import 'package:sortgame/utils/tools.dart';
+
+class FetchDataHelper {
+  FetchDataHelper();
+
+  final List<Category> _categories = [];
+  List<Category> get categories => _categories;
+
+  final List<Item> _items = [];
+  List<Item> get items => _items;
+
+  final List<GameItem> _mapping = [];
+
+  void init() {
+    try {
+      const gameData = GameData.data;
+
+      final List<dynamic> rawCategories = gameData['categories'] as List<dynamic>;
+      for (var rawElement in rawCategories) {
+        final element = rawElement.toString();
+        _categories.add(Category(key: element, text: element));
+      }
+
+      final List<dynamic> rawItems = gameData['items'] as List<dynamic>;
+      for (var rawElement in rawItems) {
+        final element = rawElement.toString();
+        _items.add(Item(key: element, text: element));
+      }
+
+      final Map<String, dynamic> rawMapping = gameData['mapping'] as Map<String, dynamic>;
+      final Map<String, dynamic> rawMappingItems = rawMapping['items'] as Map<String, dynamic>;
+      rawMappingItems.forEach(
+        (String itemName, itemMappings) {
+          List<String> rawIsCategories = itemMappings['is'] as List<String>;
+          List<String> rawIsNotCategories = itemMappings['isnot'] as List<String>;
+
+          _mapping.add(GameItem(
+            item: Item(
+              key: itemName,
+              text: itemName,
+            ),
+            isCategory: rawIsCategories
+                .map((String category) => Category(key: category, text: category))
+                .toList(),
+            isNotCategory: rawIsNotCategories
+                .map((String category) => Category(key: category, text: category))
+                .toList(),
+          ));
+        },
+      );
+    } catch (e) {
+      printlog("$e");
+    }
+  }
+
+  List<GameItem> getItems(int count) {
+    if (_mapping.isEmpty) {
+      init();
+    }
+
+    List<GameItem> items = _mapping;
+
+    // Remove items without enough data
+    items.removeWhere((GameItem question) =>
+        (question.isCategory.isEmpty || question.isNotCategory.isEmpty));
+
+    items.shuffle();
+
+    return items.take(count).toList();
+  }
+}
diff --git a/lib/data/game_data.dart b/lib/data/game_data.dart
new file mode 100644
index 0000000000000000000000000000000000000000..4566cbfcbdb18652785fc73e67541f454674a9d0
--- /dev/null
+++ b/lib/data/game_data.dart
@@ -0,0 +1,376 @@
+class GameData {
+  static const Map<String, dynamic> data = {
+    "categories": ["artificiel", "gazeux", "inerte", "liquide", "naturel", "solide", "vivant"],
+    "exclusions": [
+      ["liquide", "solide", "gazeux"],
+      ["inerte", "vivant"],
+      ["naturel", "artificiel"]
+    ],
+    "items": [
+      "ABEILLE",
+      "AMPOULE",
+      "ARBRE",
+      "ASPIRATEUR",
+      "BALAI",
+      "BANANE",
+      "BERCEAU",
+      "BONBON",
+      "BOUGIE",
+      "BROUETTE",
+      "CAFETIÈRE",
+      "CANARD",
+      "CASQUETTE",
+      "CHAISE",
+      "CHAUSSURE",
+      "CINTRE",
+      "COCCINELLE",
+      "CONFITURE",
+      "CORDE",
+      "CROCODILE",
+      "DROMADAIRE",
+      "FENÊTRE",
+      "FOURMI",
+      "FUSÉE",
+      "GOURDE",
+      "GUÊPE",
+      "HÉLICOPTÈRE",
+      "KANGOUROU",
+      "LAMPE",
+      "LICORNE",
+      "LIVRE",
+      "MAISON",
+      "MOUCHE",
+      "NOEUD",
+      "ORAGE",
+      "OURS",
+      "PAPILLON",
+      "PEIGNE",
+      "PENDULE",
+      "PIANO",
+      "PIZZA",
+      "POMME",
+      "POULET",
+      "PUZZLE",
+      "PÊCHE",
+      "REQUIN",
+      "ROSE",
+      "SAC À DOS",
+      "SANGLIER",
+      "SAVON",
+      "SINGE",
+      "STADE",
+      "TABOURET",
+      "TARTINE",
+      "TIROIR",
+      "TORTUE",
+      "TROMPETTE",
+      "VACHE",
+      "VOILIER",
+      "ZÈBRE"
+    ],
+    "mapping": {
+      "items": {
+        "ABEILLE": {
+          "is": ["naturel", "vivant"],
+          "isnot": ["artificiel", "gazeux", "inerte"],
+          "na": ["liquide"]
+        },
+        "AMPOULE": {
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "ARBRE": {
+          "is": ["naturel", "vivant"],
+          "isnot": ["artificiel", "inerte", "liquide"],
+          "na": []
+        },
+        "ASPIRATEUR": {
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "BALAI": {
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "BANANE": {
+          "is": ["solide", "vivant"],
+          "isnot": ["gazeux", "inerte", "liquide"],
+          "na": []
+        },
+        "BERCEAU": {
+          "is": ["artificiel", "inerte"],
+          "isnot": ["liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "BONBON": {
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "BOUGIE": {
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "BROUETTE": {
+          "is": ["artificiel", "inerte"],
+          "isnot": ["liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "CAFETIÈRE": {
+          "is": ["inerte"],
+          "isnot": ["liquide", "vivant"],
+          "na": []
+        },
+        "CANARD": {
+          "is": ["naturel", "solide", "vivant"],
+          "isnot": ["artificiel", "gazeux", "inerte", "liquide"],
+          "na": ["liquide"]
+        },
+        "CASQUETTE": {
+          "is": ["artificiel", "inerte"],
+          "isnot": ["liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "CHAISE": {
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "CHAUSSURE": {
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "CINTRE": {
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "COCCINELLE": {
+          "is": ["naturel", "vivant"],
+          "isnot": ["artificiel", "gazeux", "inerte"],
+          "na": ["liquide", "solide"]
+        },
+        "CONFITURE": {
+          "is": ["inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "vivant"],
+          "na": ["liquide"]
+        },
+        "CORDE": {
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "CROCODILE": {
+          "is": ["naturel", "vivant"],
+          "isnot": ["artificiel", "gazeux", "inerte"],
+          "na": ["liquide", "solide"]
+        },
+        "DROMADAIRE": {
+          "is": ["naturel", "solide", "vivant"],
+          "isnot": ["artificiel", "gazeux", "inerte", "liquide"],
+          "na": []
+        },
+        "FENÊTRE": {
+          "is": ["artificiel", "inerte"],
+          "isnot": ["naturel", "vivant"],
+          "na": ["liquide"]
+        },
+        "FOURMI": {
+          "is": ["naturel", "solide", "vivant"],
+          "isnot": ["artificiel", "gazeux", "inerte", "liquide"],
+          "na": ["liquide"]
+        },
+        "FUSÉE": {
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "GOURDE": {
+          "is": ["artificiel", "solide"],
+          "isnot": ["gazeux", "liquide", "naturel"],
+          "na": []
+        },
+        "GUÊPE": {
+          "is": ["naturel", "vivant"],
+          "isnot": ["artificiel", "inerte"],
+          "na": ["liquide"]
+        },
+        "HÉLICOPTÈRE": {
+          "is": ["artificiel", "inerte"],
+          "isnot": ["gazeux", "naturel", "vivant"],
+          "na": []
+        },
+        "KANGOUROU": {
+          "is": ["naturel", "solide", "vivant"],
+          "isnot": ["artificiel", "gazeux", "inerte", "liquide"],
+          "na": []
+        },
+        "LAMPE": {
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "LICORNE": {
+          "is": ["naturel", "solide", "vivant"],
+          "isnot": ["artificiel", "gazeux", "inerte", "liquide"],
+          "na": ["naturel"]
+        },
+        "LIVRE": {
+          "is": ["artificiel"],
+          "isnot": ["liquide", "naturel"],
+          "na": []
+        },
+        "MAISON": {
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "MOUCHE": {
+          "is": ["naturel"],
+          "isnot": ["artificiel"],
+          "na": ["liquide"]
+        },
+        "NOEUD": {
+          "is": ["inerte"],
+          "isnot": ["liquide", "vivant"],
+          "na": ["artificiel", "solide"]
+        },
+        "ORAGE": {
+          "is": ["inerte", "naturel"],
+          "isnot": ["artificiel", "vivant"],
+          "na": ["solide"]
+        },
+        "OURS": {
+          "is": ["naturel", "vivant"],
+          "isnot": ["artificiel", "gazeux", "inerte"],
+          "na": ["liquide"]
+        },
+        "PAPILLON": {
+          "is": ["naturel", "vivant"],
+          "isnot": ["artificiel", "gazeux", "inerte"],
+          "na": ["solide"]
+        },
+        "PEIGNE": {
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "PENDULE": {
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "PIANO": {
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "PIZZA": {
+          "is": ["artificiel", "inerte"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "POMME": {
+          "is": ["naturel", "solide", "vivant"],
+          "isnot": ["artificiel", "gazeux", "inerte", "liquide"],
+          "na": []
+        },
+        "POULET": {
+          "is": ["naturel", "vivant"],
+          "isnot": ["artificiel", "gazeux", "inerte"],
+          "na": ["liquide", "solide"]
+        },
+        "PUZZLE": {
+          "is": ["artificiel", "inerte"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "PÊCHE": {
+          "is": ["naturel", "vivant"],
+          "isnot": ["artificiel", "gazeux", "inerte", "liquide"],
+          "na": []
+        },
+        "REQUIN": {
+          "is": ["naturel", "vivant"],
+          "isnot": ["artificiel", "inerte"],
+          "na": []
+        },
+        "ROSE": {
+          "is": ["naturel", "solide", "vivant"],
+          "isnot": ["artificiel", "gazeux", "inerte", "liquide"],
+          "na": []
+        },
+        "SAC À DOS": {
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "SANGLIER": {
+          "is": ["naturel"],
+          "isnot": ["artificiel", "gazeux"],
+          "na": ["solide"]
+        },
+        "SAVON": {
+          "is": ["artificiel", "inerte"],
+          "isnot": ["naturel", "vivant"],
+          "na": ["liquide", "solide"]
+        },
+        "SINGE": {
+          "is": ["naturel", "vivant"],
+          "isnot": ["artificiel", "inerte"],
+          "na": []
+        },
+        "STADE": {
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "TABOURET": {
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "TARTINE": {
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "TIROIR": {
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "TORTUE": {
+          "is": ["naturel", "solide", "vivant"],
+          "isnot": ["artificiel", "gazeux", "inerte", "liquide"],
+          "na": ["liquide"]
+        },
+        "TROMPETTE": {
+          "is": ["inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "vivant"],
+          "na": []
+        },
+        "VACHE": {
+          "is": ["naturel", "solide", "vivant"],
+          "isnot": ["artificiel", "gazeux", "inerte", "liquide"],
+          "na": ["liquide"]
+        },
+        "VOILIER": {
+          "is": ["artificiel", "inerte", "solide"],
+          "isnot": ["gazeux", "liquide", "naturel", "vivant"],
+          "na": []
+        },
+        "ZÈBRE": {
+          "is": ["naturel", "vivant"],
+          "isnot": ["artificiel", "gazeux", "inerte"],
+          "na": ["solide"]
+        }
+      }
+    }
+  };
+}
diff --git a/lib/main.dart b/lib/main.dart
index 19b7ded76a61c82c9de189319de1bf5df982151b..3d37ac60e06f202a1ec314397fd043bc84b6446d 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,31 +1,64 @@
+import 'dart:io';
+
+import 'package:easy_localization/easy_localization.dart';
 import 'package:flutter/material.dart';
-import 'package:provider/provider.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:sortgame/config/theme.dart';
+import 'package:sortgame/cubit/game_cubit.dart';
+import 'package:sortgame/cubit/settings_game_cubit.dart';
+import 'package:sortgame/cubit/settings_global_cubit.dart';
+import 'package:sortgame/ui/skeleton.dart';
 
-import 'provider/data.dart';
-import 'screens/home.dart';
+void main() async {
+  // Initialize packages
+  WidgetsFlutterBinding.ensureInitialized();
+  await EasyLocalization.ensureInitialized();
+  final Directory tmpDir = await getTemporaryDirectory();
+  Hive.init(tmpDir.toString());
+  HydratedBloc.storage = await HydratedStorage.build(
+    storageDirectory: tmpDir,
+  );
 
-void main() => runApp(const MyApp());
+  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 {
   const MyApp({super.key});
 
   @override
   Widget build(BuildContext context) {
-    return ChangeNotifierProvider(
-      create: (BuildContext context) => Data(),
-      child: Consumer<Data>(builder: (context, data, child) {
-        return MaterialApp(
-          debugShowCheckedModeBanner: false,
-          theme: ThemeData(
-            primaryColor: Colors.blue,
-            visualDensity: VisualDensity.adaptivePlatformDensity,
-          ),
-          home: const Home(),
-          routes: {
-            Home.id: (context) => const Home(),
-          },
-        );
-      }),
+    return MultiBlocProvider(
+      providers: [
+        BlocProvider<GameCubit>(create: (context) => GameCubit()),
+        BlocProvider<GlobalSettingsCubit>(create: (context) => GlobalSettingsCubit()),
+        BlocProvider<GameSettingsCubit>(create: (context) => GameSettingsCubit()),
+      ],
+      child: MaterialApp(
+        title: 'SortGame',
+        theme: appTheme,
+        home: const SkeletonScreen(),
+
+        // Localization stuff
+        localizationsDelegates: context.localizationDelegates,
+        supportedLocales: context.supportedLocales,
+        locale: context.locale,
+        debugShowCheckedModeBanner: false,
+      ),
     );
   }
 }
diff --git a/lib/models/data/category.dart b/lib/models/data/category.dart
new file mode 100644
index 0000000000000000000000000000000000000000..9e561ecf1da7c9b7a417c58027e316f69b3ba25f
--- /dev/null
+++ b/lib/models/data/category.dart
@@ -0,0 +1,21 @@
+class Category {
+  final String key;
+  final String text;
+
+  const Category({
+    required this.key,
+    required this.text,
+  });
+
+  Map<String, dynamic> toJson() {
+    return {
+      'key': key,
+      'text': text,
+    };
+  }
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/lib/models/data/game_item.dart b/lib/models/data/game_item.dart
new file mode 100644
index 0000000000000000000000000000000000000000..f1c8cc3075e4363831920fa2842750a4772a1819
--- /dev/null
+++ b/lib/models/data/game_item.dart
@@ -0,0 +1,27 @@
+import 'package:sortgame/models/data/category.dart';
+import 'package:sortgame/models/data/item.dart';
+
+class GameItem {
+  final Item item;
+  final List<Category> isCategory;
+  final List<Category> isNotCategory;
+
+  GameItem({
+    required this.item,
+    required this.isCategory,
+    required this.isNotCategory,
+  });
+
+  @override
+  String toString() {
+    return '$GameItem(${toJson()})';
+  }
+
+  Map<String, dynamic>? toJson() {
+    return <String, dynamic>{
+      'item': item.toJson(),
+      'isCategory': isCategory.toString(),
+      'isNotCategory': isNotCategory.toString(),
+    };
+  }
+}
diff --git a/lib/models/data/item.dart b/lib/models/data/item.dart
new file mode 100644
index 0000000000000000000000000000000000000000..f22ca4aaf55727f84c08b9a16a7ab1cca5557821
--- /dev/null
+++ b/lib/models/data/item.dart
@@ -0,0 +1,21 @@
+class Item {
+  final String key;
+  final String text;
+
+  const Item({
+    required this.key,
+    required this.text,
+  });
+
+  Map<String, dynamic> toJson() {
+    return {
+      'key': key,
+      'text': text,
+    };
+  }
+
+  @override
+  String toString() {
+    return toJson().toString();
+  }
+}
diff --git a/lib/models/game.dart b/lib/models/game.dart
new file mode 100644
index 0000000000000000000000000000000000000000..797ac0b2bac87b3e691bc1a4ad364a0e9e5ba38f
--- /dev/null
+++ b/lib/models/game.dart
@@ -0,0 +1,104 @@
+import 'package:sortgame/data/fetch_data_helper.dart';
+import 'package:sortgame/models/data/game_item.dart';
+import 'package:sortgame/models/settings_game.dart';
+import 'package:sortgame/models/settings_global.dart';
+import 'package:sortgame/utils/tools.dart';
+
+class Game {
+  final List<GameItem> items;
+  final GameSettings gameSettings;
+  final GlobalSettings globalSettings;
+  bool isRunning = false;
+  bool isFinished = false;
+  int position = 1;
+  int score = 0;
+
+  Game({
+    required this.items,
+    required this.gameSettings,
+    required this.globalSettings,
+    this.isRunning = false,
+    this.isFinished = false,
+    this.position = 1,
+    this.score = 0,
+  });
+
+  factory Game.createNull() {
+    return Game(
+      items: [],
+      gameSettings: GameSettings.createDefault(),
+      globalSettings: GlobalSettings.createDefault(),
+    );
+  }
+
+  factory Game.createNew({
+    GameSettings? gameSettings,
+    GlobalSettings? globalSettings,
+  }) {
+    GameSettings newGameSettings = gameSettings ?? GameSettings.createDefault();
+    GlobalSettings newGlobalSettings = globalSettings ?? GlobalSettings.createDefault();
+
+    List<GameItem> items = FetchDataHelper().getItems(newGameSettings.itemsCount);
+
+    return Game(
+      items: items,
+      gameSettings: newGameSettings,
+      globalSettings: newGlobalSettings,
+      isRunning: true,
+    );
+  }
+
+  void increaseScore(int? count) {
+    score += (count ?? 0);
+  }
+
+  void increasePosition() {
+    position += 1;
+  }
+
+  void updateGameIsRunning(bool gameIsRunning) {
+    isRunning = gameIsRunning;
+  }
+
+  void updateGameIsFinished(bool gameIsFinished) {
+    isFinished = gameIsFinished;
+  }
+
+  GameItem getCurrentQuestion() {
+    return items[position - 1];
+  }
+
+  void dump() {
+    printlog('');
+    printlog('## Current game dump:');
+    printlog('');
+    gameSettings.dump();
+    globalSettings.dump();
+    printlog('');
+    items.toString();
+    printlog('');
+    printlog('Game: ');
+    printlog('  isRunning: $isRunning');
+    printlog('  isFinished: $isFinished');
+    printlog('  position: $position');
+    printlog('  score: $score');
+    printlog('');
+  }
+
+  @override
+  String toString() {
+    return '$Game(${toJson()})';
+  }
+
+  Map<String, dynamic>? toJson() {
+    return <String, dynamic>{
+      'items': items.toString(),
+      'gameSettings': gameSettings.toJson(),
+      'globalSettings': globalSettings.toJson(),
+      'isRunning': isRunning,
+      'isFinished': isFinished,
+      'position': position,
+      'score': score,
+    };
+  }
+}
diff --git a/lib/models/settings_game.dart b/lib/models/settings_game.dart
new file mode 100644
index 0000000000000000000000000000000000000000..67681ec8b9a761986cf41cc0db681fb39f82b8e0
--- /dev/null
+++ b/lib/models/settings_game.dart
@@ -0,0 +1,40 @@
+import 'package:sortgame/config/default_game_settings.dart';
+import 'package:sortgame/utils/tools.dart';
+
+class GameSettings {
+  final int itemsCount;
+
+  GameSettings({
+    required this.itemsCount,
+  });
+
+  static int getItemsCountValueFromUnsafe(int itemsCount) {
+    if (DefaultGameSettings.allowedItemsCountValues.contains(itemsCount)) {
+      return itemsCount;
+    }
+
+    return DefaultGameSettings.defaultItemsCountValue;
+  }
+
+  factory GameSettings.createDefault() {
+    return GameSettings(
+      itemsCount: DefaultGameSettings.defaultItemsCountValue,
+    );
+  }
+
+  void dump() {
+    printlog('Settings: ');
+    printlog('  itemsCount: $itemsCount');
+  }
+
+  @override
+  String toString() {
+    return '$GameSettings(${toJson()})';
+  }
+
+  Map<String, dynamic>? toJson() {
+    return <String, dynamic>{
+      'itemsCount': itemsCount,
+    };
+  }
+}
diff --git a/lib/models/settings_global.dart b/lib/models/settings_global.dart
new file mode 100644
index 0000000000000000000000000000000000000000..1da37395f09b1c71c656274c5248a2f6d0edae95
--- /dev/null
+++ b/lib/models/settings_global.dart
@@ -0,0 +1,22 @@
+import 'package:sortgame/utils/tools.dart';
+
+class GlobalSettings {
+  GlobalSettings();
+
+  factory GlobalSettings.createDefault() {
+    return GlobalSettings();
+  }
+
+  void dump() {
+    printlog('Settings: ');
+  }
+
+  @override
+  String toString() {
+    return '$GlobalSettings(${toJson()})';
+  }
+
+  Map<String, dynamic>? toJson() {
+    return <String, dynamic>{};
+  }
+}
diff --git a/lib/provider/data.dart b/lib/provider/data.dart
deleted file mode 100644
index 9e9148993cc5dfe304c231ae7165428d8f93c3af..0000000000000000000000000000000000000000
--- a/lib/provider/data.dart
+++ /dev/null
@@ -1,25 +0,0 @@
-import 'package:flutter/foundation.dart';
-
-class Data extends ChangeNotifier {
-  bool _searchingImage = false;
-  String _image = '';
-
-  bool get searchingImage => _searchingImage;
-
-  set searchingImage(bool value) {
-    _searchingImage = value;
-    notifyListeners();
-  }
-
-  String get image => _image;
-
-  set updateImage(String value) {
-    _image = value;
-    notifyListeners();
-  }
-
-  void resetGame() {
-    _image = '';
-    notifyListeners();
-  }
-}
diff --git a/lib/screens/home.dart b/lib/screens/home.dart
deleted file mode 100644
index 7ba9dea966562c242250a4e19f0d8e91db3508b8..0000000000000000000000000000000000000000
--- a/lib/screens/home.dart
+++ /dev/null
@@ -1,55 +0,0 @@
-import 'package:flutter/material.dart';
-
-import 'package:sortgame/utils/tools.dart';
-
-class Home extends StatelessWidget {
-  const Home({super.key});
-
-  static const String id = 'home';
-
-  @override
-  Widget build(BuildContext context) {
-    return Scaffold(
-      appBar: AppBar(
-        title: const Text('Sorting game'),
-      ),
-      body: Center(
-        child: Column(
-          mainAxisAlignment: MainAxisAlignment.center,
-          children: <Widget>[
-            Column(
-              mainAxisSize: MainAxisSize.min,
-              mainAxisAlignment: MainAxisAlignment.center,
-              children: [
-                Container(
-                  margin: const EdgeInsets.all(4),
-                  padding: const EdgeInsets.all(4),
-                  decoration: BoxDecoration(
-                    color: Colors.blue,
-                    borderRadius: BorderRadius.circular(4),
-                    border: Border.all(
-                      color: Colors.green,
-                      width: 4,
-                    ),
-                  ),
-                  child: TextButton(
-                    child: const Text(
-                      '🎲',
-                      textAlign: TextAlign.center,
-                      style: TextStyle(
-                        fontSize: 50,
-                        fontWeight: FontWeight.w600,
-                        color: Colors.black,
-                      ),
-                    ),
-                    onPressed: () => printlog('X'),
-                  ),
-                ),
-              ],
-            ),
-          ],
-        ),
-      ),
-    );
-  }
-}
diff --git a/lib/ui/painters/parameter_painter.dart b/lib/ui/painters/parameter_painter.dart
new file mode 100644
index 0000000000000000000000000000000000000000..fd4e3921d5fdecf4812a263148c4f1a3641b2c4e
--- /dev/null
+++ b/lib/ui/painters/parameter_painter.dart
@@ -0,0 +1,149 @@
+import 'dart:math';
+
+import 'package:flutter/material.dart';
+
+import 'package:sortgame/config/default_game_settings.dart';
+import 'package:sortgame/models/settings_game.dart';
+import 'package:sortgame/models/settings_global.dart';
+import 'package:sortgame/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 int 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 = 20 / 100 * canvasSize;
+    canvas.drawRect(
+        Rect.fromPoints(const Offset(0, 0), Offset(canvasSize, canvasSize)), paint);
+
+    // content
+    switch (code) {
+      case 'itemsCount':
+        paintItemsCountParameterItem(value, canvas, canvasSize);
+        break;
+      default:
+        printlog('Unknown parameter: $code/$value');
+        paintUnknownParameterItem(value, canvas, canvasSize);
+    }
+  }
+
+  @override
+  bool shouldRepaint(CustomPainter oldDelegate) {
+    return false;
+  }
+
+  // "unknown" parameter -> simple bock with text
+  void paintUnknownParameterItem(
+    final int value,
+    final Canvas canvas,
+    final double size,
+  ) {
+    final paint = Paint();
+    paint.strokeJoin = StrokeJoin.round;
+    paint.strokeWidth = 3 / 100 * size;
+
+    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,
+    );
+    textPainter.layout();
+    textPainter.paint(
+      canvas,
+      Offset(
+        (size - textPainter.width) * 0.5,
+        (size - textPainter.height) * 0.5,
+      ),
+    );
+  }
+
+  void paintItemsCountParameterItem(
+    final int value,
+    final Canvas canvas,
+    final double size,
+  ) {
+    Color backgroundColor = Colors.grey;
+
+    switch (value) {
+      case DefaultGameSettings.itemsCountValueLow:
+        backgroundColor = Colors.green;
+        break;
+      case DefaultGameSettings.itemsCountValueMedium:
+        backgroundColor = Colors.orange;
+        break;
+      case DefaultGameSettings.itemsCountValueHigh:
+        backgroundColor = Colors.red;
+        break;
+      case DefaultGameSettings.itemsCountValueVeryHigh:
+        backgroundColor = Colors.purple;
+        break;
+      default:
+        printlog('Wrong value for itemsCount parameter value: $value');
+    }
+
+    final paint = Paint();
+    paint.strokeJoin = StrokeJoin.round;
+    paint.strokeWidth = 3 / 100 * size;
+
+    // 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: value.toString(),
+      style: TextStyle(
+        color: Colors.black,
+        fontSize: size / 4,
+        fontWeight: FontWeight.bold,
+      ),
+    );
+    final textPainter = TextPainter(
+      text: textSpan,
+      textDirection: TextDirection.ltr,
+    );
+    textPainter.layout();
+    textPainter.paint(
+      canvas,
+      Offset(
+        (size - textPainter.width) * 0.5,
+        (size - textPainter.height) * 0.5,
+      ),
+    );
+  }
+}
diff --git a/lib/ui/screens/screen_game.dart b/lib/ui/screens/screen_game.dart
new file mode 100644
index 0000000000000000000000000000000000000000..154842b3c627266ad2e6727980a11c8e40480b27
--- /dev/null
+++ b/lib/ui/screens/screen_game.dart
@@ -0,0 +1,37 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:sortgame/cubit/game_cubit.dart';
+import 'package:sortgame/models/game.dart';
+import 'package:sortgame/ui/widgets/game_bottom_buttons.dart';
+import 'package:sortgame/ui/widgets/game_question.dart';
+import 'package:sortgame/ui/widgets/game_top_indicator.dart';
+
+class ScreenGame extends StatelessWidget {
+  const ScreenGame({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return BlocBuilder<GameCubit, GameState>(
+      builder: (BuildContext context, GameState gameState) {
+        final Game currentGame = gameState.currentGame;
+
+        return Container(
+          padding: const EdgeInsets.all(4),
+          child: Column(
+            mainAxisAlignment: MainAxisAlignment.start,
+            crossAxisAlignment: CrossAxisAlignment.center,
+            children: [
+              const SizedBox(height: 8),
+              const GameTopIndicatorWidget(),
+              const SizedBox(height: 8),
+              !currentGame.isFinished
+                  ? const GameQuestionWidget()
+                  : const GameBottomButtonsWidget(),
+            ],
+          ),
+        );
+      },
+    );
+  }
+}
diff --git a/lib/ui/screens/screen_parameters.dart b/lib/ui/screens/screen_parameters.dart
new file mode 100644
index 0000000000000000000000000000000000000000..3c43c7b1d20b335f0b5b33d534d67c03bab958a9
--- /dev/null
+++ b/lib/ui/screens/screen_parameters.dart
@@ -0,0 +1,159 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:sortgame/config/default_game_settings.dart';
+import 'package:sortgame/config/default_global_settings.dart';
+import 'package:sortgame/cubit/game_cubit.dart';
+import 'package:sortgame/cubit/settings_game_cubit.dart';
+import 'package:sortgame/cubit/settings_global_cubit.dart';
+import 'package:sortgame/ui/painters/parameter_painter.dart';
+
+class ScreenParameters extends StatelessWidget {
+  const ScreenParameters({super.key});
+
+  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));
+    lines.add(Expanded(child: buildStartNewGameButton()));
+    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<int> availableValues = isGlobal
+        ? DefaultGlobalSettings.getAvailableValues(code)
+        : DefaultGameSettings.getAvailableValues(code);
+
+    for (int 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 int 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 - 25;
+
+              return TextButton(
+                child: Container(
+                  margin: const EdgeInsets.all(0),
+                  padding: const EdgeInsets.all(0),
+                  child: 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;
+  }
+
+  Image buildImageWidget(String imageAssetCode) {
+    return Image(
+      image: AssetImage('assets/icons/$imageAssetCode.png'),
+      fit: BoxFit.fill,
+    );
+  }
+
+  Container buildImageContainerWidget(String imageAssetCode) {
+    return Container(
+      child: buildImageWidget(imageAssetCode),
+    );
+  }
+
+  Column buildDecorationImageWidget() {
+    return Column(
+      children: [
+        TextButton(
+          child: buildImageContainerWidget('placeholder'),
+          onPressed: () {},
+        ),
+      ],
+    );
+  }
+
+  Widget buildStartNewGameButton() {
+    return BlocBuilder<GameSettingsCubit, GameSettingsState>(
+      builder: (BuildContext context, GameSettingsState gameSettingsState) {
+        return BlocBuilder<GlobalSettingsCubit, GlobalSettingsState>(
+          builder: (BuildContext context, GlobalSettingsState globalSettingsState) {
+            final GameCubit gameCubit = BlocProvider.of<GameCubit>(context);
+
+            return TextButton(
+              child: buildImageContainerWidget('button_start'),
+              onPressed: () => gameCubit.startNewGame(
+                gameSettings: gameSettingsState.settings,
+                globalSettings: globalSettingsState.settings,
+              ),
+            );
+          },
+        );
+      },
+    );
+  }
+}
diff --git a/lib/ui/skeleton.dart b/lib/ui/skeleton.dart
new file mode 100644
index 0000000000000000000000000000000000000000..ecf652e45d5563f8e7f6d64c88723594f2784e86
--- /dev/null
+++ b/lib/ui/skeleton.dart
@@ -0,0 +1,30 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:sortgame/cubit/game_cubit.dart';
+import 'package:sortgame/ui/screens/screen_game.dart';
+import 'package:sortgame/ui/screens/screen_parameters.dart';
+import 'package:sortgame/ui/widgets/global_app_bar.dart';
+
+class SkeletonScreen extends StatelessWidget {
+  const SkeletonScreen({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: const GlobalAppBar(),
+      extendBodyBehindAppBar: false,
+      body: Material(
+        color: Theme.of(context).colorScheme.background,
+        child: BlocBuilder<GameCubit, GameState>(
+          builder: (BuildContext context, GameState gameState) {
+            return gameState.currentGame.isRunning
+                ? const ScreenGame()
+                : const ScreenParameters();
+          },
+        ),
+      ),
+      backgroundColor: Theme.of(context).colorScheme.background,
+    );
+  }
+}
diff --git a/lib/ui/widgets/game_bottom_buttons.dart b/lib/ui/widgets/game_bottom_buttons.dart
new file mode 100644
index 0000000000000000000000000000000000000000..2af6424a0a7633602a6ba6b3ba53db9877ff4017
--- /dev/null
+++ b/lib/ui/widgets/game_bottom_buttons.dart
@@ -0,0 +1,51 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:sortgame/cubit/game_cubit.dart';
+
+class GameBottomButtonsWidget extends StatelessWidget {
+  const GameBottomButtonsWidget({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    const String decorationImageAssetName = 'assets/icons/placeholder.png';
+
+    const Widget decorationWidget = TextButton(
+      onPressed: null,
+      child: Image(
+        image: AssetImage(decorationImageAssetName),
+        fit: BoxFit.fill,
+      ),
+    );
+
+    return Table(
+      defaultColumnWidth: const IntrinsicColumnWidth(),
+      children: [
+        TableRow(
+          children: [
+            const Column(
+              children: [decorationWidget],
+            ),
+            Column(
+              children: [
+                TextButton(
+                  child: const Image(
+                    image: AssetImage('assets/icons/button_back.png'),
+                    fit: BoxFit.fill,
+                  ),
+                  onPressed: () {
+                    final GameCubit gameCubit = BlocProvider.of<GameCubit>(context);
+                    gameCubit.quitGame();
+                  },
+                )
+              ],
+            ),
+            const Column(
+              children: [decorationWidget],
+            ),
+          ],
+        ),
+      ],
+    );
+  }
+}
diff --git a/lib/ui/widgets/game_question.dart b/lib/ui/widgets/game_question.dart
new file mode 100644
index 0000000000000000000000000000000000000000..83153dc46dc7111b58321611d52d73ff7cb1d6fa
--- /dev/null
+++ b/lib/ui/widgets/game_question.dart
@@ -0,0 +1,46 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:sortgame/cubit/game_cubit.dart';
+import 'package:sortgame/models/data/game_item.dart';
+import 'package:sortgame/models/game.dart';
+import 'package:sortgame/ui/widgets/games/buttons_yes_no.dart';
+import 'package:sortgame/ui/widgets/helpers/outlined_text_widget.dart';
+
+class GameQuestionWidget extends StatelessWidget {
+  const GameQuestionWidget({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return BlocBuilder<GameCubit, GameState>(
+      builder: (BuildContext context, GameState gameState) {
+        final Game currentGame = gameState.currentGame;
+
+        final GameItem currentQuestion = currentGame.getCurrentQuestion();
+
+        return Column(
+          children: [
+            OutlinedText(
+              text: currentQuestion.item.text,
+              fontSize: 50,
+              textColor: Theme.of(context).colorScheme.onSurface,
+            ),
+            Container(
+              padding: const EdgeInsets.all(10),
+              margin: const EdgeInsets.all(20),
+              decoration: BoxDecoration(
+                border: Border.all(
+                  color: Theme.of(context).colorScheme.surface,
+                  width: 8,
+                ),
+                borderRadius: const BorderRadius.all(Radius.circular(20)),
+                color: Theme.of(context).colorScheme.inversePrimary,
+              ),
+              child: GameButtonsYesNo(question: currentQuestion),
+            ),
+          ],
+        );
+      },
+    );
+  }
+}
diff --git a/lib/ui/widgets/game_top_indicator.dart b/lib/ui/widgets/game_top_indicator.dart
new file mode 100644
index 0000000000000000000000000000000000000000..6ff87554a7395e946d12278cda6a6160c74e080e
--- /dev/null
+++ b/lib/ui/widgets/game_top_indicator.dart
@@ -0,0 +1,27 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:sortgame/cubit/game_cubit.dart';
+import 'package:sortgame/models/game.dart';
+import 'package:sortgame/ui/widgets/indicators/indicator_position.dart';
+import 'package:sortgame/ui/widgets/indicators/indicator_score.dart';
+
+class GameTopIndicatorWidget extends StatelessWidget {
+  const GameTopIndicatorWidget({super.key});
+
+  @override
+  Widget build(BuildContext context) {
+    return BlocBuilder<GameCubit, GameState>(
+      builder: (BuildContext context, GameState gameState) {
+        final Game currentGame = gameState.currentGame;
+
+        return Column(
+          children: [
+            PositionIndicator(game: currentGame),
+            ScoreIndicator(game: currentGame),
+          ],
+        );
+      },
+    );
+  }
+}
diff --git a/lib/ui/widgets/games/buttons_yes_no.dart b/lib/ui/widgets/games/buttons_yes_no.dart
new file mode 100644
index 0000000000000000000000000000000000000000..44f92806d1f0990a2a21e9c89cff22182fa4ed5a
--- /dev/null
+++ b/lib/ui/widgets/games/buttons_yes_no.dart
@@ -0,0 +1,68 @@
+import 'dart:math';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:unicons/unicons.dart';
+
+import 'package:sortgame/cubit/game_cubit.dart';
+import 'package:sortgame/models/data/category.dart';
+import 'package:sortgame/models/data/game_item.dart';
+import 'package:sortgame/ui/widgets/helpers/outlined_text_widget.dart';
+
+class GameButtonsYesNo extends StatelessWidget {
+  const GameButtonsYesNo({super.key, required this.question});
+
+  final GameItem question;
+
+  @override
+  Widget build(BuildContext context) {
+    final GameCubit gameCubit = BlocProvider.of<GameCubit>(context);
+
+    final bool pickInIsCategory = Random().nextBool();
+
+    final List<Category> categories =
+        pickInIsCategory ? question.isCategory : question.isNotCategory;
+
+    categories.shuffle();
+    final Category category = categories.first;
+
+    final List<Widget> buttons = [
+      IconButton(
+        color: Theme.of(context).colorScheme.onSurface,
+        iconSize: 80,
+        onPressed: () {
+          if (pickInIsCategory) {
+            gameCubit.increaseScore(1);
+          }
+          gameCubit.increasePosition();
+        },
+        icon: const Icon(UniconsLine.thumbs_up),
+      ),
+      IconButton(
+        color: Theme.of(context).colorScheme.onSurface,
+        iconSize: 80,
+        onPressed: () {
+          if (!pickInIsCategory) {
+            gameCubit.increaseScore(1);
+          }
+          gameCubit.increasePosition();
+        },
+        icon: const Icon(UniconsLine.thumbs_down),
+      ),
+    ];
+
+    return Column(
+      children: [
+        OutlinedText(
+          text: category.text,
+          fontSize: 40,
+          textColor: Theme.of(context).colorScheme.onSurface,
+        ),
+        Row(
+          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
+          children: buttons,
+        )
+      ],
+    );
+  }
+}
diff --git a/lib/ui/widgets/global_app_bar.dart b/lib/ui/widgets/global_app_bar.dart
new file mode 100644
index 0000000000000000000000000000000000000000..02ff38f5b214d1239b144fedfe916e534fbb48d0
--- /dev/null
+++ b/lib/ui/widgets/global_app_bar.dart
@@ -0,0 +1,43 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+
+import 'package:sortgame/cubit/game_cubit.dart';
+import 'package:sortgame/models/game.dart';
+import 'package:sortgame/ui/widgets/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) {
+        final Game currentGame = gameState.currentGame;
+
+        final List<Widget> menuActions = [];
+
+        if (currentGame.isRunning) {
+          menuActions.add(TextButton(
+            child: const Image(
+              image: AssetImage('assets/icons/button_back.png'),
+              fit: BoxFit.fill,
+            ),
+            onPressed: () {},
+            onLongPress: () {
+              final GameCubit gameCubit = BlocProvider.of<GameCubit>(context);
+              gameCubit.quitGame();
+            },
+          ));
+        }
+
+        return AppBar(
+          title: const AppTitle(text: 'app_name'),
+          actions: menuActions,
+        );
+      },
+    );
+  }
+
+  @override
+  Size get preferredSize => const Size.fromHeight(50);
+}
diff --git a/lib/ui/widgets/helpers/app_titles.dart b/lib/ui/widgets/helpers/app_titles.dart
new file mode 100644
index 0000000000000000000000000000000000000000..7cbbb2030419047b3dcf093a2195a498bd8e8ce9
--- /dev/null
+++ b/lib/ui/widgets/helpers/app_titles.dart
@@ -0,0 +1,17 @@
+import 'package:easy_localization/easy_localization.dart';
+import 'package:flutter/material.dart';
+
+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.headlineLarge!.apply(fontWeightDelta: 2),
+    );
+  }
+}
diff --git a/lib/ui/widgets/helpers/outlined_text_widget.dart b/lib/ui/widgets/helpers/outlined_text_widget.dart
new file mode 100644
index 0000000000000000000000000000000000000000..bdf29f25e24105c2d7137b8d9cffd421ad9c0f46
--- /dev/null
+++ b/lib/ui/widgets/helpers/outlined_text_widget.dart
@@ -0,0 +1,51 @@
+import 'package:flutter/material.dart';
+
+import 'package:sortgame/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 / 35;
+
+    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/widgets/indicators/indicator_position.dart b/lib/ui/widgets/indicators/indicator_position.dart
new file mode 100644
index 0000000000000000000000000000000000000000..335cad77e235f59b0363cf2fe3f28dc016fdfba5
--- /dev/null
+++ b/lib/ui/widgets/indicators/indicator_position.dart
@@ -0,0 +1,42 @@
+import 'package:flutter/material.dart';
+
+import 'package:sortgame/models/game.dart';
+import 'package:sortgame/ui/widgets/helpers/outlined_text_widget.dart';
+import 'package:sortgame/utils/color_extensions.dart';
+
+class PositionIndicator extends StatelessWidget {
+  const PositionIndicator({super.key, required this.game});
+
+  final Game game;
+
+  @override
+  Widget build(BuildContext context) {
+    // Normalized [0..1] value
+    final double barValue = game.position / game.gameSettings.itemsCount;
+
+    const Color baseColor = Color.fromARGB(255, 215, 1, 133);
+
+    const barHeight = 40.0;
+    const Color textColor = Color.fromARGB(255, 238, 238, 238);
+    const Color outlineColor = Color.fromARGB(255, 200, 200, 200);
+
+    return Stack(
+      alignment: Alignment.center,
+      children: [
+        LinearProgressIndicator(
+          value: barValue,
+          color: baseColor,
+          backgroundColor: baseColor.darken(),
+          minHeight: barHeight,
+          borderRadius: const BorderRadius.all(Radius.circular(barHeight / 4)),
+        ),
+        OutlinedText(
+          text: '${game.position}/${game.gameSettings.itemsCount}',
+          fontSize: 0.9 * barHeight,
+          textColor: textColor,
+          outlineColor: outlineColor,
+        ),
+      ],
+    );
+  }
+}
diff --git a/lib/ui/widgets/indicators/indicator_score.dart b/lib/ui/widgets/indicators/indicator_score.dart
new file mode 100644
index 0000000000000000000000000000000000000000..2ab1774f25e476312a5b6b9683ebd531299e6273
--- /dev/null
+++ b/lib/ui/widgets/indicators/indicator_score.dart
@@ -0,0 +1,21 @@
+import 'package:flutter/material.dart';
+
+import 'package:sortgame/models/game.dart';
+import 'package:sortgame/ui/widgets/helpers/outlined_text_widget.dart';
+
+class ScoreIndicator extends StatelessWidget {
+  const ScoreIndicator({super.key, required this.game});
+
+  final Game game;
+
+  @override
+  Widget build(BuildContext context) {
+    const Color baseColor = Color.fromARGB(255, 121, 93, 246);
+
+    return OutlinedText(
+      text: game.score.toString(),
+      fontSize: 70,
+      textColor: baseColor,
+    );
+  }
+}
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 b15ebfbb8fc4b11d61a5733db2b95e116d18c681..e2bc2cc1cc9e169f5a1b8dde16dff652ac4d8d4c 100644
--- a/pubspec.lock
+++ b/pubspec.lock
@@ -1,6 +1,22 @@
 # Generated by pub
 # See https://dart.dev/tools/pub/glossary#lockfile
 packages:
+  args:
+    dependency: transitive
+    description:
+      name: args
+      sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.5.0"
+  bloc:
+    dependency: transitive
+    description:
+      name: bloc
+      sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e"
+      url: "https://pub.dev"
+    source: hosted
+    version: "8.1.4"
   characters:
     dependency: transitive
     description:
@@ -9,6 +25,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.3.0"
+  clock:
+    dependency: transitive
+    description:
+      name: clock
+      sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.1.1"
   collection:
     dependency: transitive
     description:
@@ -17,19 +41,109 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.18.0"
+  crypto:
+    dependency: transitive
+    description:
+      name: crypto
+      sha256: ff625774173754681d66daaf4a448684fb04b78f902da9cb3d308c19cc5e8bab
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.0.3"
+  easy_localization:
+    dependency: "direct main"
+    description:
+      name: easy_localization
+      sha256: c145aeb6584aedc7c862ab8c737c3277788f47488bfdf9bae0fe112bd0a4789c
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.0.5"
+  easy_logger:
+    dependency: transitive
+    description:
+      name: easy_logger
+      sha256: c764a6e024846f33405a2342caf91c62e357c24b02c04dbc712ef232bf30ffb7
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.0.2"
+  equatable:
+    dependency: "direct main"
+    description:
+      name: equatable
+      sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.0.5"
+  ffi:
+    dependency: transitive
+    description:
+      name: ffi
+      sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.2"
+  file:
+    dependency: transitive
+    description:
+      name: file
+      sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c"
+      url: "https://pub.dev"
+    source: hosted
+    version: "7.0.0"
   flutter:
     dependency: "direct main"
     description: flutter
     source: sdk
     version: "0.0.0"
+  flutter_bloc:
+    dependency: "direct main"
+    description:
+      name: flutter_bloc
+      sha256: f0ecf6e6eb955193ca60af2d5ca39565a86b8a142452c5b24d96fb477428f4d2
+      url: "https://pub.dev"
+    source: hosted
+    version: "8.1.5"
   flutter_lints:
     dependency: "direct dev"
     description:
       name: flutter_lints
-      sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7
+      sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1"
       url: "https://pub.dev"
     source: hosted
-    version: "3.0.1"
+    version: "3.0.2"
+  flutter_localizations:
+    dependency: transitive
+    description: flutter
+    source: sdk
+    version: "0.0.0"
+  flutter_web_plugins:
+    dependency: transitive
+    description: flutter
+    source: sdk
+    version: "0.0.0"
+  hive:
+    dependency: "direct main"
+    description:
+      name: hive
+      sha256: "8dcf6db979d7933da8217edcec84e9df1bdb4e4edc7fc77dbd5aa74356d6d941"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.2.3"
+  hydrated_bloc:
+    dependency: "direct main"
+    description:
+      name: hydrated_bloc
+      sha256: af35b357739fe41728df10bec03aad422cdc725a1e702e03af9d2a41ea05160c
+      url: "https://pub.dev"
+    source: hosted
+    version: "9.1.5"
+  intl:
+    dependency: transitive
+    description:
+      name: intl
+      sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.18.1"
   lints:
     dependency: transitive
     description:
@@ -62,19 +176,171 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "1.0.0"
-  provider:
+  path:
+    dependency: transitive
+    description:
+      name: path
+      sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.9.0"
+  path_provider:
     dependency: "direct main"
+    description:
+      name: path_provider
+      sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.3"
+  path_provider_android:
+    dependency: transitive
+    description:
+      name: path_provider_android
+      sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.2.4"
+  path_provider_foundation:
+    dependency: transitive
+    description:
+      name: path_provider_foundation
+      sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.3.2"
+  path_provider_linux:
+    dependency: transitive
+    description:
+      name: path_provider_linux
+      sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.2.1"
+  path_provider_platform_interface:
+    dependency: transitive
+    description:
+      name: path_provider_platform_interface
+      sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.2"
+  path_provider_windows:
+    dependency: transitive
+    description:
+      name: path_provider_windows
+      sha256: "8bc9f22eee8690981c22aa7fc602f5c85b497a6fb2ceb35ee5a5e5ed85ad8170"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.2.1"
+  platform:
+    dependency: transitive
+    description:
+      name: platform
+      sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.1.4"
+  plugin_platform_interface:
+    dependency: transitive
+    description:
+      name: plugin_platform_interface
+      sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.8"
+  provider:
+    dependency: transitive
     description:
       name: provider
       sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
       url: "https://pub.dev"
     source: hosted
     version: "6.1.2"
+  shared_preferences:
+    dependency: transitive
+    description:
+      name: shared_preferences
+      sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.2.3"
+  shared_preferences_android:
+    dependency: transitive
+    description:
+      name: shared_preferences_android
+      sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.2.2"
+  shared_preferences_foundation:
+    dependency: transitive
+    description:
+      name: shared_preferences_foundation
+      sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.3.5"
+  shared_preferences_linux:
+    dependency: transitive
+    description:
+      name: shared_preferences_linux
+      sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.3.2"
+  shared_preferences_platform_interface:
+    dependency: transitive
+    description:
+      name: shared_preferences_platform_interface
+      sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.3.2"
+  shared_preferences_web:
+    dependency: transitive
+    description:
+      name: shared_preferences_web
+      sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.3.0"
+  shared_preferences_windows:
+    dependency: transitive
+    description:
+      name: shared_preferences_windows
+      sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59"
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.3.2"
   sky_engine:
     dependency: transitive
     description: flutter
     source: sdk
     version: "0.0.99"
+  synchronized:
+    dependency: transitive
+    description:
+      name: synchronized
+      sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558"
+      url: "https://pub.dev"
+    source: hosted
+    version: "3.1.0+1"
+  typed_data:
+    dependency: transitive
+    description:
+      name: typed_data
+      sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.3.2"
+  unicons:
+    dependency: "direct main"
+    description:
+      name: unicons
+      sha256: dbfcf93ff4d4ea19b324113857e358e4882115ab85db04417a4ba1c72b17a670
+      url: "https://pub.dev"
+    source: hosted
+    version: "2.1.1"
   vector_math:
     dependency: transitive
     description:
@@ -83,6 +349,30 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.1.4"
+  web:
+    dependency: transitive
+    description:
+      name: web
+      sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27"
+      url: "https://pub.dev"
+    source: hosted
+    version: "0.5.1"
+  win32:
+    dependency: transitive
+    description:
+      name: win32
+      sha256: "0a989dc7ca2bb51eac91e8fd00851297cfffd641aa7538b165c62637ca0eaa4a"
+      url: "https://pub.dev"
+    source: hosted
+    version: "5.4.0"
+  xdg_directories:
+    dependency: transitive
+    description:
+      name: xdg_directories
+      sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.0.4"
 sdks:
-  dart: ">=3.2.0-0 <4.0.0"
-  flutter: ">=1.16.0"
+  dart: ">=3.3.0 <4.0.0"
+  flutter: ">=3.19.0"
diff --git a/pubspec.yaml b/pubspec.yaml
index 9de92ceae6e2132cf07b41ead441a8bfcde88910..bc808043a9ba69f21af5f7e701e5157e2d434bd6 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,7 +1,9 @@
 name: sortgame
 description: A sorting game application.
+
 publish_to: 'none'
-version: 0.0.17+17
+
+version: 0.0.18+18
 
 environment:
   sdk: '^3.0.0'
@@ -9,12 +11,31 @@ environment:
 dependencies:
   flutter:
     sdk: flutter
-  provider: ^6.0.5
+  easy_localization: ^3.0.1
+  equatable: ^2.0.5
+  flutter_bloc: ^8.1.1
+  hive: ^2.2.3
+  hydrated_bloc: ^9.0.0
+  path_provider: ^2.0.11
+  unicons: ^2.1.1
 
 dev_dependencies:
   flutter_lints: ^3.0.1
 
 flutter:
-  uses-material-design: true
+  uses-material-design: false
   assets:
-    - assets/files/
+    - assets/icons/
+    - assets/translations/
+
+  fonts:
+    - family: Nunito
+      fonts:
+        - asset: assets/fonts/Nunito-Bold.ttf
+          weight: 700
+        - asset: assets/fonts/Nunito-Medium.ttf
+          weight: 500
+        - asset: assets/fonts/Nunito-Regular.ttf
+          weight: 400
+        - asset: assets/fonts/Nunito-Light.ttf
+          weight: 300