diff --git a/android/gradle.properties b/android/gradle.properties
index d96c32178c38990e00612de2cd3fa50f85d88126..621336f47b3be71128005116384f1c3636771131 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.39
-app.versionCode=40
+app.versionName=1.0.40
+app.versionCode=41
diff --git a/lib/models/game_data.dart b/lib/models/game_data.dart
index fce00e1eaf10f90c4fe4b49b9e0fe17f9866e124..6a519d5bb925009b7cb338ad245eb00586130803 100644
--- a/lib/models/game_data.dart
+++ b/lib/models/game_data.dart
@@ -2,15 +2,21 @@ import 'dart:convert';
 import 'dart:math';
 
 class GameDataItem {
-  final int value;
+  final int? value;
 
   const GameDataItem({
     required this.value,
   });
 
+  factory GameDataItem.fromValue(int? value) {
+    return GameDataItem(
+      value: value,
+    );
+  }
+
   factory GameDataItem.fromJson(Map<String, dynamic>? json) {
     return GameDataItem(
-      value: (json?['value'] != null) ? (json?['value'] as int) : 0,
+      value: (json?['value'] != null) ? (json?['value'] as int) : null,
     );
   }
 
@@ -26,10 +32,12 @@ class GameDataItem {
 }
 
 class GameData {
+  final bool isReady;
   final int boardSize;
   final List<List<GameDataItem>> board;
 
   const GameData({
+    required this.isReady,
     required this.boardSize,
     required this.board,
   });
@@ -40,7 +48,7 @@ class GameData {
     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);
+        final GameDataItem item = new GameDataItem(value: null);
         line.add(item);
       }
 
@@ -48,6 +56,7 @@ class GameData {
     }
 
     return GameData(
+      isReady: true,
       boardSize: boardSize,
       board: cells,
     );
@@ -71,13 +80,27 @@ class GameData {
     }
 
     return GameData(
+      isReady: true,
       boardSize: boardSize,
       board: cells,
     );
   }
 
