diff --git a/build.log b/build.log
index c231ec6..8971de4 100644
--- a/build.log
+++ b/build.log
@@ -1,3 +1,4 @@
-[LINK] g++ src\build\src\Engine.o src\build\src\main.o src\build\src\Renderer.o src\build\src\Components\CameraComponent.o src\build\src\Components\LightComponent.o src\build\src\Components\SpriteComponent.o src\build\src\Entitys\Object.o src\build\src\utils\FileDialog.o src\build\src\utils\Logging.o src\build\src\utils\Shader.o src\build\src\utils\utils.o src\build\vendor\imgui\imgui.o src\build\vendor\imgui\imgui_demo.o src\build\vendor\imgui\imgui_draw.o src\build\vendor\imgui\imgui_impl_glfw.o src\build\vendor\imgui\imgui_impl_opengl3.o src\build\vendor\imgui\imgui_tables.o src\build\vendor\imgui\imgui_widgets.o -o src\build\app.exe -LC:\msys64\mingw64\lib -lglfw3 -lglew32 -lopengl32 -lgdi32 -lyaml-cpp -lcomdlg32 -lssl -lcrypto
-[ERROR] Runtime crash
-Command 'src\build\app.exe' returned non-zero exit status 3221225477.
+[COMPILE] g++ -std=c++20 -Wall -Isrc/include -Isrc/vendor -Isrc/vendor/imgui -IC:/msys64/mingw64/include -Isrc/include -Isrc/vendor -Isrc/vendor/imgui -IC:/msys64/mingw64/include -Isrc\vendor\imgui -IC:\msys64\mingw64\lib\libyaml-cpp.a -MMD -MP -c src\src\Components\TilemapComponent.cpp -o src\build\src\Components\TilemapComponent.o
+[COMPILE] g++ -std=c++20 -Wall -Isrc/include -Isrc/vendor -Isrc/vendor/imgui -IC:/msys64/mingw64/include -Isrc/include -Isrc/vendor -Isrc/vendor/imgui -IC:/msys64/mingw64/include -Isrc\vendor\imgui -IC:\msys64\mingw64\lib\libyaml-cpp.a -MMD -MP -c src\src\utils\utils.cpp -o src\build\src\utils\utils.o
+[LINK] g++ src\build\src\Engine.o src\build\src\main.o src\build\src\Renderer.o src\build\src\Components\CameraComponent.o src\build\src\Components\LightComponent.o src\build\src\Components\SpriteComponent.o src\build\src\Components\TilemapComponent.o src\build\src\Entitys\Object.o src\build\src\utils\EngineConfig.o src\build\src\utils\FileDialog.o src\build\src\utils\Logging.o src\build\src\utils\Shader.o src\build\src\utils\utils.o src\build\vendor\imgui\imgui.o src\build\vendor\imgui\imgui_demo.o src\build\vendor\imgui\imgui_draw.o src\build\vendor\imgui\imgui_impl_glfw.o src\build\vendor\imgui\imgui_impl_opengl3.o src\build\vendor\imgui\imgui_tables.o src\build\vendor\imgui\imgui_widgets.o -o src\build\app.exe -LC:\msys64\mingw64\lib -lglfw3 -lglew32 -lopengl32 -lgdi32 -lyaml-cpp -lcomdlg32 -lssl -lcrypto
+[RUN] Executed app.exe successfully.
diff --git a/imgui.ini b/imgui.ini
index ec42917..d622fe7 100644
--- a/imgui.ini
+++ b/imgui.ini
@@ -47,12 +47,18 @@ Size=1141,287
 Collapsed=0
 DockId=0x00000008,0
 
+[Window][Tilemap Editor]
+Pos=265,19
+Size=1141,869
+Collapsed=0
+DockId=0x00000007,1
+
 [Docking][Data]
 DockSpace       ID=0x11111111 Window=0x1BBC0F80 Pos=0,19 Size=1920,1158 Split=X
   DockNode      ID=0x00000003 Parent=0x11111111 SizeRef=1406,1158 Split=X
     DockNode    ID=0x00000001 Parent=0x00000003 SizeRef=263,701 HiddenTabBar=1 Selected=0x12EF0F59
     DockNode    ID=0x00000002 Parent=0x00000003 SizeRef=1141,701 Split=Y Selected=0xC450F867
-      DockNode  ID=0x00000007 Parent=0x00000002 SizeRef=606,869 CentralNode=1 HiddenTabBar=1 Selected=0xC450F867
+      DockNode  ID=0x00000007 Parent=0x00000002 SizeRef=606,869 CentralNode=1 Selected=0xC450F867
       DockNode  ID=0x00000008 Parent=0x00000002 SizeRef=606,287 HiddenTabBar=1 Selected=0xEA83D666
   DockNode      ID=0x00000004 Parent=0x11111111 SizeRef=512,1158 Split=Y Selected=0x36DC96AB
     DockNode    ID=0x00000005 Parent=0x00000004 SizeRef=407,835 HiddenTabBar=1 Selected=0x36DC96AB
