diff --git a/src/Classes/Cels/CelTileMap.gd b/src/Classes/Cels/CelTileMap.gd
index cb4ba7d62..83e3737aa 100644
--- a/src/Classes/Cels/CelTileMap.gd
+++ b/src/Classes/Cels/CelTileMap.gd
@@ -4,7 +4,7 @@ extends PixelCel
 enum TileEditingMode { MANUAL, AUTO, STACK }
 
 var tileset: TileSetCustom
-var tile_editing_mode := TileEditingMode.MANUAL
+var tile_editing_mode := TileEditingMode.STACK
 var indices := PackedInt32Array()
 var indices_x: int
 var indices_y: int
@@ -38,7 +38,7 @@ func update_texture() -> void:
 			if not tile_used:
 				tiles_to_delete.append(j)
 		for j in tiles_to_delete:
-			tileset.tiles.remove_at(j)
+			tileset.remove_tile_at_index(j)
 	for i in indices.size():
 		var x_coord := float(tileset.tile_size.x) * (i % indices_x)
 		var y_coord := float(tileset.tile_size.y) * (i / indices_x)
@@ -51,7 +51,7 @@ func update_texture() -> void:
 			if index == 0 or tileset.tiles.size() <= index:
 				continue
 			if image_portion.get_data() != tileset.tiles[index].get_data():
-				tileset.tiles[index].copy_from(image_portion)
+				tileset.replace_tile_at(image_portion, index)
 				# TODO: Update the rest of the tilemap
 		else:
 			var found_tile := false
@@ -62,7 +62,7 @@ func update_texture() -> void:
 					found_tile = true
 					break
 			if not found_tile:
-				tileset.tiles.append(image_portion)
+				tileset.add_tile(image_portion)
 				indices[i] = tileset.tiles.size()
 
 
diff --git a/src/Classes/Project.gd b/src/Classes/Project.gd
index bdea6a52b..12d8e2712 100644
--- a/src/Classes/Project.gd
+++ b/src/Classes/Project.gd
@@ -8,6 +8,7 @@ signal serialized(dict: Dictionary)
 signal about_to_deserialize(dict: Dictionary)
 signal resized
 signal timeline_updated
+signal tilesets_updated
 
 const INDEXED_MODE := Image.FORMAT_MAX + 1
 
@@ -936,3 +937,4 @@ func reorder_reference_image(from: int, to: int) -> void:
 
 func add_tileset(tileset: TileSetCustom) -> void:
 	tilesets.append(tileset)
+	tilesets_updated.emit()
diff --git a/src/Classes/TileSetCustom.gd b/src/Classes/TileSetCustom.gd
index 2feafe1ed..368e44a4b 100644
--- a/src/Classes/TileSetCustom.gd
+++ b/src/Classes/TileSetCustom.gd
@@ -1,6 +1,8 @@
 class_name TileSetCustom
 extends RefCounted
 
+signal updated
+
 var name := ""
 var tile_size: Vector2i
 var tiles: Array[Image] = []
@@ -14,3 +16,18 @@ func _init(_tile_size: Vector2i, _name := "") -> void:
 	#tiles.resize(indices_x * indices_y + 1)
 	var empty_image := Image.create_empty(tile_size.x, tile_size.y, false, Image.FORMAT_RGBA8)
 	tiles.append(empty_image)