+  GameDataItem getCell(int x, int y) {
+    return this.board[y][x];
+  }
+
+  int? getCellValue(int x, int y) {
+    return this.getCell(x, y).value;
+  }
+
+  void updateCellValue(int x, int y, int? value) {
+    this.board[y][x] = new GameDataItem.fromValue(value);
+  }
+
   factory GameData.fromJson(Map<String, dynamic>? json) {
     return GameData(
+      isReady: (json?['isReady'] != null) ? (json?['isReady'] as bool) : false,
       boardSize: (json?['boardSize'] != null) ? (json?['boardSize'] as int) : 0,
       board: (json?['board'] != null) ? (json?['board'] as List<List<GameDataItem>>) : [],
     );
@@ -85,6 +108,7 @@ class GameData {
 
   Map<String, dynamic>? toJson() {
     return <String, dynamic>{
+      'isReady': this.isReady,
       'boardSize': this.boardSize,
       'board': this.board,
     };
diff --git a/lib/ui/painters/cell_painter.dart b/lib/ui/painters/cell_painter.dart
index b67c76edde50c7dce6b39e50479660ddff90dccf..e50ce3d26370860f7137b60613de5b44a375c7c9 100644
--- a/lib/ui/painters/cell_painter.dart
+++ b/lib/ui/painters/cell_painter.dart
@@ -58,6 +58,6 @@ class CellPainter extends CustomPainter {
 
   @override
   bool shouldRepaint(CustomPainter oldDelegate) {
-    return false;
+    return true;
   }
 }
diff --git a/lib/ui/screens/game_page.dart b/lib/ui/screens/game_page.dart
index faf19a310679b1e6c2b783a7832fa8f3740d9792..93cd8573714e6ecd1e1a31767cee758f05619302 100644
--- a/lib/ui/screens/game_page.dart
+++ b/lib/ui/screens/game_page.dart
@@ -13,12 +13,89 @@ class GamePage extends StatefulWidget {
   State<GamePage> createState() => _GamePageState();
 }
 
-void createNewGame(GameCubit gameCubit, int boardSize) {
-  final GameData newGame = GameData.createRandom(boardSize);
-  gameCubit.updateGameState(newGame);
-}
+class _GamePageState extends State<GamePage> with TickerProviderStateMixin {
+  static const boardSize = 6;
+
+  List<List<Animation<double>?>> animations = List.generate(
+    boardSize,
+    (i) => List.generate(
+      boardSize,
+      (i) => null,
+    ),
+  );
+
+  void resetAnimations() {
+    animations = List.generate(
+      boardSize,
+      (i) => List.generate(
+        boardSize,
+        (i) => null,
+      ),
+    );
+  }
+
+  void createNewGame(GameCubit gameCubit) {
+    final GameData newGame = GameData.createRandom(boardSize);
+    gameCubit.updateGameState(newGame);
+  }
+
+  void removeCell(GameCubit gameCubit, int x, int y) {
+    final GameData newGame = gameCubit.state.game ?? GameData.createRandom(boardSize);
+
+    // "remove" cell
+    newGame.updateCellValue(x, y, null);
+    setState(() {});
+
+    // "move down" cells
+    final controller = AnimationController(
+      vsync: this,
+      duration: Duration(milliseconds: 750),
+    )..addListener(() {
+        if (mounted) {
+          setState(() {});
+        }
+      });
+
+    if (mounted) {
+      setState(() {});
+    }
+
+    Animation<double> animation = Tween(
+      begin: 0.0,
+      end: 1.0,
+    ).animate(CurvedAnimation(
+      curve: Curves.bounceOut,
+      parent: controller,
+    ))
+      ..addStatusListener((status) {
+        if (status == AnimationStatus.completed) {
+          for (var i = 0; i < y; i++) {
+            newGame.updateCellValue(x, (y - i), newGame.getCellValue(x, (y - i) - 1));
+          }
+          newGame.updateCellValue(x, 0, null);
+
+          resetAnimations();
+          setState(() {});
+
+          controller.dispose();
+        }
+      });
+
+    for (var i = 0; i < y; i++) {
+      animations[(y - i) - 1][x] = animation;
+    }
+
+    controller.forward().orCancel;
+  }
+
+  void updateCellValue(GameCubit gameCubit, int x, int y, int value) {
+    final GameData newGame = gameCubit.state.game ?? GameData.createRandom(boardSize);
+    newGame.updateCellValue(x, y, value);
+
+    gameCubit.updateGameState(newGame);
+    setState(() {});
+  }
 
-class _GamePageState extends State<GamePage> {
   @override
   Widget build(BuildContext context) {
     return BlocBuilder<GameCubit, GameState>(
@@ -29,19 +106,36 @@ class _GamePageState extends State<GamePage> {
 
         final GameCubit gameCubit = BlocProvider.of<GameCubit>(context);
 
+        if (gameState.game?.isReady != true) {
+          createNewGame(gameCubit);
+        }
+
         return Column(
           mainAxisAlignment: MainAxisAlignment.start,
           crossAxisAlignment: CrossAxisAlignment.center,
           children: [
-            gameState.game != null
-                ? GameBoardWidget(
-                    gameData: gameState.game!,
-                    size: Size(boardWidgetWidth, boardWidgetHeight),
-                  )
-                : SizedBox.shrink(),
+            GestureDetector(
+              child: gameState.game != null
+                  ? GameBoardWidget(
+                      gameData: gameState.game!,
+                      size: Size(boardWidgetWidth, boardWidgetHeight),
+                      animations: animations,
+                    )
+                  : SizedBox.shrink(),
+              onTapUp: (details) {
+                double xTap = details.localPosition.dx;
+                double yTap = details.localPosition.dy;
+
+                int x = (xTap / boardWidgetWidth * boardSize).toInt();
+                int y = (yTap / boardWidgetHeight * boardSize).toInt();
+                print('[' + x.toString() + ',' + y.toString() + ']');
+
+                removeCell(gameCubit, x, y);
+              },
+            ),
             IconButton(
               onPressed: () {
-                createNewGame(gameCubit, boardSize);
+                createNewGame(gameCubit);
               },
               icon: Icon(UniconsSolid.star),
               color: Colors.white,
diff --git a/lib/ui/widgets/game_board.dart b/lib/ui/widgets/game_board.dart
index 30581d81eeac54524d089ba2830868182a30521b..32e980c2283e14547676784e17deb4a9e37113ff 100644
--- a/lib/ui/widgets/game_board.dart
+++ b/lib/ui/widgets/game_board.dart
@@ -3,64 +3,64 @@ import 'package:flutter/material.dart';
 import 'package:random/models/game_data.dart';
 import 'package:random/ui/painters/cell_painter.dart';
 
-class GameBoardWidget extends StatefulWidget {
+class GameBoardWidget extends StatelessWidget {
   const GameBoardWidget({
     super.key,
     required this.gameData,
     required this.size,
+    required this.animations,
   });
 
   final GameData gameData;
   final Size size;
+  final List<List<Animation<double>?>> animations;
 
-  @override
-  State<GameBoardWidget> createState() => _GameBoardWidgetState();
-}
-
-class _GameBoardWidgetState extends State<GameBoardWidget> {
   @override
   Widget build(BuildContext context) {
-    final widgetWidth = widget.size.width;
-    final widgetHeight = widget.size.height;
+    final widgetWidth = this.size.width;
+    final widgetHeight = this.size.height;
 
-    final rowsCount = widget.gameData.board.length;
-    final columnsCount = widget.gameData.board[0].length;
-    print('counts: rows=' + rowsCount.toString() + ' / columns=' + columnsCount.toString());
+    final rowsCount = this.gameData.board.length;
+    final columnsCount = this.gameData.board[0].length;
 
     final cellWidth = widgetWidth / columnsCount;
     final cellHeight = widgetHeight / 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 = widget.gameData.board[y][x];
+        final GameDataItem item = this.gameData.board[y][x];
+        int? value = item.value;
+
+        if (value != null) {
+          final Animation<double>? translation = this.animations[y][x];
 
-        final Widget cellContent = CustomPaint(
-          size: Size(cellWidth, cellHeight),
-          willChange: false,
-          painter: CellPainter(value: item.value),
-        );
+          final Widget cellContent = CustomPaint(
+            size: Size(cellWidth, cellHeight),
+            willChange: false,
+            painter: CellPainter(value: value),
+          );
 
-        final Widget cellWidget = Positioned(
-          left: (x * cellWidth).toDouble(),
-          top: (y * cellHeight).toDouble(),
-          child: Container(
-            width: cellWidth,
-            height: cellHeight,
-            child: cellContent,
-          ),
-        );
+          final Widget cellWidget = Positioned(
+            left: (x * cellWidth).toDouble(),
+            top: ((y + (translation?.value ?? 0)) * cellHeight).toDouble(),
+            child: Container(
+              width: cellWidth,
+              height: cellHeight,
+              child: cellContent,
+            ),
+          );
 
-        cells.add(cellWidget);
+          cells.add(cellWidget);
+        }
       }
     }
 
     return Container(
       width: widgetWidth,
       height: widgetHeight,
-      color: Colors.grey,
+      color: Colors.black,
       child: Stack(
         children: cells,
       ),
diff --git a/pubspec.yaml b/pubspec.yaml
index a0dad971e0249c47f72502fbac5d16fb069f0192..b0d6d8e00aee8565822bbc1ec0a993a2da234550 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.39+40
+version: 1.0.40+41
 
 environment:
   sdk: '^3.0.0'