diff --git a/src/assets/scenes/test.cene b/src/assets/scenes/test.cene
index 5b80b8b..a49694b 100644
--- a/src/assets/scenes/test.cene
+++ b/src/assets/scenes/test.cene
@@ -32,36 +32,6 @@ objects:
             texture: C:\Users\spenc\OneDrive\Pictures\49555.jpg
             normalMap: ""
         children: []
-  - name: Bark
-    position: [1024, 0]
-    layer: -1
-    components:
-      - type: SpriteComponent
-        texture: C:\Users\spenc\OneDrive\Pictures\textures\bark_willow_02_diff_1k.png
-        normalMap: C:\Users\spenc\OneDrive\Pictures\textures\bark_willow_02_nor_gl_1k.png
-    children: []
-  - name: Sun
-    position: [-5000, -5000]
-    layer: 1
-    components:
-      - type: LightComponent
-        color:
-          - 0.990196049
-          - 0.943370163
-          - 0.791186035
-        intensity: 2.0999999
-        radius: 100000000
-        falloff: 0.100000001
-        type: 0
-    children: []
-  - name: Rocks
-    position: [0, 0]
-    layer: -1
-    components:
-      - type: SpriteComponent
-        texture: C:\Users\spenc\OneDrive\Pictures\ganges_river_pebbles_diff_1k.png
-        normalMap: C:\Users\spenc\OneDrive\Pictures\ganges_river_pebbles_nor_gl_1k.png
-    children: []
   - name: World
     position: [-436, 248]
     layer: 0
diff --git a/src/assets/scenes/tilemap.cene b/src/assets/scenes/tilemap.cene
new file mode 100644
index 0000000..089bea3
--- /dev/null
+++ b/src/assets/scenes/tilemap.cene
@@ -0,0 +1,122 @@
+engine_version: 0.1.0
+scene_name: tilemap
+scene_hash: 0ffd3035689b66c87af235dc22993fa7dac416ee447c93a1c4594a6b8aafc289
+format_version: 1
+objects:
+  - name: Hello, Create
+    position: [0, 0]
+    layer: 0
+    components:
+      - type: TilemapComponent
+        gridSize:
+          - 10
+          - 10
+        tileSize:
+          - 32
+          - 32
+        tiles:
+          - 961
+          - 961
+          - 961
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - 816
+          - -1
+          - 945
+          - 970
+          - 970
+          - -1
+          - -1
+          - -1
+          - -1
+          - 813
+          - -1
+          - -1
+          - -1
+          - 970
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - 748
+          - 840
+          - -1
+          - 970
+          - -1
+          - 840
+          - -1
+          - -1
+          - -1
+          - 812
+          - -1
+          - 805
+          - -1
+          - 845
+          - 877
+          - -1
+          - 904
+          - -1
+          - -1
+          - -1
+          - 970
+          - -1
+          - -1
+          - -1
+          - -1
+          - 970
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - 875
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+          - -1
+        atlasPath: C:\Users\spenc\OneDrive\Pictures\6656e7221e49a1774d2fb280357e56f8d25d9d95.png
+        atlasTileSize:
+          - 32
+          - 32
+    children: []
\ No newline at end of file
diff --git a/src/assets/scenes/world.cene b/src/assets/scenes/world.cene
index 08fe5aa..e926597 100644
--- a/src/assets/scenes/world.cene
+++ b/src/assets/scenes/world.cene
@@ -40,36 +40,6 @@ objects:
                 texture: C:\Users\spenc\OneDrive\Pictures\blue_logo.png
                 normalMap: C:\Users\spenc\OneDrive\Pictures\images.jpg
             children: []
-  - name: Bark
-    position: [1024, 0]
-    layer: -1
-    components:
-      - type: SpriteComponent
-        texture: C:\Users\spenc\OneDrive\Pictures\textures\bark_willow_02_diff_1k.png
-        normalMap: C:\Users\spenc\OneDrive\Pictures\textures\bark_willow_02_nor_gl_1k.png
-    children: []
-  - name: Sun
-    position: [-5000, -5000]
-    layer: 1
-    components:
-      - type: LightComponent
-        color:
-          - 0.992156863
-          - 0.984313726
-          - 0.827450991
-        intensity: 1.25
-        radius: 100000000
-        falloff: 0.100000001
-        type: 0
-    children: []
-  - name: Rocks
-    position: [0, 0]
-    layer: -1
-    components:
-      - type: SpriteComponent
-        texture: C:\Users\spenc\OneDrive\Pictures\ganges_river_pebbles_diff_1k.png
-        normalMap: C:\Users\spenc\OneDrive\Pictures\ganges_river_pebbles_nor_gl_1k.png
-    children: []
   - name: World
     position: [-436, 248]
     layer: 0
