diff --git a/android/gradle.properties b/android/gradle.properties
index 8f1cf62360192199ae6a5e17a062114475c411bc..cd511d2125450a944f1e2bd7839e9059a09ccdaa 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=1.0.37
-app.versionCode=38
+app.versionName=1.0.38
+app.versionCode=39
diff --git a/assets/translations/en.json b/assets/translations/en.json
index e57ee8a1085d69a27cfce73eaa027ae8bdb146ab..6b6d02750729a4be993e296a06bcc5e0f63d4fe2 100644
--- a/assets/translations/en.json
+++ b/assets/translations/en.json
@@ -4,6 +4,7 @@
   "bottom_nav_sample": "Sample",
   "bottom_nav_api": "API",
   "bottom_nav_chart": "Graph",
+  "bottom_nav_game": "Game",
   "bottom_nav_settings": "Settings",
   "bottom_nav_about": "About",
 
diff --git a/assets/translations/fr.json b/assets/translations/fr.json
index ef1e45bbdd2bdd2d787f6838a3ee09a145086988..72682066e0c519f9bdd04d866ef5fa0644db798f 100644
--- a/assets/translations/fr.json
+++ b/assets/translations/fr.json
@@ -4,6 +4,7 @@
   "bottom_nav_sample": "Démo",
   "bottom_nav_api": "API",
   "bottom_nav_chart": "Graph",
+  "bottom_nav_game": "Jeu",
   "bottom_nav_settings": "Paramètres",
   "bottom_nav_about": "À propos",
 
diff --git a/lib/cubit/game_cubit.dart b/lib/cubit/game_cubit.dart
new file mode 100644
index 0000000000000000000000000000000000000000..90146ddbee91b6248621d91e9f72bdec8b822329
--- /dev/null
+++ b/lib/cubit/game_cubit.dart
@@ -0,0 +1,34 @@
+import 'package:equatable/equatable.dart';
+import 'package:flutter/material.dart';
+import 'package:hydrated_bloc/hydrated_bloc.dart';
+import 'package:random/models/game_data.dart';
+
+part 'game_state.dart';
+
+class GameCubit extends HydratedCubit<GameState> {
+  GameCubit() : super(const GameState());
+
+  void getData(GameState state) {
+    emit(state);
+  }
+
+  void updateGameState(GameData game) {
+    emit(GameState(game: game));
+  }
+
+  @override
+  GameState? fromJson(Map<String, dynamic> json) {
+    GameData game = json['game'] as GameData;
+
+    return GameState(
+      game: game,
+    );
+  }
+
+  @override
+  Map<String, dynamic>? toJson(GameState state) {
+    return <String, dynamic>{
+      'game': state.game?.toJson(),
+    };
+  }
+}
diff --git a/lib/cubit/game_state.dart b/lib/cubit/game_state.dart
new file mode 100644
index 0000000000000000000000000000000000000000..ea6c33cf1ce0150ac8b9c358005e42a64447ab0d
--- /dev/null
+++ b/lib/cubit/game_state.dart
@@ -0,0 +1,15 @@
+part of 'game_cubit.dart';
+
+@immutable
+class GameState extends Equatable {
+  const GameState({
+    this.game,
+  });
+
+  final GameData? game;
+
+  @override
+  List<Object?> get props => <Object?>[
+        game,
+      ];
+}
diff --git a/lib/main.dart b/lib/main.dart
index 765b84c7b8b3c00e7e4489d11ab5d77670453128..6b6e38b6dca4897664eb5ae5212927b9ae97574f 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -10,6 +10,7 @@ import 'package:path_provider/path_provider.dart';
 import 'package:random/config/theme.dart';
 import 'package:random/cubit/bottom_nav_cubit.dart';
 import 'package:random/cubit/data_cubit.dart';
+import 'package:random/cubit/game_cubit.dart';
 import 'package:random/cubit/settings_cubit.dart';
 import 'package:random/cubit/api_cubit.dart';
 import 'package:random/repository/api.dart';