+
+
+func add_tile(tile: Image) -> void:
+	tiles.append(tile)
+	updated.emit()
+
+
+func remove_tile_at_index(index: int) -> void:
+	tiles.remove_at(index)
+	updated.emit()
+
+
+func replace_tile_at(new_tile: Image, index: int) -> void:
+	tiles[index].copy_from(new_tile)
+	updated.emit()
diff --git a/src/UI/TilesPanel.gd b/src/UI/TilesPanel.gd
new file mode 100644
index 000000000..f5c62b09e
--- /dev/null
+++ b/src/UI/TilesPanel.gd
@@ -0,0 +1,36 @@
+extends ScrollContainer
+
+@onready var h_flow_container: HFlowContainer = $PanelContainer/HFlowContainer
+
+
+func _ready() -> void:
+	Global.project_switched.connect(_on_project_switched)
+	Global.project_switched.connect(_update_tilesets)
+	Global.current_project.tilesets_updated.connect(_update_tilesets)
+
+
+func _on_project_switched() -> void:
+	if not Global.current_project.tilesets_updated.is_connected(_update_tilesets):
+		Global.current_project.tilesets_updated.connect(_update_tilesets)
+
+
+# TODO: Handle signal methods better and rename them to avoid confusion.
+func _update_tilesets() -> void:
+	for child in h_flow_container.get_children():
+		child.queue_free()
+	if Global.current_project.tilesets.size() == 0:
+		return
+	var tileset := Global.current_project.tilesets[0]
+	if not tileset.updated.is_connected(_update_tileset):
+		tileset.updated.connect(_update_tileset)
+
+
+func _update_tileset() -> void:
+	for child in h_flow_container.get_children():
+		child.queue_free()
+	var tileset := Global.current_project.tilesets[0]
+	for tile in tileset.tiles:
+		var texture_rect := TextureButton.new()
+		texture_rect.custom_minimum_size = Vector2i(32, 32)
+		texture_rect.texture_normal = ImageTexture.create_from_image(tile)
+		h_flow_container.add_child(texture_rect)
diff --git a/src/UI/TilesPanel.tscn b/src/UI/TilesPanel.tscn
new file mode 100644
index 000000000..f7840dcbd
--- /dev/null
+++ b/src/UI/TilesPanel.tscn
@@ -0,0 +1,18 @@
+[gd_scene load_steps=2 format=3 uid="uid://bfbragmmdwfbl"]
+
+[ext_resource type="Script" path="res://src/UI/TilesPanel.gd" id="1_d2oc5"]
+
+[node name="Tiles" type="ScrollContainer"]
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+script = ExtResource("1_d2oc5")
+
+[node name="PanelContainer" type="PanelContainer" parent="."]
+layout_mode = 2
+size_flags_horizontal = 3
+
+[node name="HFlowContainer" type="HFlowContainer" parent="PanelContainer"]
+layout_mode = 2
diff --git a/src/UI/UI.tscn b/src/UI/UI.tscn
index 1700b0868..b42265da8 100644
--- a/src/UI/UI.tscn
+++ b/src/UI/UI.tscn
@@ -1,4 +1,4 @@
-[gd_scene load_steps=54 format=3 uid="uid://c8dsi6ggkqa7a"]
+[gd_scene load_steps=55 format=3 uid="uid://c8dsi6ggkqa7a"]
 
 [ext_resource type="PackedScene" uid="uid://byu3rtoipuvoc" path="res://src/UI/ToolsPanel/Tools.tscn" id="1"]
 [ext_resource type="PackedScene" uid="uid://c546tskdu53j1" path="res://src/UI/Canvas/CanvasPreview.tscn" id="2"]
@@ -20,6 +20,7 @@
 [ext_resource type="PackedScene" uid="uid://ba24iuv55m4l3" path="res://src/UI/Canvas/Canvas.tscn" id="19"]
 [ext_resource type="PackedScene" uid="uid://wplk62pbgih4" path="res://src/Palette/PalettePanel.tscn" id="20"]
 [ext_resource type="Script" path="res://src/UI/ViewportContainer.gd" id="23"]
+[ext_resource type="PackedScene" uid="uid://bfbragmmdwfbl" path="res://src/UI/TilesPanel.tscn" id="23_wyr78"]
 [ext_resource type="Script" path="res://addons/dockable_container/layout_split.gd" id="27"]
 [ext_resource type="Script" path="res://addons/dockable_container/dockable_container.gd" id="35"]
 [ext_resource type="Script" path="res://addons/dockable_container/layout_panel.gd" id="36"]
@@ -36,7 +37,7 @@ shader_parameter/size = Vector2(100, 100)
 [sub_resource type="Resource" id="Resource_xnnnd"]
 resource_name = "Tabs"
 script = ExtResource("36")
-names = PackedStringArray("Tools", "Reference Images")
+names = PackedStringArray("Tools", "Reference Images", "Tiles")
 current_tab = 0
 
 [sub_resource type="Resource" id="Resource_34hle"]
@@ -401,6 +402,10 @@ size_flags_vertical = 3
 [node name="Palettes" parent="DockableContainer" instance=ExtResource("20")]
 layout_mode = 2
 
+[node name="Tiles" parent="DockableContainer" instance=ExtResource("23_wyr78")]
+visible = false
+layout_mode = 2
+
 [node name="Reference Images" parent="DockableContainer" instance=ExtResource("11")]
 visible = false
 layout_mode = 2