diff --git a/src/assets/shaders/tilemap.frag b/src/assets/shaders/tilemap.frag
new file mode 100644
index 0000000..df2cc94
--- /dev/null
+++ b/src/assets/shaders/tilemap.frag
@@ -0,0 +1,12 @@
+#version 330 core
+in vec2 vUV;
+out vec4 FragColor;
+
+uniform sampler2D uTex;
+
+void main()
+{
+    vec4 tex = texture(uTex, vUV);
+    if (tex.a < 0.1) discard;
+    FragColor = tex;
+}
diff --git a/src/assets/shaders/tilemap.vert b/src/assets/shaders/tilemap.vert
new file mode 100644
index 0000000..445920c
--- /dev/null
+++ b/src/assets/shaders/tilemap.vert
@@ -0,0 +1,20 @@
+#version 330 core
+layout(location = 0) in vec2 aPos;
+layout(location = 1) in vec2 aUV;
+
+out vec2 vUV;
+
+uniform vec2 uPos;
+uniform vec2 uSize;
+uniform vec2 uScreen;
+uniform vec2 uUVMin;
+uniform vec2 uUVMax;
+
+void main()
+{
+    vec2 pos = uPos + aPos * uSize;
+    gl_Position = vec4((pos / uScreen) * 2.0 - 1.0, 0.0, 1.0);
+
+    // Remap UV to tile slice
+    vUV = mix(uUVMin, uUVMax, aUV);
+}
diff --git a/src/assets/shaders/unlit.frag b/src/assets/shaders/unlit.frag
new file mode 100644
index 0000000..821a7aa
--- /dev/null
+++ b/src/assets/shaders/unlit.frag
@@ -0,0 +1,12 @@
+#version 330 core
+in vec2 vUV;
+out vec4 FragColor;
+uniform sampler2D uTex;
+void main() {
+    vec4 color = texture(uTex, vUV);
+    
+    if (color.a < 0.01)
+        discard;
+
+    FragColor = color;
+}
diff --git a/src/assets/shaders/unlit.vert b/src/assets/shaders/unlit.vert
new file mode 100644
index 0000000..62def40
--- /dev/null
+++ b/src/assets/shaders/unlit.vert
@@ -0,0 +1,13 @@
+#version 330 core
+layout (location = 0) in vec2 aPos;
+layout (location = 1) in vec2 aUV;
+out vec2 vUV;
+uniform vec2 uPos;
+uniform vec2 uSize;
+uniform vec2 uScreen;
+void main() {
+    vec2 worldPos = aPos * uSize + uPos;
+    vUV = aUV;
+    vec2 ndc = (worldPos / uScreen) * 2.0 - 1.0;
+    gl_Position = vec4(ndc.x, -ndc.y, 0.0, 1.0);
+}
diff --git a/src/src/Components/TilemapComponent.cpp b/src/src/Components/TilemapComponent.cpp
new file mode 100644
index 0000000..ccd3de7
--- /dev/null
+++ b/src/src/Components/TilemapComponent.cpp
@@ -0,0 +1,258 @@
+#include "TilemapComponent.h"
+#include "../utils/Logging.h"
+#include "../utils/FileDialog.h"
+#include "../utils/utils.h"
+#include <stb_image.h>
+#include <cstdio>
+#include <cstring>
+#include <GLFW/glfw3.h>
+
+static int g_selectedTileIndex = 0;
+
+
+// Constructor: initialize with a default grid (optional)
+TilemapComponent::TilemapComponent(Object *owner)
+    : Component(owner)
+{
+    // For example, create an empty 10x10 tilemap
+    SetGridSize(glm::ivec2(10, 10));
+    // Optionally set a default tile size
+    m_TileSize = glm::ivec2(32, 32);
+}
+
+// Set grid dimensions and resize tile array; initially all -1 (empty)
+void TilemapComponent::SetGridSize(const glm::ivec2 &size)
+{
+    m_GridSize = size;
+    m_Tiles.assign(size.x * size.y, -1);
+}
+
+// Set individual tile at (x, y)
+void TilemapComponent::SetTile(int x, int y, int tileIndex)
+{
+    if (x < 0 || y < 0 || x >= m_GridSize.x || y >= m_GridSize.y)
+        return;
+    m_Tiles[y * m_GridSize.x + x] = tileIndex;
+}
+
+int TilemapComponent::GetTile(int x, int y) const
+{
+    if (x < 0 || y < 0 || x >= m_GridSize.x || y >= m_GridSize.y)
+        return -1;
+    return m_Tiles[y * m_GridSize.x + x];
+}
+
+void TilemapComponent::SetTileSize(const glm::ivec2 &size)
+{
+    m_TileSize = size;
+}
+
+// Set atlas (tileset) settings; also update dimensions
+void TilemapComponent::SetAtlas(const std::string &path, int atlasTileWidth, int atlasTileHeight)
+{
+    m_AtlasPath = path;
+    m_AtlasTileWidth = atlasTileWidth;
+    m_AtlasTileHeight = atlasTileHeight;
+    UpdateAtlasDimensions();
+}
+
+// Helper: load atlas image info using stbi_info to compute columns and rows
+void TilemapComponent::UpdateAtlasDimensions()
+{
+    if (m_AtlasPath.empty())
+        return;
+    int texW, texH, comp;
+    if (stbi_info(m_AtlasPath.c_str(), &texW, &texH, &comp))
+    {
+        m_AtlasCols = texW / m_AtlasTileWidth;
+        m_AtlasRows = texH / m_AtlasTileHeight;
+    }
+    else
+    {
+        m_AtlasCols = m_AtlasRows = 0;
+        Logger::LogError("Failed to get atlas info: %s", m_AtlasPath.c_str());
+    }
+}
+
+// Serialization: store grid size, tile size, tile data, and atlas settings.
+void TilemapComponent::Save(YAML::Emitter &out) const
+{
+    out << YAML::BeginMap;
+    out << YAML::Key << "type" << YAML::Value << "TilemapComponent";
+    out << YAML::Key << "gridSize" << YAML::Value << std::vector<int>{m_GridSize.x, m_GridSize.y};
+    out << YAML::Key << "tileSize" << YAML::Value << std::vector<int>{m_TileSize.x, m_TileSize.y};
+    out << YAML::Key << "tiles" << YAML::Value << m_Tiles;
+    out << YAML::Key << "atlasPath" << YAML::Value << m_AtlasPath;
+    out << YAML::Key << "atlasTileSize" << YAML::Value << std::vector<int>{m_AtlasTileWidth, m_AtlasTileHeight};
+    out << YAML::EndMap;
+}
+
+// Deserialization: load saved data
+void TilemapComponent::Load(const YAML::Node &node)
+{
+    if (node["gridSize"])
+    {
+        auto vec = node["gridSize"].as<std::vector<int>>();
+        if (vec.size() == 2)
+            m_GridSize = glm::ivec2(vec[0], vec[1]);
+    }
+    if (node["tileSize"])
+    {
+        auto vec = node["tileSize"].as<std::vector<int>>();
+        if (vec.size() == 2)
+            m_TileSize = glm::ivec2(vec[0], vec[1]);
+    }
+    if (node["tiles"])
+        m_Tiles = node["tiles"].as<std::vector<int>>();
+    if (node["atlasPath"])
+        m_AtlasPath = node["atlasPath"].as<std::string>();
+    if (node["atlasTileSize"])
+    {
+        auto vec = node["atlasTileSize"].as<std::vector<int>>();
+        if (vec.size() == 2)
+        {
+            m_AtlasTileWidth = vec[0];
+            m_AtlasTileHeight = vec[1];
+        }
+    }
+    // Update atlas dimensions after loading settings
+    UpdateAtlasDimensions();
+}
+
+// -----------------------------
+// Editor UI
+// -----------------------------
+void TilemapComponent::DrawEditorUI()
+{
+    ImGui::Begin("Tilemap Editor");
+
+    // --- Atlas Settings ---
+    if (ImGui::CollapsingHeader("Tileset Atlas Settings"))
+    {
+        // Display current atlas path
+        ImGui::Text("Current Atlas: %s", m_AtlasPath.empty() ? "None" : m_AtlasPath.c_str());
+        if (ImGui::Button("Import Atlas"))
+        {
+            std::string path = OpenFileDialog(FileDialogType::Images);
+            if (!path.empty())
+            {
+                // For simplicity, default atlas tile dimensions are set via input later.
+                m_AtlasPath = path;
+                UpdateAtlasDimensions();
+            }
+        }
+        // Configure atlas tile size
+        int atlasW = m_AtlasTileWidth, atlasH = m_AtlasTileHeight;
+        if (ImGui::InputInt("Atlas Tile Width", &atlasW))
+        {
+            m_AtlasTileWidth = atlasW;
+            UpdateAtlasDimensions();
+        }
+        if (ImGui::InputInt("Atlas Tile Height", &atlasH))
+        {
+            m_AtlasTileHeight = atlasH;
+            UpdateAtlasDimensions();
+        }
+        ImGui::Text("Atlas Grid: %d columns x %d rows", m_AtlasCols, m_AtlasRows);
+    }
+
+    // --- Map Grid Settings ---
+    if (ImGui::CollapsingHeader("Map Settings"))
+    {
+        glm::ivec2 grid = m_GridSize;
+        int gridW = grid.x, gridH = grid.y;
+        if (ImGui::InputInt("Map Grid Width", &gridW) || ImGui::InputInt("Map Grid Height", &gridH))
+        {
+            SetGridSize(glm::ivec2(gridW, gridH));
+        }
+        glm::ivec2 ts = m_TileSize;
+        int tileW = ts.x, tileH = ts.y;
+        if (ImGui::InputInt("Tile Width", &tileW) || ImGui::InputInt("Tile Height", &tileH))
+        {
+            SetTileSize(glm::ivec2(tileW, tileH));
+        }
+    }
+
+    // --- Tileset Palette Editor ---
+    if (ImGui::CollapsingHeader("Tileset Palette"))
+    {
+        if (m_AtlasPath.empty())
+        {
+            ImGui::Text("No atlas loaded.");
+        }
+        else
+        {
+            // Retrieve texture dimensions via stbi_info (for preview UV calculation)
+            int texW, texH, comp;
+            if (stbi_info(m_AtlasPath.c_str(), &texW, &texH, &comp))
+            {
+                float uvTileW = float(m_AtlasTileWidth) / float(texW);
+                float uvTileH = float(m_AtlasTileHeight) / float(texH);
+                // Display each tile as an image button
+                ImGui::Text("Select a tile:");
+                for (int row = 0; row < m_AtlasRows; row++)
+                {
+                    for (int col = 0; col < m_AtlasCols; col++)
+                    {
+                        int tileIndex = row * m_AtlasCols + col;
+                        // UV coordinates for this tile
+                        float uvX = float(col) * uvTileW;
+                        float uvY = float(row) * uvTileH;
+                        ImVec2 uv0(uvX, uvY);
+                        ImVec2 uv1(uvX + uvTileW, uvY + uvTileH);
+
+                        char buf[32];
+                        sprintf(buf, "##tile_%d", tileIndex);
+                        // Display a button. Here, 32x32 pixels is used for preview size.
+                        GLuint textureID = LoadTextureIfNeeded(m_AtlasPath);
+                        if (ImGui::ImageButton(buf, (ImTextureID)(uintptr_t)textureID, ImVec2(32, 32), uv0, uv1))
+                        {
+                            g_selectedTileIndex = tileIndex;
+                        }
+
+                        ImGui::SameLine();
+                    }
+                    ImGui::NewLine();
+                }
+                ImGui::Text("Selected Tile: %d", g_selectedTileIndex);
+            }
+            else
+            {
+                ImGui::Text("Failed to load atlas info.");
+            }
+        }
+    }
+
+    // --- Map Editor ---
+    if (ImGui::CollapsingHeader("Map Editor"))
+    {
+        if (m_GridSize.x == 0 || m_GridSize.y == 0)
+        {
+            ImGui::Text("No map created.");
+        }
+        else
+        {
+            ImGui::Text("Click a cell to paint with the selected tile.");
+            ImGui::BeginChild("TilemapGrid", ImVec2(0, 300), true);
+            for (int y = 0; y < m_GridSize.y; y++)
+            {
+                for (int x = 0; x < m_GridSize.x; x++)
+                {
+                    int tile = GetTile(x, y);
+                    char label[32];
+                    sprintf(label, "%d##%d_%d", tile, x, y);
+                    if (ImGui::Button(label, ImVec2(30, 30)))
+                    {
+                        SetTile(x, y, g_selectedTileIndex);
+                    }
+                    ImGui::SameLine();
+                }
+                ImGui::NewLine();
+            }
+            ImGui::EndChild();
+        }
+    }
+
+    ImGui::End();
+}
+
diff --git a/src/src/Components/TilemapComponent.h b/src/src/Components/TilemapComponent.h
new file mode 100644
index 0000000..0e116d1
--- /dev/null
+++ b/src/src/Components/TilemapComponent.h
@@ -0,0 +1,56 @@
+#pragma once
+#include "Component.h"
+#include <glm/glm.hpp>
+#include <yaml-cpp/yaml.h>
+#include <string>
+#include <vector>
+#include <imgui.h>
+
+class TilemapComponent : public Component
+{
+public:
+    TilemapComponent(Object* owner);
+
+    // Editor UI for tilemap
+    void DrawEditorUI();
+
+    // Set up grid and tile dimensions
+    void SetGridSize(const glm::ivec2& size);
+    void SetTileSize(const glm::ivec2& size);
+    void SetTile(int x, int y, int tileIndex);
+    int  GetTile(int x, int y) const;
+    
+    // Getters
+    const glm::ivec2& GetGridSize() const { return m_GridSize; }
+    const glm::ivec2& GetTileSize() const { return m_TileSize; }
+    const std::vector<int>& GetTiles() const { return m_Tiles; }
+    const std::string& GetAtlasPath() const { return m_AtlasPath; }
+    
+    int GetAtlasTileWidth() const { return m_AtlasTileWidth; }
+    int GetAtlasTileHeight() const { return m_AtlasTileHeight; }
+    int GetAtlasCols() const { return m_AtlasCols; }
+    int GetAtlasRows() const { return m_AtlasRows; }
+
+    // Atlas setup: import an atlas image and configure its tile dimensions.
+    void SetAtlas(const std::string& path, int atlasTileWidth, int atlasTileHeight);
+
+    // Serialization
+    void Save(YAML::Emitter& out) const override;
+    void Load(const YAML::Node& node) override;
+    std::string GetName() const override { return "TilemapComponent"; }
+
+private:
+    // Grid and tile data
+    glm::ivec2 m_GridSize {0, 0};
+    glm::ivec2 m_TileSize {32, 32};
+    std::vector<int> m_Tiles;
+
+    // Atlas (tileset) settings
+    std::string m_AtlasPath;
+    int m_AtlasTileWidth = 32;
+    int m_AtlasTileHeight = 32;
+    int m_AtlasCols = 0;
+    int m_AtlasRows = 0;
+
+    void UpdateAtlasDimensions();
+};
diff --git a/src/src/Engine.cpp b/src/src/Engine.cpp
index 82adcd0..d4a4e1c 100644
--- a/src/src/Engine.cpp
+++ b/src/src/Engine.cpp
@@ -4,6 +4,8 @@
 #include "components/SpriteComponent.h"
 #include "components/CameraComponent.h"
 #include "components/LightComponent.h"
