diff --git a/ACViewer/Config/MapViewerOptions.cs b/ACViewer/Config/MapViewerOptions.cs
index 6daf1a9..ed40d08 100644
--- a/ACViewer/Config/MapViewerOptions.cs
+++ b/ACViewer/Config/MapViewerOptions.cs
@@ -5,6 +5,9 @@ namespace ACViewer.Config
     public class MapViewerOptions
     {
         public MapViewerMode Mode { get; set; }
+        public bool EnableZSlicing { get; set; } = false;
+        public int CurrentZLevel { get; set; } = 1;
+        public float LevelHeight { get; set; } = 10.0f;
 
         public MapViewerOptions()
         {
diff --git a/ACViewer/Extensions/CommandHandler.cs b/ACViewer/Extensions/CommandHandler.cs
index 2ab31e4..3ef602e 100644
--- a/ACViewer/Extensions/CommandHandler.cs
+++ b/ACViewer/Extensions/CommandHandler.cs
@@ -1,5 +1,6 @@
 using System;
 using System.Windows.Input;
+using ACViewer.Config;
 
 namespace ACViewer.Extensions
 {
diff --git a/ACViewer/Extensions/Vector3Extensions.cs b/ACViewer/Extensions/Vector3Extensions.cs
index 808c1f2..de74dc0 100644
--- a/ACViewer/Extensions/Vector3Extensions.cs
+++ b/ACViewer/Extensions/Vector3Extensions.cs
@@ -1,11 +1,16 @@
 using System;
 
+using Microsoft.Xna.Framework;
+
+using System.Numerics;
+
 using ACE.Server.Physics;
 
 namespace ACViewer
 {
     public static class Vector3Extensions
     {
+
         public static System.Numerics.Vector3 ToNumerics(this Microsoft.Xna.Framework.Vector3 v)
         {
             return new System.Numerics.Vector3(v.X, v.Y, v.Z);
diff --git a/ACViewer/Model/VertexInstance.cs b/ACViewer/Model/VertexInstance.cs
index cbfa891..8c3a6d2 100644
--- a/ACViewer/Model/VertexInstance.cs
+++ b/ACViewer/Model/VertexInstance.cs
@@ -5,9 +5,10 @@ namespace ACViewer.Model
 {
     public struct VertexInstance : IVertexType
     {
-        public Vector3 Position;
+        public Vector3 Position { get; set; }
         public Vector4 Orientation;
         public Vector3 Scale;
+        
 
         public readonly static VertexDeclaration VertexDeclaration = new VertexDeclaration
         (
diff --git a/ACViewer/Render/Buffer.cs b/ACViewer/Render/Buffer.cs
index 1afad3f..36b524a 100644
--- a/ACViewer/Render/Buffer.cs
+++ b/ACViewer/Render/Buffer.cs
@@ -1,12 +1,14 @@
 using System;
 using System.Collections.Generic;
+using System.Linq;
 
 using Microsoft.Xna.Framework;
 using Microsoft.Xna.Framework.Graphics;
 
 using ACE.DatLoader.Entity;
 using ACE.Server.Physics;
-
+using ACViewer.Config;
+using ACViewer.Extensions;
 using ACViewer.Enum;
 using ACViewer.Model;
 
@@ -86,6 +88,95 @@ public void Init()
 
             AnimatedTextureAtlasChains = new Dictionary<TextureFormat, TextureAtlasChain>();
         }
+        
+        private bool IsInCurrentZLevel(Vector3 position)
+        {
+            if (!ConfigManager.Config.MapViewer.EnableZSlicing)
+                return true;
+
+            var config = ConfigManager.Config.MapViewer;
+            float levelBottom = (config.CurrentZLevel - 1) * config.LevelHeight;
+            float levelTop = levelBottom + config.LevelHeight;
+
+            return position.Z >= levelBottom && position.Z < levelTop;
+        }
+
+        public void DrawWithZSlicing()
+        {
+            Effect.Parameters["xWorld"].SetValue(Matrix.Identity);
+            Effect.Parameters["xLightDirection"].SetValue(-Vector3.UnitZ);
+            Effect.Parameters["xAmbient"].SetValue(0.5f);
+
+            Effect_Clamp.Parameters["xWorld"].SetValue(Matrix.Identity);
+            Effect_Clamp.Parameters["xLightDirection"].SetValue(-Vector3.UnitZ);
+            Effect_Clamp.Parameters["xAmbient"].SetValue(0.5f);
+
+            PerfTimer.Start(ProfilerSection.Draw);
+
+            if (drawTerrain)
+            {
+                SetRasterizerState();
+                TerrainBatch.DrawWithZFiltering(IsInCurrentZLevel);
+            }
+
+            if (drawEnvCells)
+                DrawBufferWithZSlicing(RB_EnvCell, true);
+
+            if (drawStaticObjs)
+                DrawBufferWithZSlicing(RB_StaticObjs);
+
+            if (drawBuildings)
+                DrawBufferWithZSlicing(RB_Buildings);
+
+            if (drawScenery)
+                DrawBufferWithZSlicing(RB_Scenery);
+
+            if (drawInstances && Server.InstancesLoaded)
+                DrawBufferWithZSlicing(RB_Instances);
+
+            if (drawEncounters && Server.EncountersLoaded)
+                DrawBufferWithZSlicing(RB_Encounters);
+
+            DrawBufferWithZSlicing(RB_Animated);
+
+            if (Picker.HitVertices != null)
+                Picker.DrawHitPoly();
+
+            PerfTimer.Stop(ProfilerSection.Draw);
+        }
+
+        private void DrawBufferWithZSlicing(Dictionary<uint, GfxObjInstance_Shared> batches)
+        {
+            SetRasterizerState(CullMode.None);
+
+            foreach (var batch in batches.Values)
+                batch.DrawFiltered(IsInCurrentZLevel);
+        }
+
+        private void DrawBufferWithZSlicing(Dictionary<GfxObjTexturePalette, GfxObjInstance_Shared> batches)
+        {
+            SetRasterizerState(CullMode.None);
+
+            foreach (var batch in batches.Values)
+                batch.DrawFiltered(IsInCurrentZLevel);
+        }
+
+        private void DrawBufferWithZSlicing(Dictionary<TextureSet, InstanceBatch> batches, bool culling = false)
+        {
+            var cullMode = WorldViewer.Instance.DungeonMode || culling ? 
+                CullMode.CullClockwiseFace : CullMode.None;
+
+            SetRasterizerState(cullMode);
+
+            Effect.CurrentTechnique = Effect.Techniques["TexturedInstanceEnv"];
+            Effect_Clamp.CurrentTechnique = Effect_Clamp.Techniques["TexturedInstanceEnv"];
+
+            foreach (var batch in batches.Values)
+            {
+                batch.DrawFiltered(IsInCurrentZLevel);
+            }
+        }
+
 
         public void ClearBuffer()
         {
diff --git a/ACViewer/Render/Camera.cs b/ACViewer/Render/Camera.cs
index e758253..e2a72d8 100644
--- a/ACViewer/Render/Camera.cs
+++ b/ACViewer/Render/Camera.cs
@@ -295,6 +295,31 @@ public void Update(GameTime gameTime)
                 Position -= Vector3.Cross(Up, Dir) * Speed;
             if (keyboardState.IsKeyDown(Keys.Space))
                 Position += Up * Speed;
+            // Shift key control for downward movement
+            if (keyboardState.IsKeyDown(Keys.LeftShift) || keyboardState.IsKeyDown(Keys.RightShift))
+                Position -= Up * Speed;
+            
+            // Z-level controls
+            if (keyboardState.IsKeyDown(Keys.F3) && LastKeyboardState != null && !LastKeyboardState.IsKeyDown(Keys.F3))
+            {
+                ConfigManager.Config.MapViewer.EnableZSlicing = !ConfigManager.Config.MapViewer.EnableZSlicing;
+                ConfigManager.Config.MapViewer.CurrentZLevel = 1;
+            }
+
+            // Z-level adjustment
+            if (ConfigManager.Config.MapViewer.EnableZSlicing)
+            {
+                if ((keyboardState.IsKeyDown(Keys.LeftAlt) || keyboardState.IsKeyDown(Keys.RightAlt)))
+                {
+                    var config = ConfigManager.Config.MapViewer;
+                    if (keyboardState.IsKeyDown(Keys.OemPlus) && !LastKeyboardState.IsKeyDown(Keys.OemPlus))
+                        config.CurrentZLevel = Math.Min(config.CurrentZLevel + 1, 20);
+                    if (keyboardState.IsKeyDown(Keys.OemMinus) && !LastKeyboardState.IsKeyDown(Keys.OemMinus))
+                        config.CurrentZLevel--;
+                }
+            }
+
+            LastKeyboardState = keyboardState; 
 
             // camera speed control
             if (mouseState.ScrollWheelValue != PrevMouseState.ScrollWheelValue)
@@ -368,6 +393,7 @@ public void Update(GameTime gameTime)
             //Console.WriteLine("Camera dir: " + GameView.Instance.Render.Camera.Dir);
         }
 
+        private KeyboardState LastKeyboardState;
         public int centerX => GameView.GraphicsDevice.Viewport.Width / 2;
         public int centerY => GameView.GraphicsDevice.Viewport.Height / 2;
 
diff --git a/ACViewer/Render/GfxObjInstance_Shared.cs b/ACViewer/Render/GfxObjInstance_Shared.cs
index da16e5e..175a00e 100644
--- a/ACViewer/Render/GfxObjInstance_Shared.cs
+++ b/ACViewer/Render/GfxObjInstance_Shared.cs
@@ -1,5 +1,6 @@
-using System.Collections.Generic;
-
+using System;
+using System.Collections.Generic;
+using System.Linq;
 using Microsoft.Xna.Framework;
 using Microsoft.Xna.Framework.Graphics;
 
@@ -25,9 +26,8 @@ public class GfxObjInstance_Shared
         public Dictionary<TextureFormatChain, GfxObjInstance_TextureFormat> BaseFormats_Alpha { get; set; }
 
         public List<VertexPositionNormalTextures> Vertices { get; set; }
-
+        
         public List<VertexInstance> Instances { get; set; }
-
         public VertexInstance[] Instances_ { get; set; }
 
         public VertexBuffer Shared_VB { get; set; }
@@ -39,9 +39,7 @@ public class GfxObjInstance_Shared
         public GfxObjInstance_Shared(GfxObj gfxObj, Dictionary<TextureFormat, TextureAtlasChain> textureAtlasChains, Dictionary<uint, uint> textureChanges = null, PaletteChanges paletteChanges = null)
         {
             GfxObj = gfxObj;
-
             BuildStatic(gfxObj, textureAtlasChains, textureChanges, paletteChanges);
-
             Instances = new List<VertexInstance>();
         }
 
@@ -185,6 +183,51 @@ public void Draw()
             foreach (var baseFormat in BaseFormats_Alpha.Values)
                 baseFormat.Draw(Instances.Count);
         }
+        
+        public void DrawFiltered(Func<Vector3, bool> filter)
+        {
+            if (Bindings == null) return;
+
+            if (isDirty)
+            {
+                Instances_VB.SetData(Instances_);
+                isDirty = false;
+            }
+
+            // Store original instances
+            var originalInstances = Instances_.ToArray();
+        
+            // Filter instances
+            var filteredInstances = Instances.Where(instance => filter(instance.Position)).ToArray();
+        
+            if (filteredInstances.Length > 0)
+            {
+                // Update vertex buffer with filtered instances
+                Instances_ = filteredInstances;
+                Instances_VB.SetData(filteredInstances);
+
+                GraphicsDevice.SetVertexBuffers(Bindings);
+
+                Effect.CurrentTechnique = Effect.Techniques["TexturedInstance"];
+                Effect_Clamp.CurrentTechnique = Effect_Clamp.Techniques["TexturedInstance"];
+
+                foreach (var baseFormat in BaseFormats_Solid.Values)
+                    baseFormat.Draw(filteredInstances.Length);
+
+                if (Buffer.drawAlpha)
+                {
+                    Effect.CurrentTechnique = Effect.Techniques["TexturedInstanceAlpha"];
+                    Effect_Clamp.CurrentTechnique = Effect_Clamp.Techniques["TexturedInstanceAlpha"];
+                }
+
+                foreach (var baseFormat in BaseFormats_Alpha.Values)
+                    baseFormat.Draw(filteredInstances.Length);
+            }
+
+            // Restore original instances
+            Instances_ = originalInstances;
+            Instances_VB.SetData(originalInstances);
+        }
 
         public void Dispose()
         {
diff --git a/ACViewer/Render/InstanceBatch.cs b/ACViewer/Render/InstanceBatch.cs
index 10c413b..b7d363c 100644
--- a/ACViewer/Render/InstanceBatch.cs
+++ b/ACViewer/Render/InstanceBatch.cs
@@ -1,7 +1,8 @@
-using System.Collections.Generic;
-
+using System;
+using System.Collections.Generic;
+using System.Linq;
 using ACE.Entity.Enum;
-
+using Microsoft.Xna.Framework;
 using Microsoft.Xna.Framework.Graphics;
 
 namespace ACViewer.Render
@@ -17,6 +18,28 @@ public class InstanceBatch
         public VertexBuffer InstanceBuffer { get; set; }
 
         public R_Environment R_Environment { get; set; }
+        
+        public void DrawFiltered(Func<Vector3, bool> filter)
+        {
+            // Store original instances
+            var originalInstances = new List<VertexInstanceEnv>(Instances_Env);
+
+            // Filter instances based on Z position
+            Instances_Env = Instances_Env.Where(instance => filter(instance.Position)).ToList();
+
+            if (Instances_Env.Count > 0)
+            {
+                // Rebuild instance buffer with filtered instances
+                BuildInstanceBuffer();
+                BuildBindings();
+                Draw();
+            }
+
+            // Restore original instances
+            Instances_Env = originalInstances;
+            BuildInstanceBuffer();
+            BuildBindings();
+        }
 
         public InstanceBatch(R_EnvCell envCell)
         {
diff --git a/ACViewer/Render/Render.cs b/ACViewer/Render/Render.cs
index 110a17a..56d44d2 100644
--- a/ACViewer/Render/Render.cs
+++ b/ACViewer/Render/Render.cs
@@ -25,6 +25,9 @@ public class Render
 
         // multiple SamplerStates in the same .fx file apparently don't work
         public static Effect Effect_Clamp { get; set; }
+        
+        // Add to existing properties
+        private MapViewerOptions Config => ConfigManager.Config.MapViewer;
 
         public Camera Camera
         {
@@ -67,21 +70,23 @@ public void SetRasterizerState(bool wireframe = true)
 
             GraphicsDevice.RasterizerState = rs;
         }
-
+        
         public void Draw()
         {
             GraphicsDevice.Clear(ConfigManager.Config.BackgroundColors.WorldViewer);
 
             SetRasterizerState(false);
-            
+    
             Effect.Parameters["xView"].SetValue(Camera.ViewMatrix);
             Effect_Clamp.Parameters["xView"].SetValue(Camera.ViewMatrix);
 
-            //landblock.Draw();
-            Buffer.Draw();
+            if (ConfigManager.Config.MapViewer.EnableZSlicing)
+                Buffer.DrawWithZSlicing();
+            else
+                Buffer.Draw();
 
-            //DrawEmitters_Naive();
             DrawEmitters_Batch();
+            DrawHUD();
         }
 
         public bool ParticlesInitted { get; set; }
@@ -186,14 +191,29 @@ public void DestroyEmitters()
 
         private static readonly Vector2 TextPos = new Vector2(10, 10);
 
+        // DrawHUD to show Z-slice information
         public void DrawHUD()
         {
-            var cameraPos = GameView.Camera.GetPosition();
+            var text = "";
+    
+            if (ConfigManager.Config.MapViewer.EnableZSlicing)
+            {
+                var config = ConfigManager.Config.MapViewer;
+                string levelPrefix = config.CurrentZLevel < 0 ? "B" : "";  // Add "B" prefix for basement levels
+                int displayLevel = config.CurrentZLevel < 0 ? -config.CurrentZLevel : config.CurrentZLevel;
+        
+                text += $"Current Z-Level: {levelPrefix}{displayLevel}\n";  // Shows B1, B2, etc. for basement levels
+                text += $"Height Range: {(config.CurrentZLevel - 1) * config.LevelHeight:F1}m - {config.CurrentZLevel * config.LevelHeight:F1}m\n";
+            }
 
+            var cameraPos = Camera.GetPosition();
             if (cameraPos != null)
+                text += $"Location: {cameraPos}";
+
+            if (!string.IsNullOrEmpty(text))
             {
                 SpriteBatch.Begin(SpriteSortMode.Deferred, null, SamplerState.LinearClamp);
-                SpriteBatch.DrawString(Font, $"Location: {cameraPos}", TextPos, Color.White);
+                SpriteBatch.DrawString(Font, text, TextPos, Color.White);
                 SpriteBatch.End();
             }
         }
diff --git a/ACViewer/Render/TerrainBatch.cs b/ACViewer/Render/TerrainBatch.cs
index 5615084..7c6b764 100644
--- a/ACViewer/Render/TerrainBatch.cs
+++ b/ACViewer/Render/TerrainBatch.cs
@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
-
+using System.Linq;
+using Microsoft.Xna.Framework;
 using Microsoft.Xna.Framework.Graphics;
 
 namespace ACViewer.Render
@@ -56,6 +57,33 @@ public void Draw()
             foreach (var batch in Batches)
                 batch.Draw();
         }
+        
+        public void DrawWithZFiltering(Func<Vector3, bool> filter)
+        {
+            Effect.CurrentTechnique = Effect.Techniques["LandscapeSinglePass"];
+
+            if (OverlayAtlasChain.TextureAtlases.Count > 0)
+                Effect.Parameters["xOverlays"].SetValue(OverlayAtlasChain.TextureAtlases[0]._Textures);
+            if (AlphaAtlasChain.TextureAtlases.Count > 0)
+                Effect.Parameters["xAlphas"].SetValue(AlphaAtlasChain.TextureAtlases[0]._Textures);
+
+            foreach (var batch in Batches)
+            {
+                if (batch.Vertices.Count == 0) continue;
+
+                var originalVertices = new List<LandVertex>(batch.Vertices);
+                batch.Vertices = batch.Vertices.Where(v => filter(v.Position)).ToList();
+
+                if (batch.Vertices.Count > 0)
+                {
+                    batch.OnCompleted();
+                    batch.Draw();
+                }
+
+                batch.Vertices = originalVertices;
+                batch.OnCompleted();
+            }
+        }
 
         public void Dispose()
         {