@@ -50,6 +51,7 @@ class MyApp extends StatelessWidget {
         BlocProvider<SettingsCubit>(create: (context) => SettingsCubit()),
         BlocProvider<BottomNavCubit>(create: (context) => BottomNavCubit()),
         BlocProvider<DataCubit>(create: (context) => DataCubit()),
+        BlocProvider<GameCubit>(create: (context) => GameCubit()),
         BlocProvider<ApiDataCubit>(
           create: (context) => ApiDataCubit(
             apiRepository: ApiRepository(
diff --git a/lib/models/game_data.dart b/lib/models/game_data.dart
new file mode 100644
index 0000000000000000000000000000000000000000..fce00e1eaf10f90c4fe4b49b9e0fe17f9866e124
--- /dev/null
+++ b/lib/models/game_data.dart
@@ -0,0 +1,96 @@
+import 'dart:convert';
+import 'dart:math';
+
+class GameDataItem {
+  final int value;
+
+  const GameDataItem({
+    required this.value,
+  });
+
+  factory GameDataItem.fromJson(Map<String, dynamic>? json) {
+    return GameDataItem(
+      value: (json?['value'] != null) ? (json?['value'] as int) : 0,
+    );
+  }
+
+  Map<String, dynamic>? toJson() {
+    return <String, dynamic>{
+      'value': this.value,
+    };
+  }
+
+  String toString() {
+    return jsonEncode(this.toJson());
+  }
+}
+
+class GameData {
+  final int boardSize;
+  final List<List<GameDataItem>> board;
+
+  const GameData({
+    required this.boardSize,
+    required this.board,
+  });
+
+  factory GameData.createNew(int boardSize) {
+    final List<List<GameDataItem>> cells = [];
+
+    for (var y = 0; y < boardSize; y++) {
+      final List<GameDataItem> line = [];
+      for (var x = 0; x < boardSize; x++) {
+        final GameDataItem item = new GameDataItem(value: 0);
+        line.add(item);
+      }
+
+      cells.add(line);
+    }
+
+    return GameData(
+      boardSize: boardSize,
+      board: cells,
+    );
+  }
+
+  factory GameData.createRandom(int boardSize) {
+    const allowedValues = [0, 1, 2, 3, 4, 5];
+    final allowedValuesSize = allowedValues.length;
+
+    final List<List<GameDataItem>> cells = [];
+
+    for (var y = 0; y < boardSize; y++) {
+      final List<GameDataItem> line = [];
+      for (var x = 0; x < boardSize; x++) {
+        final value = allowedValues[Random().nextInt(allowedValuesSize)];
+        final GameDataItem item = new GameDataItem(value: value);
+        line.add(item);
+      }
+
+      cells.add(line);
+    }
+
+    return GameData(
+      boardSize: boardSize,
+      board: cells,
+    );
+  }
+
+  factory GameData.fromJson(Map<String, dynamic>? json) {
+    return GameData(
+      boardSize: (json?['boardSize'] != null) ? (json?['boardSize'] as int) : 0,
+      board: (json?['board'] != null) ? (json?['board'] as List<List<GameDataItem>>) : [],
+    );
+  }
+
+  Map<String, dynamic>? toJson() {
+    return <String, dynamic>{
+      'boardSize': this.boardSize,
+      'board': this.board,
+    };
+  }
+
+  String toString() {
+    return jsonEncode(this.toJson());
+  }
+}
diff --git a/lib/ui/painters/cell_painter.dart b/lib/ui/painters/cell_painter.dart
new file mode 100644
index 0000000000000000000000000000000000000000..26ee97ddb41f0715a238a49196c97e72f2865d09
--- /dev/null
+++ b/lib/ui/painters/cell_painter.dart
@@ -0,0 +1,39 @@
+import 'package:flutter/material.dart';
+
+import 'package:random/config/app_colors.dart';
+
+class CellPainter extends CustomPainter {
+  const CellPainter({required this.value});
+
+  final int value;
+
+  Color getIndexedColor(int index) {
+    const List<Color> availableColors = [
+      AppColors.contentColorCyan,
+      AppColors.contentColorGreen,
+      AppColors.contentColorOrange,
+      AppColors.contentColorPurple,
+      AppColors.contentColorYellow,
+      AppColors.contentColorPink,
+      AppColors.contentColorWhite,
+      AppColors.mainTextColor3,
+    ];
+
+    return availableColors[index % availableColors.length];
+  }
+
+  @override
+  void paint(Canvas canvas, Size size) {
+    final paintBackground = Paint();
+    paintBackground.color = getIndexedColor(value);
+    paintBackground.style = PaintingStyle.fill;
+
+    final Rect rectBackground = Rect.fromPoints(Offset(0, 0), Offset(size.width, size.height));
+    canvas.drawRect(rectBackground, paintBackground);
+  }
+
+  @override
+  bool shouldRepaint(CustomPainter oldDelegate) {
+    return false;
+  }
+}
diff --git a/lib/ui/screens/game_page.dart b/lib/ui/screens/game_page.dart
new file mode 100644
index 0000000000000000000000000000000000000000..8ccb67fd641d663dd02f016515e98d0ece89e3a3
--- /dev/null
+++ b/lib/ui/screens/game_page.dart
@@ -0,0 +1,50 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_bloc/flutter_bloc.dart';
+import 'package:random/cubit/game_cubit.dart';
+import 'package:random/models/game_data.dart';
+
+import 'package:random/ui/widgets/game_board.dart';
+import 'package:unicons/unicons.dart';
+
+class GamePage extends StatefulWidget {
+  const GamePage({super.key});
+
+  @override
+  State<GamePage> createState() => _GamePageState();
+}
+
+class _GamePageState extends State<GamePage> {
+  @override
+  Widget build(BuildContext context) {
+    return BlocBuilder<GameCubit, GameState>(
+      builder: (context, gameState) {
+        return Column(
+          mainAxisAlignment: MainAxisAlignment.start,
+          crossAxisAlignment: CrossAxisAlignment.center,
+          children: [
+            gameState.game != null
+                ? Container(
+                    margin: EdgeInsets.all(4),
+                    padding: EdgeInsets.all(4),
+                    child: GameBoardWidget(
+                      gameData: gameState.game!,
+                    ),
+                  )
+                : SizedBox.shrink(),
+            IconButton(
+              onPressed: () {
+                const boardSize = 6;
+
+                final GameData newGame = GameData.createRandom(boardSize);
+                BlocProvider.of<GameCubit>(context).updateGameState(newGame);
+                print(gameState);
+              },
+              icon: Icon(UniconsSolid.star),
+              color: Colors.white,
+            ),
+          ],
+        );
+      },
+    );
+  }
+}
diff --git a/lib/ui/skeleton.dart b/lib/ui/skeleton.dart
index f44393db9c3aee06006e962728fe4e521d7d5d8d..275a44618b4c0780dd33157aa5d81f492c09219e 100644
--- a/lib/ui/skeleton.dart
+++ b/lib/ui/skeleton.dart
@@ -6,6 +6,7 @@ import 'package:random/cubit/bottom_nav_cubit.dart';
 import 'package:random/ui/screens/about_page.dart';
 import 'package:random/ui/screens/api_page.dart';
 import 'package:random/ui/screens/demo_page.dart';
+import 'package:random/ui/screens/game_page.dart';
 import 'package:random/ui/screens/graph_page.dart';
 import 'package:random/ui/screens/settings_page.dart';
 import 'package:random/ui/widgets/app_bar.dart';
@@ -25,6 +26,7 @@ class _SkeletonScreenState extends State<SkeletonScreen> {
       DemoPage(),
       ApiPage(),
       GraphPage(),
+      GamePage(),
       SettingsPage(),
       AboutPage(),
     ];
diff --git a/lib/ui/widgets/bottom_nav_bar.dart b/lib/ui/widgets/bottom_nav_bar.dart
index 9ab56ea6333ba956d3e362b20bf75c9586cbacd8..6d6f83d1e47a4c73acaca1aca929a59224dc43ec 100644
--- a/lib/ui/widgets/bottom_nav_bar.dart
+++ b/lib/ui/widgets/bottom_nav_bar.dart
@@ -54,6 +54,10 @@ class BottomNavBar extends StatelessWidget {
                 icon: const Icon(UniconsLine.pen),
                 label: tr('bottom_nav_chart'),
               ),
+              BottomNavigationBarItem(
+                icon: const Icon(UniconsLine.star),
+                label: tr('bottom_nav_game'),
+              ),
               BottomNavigationBarItem(
                 icon: const Icon(UniconsLine.setting),
                 label: tr('bottom_nav_settings'),
diff --git a/lib/ui/widgets/game_board.dart b/lib/ui/widgets/game_board.dart
new file mode 100644
index 0000000000000000000000000000000000000000..427ff46ce0685cf3e506889ebd010065af6a9c0a
--- /dev/null
+++ b/lib/ui/widgets/game_board.dart
@@ -0,0 +1,60 @@
+import 'package:flutter/material.dart';
+
+import 'package:random/models/game_data.dart';
+import 'package:random/ui/painters/cell_painter.dart';
+
+class GameBoardWidget extends StatelessWidget {
+  const GameBoardWidget({super.key, required this.gameData});
+
+  final GameData gameData;
+
+  @override
+  Widget build(BuildContext context) {
+    const staticBoardWidth = 300;
+    const staticBoardHeight = 300;
+
+    final rowsCount = this.gameData.board.length;
+    final columnsCount = this.gameData.board[0].length;
+    print('counts: rows=' + rowsCount.toString() + ' / columns=' + columnsCount.toString());
+
+    final cellWidth = staticBoardWidth / columnsCount;
+    final cellHeight = staticBoardHeight / rowsCount;
+    print('cell: width=' + cellWidth.toString() + ' / height=' + cellHeight.toString());
+
+    final List<Widget> cells = [];
+
+    for (var y = 0; y < rowsCount; y++) {
+      for (var x = 0; x < columnsCount; x++) {
+        final GameDataItem item = this.gameData.board[y][x];
+
+        final Widget cellContent = CustomPaint(
+          size: Size(cellWidth, cellHeight),
+          willChange: false,
+          painter: CellPainter(value: item.value),
+        );
+
+        final Widget widget = Positioned(
+          left: (x * cellWidth).toDouble(),
+          top: (y * cellHeight).toDouble(),
+          child: Container(
+            width: cellWidth,
+            height: cellHeight,
+            color: Colors.deepPurpleAccent,
+            child: cellContent,
+          ),
+        );
+
+        cells.add(widget);
+      }
+    }
+
+    return Container(
+      width: staticBoardWidth.toDouble(),
+      height: staticBoardHeight.toDouble(),
+      color: Colors.grey,
+      child: Stack(
+        children: cells,
+      ),
+    );
+  }
+}
diff --git a/pubspec.yaml b/pubspec.yaml
index 614ad4a20d09270ad2000c910371483f6c373fef..5e18bdd7ad704a826e15dbb34241d0ad5be3432f 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -3,7 +3,7 @@ description: A random application, for testing purpose only.
 
 publish_to: 'none'
 
-version: 1.0.37+38
+version: 1.0.38+39
 
 environment:
   sdk: '^3.0.0'