+#include "components/TilemapComponent.h"
+
 
 #include "utils/FileDialog.h"
 #include "utils/Logging.h"
@@ -162,6 +164,11 @@ void DrawInspectorUI(std::shared_ptr<Object> selected)
         if (!selected->GetComponent<LightComponent>())
             selected->AddComponent<LightComponent>();
     }
+    if (ImGui::Button("Add TilemapComponent"))
+    {
+        if (!selected->GetComponent<TilemapComponent>())
+            selected->AddComponent<TilemapComponent>();
+    }
 
     // Sprite UI...
     if (auto sprite = selected->GetComponent<SpriteComponent>())
@@ -230,7 +237,23 @@ void DrawInspectorUI(std::shared_ptr<Object> selected)
             selected->RemoveComponent<LightComponent>();
     }
 
+    if (auto tilemap = selected->GetComponent<TilemapComponent>())
+    {
+        ImGui::SeparatorText("Tilemap Component");
+
+        ImGui::Text("Refer to Tilemap Editor Window");
+
+        if (ImGui::Button("Remove TilemapComponent"))
+            selected->RemoveComponent<TilemapComponent>();
+    }
+
     ImGui::End();
+
+    if (auto tilemap = selected->GetComponent<TilemapComponent>())
+    {
+        tilemap->DrawEditorUI();
+
+    }
 }
 
 
diff --git a/src/src/Renderer.cpp b/src/src/Renderer.cpp
index 3c62147..3cdcd51 100644
--- a/src/src/Renderer.cpp
+++ b/src/src/Renderer.cpp
@@ -2,18 +2,22 @@
 #include "Components/SpriteComponent.h"
 #include "utils/Shader.h"
 #include "utils/Logging.h"
+#include "utils/EngineConfig.h"
+#include "utils/utils.h"
 
+#include "stb_image.h"
 
 #include <GL/glew.h>
 #include <glm/glm.hpp>
 #include <iostream>
+#include <map>
 
 static Shader spriteShader;
+static Shader unlitShader;
 
 GLuint Renderer::fbo = 0;
 GLuint Renderer::textureColorBuffer = 0;
 GLuint Renderer::defaultNormalMap = 0;
-
 GLuint Renderer::rbo = 0;
 GLuint Renderer::quadVAO = 0;
 GLuint Renderer::quadVBO = 0;
@@ -22,9 +26,7 @@ int Renderer::height = 720;
 int Renderer::s_DrawCalls = 0;
 std::vector<Light> Renderer::s_Lights;
 
-
-
-
+static Shader tilemapShader;
 
 
 void Renderer::InitQuad() {
@@ -74,7 +76,10 @@ void Renderer::Init() {
 
     InitQuad();
 
+    // Load lit shader
     spriteShader.LoadFromFile("src/assets/shaders/sprite.vert", "src/assets/shaders/sprite.frag");
+    // Load unlit shader
+    unlitShader.LoadFromFile("src/assets/shaders/unlit.vert", "src/assets/shaders/unlit.frag");
 
     // Create a 1x1 flat normal map (RGB: 128,128,255)
     unsigned char flatNormal[3] = { 128, 128, 255 };
@@ -115,33 +120,64 @@ void Renderer::End() {
     glBindFramebuffer(GL_FRAMEBUFFER, 0);
 }
 
-//void Renderer::DrawSprite(SpriteComponent* sprite, const glm::vec2& pos, float scale) {
-//    GLuint tex = sprite->GetTextureID();
-//    if (!tex) return;
-//
-//    glBindTexture(GL_TEXTURE_2D, tex);
-//    glBegin(GL_QUADS);
-//    float size = 100.0f * scale;
-//
-//    glTexCoord2f(0, 0); glVertex2f(pos.x, pos.y);
-//    glTexCoord2f(1, 0); glVertex2f(pos.x + size, pos.y);
-//    glTexCoord2f(1, 1); glVertex2f(pos.x + size, pos.y + size);
-//    glTexCoord2f(0, 1); glVertex2f(pos.x, pos.y + size);
-//    glEnd();
-//}
-
-
 void Renderer::ClearLights() {
     s_Lights.clear();
 }
 
-
-
 void Renderer::AddLight(const glm::vec2& screenPos, const glm::vec3& color, float intensity, float radius) {
     if (s_Lights.size() >= 8) return;
     s_Lights.push_back({screenPos, color, intensity, radius});
 }
 
+void Renderer::DrawTilemap(TilemapComponent* tilemap, const glm::vec2& worldPos, float zoom, const glm::vec2& cameraPos) {
+    if (!tilemap || tilemap->GetAtlasPath().empty()) return;
+
+    glm::ivec2 grid = tilemap->GetGridSize();
+    glm::ivec2 tileSize = tilemap->GetTileSize();
+    int cols = tilemap->GetAtlasCols();
+    int rows = tilemap->GetAtlasRows();
+
+    const std::string& atlasPath = tilemap->GetAtlasPath();
+    GLuint atlasTex = LoadTextureIfNeeded(atlasPath);
+    if (atlasTex == 0) return;
+
+    tilemapShader.Use();
+    tilemapShader.SetVec2("uScreen", glm::vec2(width, height));
+    tilemapShader.SetInt("uTex", 0);
+    glActiveTexture(GL_TEXTURE0);
+    glBindTexture(GL_TEXTURE_2D, atlasTex);
+
+    glBindVertexArray(quadVAO);
+
+    for (int y = 0; y < grid.y; ++y) {
+        for (int x = 0; x < grid.x; ++x) {
+            int index = tilemap->GetTile(x, y);
+            if (index < 0 || index >= cols * rows) continue;
+
+            int atlasX = index % cols;
+            int atlasY = index / cols;
+
+            glm::vec2 uvMin = glm::vec2(atlasX, atlasY) / glm::vec2(cols, rows);
+            glm::vec2 uvMax = (glm::vec2(atlasX + 1, atlasY + 1)) / glm::vec2(cols, rows);
+
+            tilemapShader.SetVec2("uUVMin", uvMin);
+            tilemapShader.SetVec2("uUVMax", uvMax);
+
+            glm::vec2 tileWorld = worldPos + glm::vec2(x * tileSize.x, y * tileSize.y);
+            glm::vec2 screenPos = (tileWorld - cameraPos) * zoom + glm::vec2(width, height) * 0.5f;
+
+            tilemapShader.SetVec2("uPos", screenPos);
+            tilemapShader.SetVec2("uSize", glm::vec2(tileSize) * zoom);
+
+            glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+            s_DrawCalls++;
+        }
+    }
+
+    glBindVertexArray(0);
+}
+
+
 
 void Renderer::DrawSprite(SpriteComponent* sprite, const glm::vec2& pos, float zoom, glm::vec2& CameraPos) {
     if (!sprite->HasTexture()) {
@@ -149,54 +185,65 @@ void Renderer::DrawSprite(SpriteComponent* sprite, const glm::vec2& pos, float z
         return;
     }
 
-    spriteShader.Use();
+    // Choose the shader based on engine configuration
+    if (g_engineConfig.lighting_enabled) {
+        spriteShader.Use();
+    } else {
+        unlitShader.Use();
+    }
 
     glm::vec2 size = sprite->GetSize();
     glm::vec2 screenPos = (pos - CameraPos) * zoom + glm::vec2(width, height) * 0.5f - (size * zoom * 0.5f);
 
-    spriteShader.SetVec2("uPos", screenPos);
-    spriteShader.SetVec2("uSize", size * zoom);
-    spriteShader.SetVec2("uScreen", glm::vec2(width, height));
+    // Set common uniforms
+    if (g_engineConfig.lighting_enabled) {
+        spriteShader.SetVec2("uPos", screenPos);
+        spriteShader.SetVec2("uSize", size * zoom);
+        spriteShader.SetVec2("uScreen", glm::vec2(width, height));
 
-    spriteShader.SetInt("uLightCount", static_cast<int>(s_Lights.size()));
-    for (size_t i = 0; i < s_Lights.size(); ++i) {
-        spriteShader.SetVec2(("uLightPos[" + std::to_string(i) + "]").c_str(), s_Lights[i].screenPos);
-        spriteShader.SetVec3(("uLightColor[" + std::to_string(i) + "]").c_str(), s_Lights[i].color);
-        spriteShader.SetFloat(("uLightIntensity[" + std::to_string(i) + "]").c_str(), s_Lights[i].intensity);
-        spriteShader.SetFloat(("uLightRadius[" + std::to_string(i) + "]").c_str(), s_Lights[i].radius);
+        spriteShader.SetInt("uLightCount", static_cast<int>(s_Lights.size()));
+        for (size_t i = 0; i < s_Lights.size(); ++i) {
+            spriteShader.SetVec2(("uLightPos[" + std::to_string(i) + "]").c_str(), s_Lights[i].screenPos);
+            spriteShader.SetVec3(("uLightColor[" + std::to_string(i) + "]").c_str(), s_Lights[i].color);
+            spriteShader.SetFloat(("uLightIntensity[" + std::to_string(i) + "]").c_str(), s_Lights[i].intensity);
+            spriteShader.SetFloat(("uLightRadius[" + std::to_string(i) + "]").c_str(), s_Lights[i].radius);
+        }
+    } else {
+        // Unlit shader uniforms
+        unlitShader.SetVec2("uPos", screenPos);
+        unlitShader.SetVec2("uSize", size * zoom);
+        unlitShader.SetVec2("uScreen", glm::vec2(width, height));
+    }
+    
+    // Bind the diffuse texture (common to both shaders)
+    if (g_engineConfig.lighting_enabled) {
+        spriteShader.SetInt("uTex", 0);
+    } else {
+        unlitShader.SetInt("uTex", 0);
     }
-
-    spriteShader.SetInt("uTex", 0);
-    spriteShader.SetInt("uNormalMap", 1);
-
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, sprite->GetTextureID());
 
-    glActiveTexture(GL_TEXTURE1);
-    if (sprite->GetNormalMapID()) {
-        glBindTexture(GL_TEXTURE_2D, sprite->GetNormalMapID());
-    } else {
-        glBindTexture(GL_TEXTURE_2D, defaultNormalMap);
+    if (g_engineConfig.lighting_enabled) {
+        spriteShader.SetInt("uNormalMap", 1);
+        glActiveTexture(GL_TEXTURE1);
+        if (sprite->GetNormalMapID()) {
+            glBindTexture(GL_TEXTURE_2D, sprite->GetNormalMapID());
+        } else {
+            glBindTexture(GL_TEXTURE_2D, defaultNormalMap);
+        }
     }
-
+    
     glBindVertexArray(quadVAO);
     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
     glBindVertexArray(0);
     s_DrawCalls++;
 }
 
-
-
-
-
-
-
-int Renderer::GetDrawCallCount()
-{
+int Renderer::GetDrawCallCount() {
     return s_DrawCalls;
 }
 
-
 void Renderer::DrawEditorGrid(const glm::vec2& cameraPos, float zoom) {
     glUseProgram(0);
     glColor4f(0.5f, 0.5f, 0.5f, 0.25f);
@@ -226,11 +273,9 @@ void Renderer::DrawEditorGrid(const glm::vec2& cameraPos, float zoom) {
         glVertex2f(left, (float)y);
         glVertex2f(right, (float)y);
     }
-
     glEnd();
 }
 
-
 GLuint Renderer::GetRenderTexture() {
     return textureColorBuffer;
 }
diff --git a/src/src/Renderer.h b/src/src/Renderer.h
index a589db3..54c97b3 100644
--- a/src/src/Renderer.h
+++ b/src/src/Renderer.h
@@ -3,8 +3,11 @@
 #include <glm/glm.hpp>
 #include <vector>
 
+#include "Components/TilemapComponent.h"
+#include "Components/SpriteComponent.h"
+
+
 
-class SpriteComponent;
 
 struct Light {
     glm::vec2 screenPos;
@@ -21,6 +24,7 @@ public:
     static void End();
     static void DrawSprite(SpriteComponent* sprite, const glm::vec2& pos, float zoom, glm::vec2& CameraPos);
     static void AddLight(const glm::vec2& screenPos, const glm::vec3& color, float intensity, float radius);
+    static void DrawTilemap(TilemapComponent* tilemap, const glm::vec2& worldPos, float zoom, const glm::vec2& cameraPos);
     static void ClearLights();
     static void DrawEditorGrid(const glm::vec2& cameraPos, float zoom);
     static GLuint GetRenderTexture();
diff --git a/src/src/utils/EngineConfig.cpp b/src/src/utils/EngineConfig.cpp
new file mode 100644
index 0000000..4f53181
--- /dev/null
+++ b/src/src/utils/EngineConfig.cpp
@@ -0,0 +1,8 @@
+// EngineConfig.cpp
+#include "EngineConfig.h"
+
+
+EngineConfig g_engineConfig { 
+    .lighting_enabled = false,
+
+};
diff --git a/src/src/utils/EngineConfig.h b/src/src/utils/EngineConfig.h
new file mode 100644
index 0000000..9957b40
--- /dev/null
+++ b/src/src/utils/EngineConfig.h
@@ -0,0 +1,7 @@
+#pragma once
+
+
+struct EngineConfig {
+    bool lighting_enabled;
+};
+extern EngineConfig g_engineConfig;
diff --git a/src/src/utils/utils.cpp b/src/src/utils/utils.cpp
index 050b012..3c76caa 100644
--- a/src/src/utils/utils.cpp
+++ b/src/src/utils/utils.cpp
@@ -1,12 +1,37 @@
 #include "utils.h"
+#include <map>
+#include "stb_image.h"
+
+static std::map<std::string, GLuint> textureCache;
+
+GLuint LoadTextureIfNeeded(const std::string& path) {
+    if (textureCache.count(path))
+        return textureCache[path];
+
+    int w, h, channels;
+    stbi_set_flip_vertically_on_load(false);
+    unsigned char* data = stbi_load(path.c_str(), &w, &h, &channels, 4);
+    if (!data)
+        return 0;
+
+    GLuint id;
+    glGenTextures(1, &id);
+    glBindTexture(GL_TEXTURE_2D, id);
+    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+    stbi_image_free(data);
+
+    textureCache[path] = id;
+    return id;
+}
 
 std::string GetFilenameFromPath(const std::string& path)
 {
-    // Find the last slash or backslash
     size_t lastSlash = path.find_last_of("/\\");
     std::string filename = (lastSlash == std::string::npos) ? path : path.substr(lastSlash + 1);
 
-    // Strip trailing slashes (if any)
+    // Strip trailing slashes
     while (!filename.empty() && (filename.back() == '/' || filename.back() == '\\'))
         filename.pop_back();
 
diff --git a/src/src/utils/utils.h b/src/src/utils/utils.h
index b44a32e..e9e3320 100644
--- a/src/src/utils/utils.h
+++ b/src/src/utils/utils.h
@@ -1,4 +1,10 @@
-#include <string>
-#include <algorithm>
+#pragma once
 
+#include <string>
+#include <GL/glew.h>
+
+// Returns filename from a full path (e.g., "C:/foo/bar.png" → "bar.png")
 std::string GetFilenameFromPath(const std::string& path);
+
+// Loads a texture (with caching). Returns OpenGL texture ID
+GLuint LoadTextureIfNeeded(const std::string& path);