From d1621e334a9df13294e5694582769251e8e3294f Mon Sep 17 00:00:00 2001
From: syeyoung <cyoung06@naver.com>
Date: Fri, 27 Jan 2023 15:23:37 +0900
Subject: - Snapping, and new gui config

Signed-off-by: syeyoung <cyoung06@naver.com>
---
 .../mod/config/guiconfig/RootConfigPanel.java      |   5 +-
 .../guiconfig/location/GuiGuiLocationConfig.java   | 128 ++--
 .../mod/config/guiconfig/location/Marker.java      |  90 +--
 .../config/guiconfig/location/PanelDelegate.java   | 808 ++++++++++-----------
 .../guiconfig/location2/HUDConfigRootWidget.java   | 314 ++++++++
 .../guiconfig/location2/HUDLocationConfig.java     |  43 ++
 .../guiconfig/location2/HUDWidgetWrapper.java      | 392 ++++++++++
 .../config/guiconfig/location2/MarkerProvider.java |  27 +
 .../guiconfig/location2/WidgetPopupMenu.java       |  33 +
 .../mod/config/types/GUIPosition.java              | 143 ++++
 .../mod/config/types/GUIRectangle.java             |  81 ---
 .../mod/config/types/TCGUIPosition.java            |  54 ++
 .../mod/config/types/TCGUIRectangle.java           |  50 --
 .../mod/config/types/TypeConverterRegistry.java    |   2 +-
 .../mod/cosmetics/CosmeticsManager.java            |   1 +
 .../mod/features/AbstractHUDFeature.java           |  83 ++-
 .../mod/features/RawRenderingGuiFeature.java       |  75 +-
 .../features/impl/advanced/FeatureDebugTrap.java   |   2 +-
 .../impl/advanced/FeatureDebuggableMap.java        |  23 +-
 .../impl/advanced/FeatureRoomCoordDisplay.java     |   2 +-
 .../impl/advanced/FeatureRoomDebugInfo.java        |   2 +-
 .../mod/features/impl/boss/FeatureBossHealth.java  |   8 +-
 .../features/impl/boss/FeatureCurrentPhase.java    |   2 +-
 .../features/impl/boss/FeatureTerracotaTimer.java  |   2 +-
 .../impl/boss/FeatureThornBearPercentage.java      |   2 +-
 .../impl/boss/FeatureThornSpiritBowTimer.java      |   2 +-
 .../dungeon/FeatureDungeonCurrentRoomSecrets.java  |   2 +-
 .../impl/dungeon/FeatureDungeonDeaths.java         |  10 +-
 .../features/impl/dungeon/FeatureDungeonMap.java   |  23 +-
 .../impl/dungeon/FeatureDungeonMilestone.java      |   6 +-
 .../impl/dungeon/FeatureDungeonRealTime.java       |   2 +-
 .../impl/dungeon/FeatureDungeonRoomName.java       |   2 +-
 .../impl/dungeon/FeatureDungeonSBTime.java         |   2 +-
 .../features/impl/dungeon/FeatureDungeonScore.java |   2 +-
 .../impl/dungeon/FeatureDungeonSecrets.java        |   2 +-
 .../features/impl/dungeon/FeatureDungeonTombs.java |   5 +-
 .../impl/dungeon/FeatureWarnLowHealth.java         |   6 +-
 .../impl/dungeon/FeatureWatcherWarning.java        |   3 +-
 .../features/impl/etc/FeatureCooldownCounter.java  |   7 +-
 .../impl/etc/ability/FeatureAbilityCooldown.java   |   7 +-
 .../mod/features/impl/party/FeaturePartyList.java  |   7 +-
 .../mod/features/impl/party/FeaturePartyReady.java |   7 +-
 .../mod/features/impl/secret/FeatureActions.java   |   7 +-
 .../impl/secret/FeatureSoulRoomWarning.java        |   2 +-
 .../mechanicbrowser/FeatureMechanicBrowse.java     |  14 +-
 .../mod/features/text/TextHUDFeature.java          | 111 ++-
 .../dungeonsguide/mod/guiv2/DomElement.java        |  13 +-
 .../dungeonsguide/mod/guiv2/GuiScreenAdapter.java  |   2 +-
 .../mod/guiv2/elements/GlobalHUDScale.java         | 124 ++++
 .../mod/guiv2/elements/RoundRect.java              |   2 +-
 .../mod/overlay/GUIRectPositioner.java             |  40 +
 .../mod/overlay/GUIRectanglePositioner.java        |  63 --
 .../dungeonsguide/mod/overlay/OverlayManager.java  |  15 +-
 .../assets/dungeonsguide/gui/config/hudconfig.gui  |  28 +
 .../assets/dungeonsguide/gui/config/popupmenu.gui  |  49 ++
 55 files changed, 2049 insertions(+), 888 deletions(-)
 create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location2/HUDConfigRootWidget.java
 create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location2/HUDLocationConfig.java
 create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location2/HUDWidgetWrapper.java
 create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location2/MarkerProvider.java
 create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location2/WidgetPopupMenu.java
 create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/types/GUIPosition.java
 delete mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/types/GUIRectangle.java
 create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/types/TCGUIPosition.java
 delete mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/types/TCGUIRectangle.java
 create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/GlobalHUDScale.java
 create mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/overlay/GUIRectPositioner.java
 delete mode 100644 mod/src/main/java/kr/syeyoung/dungeonsguide/mod/overlay/GUIRectanglePositioner.java
 create mode 100644 mod/src/main/resources/assets/dungeonsguide/gui/config/hudconfig.gui
 create mode 100644 mod/src/main/resources/assets/dungeonsguide/gui/config/popupmenu.gui

(limited to 'mod/src')

diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/RootConfigPanel.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/RootConfigPanel.java
index 0bc16fbb..ebe09875 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/RootConfigPanel.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/RootConfigPanel.java
@@ -21,10 +21,13 @@ package kr.syeyoung.dungeonsguide.mod.config.guiconfig;
 import com.google.common.base.Function;
 import kr.syeyoung.dungeonsguide.launcher.auth.AuthManager;
 import kr.syeyoung.dungeonsguide.mod.config.guiconfig.location.GuiGuiLocationConfig;
+import kr.syeyoung.dungeonsguide.mod.config.guiconfig.location2.HUDLocationConfig;
 import kr.syeyoung.dungeonsguide.mod.features.AbstractFeature;
 import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
 import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
 import kr.syeyoung.dungeonsguide.mod.gui.elements.*;
+import kr.syeyoung.dungeonsguide.mod.guiv2.GuiScreenAdapter;
+import kr.syeyoung.dungeonsguide.mod.guiv2.elements.GlobalHUDScale;
 import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
 import lombok.Getter;
 import lombok.Setter;
@@ -99,7 +102,7 @@ public class RootConfigPanel extends MPanelScaledGUI {
         guiRelocate = new MButton();
         guiRelocate.setText("Edit Gui Locations");
         guiRelocate.setOnActionPerformed(() -> {
-            Minecraft.getMinecraft().displayGuiScreen(new GuiGuiLocationConfig(gui, null));
+            Minecraft.getMinecraft().displayGuiScreen(new GuiScreenAdapter(new GlobalHUDScale(new HUDLocationConfig())));
             guiRelocate.setBeingClicked(false);
         });
         guiRelocate.setBorder(RenderUtils.blendTwoColors(0xFF141414,0x7702EE67));
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location/GuiGuiLocationConfig.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location/GuiGuiLocationConfig.java
index 365a1182..d88991be 100755
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location/GuiGuiLocationConfig.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location/GuiGuiLocationConfig.java
@@ -42,24 +42,24 @@ public class GuiGuiLocationConfig extends MGui {
     @Getter
     private final GuiScreen before;
 
-    @Getter
-    private TreeMap<Integer, List<Marker>> markerTreeMapByX = new TreeMap<>();
-    @Getter
-    private TreeMap<Integer, List<Marker>> markerTreeMapByY = new TreeMap<>();
-    @Getter
-    private Set<Marker> markerSet = new HashSet<>();
-
-
-    Marker[] markers = new Marker[4];
+//    @Getter
+//    private TreeMap<Integer, List<Marker>> markerTreeMapByX = new TreeMap<>();
+//    @Getter
+//    private TreeMap<Integer, List<Marker>> markerTreeMapByY = new TreeMap<>();
+//    @Getter
+//    private Set<Marker> markerSet = new HashSet<>();
+//
+//
+//    Marker[] markers = new Marker[4];
 
 
     public GuiGuiLocationConfig(final GuiScreen before, AbstractFeature featureWhitelist) {
         this.before = before;
-        for (AbstractFeature feature : FeatureRegistry.getFeatureList()) {
-            if (feature instanceof AbstractHUDFeature && feature.isEnabled()) {
-                getMainPanel().add(new PanelDelegate((AbstractHUDFeature) feature, featureWhitelist == null || feature == featureWhitelist, this));
-            }
-        }
+//        for (AbstractFeature feature : FeatureRegistry.getFeatureList()) {
+//            if (feature instanceof AbstractHUDFeature && feature.isEnabled()) {
+//                getMainPanel().add(new PanelDelegate((AbstractHUDFeature) feature, featureWhitelist == null || feature == featureWhitelist, this));
+//            }
+//        }
 
         getMainPanel().setBackgroundColor(new Color(0,0,0, 100));
     }
@@ -71,49 +71,49 @@ public class GuiGuiLocationConfig extends MGui {
             new Vec3(1, 0.5, 4),
     };
 
-    public void removeAndAddMarker(Marker prev, Marker newM) {
-        if (prev != null) {
-            markerTreeMapByX.computeIfPresent(prev.getX(),(k,v) -> {
-                v.remove(prev);
-                if (v.isEmpty()) return null;
-                else return v;
-            });
-            markerTreeMapByY.computeIfPresent(prev.getY(),(k,v) -> {
-                v.remove(prev);
-                if (v.isEmpty()) return null;
-                else return v;
-            });
-            markerSet.remove(prev);
-        }
-        if (newM != null) {
-            markerTreeMapByX.compute(newM.getX(), (k,v) -> {
-                if (v == null) {
-                    return new ArrayList<>(Arrays.asList(newM));
-                } else {
-                    v.add(newM);
-                    return v;
-                }
-            });
-            markerTreeMapByY.compute(newM.getY(), (k,v) -> {
-                if (v == null) {
-                    return new ArrayList<>(Arrays.asList(newM));
-                } else {
-                    v.add(newM);
-                    return v;
-                }
-            });
-            markerSet.add(newM);
-        }
-    }
+//    public void removeAndAddMarker(Marker prev, Marker newM) {
+//        if (prev != null) {
+//            markerTreeMapByX.computeIfPresent(prev.getX(),(k,v) -> {
+//                v.remove(prev);
+//                if (v.isEmpty()) return null;
+//                else return v;
+//            });
+//            markerTreeMapByY.computeIfPresent(prev.getY(),(k,v) -> {
+//                v.remove(prev);
+//                if (v.isEmpty()) return null;
+//                else return v;
+//            });
+//            markerSet.remove(prev);
+//        }
+//        if (newM != null) {
+//            markerTreeMapByX.compute(newM.getX(), (k,v) -> {
+//                if (v == null) {
+//                    return new ArrayList<>(Arrays.asList(newM));
+//                } else {
+//                    v.add(newM);
+//                    return v;
+//                }
+//            });
+//            markerTreeMapByY.compute(newM.getY(), (k,v) -> {
+//                if (v == null) {
+//                    return new ArrayList<>(Arrays.asList(newM));
+//                } else {
+//                    v.add(newM);
+//                    return v;
+//                }
+//            });
+//            markerSet.add(newM);
+//        }
+//    }
 
     public void setupMarkers() {
-        for (int i1 = 0; i1 < markers.length; i1++) {
-            Marker orig = markers[i1];
-            Vec3 pt = facing[i1];
-            markers[i1] = new Marker((int) (pt.xCoord  * getMainPanel().getBounds().width), (int) (pt.yCoord  * getMainPanel().getBounds().height), (int) pt.zCoord, this);
-
-            removeAndAddMarker(orig, markers[i1]);
-        }
+//        for (int i1 = 0; i1 < markers.length; i1++) {
+//            Marker orig = markers[i1];
+//            Vec3 pt = facing[i1];
+//            markers[i1] = new Marker((int) (pt.xCoord  * getMainPanel().getBounds().width), (int) (pt.yCoord  * getMainPanel().getBounds().height), (int) pt.zCoord, this);
+//
+//            removeAndAddMarker(orig, markers[i1]);
+//        }
     }
 
     @Override
@@ -151,15 +151,15 @@ public class GuiGuiLocationConfig extends MGui {
     public void initGui() {
         super.initGui();
         getMainPanel().setBounds(new Rectangle(0,0,Minecraft.getMinecraft().displayWidth,Minecraft.getMinecraft().displayHeight));
-        markerTreeMapByX.clear();
-        markerTreeMapByY.clear();
-        markerSet.clear();
-        setupMarkers();
-        for (MPanel childComponent : getMainPanel().getChildComponents()) {
-            if (childComponent instanceof PanelDelegate) {
-                ((PanelDelegate) childComponent).rebuildMarker();
-            }
-        }
+//        markerTreeMapByX.clear();
+//        markerTreeMapByY.clear();
+//        markerSet.clear();
+//        setupMarkers();
+//        for (MPanel childComponent : getMainPanel().getChildComponents()) {
+//            if (childComponent instanceof PanelDelegate) {
+//                ((PanelDelegate) childComponent).rebuildMarker();
+//            }
+//        }
 
     }
 
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location/Marker.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location/Marker.java
index 10683425..b622e3b6 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location/Marker.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location/Marker.java
@@ -1,45 +1,45 @@
-/*
- * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
- * Copyright (C) 2021  cyoung06
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-package kr.syeyoung.dungeonsguide.mod.config.guiconfig.location;
-
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.ToString;
-
-@Getter
-@ToString
-@AllArgsConstructor
-public class Marker {
-    private final int x;
-    private final int y;
-    /**
-     * 0xABCDEFGH
-     * A: ?
-     * B: ?
-     * C: ?
-     * D: ?
-     * EF: 0~3 (TC 0x00 CL 0x01 BC 0x10 CR 0x11)
-     */
-    private final int type;
-    private final Object parent;
-
-    public int distanceSQ(Marker m2) {
-        return (m2.x - x)*(m2.x - x) + (m2.y - y)*(m2.y - y);
-    }
-}
+///*
+// * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+// * Copyright (C) 2021  cyoung06
+// *
+// * This program is free software: you can redistribute it and/or modify
+// * it under the terms of the GNU Affero General Public License as published
+// * by the Free Software Foundation, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * This program is distributed in the hope that it will be useful,
+// * but WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// * GNU Affero General Public License for more details.
+// *
+// * You should have received a copy of the GNU Affero General Public License
+// * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+// */
+//
+//package kr.syeyoung.dungeonsguide.mod.config.guiconfig.location;
+//
+//import lombok.AllArgsConstructor;
+//import lombok.Getter;
+//import lombok.ToString;
+//
+//@Getter
+//@ToString
+//@AllArgsConstructor
+//public class Marker {
+//    private final int x;
+//    private final int y;
+//    /**
+//     * 0xABCDEFGH
+//     * A: ?
+//     * B: ?
+//     * C: ?
+//     * D: ?
+//     * EF: 0~3 (TC 0x00 CL 0x01 BC 0x10 CR 0x11)
+//     */
+//    private final int type;
+//    private final Object parent;
+//
+//    public int distanceSQ(Marker m2) {
+//        return (m2.x - x)*(m2.x - x) + (m2.y - y)*(m2.y - y);
+//    }
+//}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location/PanelDelegate.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location/PanelDelegate.java
index 3bcae70b..b12e59c6 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location/PanelDelegate.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location/PanelDelegate.java
@@ -1,404 +1,404 @@
-/*
- * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
- * Copyright (C) 2021  cyoung06
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-package kr.syeyoung.dungeonsguide.mod.config.guiconfig.location;
-
-
-import kr.syeyoung.dungeonsguide.mod.config.types.GUIRectangle;
-import kr.syeyoung.dungeonsguide.mod.features.AbstractHUDFeature;
-import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
-import kr.syeyoung.dungeonsguide.mod.gui.elements.MPopupMenu;
-import kr.syeyoung.dungeonsguide.mod.gui.elements.MTooltip;
-import kr.syeyoung.dungeonsguide.mod.utils.cursor.EnumCursor;
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.gui.Gui;
-import net.minecraft.client.renderer.GlStateManager;
-import net.minecraft.client.renderer.Tessellator;
-import net.minecraft.client.renderer.WorldRenderer;
-import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
-import net.minecraft.util.EnumFacing;
-import net.minecraft.util.Tuple;
-import net.minecraft.util.Vec3;
-import org.lwjgl.opengl.GL11;
-
-import java.awt.*;
-import java.util.List;
-import java.util.*;
-
-public class PanelDelegate extends MPanel {
-    private final AbstractHUDFeature guiFeature;
-    private boolean draggable = false;
-    private GuiGuiLocationConfig guiGuiLocationConfig;
-
-    private Set<Marker> markerSet = new HashSet<>();
-    public PanelDelegate(AbstractHUDFeature guiFeature, boolean draggable, GuiGuiLocationConfig guiGuiLocationConfig) {
-        this.guiFeature = guiFeature;
-        this.draggable = draggable;
-        this.guiGuiLocationConfig = guiGuiLocationConfig;
-    }
-
-    public void rebuildMarker() {
-        internallyThinking = guiFeature.getFeatureRect().getRectangleNoScale();
-        applyConstraint();
-    }
-
-    @Override
-    public Rectangle getBounds() {
-        Rectangle rectangle = guiFeature.getFeatureRect().getRectangle();
-        return new Rectangle(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
-    }
-
-    @Override
-    public void render(int absMousex, int absMousey, int relMouseX, int relMouseY, float partialTicks, Rectangle scissor) {
-        if (!guiFeature.isEnabled()) return;
-
-        GlStateManager.pushMatrix();
-        guiFeature.drawDemo(partialTicks);
-        GlStateManager.popMatrix();
-        if (!draggable) return;
-        Gui.drawRect(0,0, 4, 4, 0xFFBBBBBB);
-        Gui.drawRect(0, getBounds().height - 4, 4, getBounds().height, 0xFFBBBBBB);
-        Gui.drawRect(getBounds().width - 4,0, getBounds().width, 4, 0xFFBBBBBB);
-        Gui.drawRect(getBounds().width - 4,getBounds().height - 4, getBounds().width, getBounds().height, 0xFFBBBBBB);
-        if (lastAbsClip.contains(absMousex, absMousey)) {
-            if (relMouseX < 4 && relMouseY < 4) {
-                Gui.drawRect(0,0, 4, 4, 0x55FFFFFF);
-            } else if (relMouseX < 4 && relMouseY > getBounds().height - 4) {
-                Gui.drawRect(0, getBounds().height - 4, 4, getBounds().height, 0x55FFFFFF);
-            } else if (relMouseX > getBounds().width - 4 && relMouseY > getBounds().height - 4) {
-                Gui.drawRect(getBounds().width - 4,getBounds().height - 4, getBounds().width, getBounds().height, 0x55FFFFFF);
-            } else if (relMouseX > getBounds().width - 4 && relMouseY < 4) {
-                Gui.drawRect(getBounds().width - 4,0, getBounds().width, 4, 0x55FFFFFF);
-            } else if (selectedPart == -2){
-                Gui.drawRect(0,0, getBounds().width, getBounds().height, 0x55FFFFFF);
-            }
-        }
-        GlStateManager.enableBlend();
-    }
-
-    @Override
-    public void render0(double scale, Point parentPoint, Rectangle parentClip, int absMousex, int absMousey, int relMousex0, int relMousey0, float partialTicks) {
-        GlStateManager.pushMatrix();
-        super.render0(scale, parentPoint, parentClip, absMousex, absMousey, relMousex0, relMousey0, partialTicks);
-        GlStateManager.popMatrix();
-
-        if (snapped != null && selectedPart != -2) {
-            Tessellator tessellator = Tessellator.getInstance();
-            GlStateManager.disableTexture2D();
-            WorldRenderer worldRenderer = tessellator.getWorldRenderer();
-            worldRenderer.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR);
-            GL11.glLineWidth(1);
-            for (Tuple<Marker[], EnumFacing.Axis> markerAxisTuple : snapped) {
-                if (markerAxisTuple.getSecond() == EnumFacing.Axis.X) {
-                    worldRenderer.pos(markerAxisTuple.getFirst()[0].getX(), 0, 0).color(0,255,0,255).endVertex();
-                    worldRenderer.pos(markerAxisTuple.getFirst()[0].getX(), Minecraft.getMinecraft().displayHeight, 0).color(0,255,0,255).endVertex();
-                } else {
-                    worldRenderer.pos(0, markerAxisTuple.getFirst()[0].getY(), 0).color(0,255,0,255).endVertex();
-                    worldRenderer.pos(Minecraft.getMinecraft().displayWidth, markerAxisTuple.getFirst()[0].getY(), 0).color(0,255,0,255).endVertex();
-                }
-            }
-            tessellator.draw();
-            for (Marker marker : guiGuiLocationConfig.getMarkerSet()) {
-                Gui.drawRect(marker.getX(),marker.getY(), marker.getX()+1, marker.getY()+1, 0xFFFF0000);
-            }
-        }
-    }
-
-    private int selectedPart = -2;
-
-    private int lastX = 0;
-    private int lastY = 0;
-
-    private Rectangle internallyThinking;
-    private Rectangle constraintApplied;
-
-    private Set<Tuple<Marker[], EnumFacing.Axis>> snapped = new HashSet<>();
-
-    public void applyConstraint() {
-        constraintApplied = internallyThinking.getBounds();
-
-        // SNAP Moving Point.
-        snapped.clear();
-        int scailingThreshold = 5;
-        if (selectedPart == 0){
-            Point snapPt = new Point(constraintApplied.x +constraintApplied.width, constraintApplied.y + constraintApplied.height);
-            Optional<Marker> snapX, snapY;
-            SortedMap<Integer, List<Marker>> markerSortedMap = guiGuiLocationConfig.getMarkerTreeMapByX().subMap(snapPt.x-scailingThreshold, snapPt.x +scailingThreshold);
-            snapX = markerSortedMap.values().stream()
-                    .filter(Objects::nonNull)
-                    .flatMap(Collection::stream)
-                    .filter(a -> a.getParent() != this)
-                    .min(Comparator.comparingInt(a -> (int) snapPt.distanceSq(a.getX(), a.getY())));
-            markerSortedMap = guiGuiLocationConfig.getMarkerTreeMapByY().subMap(snapPt.y-scailingThreshold, snapPt.y +scailingThreshold);
-            snapY = markerSortedMap.values().stream()
-                    .filter(Objects::nonNull)
-                    .flatMap(Collection::stream)
-                    .filter(a -> a.getParent() != this)
-                    .min(Comparator.comparingInt(a -> (int) snapPt.distanceSq(a.getX(), a.getY())));
-            snapX.ifPresent(a -> {
-                snapPt.x = a.getX();
-            });
-            snapY.ifPresent(a -> {
-                snapPt.y = a.getY();
-            });
-
-            constraintApplied = new Rectangle(constraintApplied.x, constraintApplied.y, snapPt.x - constraintApplied.x, snapPt.y - constraintApplied.y);
-
-
-
-            int minWidth;
-            int minHeight;
-            if (guiFeature.isKeepRatio()) {
-                if (guiFeature.getDefaultRatio() >= 1) {
-                    minHeight = constraintApplied.height < 0 ? -8 : 8;
-                    minWidth = (int) (guiFeature.getDefaultRatio() * minHeight);
-                } else {
-                    minWidth = constraintApplied.width < 0 ? -8 : 8;
-                    minHeight = (int) (minWidth / guiFeature.getDefaultRatio());
-                }
-            } else {
-                minWidth = constraintApplied.width < 0 ? -8 : 8;
-                minHeight = constraintApplied.height < 0 ? -8 : 8;
-            }
-
-
-            constraintApplied.width = Math.abs(constraintApplied.width) > Math.abs(minWidth) ? constraintApplied.width :
-                    Math.abs(internallyThinking.width) > Math.abs(minWidth) ? internallyThinking.width : minWidth;
-            constraintApplied.height = Math.abs(constraintApplied.height) > Math.abs(minHeight) ? constraintApplied.height :
-                    Math.abs(internallyThinking.height) > Math.abs(minHeight) ? internallyThinking.height : minHeight;
-
-            if (guiFeature.isKeepRatio()) {
-                double ratio = guiFeature.getDefaultRatio();
-
-                int heightWhenWidthFix = (int) Math.abs(constraintApplied.width / ratio);
-                int widthWhenHeightFix = (int) Math.abs(ratio * constraintApplied.height);
-                if (Math.abs(heightWhenWidthFix) <= Math.abs(constraintApplied.height)) {
-                    constraintApplied.height = constraintApplied.height < 0 ? -heightWhenWidthFix : heightWhenWidthFix;
-                } else if (Math.abs(widthWhenHeightFix) <= Math.abs(constraintApplied.width)) {
-                    constraintApplied.width =constraintApplied.width < 0 ? - widthWhenHeightFix : widthWhenHeightFix;
-                }
-            }
-
-
-            snapX.ifPresent(a -> {
-                if (snapPt.x - constraintApplied.x == constraintApplied.width) {
-                    Marker m = new Marker((int) (GuiGuiLocationConfig.facing[3].xCoord * constraintApplied.width) + constraintApplied.x, (int) (GuiGuiLocationConfig.facing[3].yCoord * constraintApplied.height) + constraintApplied.y, (int) GuiGuiLocationConfig.facing[3].zCoord, this);
-                    snapped.add(new Tuple<>(new Marker[]{a, m}, EnumFacing.Axis.X));
-                }
-            });
-            snapY.ifPresent(a -> {
-                if (snapPt.y - constraintApplied.y == constraintApplied.height) {
-                    Marker m = new Marker((int) (GuiGuiLocationConfig.facing[2].xCoord * constraintApplied.width) + constraintApplied.x, (int) (GuiGuiLocationConfig.facing[2].yCoord * constraintApplied.height) + constraintApplied.y, (int) GuiGuiLocationConfig.facing[2].zCoord, this);
-                    snapped.add(new Tuple<>(new Marker[]{a, m}, EnumFacing.Axis.Y));
-                }
-            });
-
-            if (constraintApplied.height < 0) {
-                constraintApplied.height = -constraintApplied.height;
-                constraintApplied.y -= constraintApplied.height;
-            }
-
-            if (constraintApplied.width < 0) {
-                constraintApplied.width = -constraintApplied.width;
-                constraintApplied.x -= constraintApplied.width;
-            }
-        } else if (selectedPart == -1) {
-            for (int i : Arrays.asList(0,3,1,2)) {
-                Vec3 pt = GuiGuiLocationConfig.facing[i];
-                Marker m = new Marker((int) (pt.xCoord * constraintApplied.width) + constraintApplied.x, (int) (pt.yCoord * constraintApplied.height) + constraintApplied.y, (int) pt.zCoord, this);
-                    Optional<Marker> result = guiGuiLocationConfig.getMarkerTreeMapByX().subMap(m.getX()-scailingThreshold, m.getX() +scailingThreshold).values().stream()
-                            .filter(Objects::nonNull)
-                            .flatMap(Collection::stream)
-                            .filter(a -> a.getParent() != this)
-                            .filter(a -> Math.abs(a.getX() - m.getX()) < scailingThreshold)
-                            .filter(a -> ((a.getX() - pt.xCoord * constraintApplied.width) >= 0
-                                && (a.getX() - pt.xCoord * constraintApplied.width + constraintApplied.width) <= Minecraft.getMinecraft().displayWidth))
-                            .min(Comparator.comparingInt(a -> a.distanceSQ(m)));
-                    if (result.isPresent()) {
-                        int x = result.get().getX();
-                        constraintApplied.x = (int) (x - pt.xCoord * constraintApplied.width);
-
-                        snapped.add(new Tuple<>(new Marker[] {result.get(), m}, EnumFacing.Axis.X));
-                        break;
-                    }
-            }
-            for (int i : Arrays.asList(1,2,0,3)) {
-                Vec3 pt = GuiGuiLocationConfig.facing[i];
-                Marker m = new Marker((int) (pt.xCoord * constraintApplied.width) + constraintApplied.x, (int) (pt.yCoord * constraintApplied.height) + constraintApplied.y, (int) pt.zCoord, this);
-                    Optional<Marker> result = guiGuiLocationConfig.getMarkerTreeMapByY().subMap(m.getY()-scailingThreshold, m.getY() +scailingThreshold).values().stream()
-                            .filter(Objects::nonNull)
-                            .flatMap(Collection::stream)
-                            .filter(a -> a.getParent() != this)
-                            .filter(a -> Math.abs(a.getY() - m.getY()) < scailingThreshold)
-                            .filter(a -> ((a.getY() - pt.yCoord * constraintApplied.height) >= 0
-                                    && (a.getY() - pt.yCoord * constraintApplied.height+ constraintApplied.height) <= Minecraft.getMinecraft().displayHeight))
-                            .min(Comparator.comparingInt(a -> a.distanceSQ(m)));
-                    if (result.isPresent()) {
-                        int y = result.get().getY();
-                        constraintApplied.y = (int) (y - pt.yCoord * constraintApplied.height);
-                        snapped.add(new Tuple<>(new Marker[] {result.get(), m}, EnumFacing.Axis.Y));
-                        break;
-                    }
-            }
-        }
-
-        if (constraintApplied.x < 0) constraintApplied.x = 0;
-        if (constraintApplied.y < 0) constraintApplied.y = 0;
-        if (constraintApplied.x + constraintApplied.width + 1 >=Minecraft.getMinecraft().displayWidth) constraintApplied.x = Minecraft.getMinecraft().displayWidth - constraintApplied.width - 1;
-        if (constraintApplied.y + constraintApplied.height  + 1>= Minecraft.getMinecraft().displayHeight) constraintApplied.y = Minecraft.getMinecraft().displayHeight - constraintApplied.height - 1;
-
-
-        setupMarkers();
-    }
-
-    Marker[] markers = new Marker[4];
-    public void setupMarkers() {
-        for (int i1 = 0; i1 < markers.length; i1++) {
-            Marker orig = markers[i1];
-
-            Vec3 pt = GuiGuiLocationConfig.facing[i1];
-            markers[i1] = new Marker((int) (pt.xCoord * constraintApplied.width) + constraintApplied.x, (int) (pt.yCoord * constraintApplied.height) + constraintApplied.y, (int) pt.zCoord, this);
-
-            guiGuiLocationConfig.removeAndAddMarker(orig, markers[i1]);
-        }
-    }
-
-    MTooltip mTooltip;
-
-    @Override
-    public void mouseClicked(int absMouseX, int absMouseY, int relMouseX, int relMouseY, int mouseButton) {
-        if (!draggable) return;
-        if (!guiFeature.isEnabled()) return;
-        if (getTooltipsOpen() > 0) return;
-        if (!lastAbsClip.contains(absMouseX, absMouseY)) return;
-        if (mouseButton == 0) {
-            internallyThinking = guiFeature.getFeatureRect().getRectangleNoScale();
-            if (relMouseX < 4 && relMouseY < 4) { // TL
-                selectedPart = 0;
-                internallyThinking.y += internallyThinking.height;
-                internallyThinking.height = -internallyThinking.height;
-                internallyThinking.x += internallyThinking.width;
-                internallyThinking.width = -internallyThinking.width;
-            } else if (relMouseX < 4 && relMouseY > getBounds().height - 4) { // BL
-                selectedPart = 0;
-                internallyThinking.x += internallyThinking.width;
-                internallyThinking.width = -internallyThinking.width;
-            } else if (relMouseX > getBounds().width - 4 && relMouseY > getBounds().height - 4) { // BR
-                selectedPart = 0;
-            } else if (relMouseX > getBounds().width - 4 && relMouseY < 4) { // TR
-                selectedPart = 0;
-                internallyThinking.y += internallyThinking.height;
-                internallyThinking.height = -internallyThinking.height;
-            } else {
-                selectedPart = -1;
-            }
-            lastX = absMouseX;
-            lastY = absMouseY;
-            applyConstraint();
-
-        } else if (getTooltipsOpen() == 0){
-            if (mTooltip != null) mTooltip.close();
-            mTooltip = new MPopupMenu(absMouseX, absMouseY, guiFeature.getTooltipForEditor(guiGuiLocationConfig));
-            mTooltip.setScale(2.0f);
-            mTooltip.open(this);
-        }
-        throw new IllegalArgumentException("bruh, a hack to stop event progress");
-    }
-
-    @Override
-    public void mouseReleased(int absMouseX, int absMouseY, int relMouseX, int relMouseY, int state) {
-        if (!draggable) return;
-        if (!guiFeature.isEnabled()) return;
-        if (selectedPart >= -1) {
-            guiFeature.setFeatureRect(new GUIRectangle(constraintApplied));
-        }
-
-        selectedPart = -2;
-    }
-
-    @Override
-    public void mouseClickMove(int absMouseX, int absMouseY, int relMouseX, int relMouseY, int clickedMouseButton, long timeSinceLastClick) {
-        if (!draggable) return;
-        if (!guiFeature.isEnabled()) return;
-        int dx = (absMouseX - lastX);
-        int dy = (absMouseY - lastY);
-        if (selectedPart >= 0) {
-            Rectangle rectangle = internallyThinking;
-
-            int prevWidth = rectangle.width;
-            int prevHeight= rectangle.height;
-
-            rectangle.width = prevWidth + dx;
-            rectangle.height = prevHeight + dy;
-
-            if (rectangle.height * prevHeight <= 0 && prevHeight != rectangle.height) {
-                rectangle.height += prevHeight < 0 ? 4 : -4;
-            }
-            if (rectangle.width * prevWidth <= 0 && prevWidth != rectangle.width) {
-                rectangle.width += prevWidth < 0 ? 4 : -4;
-            }
-
-
-            applyConstraint();
-            guiFeature.setFeatureRect(new GUIRectangle(constraintApplied));
-            lastX = absMouseX;
-            lastY = absMouseY;
-            throw new IllegalArgumentException("bruh, a hack to stop event progress");
-        } else if (selectedPart == -1){
-            Rectangle rectangle = internallyThinking;
-            rectangle.translate(dx, dy);
-            applyConstraint();
-            guiFeature.setFeatureRect(new GUIRectangle(constraintApplied));
-            lastX = absMouseX;
-            lastY = absMouseY;
-        }
-    }
-
-    @Override
-    public void mouseMoved(int absMouseX, int absMouseY, int relMouseX, int relMouseY) {
-        if (!draggable) return;
-        if (!guiFeature.isEnabled()) return;
-        if (getTooltipsOpen() > 0) return;
-
-        if (selectedPart == -1) {
-            setCursor(EnumCursor.CLOSED_HAND);
-        } else if (selectedPart >= 0) {
-            if (internallyThinking.width < 0 && internallyThinking.height < 0) {
-                setCursor(EnumCursor.RESIZE_TLDR);
-            } else if (internallyThinking.width < 0 && internallyThinking.height >= 0) {
-                setCursor(EnumCursor.RESIZE_TRDL);
-            } else if (internallyThinking.width >= 0 && internallyThinking.height >= 0) {
-                setCursor(EnumCursor.RESIZE_TLDR);
-            } else if (internallyThinking.width >= 0 && internallyThinking.height < 0) {
-                setCursor(EnumCursor.RESIZE_TRDL);
-            }
-        } else if (lastAbsClip.contains(absMouseX, absMouseY)) {
-            if (relMouseX < 4 && relMouseY < 4) {
-                setCursor(EnumCursor.RESIZE_TLDR);
-            } else if (relMouseX < 4 && relMouseY > getBounds().height - 4) {
-                setCursor(EnumCursor.RESIZE_TRDL);
-            } else if (relMouseX > getBounds().width - 4 && relMouseY > getBounds().height - 4) {
-                setCursor(EnumCursor.RESIZE_TLDR);
-            } else if (relMouseX > getBounds().width - 4 && relMouseY < 4) {
-                setCursor(EnumCursor.RESIZE_TRDL);
-            } else {
-                setCursor(EnumCursor.OPEN_HAND);
-            }
-        }
-    }
-}
+///*
+// * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+// * Copyright (C) 2021  cyoung06
+// *
+// * This program is free software: you can redistribute it and/or modify
+// * it under the terms of the GNU Affero General Public License as published
+// * by the Free Software Foundation, either version 3 of the License, or
+// * (at your option) any later version.
+// *
+// * This program is distributed in the hope that it will be useful,
+// * but WITHOUT ANY WARRANTY; without even the implied warranty of
+// * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// * GNU Affero General Public License for more details.
+// *
+// * You should have received a copy of the GNU Affero General Public License
+// * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+// */
+//
+//package kr.syeyoung.dungeonsguide.mod.config.guiconfig.location;
+//
+//
+//import kr.syeyoung.dungeonsguide.mod.features.AbstractHUDFeature;
+//import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
+//import kr.syeyoung.dungeonsguide.mod.gui.elements.MPopupMenu;
+//import kr.syeyoung.dungeonsguide.mod.gui.elements.MTooltip;
+//import kr.syeyoung.dungeonsguide.mod.utils.cursor.EnumCursor;
+//import net.minecraft.client.Minecraft;
+//import net.minecraft.client.gui.Gui;
+//import net.minecraft.client.renderer.GlStateManager;
+//import net.minecraft.client.renderer.Tessellator;
+//import net.minecraft.client.renderer.WorldRenderer;
+//import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
+//import net.minecraft.util.EnumFacing;
+//import net.minecraft.util.Tuple;
+//import net.minecraft.util.Vec3;
+//import org.lwjgl.opengl.GL11;
+//
+//import java.awt.*;
+//import java.util.List;
+//import java.util.*;
+//
+//public class PanelDelegate extends MPanel {
+//    private final AbstractHUDFeature guiFeature;
+//    private boolean draggable = false;
+//    private GuiGuiLocationConfig guiGuiLocationConfig;
+//
+//    private Set<Marker> markerSet = new HashSet<>();
+//    public PanelDelegate(AbstractHUDFeature guiFeature, boolean draggable, GuiGuiLocationConfig guiGuiLocationConfig) {
+//        this.guiFeature = guiFeature;
+//        this.draggable = draggable;
+//        this.guiGuiLocationConfig = guiGuiLocationConfig;
+//    }
+//
+//    public void rebuildMarker() {
+////        internallyThinking = guiFeature.getFeatureRect().getRectangleNoScale();
+//        applyConstraint();
+//    }
+//
+//    @Override
+//    public Rectangle getBounds() {
+////        Rectangle rectangle = guiFeature.getFeatureRect().getRectangle();
+////        return new Rectangle(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
+//        return null;
+//    }
+//
+//    @Override
+//    public void render(int absMousex, int absMousey, int relMouseX, int relMouseY, float partialTicks, Rectangle scissor) {
+//        if (!guiFeature.isEnabled()) return;
+//
+//        GlStateManager.pushMatrix();
+//        guiFeature.drawDemo(partialTicks);
+//        GlStateManager.popMatrix();
+//        if (!draggable) return;
+//        Gui.drawRect(0,0, 4, 4, 0xFFBBBBBB);
+//        Gui.drawRect(0, getBounds().height - 4, 4, getBounds().height, 0xFFBBBBBB);
+//        Gui.drawRect(getBounds().width - 4,0, getBounds().width, 4, 0xFFBBBBBB);
+//        Gui.drawRect(getBounds().width - 4,getBounds().height - 4, getBounds().width, getBounds().height, 0xFFBBBBBB);
+//        if (lastAbsClip.contains(absMousex, absMousey)) {
+//            if (relMouseX < 4 && relMouseY < 4) {
+//                Gui.drawRect(0,0, 4, 4, 0x55FFFFFF);
+//            } else if (relMouseX < 4 && relMouseY > getBounds().height - 4) {
+//                Gui.drawRect(0, getBounds().height - 4, 4, getBounds().height, 0x55FFFFFF);
+//            } else if (relMouseX > getBounds().width - 4 && relMouseY > getBounds().height - 4) {
+//                Gui.drawRect(getBounds().width - 4,getBounds().height - 4, getBounds().width, getBounds().height, 0x55FFFFFF);
+//            } else if (relMouseX > getBounds().width - 4 && relMouseY < 4) {
+//                Gui.drawRect(getBounds().width - 4,0, getBounds().width, 4, 0x55FFFFFF);
+//            } else if (selectedPart == -2){
+//                Gui.drawRect(0,0, getBounds().width, getBounds().height, 0x55FFFFFF);
+//            }
+//        }
+//        GlStateManager.enableBlend();
+//    }
+//
+//    @Override
+//    public void render0(double scale, Point parentPoint, Rectangle parentClip, int absMousex, int absMousey, int relMousex0, int relMousey0, float partialTicks) {
+//        GlStateManager.pushMatrix();
+//        super.render0(scale, parentPoint, parentClip, absMousex, absMousey, relMousex0, relMousey0, partialTicks);
+//        GlStateManager.popMatrix();
+//
+//        if (snapped != null && selectedPart != -2) {
+//            Tessellator tessellator = Tessellator.getInstance();
+//            GlStateManager.disableTexture2D();
+//            WorldRenderer worldRenderer = tessellator.getWorldRenderer();
+//            worldRenderer.begin(GL11.GL_LINES, DefaultVertexFormats.POSITION_COLOR);
+//            GL11.glLineWidth(1);
+//            for (Tuple<Marker[], EnumFacing.Axis> markerAxisTuple : snapped) {
+//                if (markerAxisTuple.getSecond() == EnumFacing.Axis.X) {
+//                    worldRenderer.pos(markerAxisTuple.getFirst()[0].getX(), 0, 0).color(0,255,0,255).endVertex();
+//                    worldRenderer.pos(markerAxisTuple.getFirst()[0].getX(), Minecraft.getMinecraft().displayHeight, 0).color(0,255,0,255).endVertex();
+//                } else {
+//                    worldRenderer.pos(0, markerAxisTuple.getFirst()[0].getY(), 0).color(0,255,0,255).endVertex();
+//                    worldRenderer.pos(Minecraft.getMinecraft().displayWidth, markerAxisTuple.getFirst()[0].getY(), 0).color(0,255,0,255).endVertex();
+//                }
+//            }
+//            tessellator.draw();
+//            for (Marker marker : guiGuiLocationConfig.getMarkerSet()) {
+//                Gui.drawRect(marker.getX(),marker.getY(), marker.getX()+1, marker.getY()+1, 0xFFFF0000);
+//            }
+//        }
+//    }
+//
+//    private int selectedPart = -2;
+//
+//    private int lastX = 0;
+//    private int lastY = 0;
+//
+//    private Rectangle internallyThinking;
+//    private Rectangle constraintApplied;
+//
+//    private Set<Tuple<Marker[], EnumFacing.Axis>> snapped = new HashSet<>();
+//
+//    public void applyConstraint() {
+//        constraintApplied = internallyThinking.getBounds();
+//
+//        // SNAP Moving Point.
+//        snapped.clear();
+//        int scailingThreshold = 5;
+//        if (selectedPart == 0){
+//            Point snapPt = new Point(constraintApplied.x +constraintApplied.width, constraintApplied.y + constraintApplied.height);
+//            Optional<Marker> snapX, snapY;
+//            SortedMap<Integer, List<Marker>> markerSortedMap = guiGuiLocationConfig.getMarkerTreeMapByX().subMap(snapPt.x-scailingThreshold, snapPt.x +scailingThreshold);
+//            snapX = markerSortedMap.values().stream()
+//                    .filter(Objects::nonNull)
+//                    .flatMap(Collection::stream)
+//                    .filter(a -> a.getParent() != this)
+//                    .min(Comparator.comparingInt(a -> (int) snapPt.distanceSq(a.getX(), a.getY())));
+//            markerSortedMap = guiGuiLocationConfig.getMarkerTreeMapByY().subMap(snapPt.y-scailingThreshold, snapPt.y +scailingThreshold);
+//            snapY = markerSortedMap.values().stream()
+//                    .filter(Objects::nonNull)
+//                    .flatMap(Collection::stream)
+//                    .filter(a -> a.getParent() != this)
+//                    .min(Comparator.comparingInt(a -> (int) snapPt.distanceSq(a.getX(), a.getY())));
+//            snapX.ifPresent(a -> {
+//                snapPt.x = a.getX();
+//            });
+//            snapY.ifPresent(a -> {
+//                snapPt.y = a.getY();
+//            });
+//
+//            constraintApplied = new Rectangle(constraintApplied.x, constraintApplied.y, snapPt.x - constraintApplied.x, snapPt.y - constraintApplied.y);
+//
+//
+//
+//            int minWidth;
+//            int minHeight;
+//            if (guiFeature.isKeepRatio()) {
+//                if (guiFeature.getDefaultRatio() >= 1) {
+//                    minHeight = constraintApplied.height < 0 ? -8 : 8;
+//                    minWidth = (int) (guiFeature.getDefaultRatio() * minHeight);
+//                } else {
+//                    minWidth = constraintApplied.width < 0 ? -8 : 8;
+//                    minHeight = (int) (minWidth / guiFeature.getDefaultRatio());
+//                }
+//            } else {
+//                minWidth = constraintApplied.width < 0 ? -8 : 8;
+//                minHeight = constraintApplied.height < 0 ? -8 : 8;
+//            }
+//
+//
+//            constraintApplied.width = Math.abs(constraintApplied.width) > Math.abs(minWidth) ? constraintApplied.width :
+//                    Math.abs(internallyThinking.width) > Math.abs(minWidth) ? internallyThinking.width : minWidth;
+//            constraintApplied.height = Math.abs(constraintApplied.height) > Math.abs(minHeight) ? constraintApplied.height :
+//                    Math.abs(internallyThinking.height) > Math.abs(minHeight) ? internallyThinking.height : minHeight;
+//
+//            if (guiFeature.isKeepRatio()) {
+//                double ratio = guiFeature.getDefaultRatio();
+//
+//                int heightWhenWidthFix = (int) Math.abs(constraintApplied.width / ratio);
+//                int widthWhenHeightFix = (int) Math.abs(ratio * constraintApplied.height);
+//                if (Math.abs(heightWhenWidthFix) <= Math.abs(constraintApplied.height)) {
+//                    constraintApplied.height = constraintApplied.height < 0 ? -heightWhenWidthFix : heightWhenWidthFix;
+//                } else if (Math.abs(widthWhenHeightFix) <= Math.abs(constraintApplied.width)) {
+//                    constraintApplied.width =constraintApplied.width < 0 ? - widthWhenHeightFix : widthWhenHeightFix;
+//                }
+//            }
+//
+//
+//            snapX.ifPresent(a -> {
+//                if (snapPt.x - constraintApplied.x == constraintApplied.width) {
+//                    Marker m = new Marker((int) (GuiGuiLocationConfig.facing[3].xCoord * constraintApplied.width) + constraintApplied.x, (int) (GuiGuiLocationConfig.facing[3].yCoord * constraintApplied.height) + constraintApplied.y, (int) GuiGuiLocationConfig.facing[3].zCoord, this);
+//                    snapped.add(new Tuple<>(new Marker[]{a, m}, EnumFacing.Axis.X));
+//                }
+//            });
+//            snapY.ifPresent(a -> {
+//                if (snapPt.y - constraintApplied.y == constraintApplied.height) {
+//                    Marker m = new Marker((int) (GuiGuiLocationConfig.facing[2].xCoord * constraintApplied.width) + constraintApplied.x, (int) (GuiGuiLocationConfig.facing[2].yCoord * constraintApplied.height) + constraintApplied.y, (int) GuiGuiLocationConfig.facing[2].zCoord, this);
+//                    snapped.add(new Tuple<>(new Marker[]{a, m}, EnumFacing.Axis.Y));
+//                }
+//            });
+//
+//            if (constraintApplied.height < 0) {
+//                constraintApplied.height = -constraintApplied.height;
+//                constraintApplied.y -= constraintApplied.height;
+//            }
+//
+//            if (constraintApplied.width < 0) {
+//                constraintApplied.width = -constraintApplied.width;
+//                constraintApplied.x -= constraintApplied.width;
+//            }
+//        } else if (selectedPart == -1) {
+//            for (int i : Arrays.asList(0,3,1,2)) {
+//                Vec3 pt = GuiGuiLocationConfig.facing[i];
+//                Marker m = new Marker((int) (pt.xCoord * constraintApplied.width) + constraintApplied.x, (int) (pt.yCoord * constraintApplied.height) + constraintApplied.y, (int) pt.zCoord, this);
+//                    Optional<Marker> result = guiGuiLocationConfig.getMarkerTreeMapByX().subMap(m.getX()-scailingThreshold, m.getX() +scailingThreshold).values().stream()
+//                            .filter(Objects::nonNull)
+//                            .flatMap(Collection::stream)
+//                            .filter(a -> a.getParent() != this)
+//                            .filter(a -> Math.abs(a.getX() - m.getX()) < scailingThreshold)
+//                            .filter(a -> ((a.getX() - pt.xCoord * constraintApplied.width) >= 0
+//                                && (a.getX() - pt.xCoord * constraintApplied.width + constraintApplied.width) <= Minecraft.getMinecraft().displayWidth))
+//                            .min(Comparator.comparingInt(a -> a.distanceSQ(m)));
+//                    if (result.isPresent()) {
+//                        int x = result.get().getX();
+//                        constraintApplied.x = (int) (x - pt.xCoord * constraintApplied.width);
+//
+//                        snapped.add(new Tuple<>(new Marker[] {result.get(), m}, EnumFacing.Axis.X));
+//                        break;
+//                    }
+//            }
+//            for (int i : Arrays.asList(1,2,0,3)) {
+//                Vec3 pt = GuiGuiLocationConfig.facing[i];
+//                Marker m = new Marker((int) (pt.xCoord * constraintApplied.width) + constraintApplied.x, (int) (pt.yCoord * constraintApplied.height) + constraintApplied.y, (int) pt.zCoord, this);
+//                    Optional<Marker> result = guiGuiLocationConfig.getMarkerTreeMapByY().subMap(m.getY()-scailingThreshold, m.getY() +scailingThreshold).values().stream()
+//                            .filter(Objects::nonNull)
+//                            .flatMap(Collection::stream)
+//                            .filter(a -> a.getParent() != this)
+//                            .filter(a -> Math.abs(a.getY() - m.getY()) < scailingThreshold)
+//                            .filter(a -> ((a.getY() - pt.yCoord * constraintApplied.height) >= 0
+//                                    && (a.getY() - pt.yCoord * constraintApplied.height+ constraintApplied.height) <= Minecraft.getMinecraft().displayHeight))
+//                            .min(Comparator.comparingInt(a -> a.distanceSQ(m)));
+//                    if (result.isPresent()) {
+//                        int y = result.get().getY();
+//                        constraintApplied.y = (int) (y - pt.yCoord * constraintApplied.height);
+//                        snapped.add(new Tuple<>(new Marker[] {result.get(), m}, EnumFacing.Axis.Y));
+//                        break;
+//                    }
+//            }
+//        }
+//
+//        if (constraintApplied.x < 0) constraintApplied.x = 0;
+//        if (constraintApplied.y < 0) constraintApplied.y = 0;
+//        if (constraintApplied.x + constraintApplied.width + 1 >=Minecraft.getMinecraft().displayWidth) constraintApplied.x = Minecraft.getMinecraft().displayWidth - constraintApplied.width - 1;
+//        if (constraintApplied.y + constraintApplied.height  + 1>= Minecraft.getMinecraft().displayHeight) constraintApplied.y = Minecraft.getMinecraft().displayHeight - constraintApplied.height - 1;
+//
+//
+//        setupMarkers();
+//    }
+//
+//    Marker[] markers = new Marker[4];
+//    public void setupMarkers() {
+//        for (int i1 = 0; i1 < markers.length; i1++) {
+//            Marker orig = markers[i1];
+//
+//            Vec3 pt = GuiGuiLocationConfig.facing[i1];
+//            markers[i1] = new Marker((int) (pt.xCoord * constraintApplied.width) + constraintApplied.x, (int) (pt.yCoord * constraintApplied.height) + constraintApplied.y, (int) pt.zCoord, this);
+//
+//            guiGuiLocationConfig.removeAndAddMarker(orig, markers[i1]);
+//        }
+//    }
+//
+//    MTooltip mTooltip;
+//
+//    @Override
+//    public void mouseClicked(int absMouseX, int absMouseY, int relMouseX, int relMouseY, int mouseButton) {
+//        if (!draggable) return;
+//        if (!guiFeature.isEnabled()) return;
+//        if (getTooltipsOpen() > 0) return;
+//        if (!lastAbsClip.contains(absMouseX, absMouseY)) return;
+//        if (mouseButton == 0) {
+//            internallyThinking = guiFeature.getFeatureRect().getRectangleNoScale();
+//            if (relMouseX < 4 && relMouseY < 4) { // TL
+//                selectedPart = 0;
+//                internallyThinking.y += internallyThinking.height;
+//                internallyThinking.height = -internallyThinking.height;
+//                internallyThinking.x += internallyThinking.width;
+//                internallyThinking.width = -internallyThinking.width;
+//            } else if (relMouseX < 4 && relMouseY > getBounds().height - 4) { // BL
+//                selectedPart = 0;
+//                internallyThinking.x += internallyThinking.width;
+//                internallyThinking.width = -internallyThinking.width;
+//            } else if (relMouseX > getBounds().width - 4 && relMouseY > getBounds().height - 4) { // BR
+//                selectedPart = 0;
+//            } else if (relMouseX > getBounds().width - 4 && relMouseY < 4) { // TR
+//                selectedPart = 0;
+//                internallyThinking.y += internallyThinking.height;
+//                internallyThinking.height = -internallyThinking.height;
+//            } else {
+//                selectedPart = -1;
+//            }
+//            lastX = absMouseX;
+//            lastY = absMouseY;
+//            applyConstraint();
+//
+//        } else if (getTooltipsOpen() == 0){
+//            if (mTooltip != null) mTooltip.close();
+//            mTooltip = new MPopupMenu(absMouseX, absMouseY, guiFeature.getTooltipForEditor(guiGuiLocationConfig));
+//            mTooltip.setScale(2.0f);
+//            mTooltip.open(this);
+//        }
+//        throw new IllegalArgumentException("bruh, a hack to stop event progress");
+//    }
+//
+//    @Override
+//    public void mouseReleased(int absMouseX, int absMouseY, int relMouseX, int relMouseY, int state) {
+//        if (!draggable) return;
+//        if (!guiFeature.isEnabled()) return;
+//        if (selectedPart >= -1) {
+//            guiFeature.setFeatureRect(new GUIRectangle(constraintApplied));
+//        }
+//
+//        selectedPart = -2;
+//    }
+//
+//    @Override
+//    public void mouseClickMove(int absMouseX, int absMouseY, int relMouseX, int relMouseY, int clickedMouseButton, long timeSinceLastClick) {
+//        if (!draggable) return;
+//        if (!guiFeature.isEnabled()) return;
+//        int dx = (absMouseX - lastX);
+//        int dy = (absMouseY - lastY);
+//        if (selectedPart >= 0) {
+//            Rectangle rectangle = internallyThinking;
+//
+//            int prevWidth = rectangle.width;
+//            int prevHeight= rectangle.height;
+//
+//            rectangle.width = prevWidth + dx;
+//            rectangle.height = prevHeight + dy;
+//
+//            if (rectangle.height * prevHeight <= 0 && prevHeight != rectangle.height) {
+//                rectangle.height += prevHeight < 0 ? 4 : -4;
+//            }
+//            if (rectangle.width * prevWidth <= 0 && prevWidth != rectangle.width) {
+//                rectangle.width += prevWidth < 0 ? 4 : -4;
+//            }
+//
+//
+//            applyConstraint();
+//            guiFeature.setFeatureRect(new GUIRectangle(constraintApplied));
+//            lastX = absMouseX;
+//            lastY = absMouseY;
+//            throw new IllegalArgumentException("bruh, a hack to stop event progress");
+//        } else if (selectedPart == -1){
+//            Rectangle rectangle = internallyThinking;
+//            rectangle.translate(dx, dy);
+//            applyConstraint();
+//            guiFeature.setFeatureRect(new GUIRectangle(constraintApplied));
+//            lastX = absMouseX;
+//            lastY = absMouseY;
+//        }
+//    }
+//
+//    @Override
+//    public void mouseMoved(int absMouseX, int absMouseY, int relMouseX, int relMouseY) {
+//        if (!draggable) return;
+//        if (!guiFeature.isEnabled()) return;
+//        if (getTooltipsOpen() > 0) return;
+//
+//        if (selectedPart == -1) {
+//            setCursor(EnumCursor.CLOSED_HAND);
+//        } else if (selectedPart >= 0) {
+//            if (internallyThinking.width < 0 && internallyThinking.height < 0) {
+//                setCursor(EnumCursor.RESIZE_TLDR);
+//            } else if (internallyThinking.width < 0 && internallyThinking.height >= 0) {
+//                setCursor(EnumCursor.RESIZE_TRDL);
+//            } else if (internallyThinking.width >= 0 && internallyThinking.height >= 0) {
+//                setCursor(EnumCursor.RESIZE_TLDR);
+//            } else if (internallyThinking.width >= 0 && internallyThinking.height < 0) {
+//                setCursor(EnumCursor.RESIZE_TRDL);
+//            }
+//        } else if (lastAbsClip.contains(absMouseX, absMouseY)) {
+//            if (relMouseX < 4 && relMouseY < 4) {
+//                setCursor(EnumCursor.RESIZE_TLDR);
+//            } else if (relMouseX < 4 && relMouseY > getBounds().height - 4) {
+//                setCursor(EnumCursor.RESIZE_TRDL);
+//            } else if (relMouseX > getBounds().width - 4 && relMouseY > getBounds().height - 4) {
+//                setCursor(EnumCursor.RESIZE_TLDR);
+//            } else if (relMouseX > getBounds().width - 4 && relMouseY < 4) {
+//                setCursor(EnumCursor.RESIZE_TRDL);
+//            } else {
+//                setCursor(EnumCursor.OPEN_HAND);
+//            }
+//        }
+//    }
+//}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location2/HUDConfigRootWidget.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location2/HUDConfigRootWidget.java
new file mode 100644
index 00000000..6fe1a8e9
--- /dev/null
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location2/HUDConfigRootWidget.java
@@ -0,0 +1,314 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2023  cyoung06 (syeyoung)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.config.guiconfig.location2;
+
+import kr.syeyoung.dungeonsguide.mod.config.types.GUIPosition;
+import kr.syeyoung.dungeonsguide.mod.features.AbstractFeature;
+import kr.syeyoung.dungeonsguide.mod.features.AbstractHUDFeature;
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.guiv2.DomElement;
+import kr.syeyoung.dungeonsguide.mod.guiv2.Widget;
+import kr.syeyoung.dungeonsguide.mod.guiv2.layouter.Layouter;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.ConstraintBox;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Position;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Rect;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Size;
+import kr.syeyoung.dungeonsguide.mod.guiv2.renderer.OnlyChildrenRenderer;
+import kr.syeyoung.dungeonsguide.mod.guiv2.renderer.Renderer;
+import kr.syeyoung.dungeonsguide.mod.guiv2.renderer.RenderingContext;
+import kr.syeyoung.dungeonsguide.mod.overlay.GUIRectPositioner;
+import kr.syeyoung.dungeonsguide.mod.overlay.OverlayWidget;
+import kr.syeyoung.dungeonsguide.mod.overlay.Positioner;
+import lombok.Getter;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.renderer.GlStateManager;
+
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+
+// Stack'em
+//
+public class HUDConfigRootWidget extends Widget implements Layouter, Renderer {
+
+    private List<Widget> widgets = new ArrayList<>();
+    private List<HUDWidgetWrapper> widgets2= new ArrayList<>();
+
+    private TreeSet<Position> markersX = new TreeSet<>(Comparator.comparingDouble(Position::getX));
+    private TreeSet<Position> markersY = new TreeSet<>(Comparator.comparingDouble(Position::getY));
+
+    private double ySnap = -1;
+    private double xSnap = -1;
+
+    private Position getVerticalSnapMarker(Position x) {
+        Position pos1 = markersX.floor(x);
+        Position pos2 = markersX.ceiling(x);
+        return Stream.of(pos1, pos2)
+                .filter(Objects::nonNull)
+                .filter(a -> Math.abs(a.x - x.x) <= 3)
+                .min(Comparator.comparingDouble(a -> Math.abs(a.x - x.x)))
+                .orElse(null);
+    }
+
+    private Position getHorizontalSnapMarker(Position x) {
+        Position pos1 = markersY.floor(x);
+        Position pos2 = markersY.ceiling(x);
+        return Stream.of(pos1, pos2)
+                .filter(Objects::nonNull)
+                .filter(a -> Math.abs(a.y - x.y) <= 3)
+                .min(Comparator.comparingDouble(a -> Math.abs(a.y - x.y)))
+                .orElse(null);
+    }
+
+    private void updateMarkers(HUDWidgetWrapper skip) {
+        markersX.clear();
+        markersY.clear();
+
+        for (HUDWidgetWrapper widgetWrapper : widgets2) {
+            if (widgetWrapper == skip) continue;
+            if (widgetWrapper.getDemoWidget() instanceof MarkerProvider) {
+                List<Position> pos = ((MarkerProvider) widgetWrapper.getDemoWidget()).getMarkers();
+                pos.stream()
+                        .map(a -> new Position(a.x + widgetWrapper.getDomElement().getRelativeBound().getX(), a.y + widgetWrapper.getDomElement().getRelativeBound().getY()))
+                        .forEach(a -> {
+                            markersY.add(a);
+                            markersX.add(a);
+                        });
+            }
+        }
+        markersX.add(new Position(lastWidth/2, 0));
+        markersY.add(new Position(0, lastHeight/2));
+    }
+
+    public HUDConfigRootWidget() {
+        widgets.add(new EventListenerWidget());
+        for (AbstractFeature abstractFeature : FeatureRegistry.getFeatureList()) {
+            if (!(abstractFeature instanceof AbstractHUDFeature)) continue;
+            if (!abstractFeature.isEnabled() && abstractFeature.isDisyllable()) continue;
+            HUDWidgetWrapper widgetWrapper = new HUDWidgetWrapper((AbstractHUDFeature) abstractFeature, this);
+            widgets.add(widgetWrapper);
+            widgets2.add(widgetWrapper);
+        }
+    }
+
+    @Override
+    public void doRender(int absMouseX, int absMouseY, double relMouseX, double relMouseY, float partialTicks, RenderingContext context, DomElement buildContext) {
+        for (int i = buildContext.getChildren().size() - 1; i >= 0; i --) {
+            DomElement value = buildContext.getChildren().get(i);
+            Rect original = value.getRelativeBound();
+            if (original == null) return;
+            GlStateManager.pushMatrix();
+            GlStateManager.translate(original.getX(), original.getY(), 0);
+
+            double absXScale = buildContext.getAbsBounds().getWidth() / buildContext.getSize().getWidth();
+            double absYScale = buildContext.getAbsBounds().getHeight() / buildContext.getSize().getHeight();
+
+            Rect elementABSBound = new Rect(
+                    (buildContext.getAbsBounds().getX() + original.getX() * absXScale),
+                    (buildContext.getAbsBounds().getY() + original.getY() * absYScale),
+                    (original.getWidth() * absXScale),
+                    (original.getHeight() * absYScale)
+            );
+            value.setAbsBounds(elementABSBound);
+
+            value.getRenderer().doRender(absMouseX, absMouseY,
+                    relMouseX - original.getX(),
+                    relMouseY - original.getY(), partialTicks, context, value);
+            GlStateManager.popMatrix();
+        }
+        if (xSnap != -1) {
+            context.drawRect(xSnap, 0, xSnap+1, buildContext.getSize().getHeight(), 0xFF00FF00);
+        }
+        if (ySnap != -1) {
+            context.drawRect(0, ySnap, buildContext.getSize().getWidth(), ySnap+1, 0xFF00FF00);
+        }
+    }
+
+    public class EventListenerWidget extends Widget implements Layouter{
+        @Override
+        public Size layout(DomElement buildContext, ConstraintBox constraintBox) {
+            return new Size(constraintBox.getMaxWidth(), constraintBox.getMaxHeight());
+        }
+
+        private HUDWidgetWrapper target;
+        private double sx, sy;
+        private Rect started;
+        private List<Position> markers;
+        @Override
+        public List<Widget> build(DomElement buildContext) {
+            return Collections.emptyList();
+        }
+
+        @Override
+        public boolean mouseClicked(int absMouseX, int absMouseY, double relMouseX, double relMouseY, int mouseButton) {
+            if (mouseButton != 0) return false;
+            this.sx = relMouseX; this.sy = relMouseY;
+            for (HUDWidgetWrapper widgetWrapper : widgets2) {
+                if (widgetWrapper.getDomElement().getAbsBounds().contains(absMouseX, absMouseY)) {
+                    target = widgetWrapper;
+                    started = widgetWrapper.getDomElement().getRelativeBound();
+                    if (target.getDemoWidget() instanceof MarkerProvider)
+                        markers = ((MarkerProvider) target.getDemoWidget()).getMarkers();
+                    getDomElement().obtainFocus();
+
+                    if (!widgetWrapper.getDemoWidget().getDomElement().getAbsBounds().contains(absMouseX, absMouseY)) {
+                        target = null;
+                        started = null;
+                        markers = null;
+                        return false;
+                    }
+                    updateMarkers(target);
+                    return true;
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public boolean mouseMoved(int absMouseX, int absMouseY, double relMouseX0, double relMouseY0) {
+            return false;
+        }
+
+        @Override
+        public void mouseClickMove(int absMouseX, int absMouseY, double relMouseX, double relMouseY, int clickedMouseButton, long timeSinceLastClick) {
+            if (started == null) return;
+            double dx = relMouseX - sx;
+            double dy = relMouseY - sy;
+            Rect newRect = new Rect(Layouter.clamp(dx + started.getX(), 0, lastWidth - started.getWidth() + target.getWidthPlus()),
+                    Layouter.clamp(dy + started.getY(), 0, lastHeight - started.getHeight() + target.getHeightPlus()), started.getWidth(), started.getHeight());
+
+            if (markers != null) {
+                Rect finalNewRect = newRect;
+                List<Position> positionedMarkers = markers.stream()
+                        .map(a -> new Position(finalNewRect.getX() + a.getX(), finalNewRect.getY() + a.getY())).collect(Collectors.toList());
+                double moveX = 0, moveY = 0;
+                xSnap = -1; ySnap = -1;
+                for (Position positionedMarker : positionedMarkers) {
+                    Position bestSnap = getVerticalSnapMarker(positionedMarker);
+                    if (bestSnap == null) continue;
+                    moveX = bestSnap.getX()-positionedMarker.getX();
+                    xSnap = bestSnap.getX();
+                    break;
+                }
+                for (Position positionedMarker : positionedMarkers) {
+                    Position bestSnap = getHorizontalSnapMarker(positionedMarker);
+                    if (bestSnap == null) continue;
+                    moveY = bestSnap.getY()-positionedMarker.getY();
+                    ySnap = bestSnap.getY();
+                    break;
+                }
+
+                newRect = new Rect(moveX + newRect.getX(), moveY + newRect.getY(), newRect.getWidth(), newRect.getHeight());
+            }
+            newRect = new Rect(Layouter.clamp(newRect.getX(), 0, lastWidth - started.getWidth() + target.getWidthPlus()),
+                    Layouter.clamp(newRect.getY(), 0, lastHeight - started.getHeight() + target.getHeightPlus()),
+                    newRect.getWidth(), newRect.getHeight());
+
+
+            target.getDomElement().setRelativeBound(newRect);
+        }
+
+        @Override
+        public void mouseReleased(int absMouseX, int absMouseY, double relMouseX, double relMouseY, int state) {
+            if (started == null) return;
+            double dx = relMouseX - sx;
+            double dy = relMouseY - sy;
+            Rect newRect = new Rect(Layouter.clamp(dx + started.getX(), 0, lastWidth - started.getWidth() + target.getWidthPlus()),
+                    Layouter.clamp(dy + started.getY(), 0, lastHeight - started.getHeight() + target.getHeightPlus()),
+                    target.getDemoWidget().getDomElement().getSize().getWidth(), target.getDemoWidget().getDomElement().getSize().getHeight());
+
+            if (markers != null) {
+                Rect finalNewRect = newRect;
+                List<Position> positionedMarkers = markers.stream()
+                        .map(a -> new Position(finalNewRect.getX() + a.getX(), finalNewRect.getY() + a.getY())).collect(Collectors.toList());
+                double moveX = 0, moveY = 0;
+                for (Position positionedMarker : positionedMarkers) {
+                    Position bestSnap = getVerticalSnapMarker(positionedMarker);
+                    if (bestSnap == null) continue;
+                    moveX = bestSnap.getX()-positionedMarker.getX();
+                    break;
+                }
+                for (Position positionedMarker : positionedMarkers) {
+                    Position bestSnap = getHorizontalSnapMarker(positionedMarker);
+                    if (bestSnap == null) continue;
+                    moveY = bestSnap.getY()-positionedMarker.getY();
+                    break;
+                }
+
+                newRect = new Rect(moveX + newRect.getX(), moveY + newRect.getY(), newRect.getWidth(), newRect.getHeight());
+            }
+
+            newRect = new Rect(Layouter.clamp(newRect.getX(), 0, lastWidth - started.getWidth() + target.getWidthPlus()),
+                    Layouter.clamp(newRect.getY(), 0, lastHeight - started.getHeight() + target.getHeightPlus()),
+                    newRect.getWidth(), newRect.getHeight());
+            GUIPosition newPos = GUIPosition.of(newRect, lastWidth, lastHeight);
+            newPos.setWidth(target.getAbstractHUDFeature().getFeatureRect().getWidth());
+            newPos.setHeight(target.getAbstractHUDFeature().getFeatureRect().getHeight());
+            target.getAbstractHUDFeature().setFeatureRect(newPos);
+            updatePosition(target);
+            target = null;
+            markers = null;
+            started = null;
+            xSnap = -1;
+            ySnap = -1;
+        }
+
+        @Override
+        public boolean mouseScrolled(int absMouseX, int absMouseY, double relMouseX0, double relMouseY0, int scrollAmount) {
+            return true;
+        }
+    }
+
+
+    @Override
+    public List<Widget> build(DomElement buildContext) {
+        return widgets;
+    }
+
+
+    @Getter
+    private double lastWidth, lastHeight;
+
+    @Override
+    public Size layout(DomElement buildContext, ConstraintBox constraintBox) {
+        lastWidth = constraintBox.getMaxWidth();
+        lastHeight = constraintBox.getMaxHeight();
+        for (DomElement child : buildContext.getChildren()) {
+            if (!(child.getWidget() instanceof HUDWidgetWrapper)) {
+                Size size = child.getLayouter().layout(child, constraintBox);
+                child.setRelativeBound(new Rect(0,0,size.getWidth(),size.getHeight()));
+                continue;
+            }
+            updatePosition((HUDWidgetWrapper) child.getWidget());
+        }
+
+        return new Size(constraintBox.getMaxWidth(), constraintBox.getMaxHeight());
+    }
+
+    private void updatePosition(HUDWidgetWrapper widget) {
+        Size size1 = widget.getDomElement().getLayouter().layout(widget.getDomElement(), new ConstraintBox(0, lastWidth,0,lastHeight));
+        Rect pos =  widget.getPositioner().position(
+                widget.getDemoWidget().getDomElement(), lastWidth, lastHeight
+        );
+        Rect newPos = new Rect(pos.getX(), pos.getY(), size1.getWidth(),size1.getHeight());
+
+        widget.getDomElement().setRelativeBound(newPos);
+    }
+}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location2/HUDLocationConfig.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location2/HUDLocationConfig.java
new file mode 100644
index 00000000..bdae741a
--- /dev/null
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location2/HUDLocationConfig.java
@@ -0,0 +1,43 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2023  cyoung06 (syeyoung)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.config.guiconfig.location2;
+
+import kr.syeyoung.dungeonsguide.mod.guiv2.BindableAttribute;
+import kr.syeyoung.dungeonsguide.mod.guiv2.DomElement;
+import kr.syeyoung.dungeonsguide.mod.guiv2.Widget;
+import kr.syeyoung.dungeonsguide.mod.guiv2.xml.AnnotatedImportOnlyWidget;
+import kr.syeyoung.dungeonsguide.mod.guiv2.xml.AnnotatedWidget;
+import kr.syeyoung.dungeonsguide.mod.guiv2.xml.annotations.Bind;
+import net.minecraft.util.ResourceLocation;
+
+public class HUDLocationConfig extends AnnotatedImportOnlyWidget {
+    @Bind(variableName = "movestuff")
+    public final BindableAttribute<Widget> stuff = new BindableAttribute<>(Widget.class);
+
+    public HUDLocationConfig() {
+        super(new ResourceLocation("dungeonsguide:gui/config/hudconfig.gui"));
+        stuff.setValue(new HUDConfigRootWidget());
+    }
+
+    @Override
+    public void onUnmount() {
+        super.onUnmount();
+        //save config or smth
+    }
+}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location2/HUDWidgetWrapper.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location2/HUDWidgetWrapper.java
new file mode 100644
index 00000000..301e9dae
--- /dev/null
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location2/HUDWidgetWrapper.java
@@ -0,0 +1,392 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2023  cyoung06 (syeyoung)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.config.guiconfig.location2;
+
+import kr.syeyoung.dungeonsguide.mod.config.types.GUIPosition;
+import kr.syeyoung.dungeonsguide.mod.features.AbstractHUDFeature;
+import kr.syeyoung.dungeonsguide.mod.guiv2.DomElement;
+import kr.syeyoung.dungeonsguide.mod.guiv2.Widget;
+import kr.syeyoung.dungeonsguide.mod.guiv2.elements.popups.AbsLocationPopup;
+import kr.syeyoung.dungeonsguide.mod.guiv2.elements.popups.PopupMgr;
+import kr.syeyoung.dungeonsguide.mod.guiv2.layouter.Layouter;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.ConstraintBox;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Rect;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Size;
+import kr.syeyoung.dungeonsguide.mod.guiv2.renderer.OnlyChildrenRenderer;
+import kr.syeyoung.dungeonsguide.mod.guiv2.renderer.Renderer;
+import kr.syeyoung.dungeonsguide.mod.guiv2.renderer.RenderingContext;
+import kr.syeyoung.dungeonsguide.mod.overlay.GUIRectPositioner;
+import kr.syeyoung.dungeonsguide.mod.utils.cursor.EnumCursor;
+import lombok.Getter;
+import net.minecraft.client.renderer.GlStateManager;
+import org.lwjgl.input.Mouse;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class HUDWidgetWrapper extends Widget implements Layouter {
+    @Getter
+    public AbstractHUDFeature abstractHUDFeature;
+    @Getter
+    public GUIRectPositioner positioner;
+
+    @Getter
+    private Widget demoWidget;
+    private WidthWidget widthWidget;
+    private HeightWidget heightWidget;
+    private CornerWidget cornerWidget;
+    private List<Widget> built = new ArrayList<>();
+    private HUDConfigRootWidget rootWidget;
+
+    @Getter
+    private double widthPlus;
+    @Getter
+    private double heightPlus;
+    public HUDWidgetWrapper(AbstractHUDFeature hudFeature, HUDConfigRootWidget hudConfigRootWidget) {
+        this.abstractHUDFeature = hudFeature;
+        positioner = new GUIRectPositioner(hudFeature::getFeatureRect);
+        demoWidget = abstractHUDFeature.instantiateDemoWidget();
+        built.add(demoWidget);
+        if (abstractHUDFeature.requiresWidthBound()) {
+            widthWidget = new WidthWidget();
+            built.add(widthWidget);
+        }
+        if (abstractHUDFeature.requiresHeightBound()) {
+            heightWidget = new HeightWidget();
+            built.add(heightWidget);
+        }
+        if ((abstractHUDFeature.requiresWidthBound() && abstractHUDFeature.requiresHeightBound()) || abstractHUDFeature.getKeepRatio() != null) {
+            // smth
+            cornerWidget = new CornerWidget();
+            built.add(cornerWidget);
+        }
+        rootWidget = hudConfigRootWidget;
+    }
+
+    @Override
+    public List<Widget> build(DomElement buildContext) {
+        return built;
+    }
+
+    @Override
+    public Size layout(DomElement buildContext, ConstraintBox constraintBox) {
+        Size size = demoWidget.getDomElement().getLayouter().layout(demoWidget.getDomElement(), new ConstraintBox(
+                0, constraintBox.getMaxWidth(),
+                0, constraintBox.getMaxHeight()
+        ));
+        demoWidget.getDomElement().setRelativeBound(new Rect(0,0,size.getWidth(), size.getHeight()));
+
+        if (widthWidget != null) {
+            Size size1 = widthWidget.getDomElement().getLayouter().layout(widthWidget.getDomElement(), new ConstraintBox(
+                    0, constraintBox.getMaxWidth(), 0, size.getHeight()
+            ));
+            widthWidget.getDomElement().setRelativeBound(new Rect(size.getWidth(), 0, size1.getWidth(), size1.getHeight()));
+            widthPlus =  size1.getWidth();
+        }
+
+        if (heightWidget != null) {
+            Size size1 = heightWidget.getDomElement().getLayouter().layout(heightWidget.getDomElement(), new ConstraintBox(
+                    0, size.getWidth(), 0, constraintBox.getMaxHeight()
+            ));
+            heightWidget.getDomElement().setRelativeBound(new Rect(0, size.getHeight(), size1.getWidth(), size1.getHeight()));
+            heightPlus= size1.getHeight();
+        }
+        if (cornerWidget != null) {
+            Size size1 = cornerWidget.getDomElement().getLayouter().layout(cornerWidget.getDomElement(), new ConstraintBox(
+                    0, size.getWidth(), 0, constraintBox.getMaxHeight()
+            ));
+            cornerWidget.getDomElement().setRelativeBound(new Rect(size.getWidth(), size.getHeight(), size1.getWidth(), size1.getHeight()));
+            widthPlus = size1.getWidth();
+            heightPlus = size1.getHeight();
+        }
+        return new Size(size.getWidth() + widthPlus, size.getHeight() + heightPlus);
+    }
+
+    @Override
+    protected Renderer createRenderer() {
+        return  HoverThingyRenderer.hoverThingyRenderer;
+    }
+
+    public static class HoverThingyRenderer extends OnlyChildrenRenderer {
+        public static final HoverThingyRenderer hoverThingyRenderer = new HoverThingyRenderer();
+        @Override
+        public void doRender(int absMouseX, int absMouseY, double relMouseX, double relMouseY, float partialTicks, RenderingContext renderingContext, DomElement buildContext) {
+            renderingContext.drawRect(0,0, buildContext.getSize().getWidth(), buildContext.getSize().getHeight(), 0x40000000);
+            GlStateManager.pushMatrix();
+            super.doRender(absMouseX, absMouseY, relMouseX, relMouseY, partialTicks, renderingContext, buildContext);
+            GlStateManager.popMatrix();
+            if (buildContext.getAbsBounds().contains(absMouseX, absMouseY))
+                renderingContext.drawRect(0,0, buildContext.getSize().getWidth(), buildContext.getSize().getHeight(), 0x33FFFFFF);
+        }
+    }
+
+    @Override
+    public boolean mouseMoved(int absMouseX, int absMouseY, double relMouseX0, double relMouseY0) {
+        if (Mouse.isButtonDown(0))
+            getDomElement().setCursor(EnumCursor.CLOSED_HAND);
+        else
+            getDomElement().setCursor(EnumCursor.OPEN_HAND);
+        return true;
+    }
+
+    @Override
+    public boolean mouseClicked(int absMouseX, int absMouseY, double relMouseX, double relMouseY, int mouseButton) {
+        if (mouseButton == 0) return false;
+
+        PopupMgr.getPopupMgr(getDomElement()).openPopup(new AbsLocationPopup(
+                absMouseX, absMouseY, new WidgetPopupMenu(), true
+        ), null);
+
+        return true;
+    }
+
+    public class WidthWidget extends Widget implements Layouter, Renderer {
+
+        @Override
+        public List<Widget> build(DomElement buildContext) {
+            return Collections.emptyList();
+        }
+
+        @Override
+        public Size layout(DomElement buildContext, ConstraintBox constraintBox) {
+            return new Size(5, constraintBox.getMaxHeight());
+        }
+
+        @Override
+        public void doRender(int absMouseX, int absMouseY, double relMouseX, double relMouseY, float partialTicks, RenderingContext context, DomElement buildContext) {
+            double thingHeight = Math.min(15, buildContext.getSize().getHeight());
+            context.drawRect(1,(buildContext.getSize().getHeight()-thingHeight)/2,2, (buildContext.getSize().getHeight()+thingHeight)/2, 0xFF888888);
+            context.drawRect(3,(buildContext.getSize().getHeight()-thingHeight)/2,4, (buildContext.getSize().getHeight()+thingHeight)/2, 0xFF888888);
+        }
+
+        private double sx = -1;
+        private double sw = 0;
+        @Override
+        public boolean mouseClicked(int absMouseX, int absMouseY, double relMouseX, double relMouseY, int mouseButton) {
+            this.sx = absMouseX;
+            this.sw = abstractHUDFeature.getFeatureRect().getWidth();
+            getDomElement().obtainFocus();
+            return true;
+        }
+
+        @Override
+        public void mouseClickMove(int absMouseX, int absMouseY, double relMouseX, double relMouseY, int clickedMouseButton, long timeSinceLastClick) {
+            if (sx == -1) return;
+            double newWidth = (absMouseX - sx) * getDomElement().getRelativeBound().getWidth() / getDomElement().getAbsBounds().getWidth() + sw;
+            abstractHUDFeature.setWidth(newWidth);
+            Rect newRect = new Rect(
+                    HUDWidgetWrapper.this.getDomElement().getRelativeBound().getX(),
+                    HUDWidgetWrapper.this.getDomElement().getRelativeBound().getY(),
+                    abstractHUDFeature.getFeatureRect().getWidth(),
+                    abstractHUDFeature.getFeatureRect().getHeight()
+            );
+            GUIPosition position = GUIPosition.of(newRect, rootWidget.getLastWidth(), rootWidget.getLastHeight());
+            position.setWidth(newRect.getWidth());
+            position.setHeight(newRect.getHeight());
+            abstractHUDFeature.setFeatureRect(position);
+            getDomElement().setCursor(EnumCursor.RESIZE_LEFT_RIGHT);
+            getDomElement().requestRelayout();
+        }
+
+        @Override
+        public void mouseReleased(int absMouseX, int absMouseY, double relMouseX, double relMouseY, int state) {
+            if (sx == -1) return;
+            double newWidth = (absMouseX - sx) * getDomElement().getRelativeBound().getWidth() / getDomElement().getAbsBounds().getWidth() + sw;
+            abstractHUDFeature.setWidth(newWidth);
+            Rect newRect = new Rect(
+                    HUDWidgetWrapper.this.getDomElement().getRelativeBound().getX(),
+                    HUDWidgetWrapper.this.getDomElement().getRelativeBound().getY(),
+                    abstractHUDFeature.getFeatureRect().getWidth(),
+                    abstractHUDFeature.getFeatureRect().getHeight()
+            );
+            GUIPosition position = GUIPosition.of(newRect, rootWidget.getLastWidth(), rootWidget.getLastHeight());
+            position.setWidth(newRect.getWidth());
+            position.setHeight(newRect.getHeight());
+            abstractHUDFeature.setFeatureRect(position);
+            getDomElement().requestRelayout();
+            this.sx = -1; this.sw = 0;
+        }
+
+        @Override
+        public boolean mouseMoved(int absMouseX, int absMouseY, double relMouseX0, double relMouseY0) {
+            getDomElement().setCursor(EnumCursor.RESIZE_LEFT_RIGHT);
+            return true;
+        }
+    }
+
+
+    public class HeightWidget extends Widget implements Layouter, Renderer {
+
+        @Override
+        public List<Widget> build(DomElement buildContext) {
+            return Collections.emptyList();
+        }
+
+        @Override
+        public Size layout(DomElement buildContext, ConstraintBox constraintBox) {
+            return new Size(constraintBox.getMaxWidth(), 5);
+        }
+
+        @Override
+        public void doRender(int absMouseX, int absMouseY, double relMouseX, double relMouseY, float partialTicks, RenderingContext context, DomElement buildContext) {
+            double thingWidth = Math.min(15, buildContext.getSize().getWidth());
+            context.drawRect((buildContext.getSize().getWidth()-thingWidth)/2,1, (buildContext.getSize().getWidth()+thingWidth)/2,2, 0xFF888888);
+            context.drawRect((buildContext.getSize().getWidth()-thingWidth)/2,3,  (buildContext.getSize().getWidth()+thingWidth)/2, 4,0xFF888888);
+        }
+
+        private double sy = -1;
+        private double sh = 0;
+        @Override
+        public boolean mouseClicked(int absMouseX, int absMouseY, double relMouseX, double relMouseY, int mouseButton) {
+            this.sy = absMouseY;
+            this.sh = abstractHUDFeature.getFeatureRect().getHeight();
+            getDomElement().obtainFocus();
+            return true;
+        }
+
+        @Override
+        public void mouseClickMove(int absMouseX, int absMouseY, double relMouseX, double relMouseY, int clickedMouseButton, long timeSinceLastClick) {
+            if (sy == -1) return;
+            double newHeight = (absMouseY - sy ) * getDomElement().getRelativeBound().getHeight() / getDomElement().getAbsBounds().getHeight()+ sh;
+            abstractHUDFeature.setHeight(newHeight);
+            Rect newRect = new Rect(
+                    HUDWidgetWrapper.this.getDomElement().getRelativeBound().getX(),
+                    HUDWidgetWrapper.this.getDomElement().getRelativeBound().getY(),
+                    abstractHUDFeature.getFeatureRect().getWidth(),
+                    abstractHUDFeature.getFeatureRect().getHeight()
+            );
+            GUIPosition position = GUIPosition.of(newRect, rootWidget.getLastWidth(), rootWidget.getLastHeight());
+            position.setWidth(newRect.getWidth());
+            position.setHeight(newRect.getHeight());
+            abstractHUDFeature.setFeatureRect(position);
+            getDomElement().setCursor(EnumCursor.RESIZE_UP_DOWN);
+            getDomElement().requestRelayout();
+        }
+
+        @Override
+        public void mouseReleased(int absMouseX, int absMouseY, double relMouseX, double relMouseY, int state) {
+            if (sy == -1) return;
+            double newHeight = (absMouseY - sy) * getDomElement().getRelativeBound().getHeight() / getDomElement().getAbsBounds().getHeight() + sh;
+            abstractHUDFeature.setHeight(newHeight);
+            Rect newRect = new Rect(
+                    HUDWidgetWrapper.this.getDomElement().getRelativeBound().getX(),
+                    HUDWidgetWrapper.this.getDomElement().getRelativeBound().getY(),
+                    abstractHUDFeature.getFeatureRect().getWidth(),
+                    abstractHUDFeature.getFeatureRect().getHeight()
+            );
+            GUIPosition position = GUIPosition.of(newRect, rootWidget.getLastWidth(), rootWidget.getLastHeight());
+            position.setWidth(newRect.getWidth());
+            position.setHeight(newRect.getHeight());
+            abstractHUDFeature.setFeatureRect(position);
+            getDomElement().requestRelayout();
+            this.sy = -1; this.sh = 0;
+        }
+
+        @Override
+        public boolean mouseMoved(int absMouseX, int absMouseY, double relMouseX0, double relMouseY0) {
+            getDomElement().setCursor(EnumCursor.RESIZE_UP_DOWN);
+            return true;
+        }
+    }
+
+
+    public class CornerWidget extends Widget implements Layouter, Renderer {
+
+        @Override
+        public List<Widget> build(DomElement buildContext) {
+            return Collections.emptyList();
+        }
+
+        @Override
+        public Size layout(DomElement buildContext, ConstraintBox constraintBox) {
+            return new Size(5, 5);
+        }
+
+        @Override
+        public void doRender(int absMouseX, int absMouseY, double relMouseX, double relMouseY, float partialTicks, RenderingContext context, DomElement buildContext) {
+            context.drawRect(3,1,4,2, 0xFF888888);
+            context.drawRect(1,3,2,4, 0xFF888888);
+            context.drawRect(3,3,4,4, 0xFF888888);
+        }
+
+        private double sy = -1;
+        private double sh = 0;
+        private double sx = -1;
+        private double sw = 0;
+        @Override
+        public boolean mouseClicked(int absMouseX, int absMouseY, double relMouseX, double relMouseY, int mouseButton) {
+            this.sy = absMouseY;
+            this.sh = abstractHUDFeature.getFeatureRect().getHeight();
+            this.sx = absMouseX;
+            this.sw = abstractHUDFeature.getFeatureRect().getWidth();
+            getDomElement().obtainFocus();
+            return true;
+        }
+
+        @Override
+        public void mouseClickMove(int absMouseX, int absMouseY, double relMouseX, double relMouseY, int clickedMouseButton, long timeSinceLastClick) {
+            if (sy == -1) return;
+            double newWidth = (absMouseX - sx ) * getDomElement().getRelativeBound().getWidth() / getDomElement().getAbsBounds().getWidth()+ sw;
+            double newHeight = (absMouseY - sy ) * getDomElement().getRelativeBound().getHeight() / getDomElement().getAbsBounds().getHeight()+ sh;
+            abstractHUDFeature.setHeight(newHeight);
+            abstractHUDFeature.setWidth(newWidth);
+            Rect newRect = new Rect(
+                    HUDWidgetWrapper.this.getDomElement().getRelativeBound().getX(),
+                    HUDWidgetWrapper.this.getDomElement().getRelativeBound().getY(),
+                    abstractHUDFeature.getFeatureRect().getWidth(),
+                    abstractHUDFeature.getKeepRatio() != null ? abstractHUDFeature.getFeatureRect().getWidth() * abstractHUDFeature.getKeepRatio() : abstractHUDFeature.getFeatureRect().getHeight()
+            );
+            GUIPosition position = GUIPosition.of(newRect, rootWidget.getLastWidth(), rootWidget.getLastHeight());
+            position.setWidth(newRect.getWidth());
+            position.setHeight(newRect.getHeight());
+            abstractHUDFeature.setFeatureRect(position);
+            getDomElement().setCursor(EnumCursor.RESIZE_TLDR);
+            getDomElement().requestRelayout();
+        }
+
+        @Override
+        public void mouseReleased(int absMouseX, int absMouseY, double relMouseX, double relMouseY, int state) {
+            if (sy == -1) return;
+            double newWidth = (absMouseX - sx ) * getDomElement().getRelativeBound().getWidth() / getDomElement().getAbsBounds().getWidth()+ sw;
+            double newHeight = (absMouseY - sy ) * getDomElement().getRelativeBound().getHeight() / getDomElement().getAbsBounds().getHeight()+ sh;
+            abstractHUDFeature.setHeight(newHeight);
+            abstractHUDFeature.setWidth(newWidth);
+            Rect newRect = new Rect(
+                    HUDWidgetWrapper.this.getDomElement().getRelativeBound().getX(),
+                    HUDWidgetWrapper.this.getDomElement().getRelativeBound().getY(),
+                    abstractHUDFeature.getFeatureRect().getWidth(),
+                    abstractHUDFeature.getKeepRatio() != null ? abstractHUDFeature.getFeatureRect().getWidth() * abstractHUDFeature.getKeepRatio() : abstractHUDFeature.getFeatureRect().getHeight()
+            );
+            GUIPosition position = GUIPosition.of(newRect, rootWidget.getLastWidth(), rootWidget.getLastHeight());
+            position.setWidth(newRect.getWidth());
+            position.setHeight(newRect.getHeight());
+            abstractHUDFeature.setFeatureRect(position);
+            getDomElement().setCursor(EnumCursor.RESIZE_TLDR);
+            getDomElement().requestRelayout();
+            this.sy = -1; this.sh = 0; this.sx = -1; this.sw = 0;
+        }
+
+        @Override
+        public boolean mouseMoved(int absMouseX, int absMouseY, double relMouseX0, double relMouseY0) {
+            getDomElement().setCursor(EnumCursor.RESIZE_TLDR);
+            return true;
+        }
+    }
+}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location2/MarkerProvider.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location2/MarkerProvider.java
new file mode 100644
index 00000000..e0356d4f
--- /dev/null
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location2/MarkerProvider.java
@@ -0,0 +1,27 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2023  cyoung06 (syeyoung)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.config.guiconfig.location2;
+
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Position;
+
+import java.util.List;
+
+public interface MarkerProvider {
+    List<Position> getMarkers();
+}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location2/WidgetPopupMenu.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location2/WidgetPopupMenu.java
new file mode 100644
index 00000000..3d10705a
--- /dev/null
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/guiconfig/location2/WidgetPopupMenu.java
@@ -0,0 +1,33 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2023  cyoung06 (syeyoung)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.config.guiconfig.location2;
+
+import kr.syeyoung.dungeonsguide.mod.guiv2.xml.AnnotatedImportOnlyWidget;
+import net.minecraft.util.ResourceLocation;
+
+public class WidgetPopupMenu extends AnnotatedImportOnlyWidget {
+    public WidgetPopupMenu() {
+        super(new ResourceLocation("dungeonsguide:gui/config/popupmenu.gui"));
+    }
+
+    @Override
+    public boolean mouseMoved(int absMouseX, int absMouseY, double relMouseX0, double relMouseY0) {
+        return true;
+    }
+}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/types/GUIPosition.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/types/GUIPosition.java
new file mode 100644
index 00000000..ceafefeb
--- /dev/null
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/types/GUIPosition.java
@@ -0,0 +1,143 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2023  cyoung06 (syeyoung)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.config.types;
+
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Rect;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Size;
+import lombok.*;
+import net.minecraft.client.Minecraft;
+
+@Data @AllArgsConstructor @NoArgsConstructor
+public class GUIPosition {
+    private OffsetType xType;
+    private double xOffset;
+    private OffsetType yType;
+    private double yOffset;
+
+    private Double width;
+    private Double height;
+
+    @Getter @RequiredArgsConstructor
+    public enum OffsetType {
+        START, CENTER, END
+    }
+
+    public static double intersectArea(Rect a, Rect b)
+    {
+        double x = Math.max(a.getX(), b.getX());
+        double num1 = Math.min(a.getX() + a.getWidth(), b.getX() + b.getWidth());
+        double y = Math.max(a.getY(), b.getY());
+        double num2 = Math.min(a.getY() + a.getHeight(), b.getY() + b.getHeight());
+        if (num1 >= x && num2 >= y)
+            return (num1 - x) * (num2 - y);
+        else
+            return 0;
+    }
+    public static GUIPosition of(Rect widgetLoc, double screenWidth, double screenHeight) {
+        double triWidth = screenWidth / 3;
+        double triHeight = screenHeight / 3;
+
+        OffsetType xOffset;
+        {
+            double left = intersectArea(widgetLoc, new Rect(0, 0, triWidth, screenHeight));
+            double center = intersectArea(widgetLoc, new Rect(triWidth, 0, triWidth, screenHeight));
+            double right = intersectArea(widgetLoc, new Rect(screenWidth - triWidth, 0, triWidth, screenHeight));
+            if (left >= center && left >= right) xOffset = OffsetType.START;
+            else if (center >= right && center >= left) xOffset = OffsetType.CENTER;
+            else xOffset = OffsetType.END;
+        }
+        OffsetType yOffset;
+        {
+            double top = intersectArea(widgetLoc, new Rect(0, 0, screenWidth, triHeight));
+            double center = intersectArea(widgetLoc, new Rect(0, triHeight, screenWidth, triHeight));
+            double bottom = intersectArea(widgetLoc, new Rect(0, screenHeight - triHeight, screenWidth, triHeight));
+            if (top >= center && top >= bottom) yOffset = OffsetType.START;
+            else if (center >= bottom && center >= top) yOffset = OffsetType.CENTER;
+            else yOffset = OffsetType.END;
+        }
+        System.out.println("X: "+xOffset+" / Y: "+yOffset);
+
+        GUIPosition guiPosition = new GUIPosition();
+        guiPosition.xType = xOffset;
+        guiPosition.yType = yOffset;
+
+        if (guiPosition.xType == OffsetType.START) {
+            guiPosition.xOffset = widgetLoc.getX();
+        } else if (guiPosition.xType == OffsetType.CENTER) {
+            guiPosition.xOffset = widgetLoc.getX() + (widgetLoc.getWidth() - screenWidth)/2;
+        } else {
+            guiPosition.xOffset = widgetLoc.getX() + widgetLoc.getWidth() - screenWidth;
+        }
+
+        if (guiPosition.yType == OffsetType.START) {
+            guiPosition.yOffset = widgetLoc.getY();
+        } else if (guiPosition.yType == OffsetType.CENTER) {
+            guiPosition.yOffset = widgetLoc.getY() + (widgetLoc.getHeight() - screenHeight)/2;
+        } else  {
+            guiPosition.yOffset = widgetLoc.getY() + widgetLoc.getHeight() - screenHeight;
+        }
+        System.out.println("X: "+guiPosition.xOffset+" / Y: "+guiPosition.yOffset);
+        double realScreenWidth = Minecraft.getMinecraft().displayWidth;
+        double realScreenHeight = Minecraft.getMinecraft().displayHeight;
+
+        guiPosition.xOffset = guiPosition.getXOffset() * realScreenWidth / screenWidth;
+        guiPosition.yOffset = guiPosition.getYOffset() * realScreenHeight / screenHeight;
+
+        return guiPosition;
+    }
+
+    public Rect position(double screenWidth0, double screenHeight0, Size widgetSize) {
+        double screenWidth = Minecraft.getMinecraft().displayWidth;
+        double screenHeight = Minecraft.getMinecraft().displayHeight;
+        double x = 0;
+        double xOff = xOffset * screenWidth0 / screenWidth;
+        double yOff = yOffset * screenHeight0 / screenHeight;
+
+        if (xType != OffsetType.CENTER && Math.abs(xOff) > screenWidth0/3) xOff = xOff > 0 ? screenWidth0/3 : -screenWidth0/3;
+        if (xType == OffsetType.CENTER && Math.abs(xOff) > screenWidth0 /6) xOff = xOff > 0 ? screenWidth0 / 6 : -screenWidth/6;
+        if (yType != OffsetType.CENTER && Math.abs(yOff) > screenHeight0/3) yOff = yOff > 0 ? screenHeight0/3 : -screenHeight0/3;
+        if (yType == OffsetType.CENTER && Math.abs(yOff) > screenHeight0/6) yOff = yOff > 0 ? screenHeight0/6 : -screenHeight0/6;
+
+
+        if (xType == OffsetType.START) {
+            x = xOff;
+        } else if (xType == OffsetType.CENTER) {
+            x = xOff + (screenWidth0 - widgetSize.getWidth())/2;
+        } else if (xType == OffsetType.END) {
+            x = xOff + screenWidth0 - widgetSize.getWidth();
+        }
+        double y = 0;
+
+        if (yType == OffsetType.START) {
+            y = yOff;
+        } else if (yType == OffsetType.CENTER) {
+            y = yOff + (screenHeight0 - widgetSize.getHeight())/2;
+        } else if (yType == OffsetType.END) {
+            y = yOff + screenHeight0 - widgetSize.getHeight();
+        }
+
+
+        return new Rect(x, y, widgetSize.getWidth(), widgetSize.getHeight());
+    }
+
+    @Override
+    public GUIPosition clone()  {
+        return new GUIPosition(this.getXType(), this.getXOffset(), this.getYType(), this.getYOffset(), this.getWidth(), this.getHeight());
+    }
+}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/types/GUIRectangle.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/types/GUIRectangle.java
deleted file mode 100644
index c5b31caa..00000000
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/types/GUIRectangle.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
- * Copyright (C) 2021  cyoung06
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-package kr.syeyoung.dungeonsguide.mod.config.types;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import net.minecraft.client.Minecraft;
-
-import java.awt.*;
-
-@Data
-@AllArgsConstructor
-@NoArgsConstructor
-public class GUIRectangle {
-    public GUIRectangle(Rectangle rectangle) {
-        if (rectangle.x < Minecraft.getMinecraft().displayWidth / 2) {
-            this.x = rectangle.x;
-            this.width = rectangle.width;
-        } else {
-            this.x = rectangle.x + rectangle.width - Minecraft.getMinecraft().displayWidth;
-            this.width = -rectangle.width;
-        }
-
-        if (rectangle.y < Minecraft.getMinecraft().displayHeight / 2) {
-            this.y = rectangle.y;
-            this.height = rectangle.height;
-        } else {
-            this.y = rectangle.y +rectangle.height - Minecraft.getMinecraft().displayHeight;
-            this.height = -rectangle.height;
-        }
-    }
-
-    private int x;
-    private int y;
-    private int width;
-    private int height;
-
-    public Rectangle getRectangle() {
-        return getRectangleNoScale();
-    }
-//    public Rectangle getRectangle(ScaledResolution scaledResolution) {
-//        double realX = (int) (x < 0 ? scaledResolution.getScaledWidth() + x : x);
-//        double realY = (int) (y < 0 ? scaledResolution.getScaledHeight() + y : y);
-//
-//        return new Rectangle((int)Math.min(realX + width, realX), (int)Math.min(realY + height, realY),
-//                (int)Math.abs(width), (int)Math.abs(height));
-//    }
-    public Rectangle getRectangleNoScale() {
-        int x = this.x, y = this.y;
-        if (Math.abs(x) > Minecraft.getMinecraft().displayWidth / 2) {
-            x = x < 0 ? -Minecraft.getMinecraft().displayWidth/2 : Minecraft.getMinecraft().displayWidth/2;
-        }
-        if (Math.abs(y) > Minecraft.getMinecraft().displayHeight / 2) {
-            y = y < 0 ? -Minecraft.getMinecraft().displayHeight/2 : Minecraft.getMinecraft().displayHeight/2;
-        }
-
-
-        double realX = (int) (x < 0 ? Minecraft.getMinecraft().displayWidth + x : x);
-        double realY = (int) (y < 0 ? Minecraft.getMinecraft().displayHeight + y : y);
-
-        return new Rectangle((int)Math.min(realX + width, realX), (int)Math.min(realY + height, realY),
-                (int)Math.abs(width), (int)Math.abs(height));
-    }
-}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/types/TCGUIPosition.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/types/TCGUIPosition.java
new file mode 100644
index 00000000..dc2f70fa
--- /dev/null
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/types/TCGUIPosition.java
@@ -0,0 +1,54 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2021  cyoung06
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.config.types;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+public class TCGUIPosition implements TypeConverter<GUIPosition> {
+    @Override
+    public String getTypeString() {
+        return "guipos";
+    }
+
+    @Override
+    public GUIPosition deserialize(JsonElement element) {
+        if (element == null) return null;
+        GUIPosition rectangle = new GUIPosition();
+        rectangle.setXOffset(((JsonObject)element).get("x").getAsDouble());
+        rectangle.setYOffset(((JsonObject)element).get("y").getAsDouble());
+        rectangle.setXType(GUIPosition.OffsetType.values()[((JsonObject)element).get("xType").getAsInt()]);
+        rectangle.setYType(GUIPosition.OffsetType.values()[((JsonObject)element).get("yType").getAsInt()]);
+        rectangle.setWidth(element.getAsJsonObject().get("width") == null ? null : element.getAsJsonObject().get("width").getAsDouble());
+        rectangle.setHeight(element.getAsJsonObject().get("height") == null ? null : element.getAsJsonObject().get("height").getAsDouble());
+        return rectangle;
+    }
+
+    @Override
+    public JsonElement serialize(GUIPosition element) {
+        JsonObject object = new JsonObject();
+        object.addProperty("x", element.getXOffset());
+        object.addProperty("y", element.getYOffset());
+        object.addProperty("xType", element.getXType().ordinal());
+        object.addProperty("yType", element.getYType().ordinal());
+        object.addProperty("width", element.getWidth());
+        object.addProperty("height", element.getHeight());
+        return object;
+    }
+}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/types/TCGUIRectangle.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/types/TCGUIRectangle.java
deleted file mode 100644
index 9a9a9a79..00000000
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/types/TCGUIRectangle.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
- * Copyright (C) 2021  cyoung06
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-package kr.syeyoung.dungeonsguide.mod.config.types;
-
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-
-public class TCGUIRectangle implements TypeConverter<GUIRectangle> {
-    @Override
-    public String getTypeString() {
-        return "guirect";
-    }
-
-    @Override
-    public GUIRectangle deserialize(JsonElement element) {
-        if (element == null) return null;
-        GUIRectangle rectangle = new GUIRectangle();
-        rectangle.setX(((JsonObject)element).get("x").getAsInt());
-        rectangle.setY(((JsonObject)element).get("y").getAsInt());
-        rectangle.setWidth(((JsonObject)element).get("width").getAsInt());
-        rectangle.setHeight(((JsonObject)element).get("height").getAsInt());
-        return rectangle;
-    }
-
-    @Override
-    public JsonElement serialize(GUIRectangle element) {
-        JsonObject object = new JsonObject();
-        object.addProperty("x", element.getX());
-        object.addProperty("y", element.getY());
-        object.addProperty("width", element.getWidth());
-        object.addProperty("height", element.getHeight());
-        return object;
-    }
-}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/types/TypeConverterRegistry.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/types/TypeConverterRegistry.java
index 9dbafe05..d8dfd5e0 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/types/TypeConverterRegistry.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/config/types/TypeConverterRegistry.java
@@ -39,7 +39,7 @@ public class TypeConverterRegistry {
         register(new TCBoolean());
         register(new TCInteger());
         register(new TCRectangle());
-        register(new TCGUIRectangle());
+        register(new TCGUIPosition());
         register(new TCString());
         register(new TCColor());
         register(new TCFloat());
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/CosmeticsManager.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/CosmeticsManager.java
index efb19c67..e2bec187 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/CosmeticsManager.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/cosmetics/CosmeticsManager.java
@@ -182,6 +182,7 @@ public class CosmeticsManager {
 
         e.getStompInterface().subscribe("/user/queue/reply/cosmetic.activelist", (stompClient, payload) -> {
             activeCosmeticMap = new HashMap<>();
+            System.out.println(payload);
             JSONArray object = new JSONArray(payload);
             for (Object o : object) {
                 JSONObject jsonObject = (JSONObject) o;
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/AbstractHUDFeature.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/AbstractHUDFeature.java
index 8e841db7..9233ac6a 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/AbstractHUDFeature.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/AbstractHUDFeature.java
@@ -21,14 +21,20 @@ package kr.syeyoung.dungeonsguide.mod.features;
 import com.google.gson.JsonObject;
 import kr.syeyoung.dungeonsguide.mod.config.guiconfig.GuiConfigV2;
 import kr.syeyoung.dungeonsguide.mod.config.guiconfig.location.GuiGuiLocationConfig;
-import kr.syeyoung.dungeonsguide.mod.config.types.GUIRectangle;
+import kr.syeyoung.dungeonsguide.mod.config.types.GUIPosition;
 import kr.syeyoung.dungeonsguide.mod.config.types.TypeConverterRegistry;
 import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
 import kr.syeyoung.dungeonsguide.mod.gui.elements.MButton;
 import kr.syeyoung.dungeonsguide.mod.gui.elements.MLabel;
 import kr.syeyoung.dungeonsguide.mod.gui.elements.MPassiveLabelAndElement;
 import kr.syeyoung.dungeonsguide.mod.gui.elements.MToggleButton;
-import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Rect;
+import kr.syeyoung.dungeonsguide.mod.guiv2.DomElement;
+import kr.syeyoung.dungeonsguide.mod.guiv2.Widget;
+import kr.syeyoung.dungeonsguide.mod.guiv2.layouter.Layouter;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.ConstraintBox;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Size;
+import kr.syeyoung.dungeonsguide.mod.guiv2.renderer.Renderer;
+import kr.syeyoung.dungeonsguide.mod.guiv2.renderer.RenderingContext;
 import lombok.AccessLevel;
 import lombok.Getter;
 import lombok.Setter;
@@ -37,47 +43,84 @@ import net.minecraft.client.gui.GuiScreen;
 
 import java.awt.*;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 @Getter
 public abstract class AbstractHUDFeature extends AbstractGuiFeature {
-    private GUIRectangle featureRect;
+    private GUIPosition featureRect;
 
-    public void setFeatureRect(GUIRectangle featureRect) {
+    public void setFeatureRect(GUIPosition featureRect) {
+        if (requiresWidthBound() && featureRect.getWidth() == null) featureRect.setWidth(100.0);
+        if (requiresHeightBound() && featureRect.getHeight() == null) featureRect.setHeight(100.0);
         this.featureRect = featureRect;
         updatePosition();
     }
 
-    @Setter(value = AccessLevel.PROTECTED)
-    private boolean keepRatio;
-    @Setter(value = AccessLevel.PROTECTED)
-    private double defaultWidth;
-    @Setter(value = AccessLevel.PROTECTED)
-    private double defaultHeight;
-    private final double defaultRatio;
+    public void setWidth(double width) {
+        if (!requiresWidthBound()) throw new UnsupportedOperationException("Width unsettable");
+        if (width < 10) width = 10;
+        featureRect.setWidth(width);
+        updatePosition();
+    }
+    public void setHeight(double height) {
+        if (!requiresHeightBound() && (getKeepRatio() == null)) throw new UnsupportedOperationException("Height unsettable");
+        if (height < 10) height = 10;
+        if (getKeepRatio() != null)
+            featureRect.setWidth(height / getKeepRatio());
+        else
+            featureRect.setHeight(height);
+        updatePosition();
+    }
 
-    protected AbstractHUDFeature(String category, String name, String description, String key, boolean keepRatio, int width, int height) {
+    protected AbstractHUDFeature(String category, String name, String description, String key) {
         super(category, name, description, key);
-        this.keepRatio = keepRatio;
-        this.defaultWidth = width;
-        this.defaultHeight = height;
-        this.defaultRatio = defaultWidth / defaultHeight;
-        this.featureRect = new GUIRectangle(0, 0, width, height);
+        this.featureRect = new GUIPosition(GUIPosition.OffsetType.START, 0, GUIPosition.OffsetType.START, 0,
+                requiresWidthBound() ? 0.0 : null,
+                requiresHeightBound() ? 0.0 : null);
     }
 
+
+
+    public boolean requiresWidthBound() {return false;}
+    public boolean requiresHeightBound() {return false;}
+    public Double getKeepRatio() {return null;}
+
+
     public abstract void drawDemo(float partialTicks);
 
+    public class WidgetFeatureWrapper extends Widget implements Renderer, Layouter {
+        @Override
+        public List<Widget> build(DomElement buildContext) {
+            return Collections.emptyList();
+        }
+
+        @Override
+        public void doRender(int absMouseX, int absMouseY, double relMouseX, double relMouseY, float partialTicks, RenderingContext context, DomElement buildContext) {
+            drawDemo(partialTicks);
+        }
+
+        @Override
+        public Size layout(DomElement buildContext, ConstraintBox constraintBox) {
+            return new Size(constraintBox.getMaxWidth(), constraintBox.getMaxHeight());
+        }
+    }
+
+    public Widget instantiateDemoWidget() {
+        return new WidgetFeatureWrapper();
+    }
+
     @Override
     public void loadConfig(JsonObject jsonObject) {
         super.loadConfig(jsonObject);
-        this.featureRect = TypeConverterRegistry.getTypeConverter("guirect",GUIRectangle.class).deserialize(jsonObject.get("$bounds"));
-        updatePosition();
+        GUIPosition position = TypeConverterRegistry.getTypeConverter("guipos", GUIPosition.class).deserialize(jsonObject.get("$pos"));
+        if (position != null) setFeatureRect(position);
     }
 
     @Override
     public JsonObject saveConfig() {
         JsonObject object = super.saveConfig();
-        object.add("$bounds", TypeConverterRegistry.getTypeConverter("guirect", GUIRectangle.class).serialize(featureRect));
+        object.add("$pos", TypeConverterRegistry.getTypeConverter("guipos", GUIPosition.class).serialize(featureRect));
         return object;
     }
 
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/RawRenderingGuiFeature.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/RawRenderingGuiFeature.java
index 79541ac5..b24aa324 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/RawRenderingGuiFeature.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/RawRenderingGuiFeature.java
@@ -18,31 +18,55 @@
 
 package kr.syeyoung.dungeonsguide.mod.features;
 
+import kr.syeyoung.dungeonsguide.mod.config.guiconfig.location2.MarkerProvider;
 import kr.syeyoung.dungeonsguide.mod.guiv2.DomElement;
 import kr.syeyoung.dungeonsguide.mod.guiv2.Widget;
 import kr.syeyoung.dungeonsguide.mod.guiv2.elements.Clip;
 import kr.syeyoung.dungeonsguide.mod.guiv2.layouter.Layouter;
 import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.ConstraintBox;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Position;
 import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Size;
 import kr.syeyoung.dungeonsguide.mod.guiv2.renderer.Renderer;
 import kr.syeyoung.dungeonsguide.mod.guiv2.renderer.RenderingContext;
-import kr.syeyoung.dungeonsguide.mod.overlay.GUIRectanglePositioner;
+import kr.syeyoung.dungeonsguide.mod.overlay.GUIRectPositioner;
 import kr.syeyoung.dungeonsguide.mod.overlay.OverlayType;
 import kr.syeyoung.dungeonsguide.mod.overlay.OverlayWidget;
 import lombok.Getter;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.FontRenderer;
-import org.lwjgl.opengl.GL11;
 
-import java.awt.*;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
 
 @Getter
 public abstract class RawRenderingGuiFeature extends AbstractHUDFeature {
+    private Double ratio;
 
-    protected RawRenderingGuiFeature(String category, String name, String description, String key, boolean keepRatio, int width, int height) {
-        super(category, name, description, key, keepRatio, width, height);
+    protected RawRenderingGuiFeature(String category, String name, String description, String key, boolean keepRatio, double width, double height) {
+        super(category, name, description, key);
+        this.ratio = keepRatio ? height / width : null;
+        if (keepRatio)
+            this.getFeatureRect().setWidth(width);
+        else {
+            this.getFeatureRect().setWidth(width);
+            this.getFeatureRect().setHeight(height);
+        }
+    }
+
+    @Override
+    public Double getKeepRatio() {
+        return ratio;
+    }
+
+    @Override
+    public boolean requiresWidthBound() {
+        return true;
+    }
+
+    @Override
+    public boolean requiresHeightBound() {
+        return ratio == null;
     }
 
     public class WidgetFeatureWrapper extends Widget implements Renderer, Layouter {
@@ -58,7 +82,41 @@ public abstract class RawRenderingGuiFeature extends AbstractHUDFeature {
 
         @Override
         public Size layout(DomElement buildContext, ConstraintBox constraintBox) {
-            return new Size(constraintBox.getMaxWidth(), constraintBox.getMaxHeight());
+            return new Size(getFeatureRect().getWidth(),
+                    ratio != null ? getFeatureRect().getWidth() * ratio : getFeatureRect().getHeight());
+        }
+    }
+    public class WidgetFeatureWrapper2 extends Widget implements Renderer, Layouter, MarkerProvider {
+        @Override
+        public List<Widget> build(DomElement buildContext) {
+            return Collections.emptyList();
+        }
+
+        @Override
+        public void doRender(int absMouseX, int absMouseY, double relMouseX, double relMouseY, float partialTicks, RenderingContext context, DomElement buildContext) {
+            if (buildContext.getSize().getWidth() <= 0 || buildContext.getSize().getHeight() <= 0)
+                return;
+            context.pushClip(buildContext.getAbsBounds(), buildContext.getSize(), 0,0, buildContext.getSize().getWidth(), buildContext.getSize().getHeight());
+            drawDemo(partialTicks);
+            context.popClip();
+        }
+
+        @Override
+        public Size layout(DomElement buildContext, ConstraintBox constraintBox) {
+            return new Size(getFeatureRect().getWidth(),
+                    ratio != null ? getFeatureRect().getWidth() * ratio : getFeatureRect().getHeight());
+        }
+
+        @Override
+        public List<Position> getMarkers() {
+            Size size = getDomElement().getSize();
+
+            return Arrays.asList(
+                    new Position(size.getWidth()/2, 0),
+                    new Position(0, size.getHeight()/2),
+                    new Position(size.getWidth()/2,size.getHeight()),
+                    new Position(size.getWidth(),size.getHeight()/2)
+            );
         }
     }
 
@@ -68,10 +126,13 @@ public abstract class RawRenderingGuiFeature extends AbstractHUDFeature {
         return new OverlayWidget(
                 clip,
                 OverlayType.UNDER_CHAT,
-                new GUIRectanglePositioner(this::getFeatureRect)
+                new GUIRectPositioner(this::getFeatureRect)
         );
     }
 
+    public Widget instantiateDemoWidget() {
+        return new WidgetFeatureWrapper2();
+    }
     public void drawScreen(float partialTicks) {
         drawHUD(partialTicks);
     }
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureDebugTrap.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureDebugTrap.java
index f2da9a70..93e7363e 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureDebugTrap.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureDebugTrap.java
@@ -34,7 +34,7 @@ import java.util.List;
 
 public class FeatureDebugTrap extends TextHUDFeature {
     public FeatureDebugTrap() {
-        super("Debug", "Display the current amount of bat entities", "", "advanced.bat", false, getFontRenderer().getStringWidth("Bats: 9999"), getFontRenderer().FONT_HEIGHT);
+        super("Debug", "Display the current amount of bat entities", "", "advanced.bat");
         getStyles().add(new TextStyle("base", new AColor(0x00, 0xAA,0xAA,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("batsamm", new AColor(0x55, 0xFF,0xFF,255), new AColor(0, 0,0,0), false));
     }
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureDebuggableMap.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureDebuggableMap.java
index ff00745f..35adaafe 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureDebuggableMap.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureDebuggableMap.java
@@ -23,6 +23,7 @@ import kr.syeyoung.dungeonsguide.mod.DungeonsGuide;
 import kr.syeyoung.dungeonsguide.mod.SkyblockStatus;
 import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
 import kr.syeyoung.dungeonsguide.mod.features.RawRenderingGuiFeature;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Size;
 import kr.syeyoung.dungeonsguide.mod.utils.MapUtils;
 import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
 import net.minecraft.client.Minecraft;
@@ -58,7 +59,7 @@ public class FeatureDebuggableMap extends RawRenderingGuiFeature {
 //        if (context == null) return;
 
         GlStateManager.pushMatrix();
-        double factor = getFeatureRect().getRectangle().getWidth() / 128;
+        double factor = getFeatureRect().getWidth() / 128;
         GlStateManager.scale(factor, factor, 1);
         int[] textureData = dynamicTexture.getTextureData();
         MapUtils.getImage().getRGB(0, 0, 128, 128, textureData, 0, 128);
@@ -70,20 +71,22 @@ public class FeatureDebuggableMap extends RawRenderingGuiFeature {
 
 
         if (!(Minecraft.getMinecraft().currentScreen instanceof GuiChat)) return;
-        Rectangle featureRect = this.getFeatureRect().getRectangleNoScale();
-
-        int i = (int) ((int) (Mouse.getEventX() - featureRect.getX()) / factor);
-        int j = (int) ((int) (Minecraft.getMinecraft().displayHeight - Mouse.getEventY() - featureRect.getY())/ factor);
-        if (i >= 0 && j>= 0 && i <= 128 && j <= 128 && MapUtils.getColors() != null) {
-            GuiUtils.drawHoveringText(Arrays.asList(i+","+j,"Color: "+MapUtils.getColors()[j * 128 + i]),(int)(Mouse.getEventX() - featureRect.getX()), (int) (Minecraft.getMinecraft().displayHeight - Mouse.getEventY() - featureRect.getY()), Minecraft.getMinecraft().displayWidth, Minecraft.getMinecraft().displayHeight, -1, Minecraft.getMinecraft().fontRendererObj);
-        }
+        // TODO: rewrite hover logic
+//        Rectangle featureRect = this.getFeatureRect().getRectangleNoScale();
+//
+//        int i = (int) ((int) (Mouse.getEventX() - featureRect.getX()) / factor);
+//        int j = (int) ((int) (Minecraft.getMinecraft().displayHeight - Mouse.getEventY() - featureRect.getY())/ factor);
+//        if (i >= 0 && j>= 0 && i <= 128 && j <= 128 && MapUtils.getColors() != null) {
+//            GuiUtils.drawHoveringText(Arrays.asList(i+","+j,"Color: "+MapUtils.getColors()[j * 128 + i]),(int)(Mouse.getEventX() - featureRect.getX()), (int) (Minecraft.getMinecraft().displayHeight - Mouse.getEventY() - featureRect.getY()), Minecraft.getMinecraft().displayWidth, Minecraft.getMinecraft().displayHeight, -1, Minecraft.getMinecraft().fontRendererObj);
+//        }
     }
 
     @Override
     public void drawDemo(float partialTicks) {
         FontRenderer fr = getFontRenderer();
-        Rectangle featureRect = getFeatureRect().getRectangle();
+        double width = getFeatureRect().getWidth();
+
         GL11.glLineWidth(2);
-        RenderUtils.drawUnfilledBox(0,0,featureRect.width, featureRect.height, 0xff000000, false);
+        RenderUtils.drawUnfilledBox(0,0, (int) width, (int) width, 0xff000000, false);
     }
 }
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureRoomCoordDisplay.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureRoomCoordDisplay.java
index f59e3187..1b5357eb 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureRoomCoordDisplay.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureRoomCoordDisplay.java
@@ -39,7 +39,7 @@ import java.util.List;
 
 public class FeatureRoomCoordDisplay extends TextHUDFeature {
     public FeatureRoomCoordDisplay() {
-        super("Debug", "Display Coordinate Relative to the Dungeon Room and room's rotation", "X: 0 Y: 3 Z: 5 Facing: Z+" , "advanced.coords", false, getFontRenderer().getStringWidth("X: 48 Y: 100 Z: 48 Facing: Z+"), 10);
+        super("Debug", "Display Coordinate Relative to the Dungeon Room and room's rotation", "X: 0 Y: 3 Z: 5 Facing: Z+" , "advanced.coords");
         this.setEnabled(false);
         getStyles().add(new TextStyle("coord", new AColor(Color.yellow.getRGB(),true), new AColor(0, 0,0,0), false));
     }
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureRoomDebugInfo.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureRoomDebugInfo.java
index e2908a18..ac7c7b90 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureRoomDebugInfo.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureRoomDebugInfo.java
@@ -39,7 +39,7 @@ import java.util.List;
 
 public class FeatureRoomDebugInfo extends TextHUDFeature {
     public FeatureRoomDebugInfo() {
-        super("Debug", "Display Room Debug Info", "ONLY WORKS WITH SECRET SETTING", "advanced.debug.roominfo", false, getFontRenderer().getStringWidth("longestplayernamepos: 100"), getFontRenderer().FONT_HEIGHT * 6);
+        super("Debug", "Display Room Debug Info", "ONLY WORKS WITH SECRET SETTING", "advanced.debug.roominfo");
         this.setEnabled(false);
         getStyles().add(new TextStyle("info", new AColor(Color.white.getRGB(),true), new AColor(0, 0,0,0), false));
     }
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/boss/FeatureBossHealth.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/boss/FeatureBossHealth.java
index 80658f1a..6cde5094 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/boss/FeatureBossHealth.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/boss/FeatureBossHealth.java
@@ -35,7 +35,7 @@ import java.util.List;
 
 public class FeatureBossHealth extends TextHUDFeature {
     public FeatureBossHealth() {
-        super("Dungeon.Bossfight", "Display Boss(es) Health", "Show the health of boss and minibosses in bossfight (Guardians, Priests..)", "bossfight.health", false, getFontRenderer().getStringWidth("The Professor: 4242m"), getFontRenderer().FONT_HEIGHT * 5);
+        super("Dungeon.Bossfight", "Display Boss(es) Health", "Show the health of boss and minibosses in bossfight (Guardians, Priests..)", "bossfight.health");
         this.setEnabled(true);
         addParameter("totalHealth", new FeatureParameter<Boolean>("totalHealth", "show total health", "Show total health along with current health", false, "boolean", nval -> totalHealth = nval));
         addParameter("formatHealth", new FeatureParameter<Boolean>("formatHealth", "format health", "1234568 -> 1m", true, "boolean", nval -> formatHealth = nval));
@@ -54,12 +54,6 @@ public class FeatureBossHealth extends TextHUDFeature {
     boolean ignoreInattackable;
 
 
-
-    @Override
-    public boolean doesScaleWithHeight() {
-        return false;
-    }
-
     @Override
     public boolean isHUDViewable() {
         return SkyblockStatus.isOnDungeon() && DungeonsGuide.getDungeonsGuide().getDungeonFacade().getContext() != null && DungeonsGuide.getDungeonsGuide().getDungeonFacade().getContext().getBossfightProcessor() != null;
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/boss/FeatureCurrentPhase.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/boss/FeatureCurrentPhase.java
index dcfb715a..bfc32c74 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/boss/FeatureCurrentPhase.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/boss/FeatureCurrentPhase.java
@@ -32,7 +32,7 @@ import java.util.List;
 
 public class FeatureCurrentPhase extends TextHUDFeature {
     public FeatureCurrentPhase() {
-        super("Dungeon.Bossfight", "Display Current Phase", "Displays the current phase of bossfight", "bossfight.phasedisplay", false, getFontRenderer().getStringWidth("Current Phase: fight-2-idk-howlng"), getFontRenderer().FONT_HEIGHT);
+        super("Dungeon.Bossfight", "Display Current Phase", "Displays the current phase of bossfight", "bossfight.phasedisplay");
         this.setEnabled(true);
         getStyles().add(new TextStyle("title", new AColor(0x00, 0xAA,0xAA,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("separator", new AColor(0x55, 0x55,0x55,255), new AColor(0, 0,0,0), false));
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/boss/FeatureTerracotaTimer.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/boss/FeatureTerracotaTimer.java
index 4fd96fbd..61ca037c 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/boss/FeatureTerracotaTimer.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/boss/FeatureTerracotaTimer.java
@@ -35,7 +35,7 @@ import java.util.List;
 
 public class FeatureTerracotaTimer extends TextHUDFeature {
     public FeatureTerracotaTimer() {
-        super("Dungeon.Bossfight.Floor 6", "Display Terracotta phase timer", "Displays Terracotta phase timer", "bossfight.terracota", true, getFontRenderer().getStringWidth("Terracottas: 1m 99s"), getFontRenderer().FONT_HEIGHT);
+        super("Dungeon.Bossfight.Floor 6", "Display Terracotta phase timer", "Displays Terracotta phase timer", "bossfight.terracota");
         this.setEnabled(true);
         getStyles().add(new TextStyle("title", new AColor(0x00, 0xAA,0xAA,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("separator", new AColor(0x55, 0x55,0x55,255), new AColor(0, 0,0,0), false));
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/boss/FeatureThornBearPercentage.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/boss/FeatureThornBearPercentage.java
index e17164fb..0c712337 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/boss/FeatureThornBearPercentage.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/boss/FeatureThornBearPercentage.java
@@ -33,7 +33,7 @@ import java.util.List;
 
 public class FeatureThornBearPercentage extends TextHUDFeature {
     public FeatureThornBearPercentage() {
-        super("Dungeon.Bossfight.Floor 4", "Display Spirit Bear Summon Percentage", "Displays spirit bear summon percentage in hud", "bossfight.spiritbear", true, getFontRenderer().getStringWidth("Spirit Bear: 100%"), getFontRenderer().FONT_HEIGHT);
+        super("Dungeon.Bossfight.Floor 4", "Display Spirit Bear Summon Percentage", "Displays spirit bear summon percentage in hud", "bossfight.spiritbear");
         this.setEnabled(true);
         getStyles().add(new TextStyle("title", new AColor(0x00, 0xAA,0xAA,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("separator", new AColor(0x55, 0x55,0x55,255), new AColor(0, 0,0,0), false));
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/boss/FeatureThornSpiritBowTimer.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/boss/FeatureThornSpiritBowTimer.java
index afbd8468..11ea4247 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/boss/FeatureThornSpiritBowTimer.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/boss/FeatureThornSpiritBowTimer.java
@@ -37,7 +37,7 @@ import java.util.List;
 
 public class FeatureThornSpiritBowTimer extends TextHUDFeature {
     public FeatureThornSpiritBowTimer() {
-        super("Dungeon.Bossfight.Floor 4", "Display Spirit bow timer", "Displays how long until spirit bow gets destroyed", "bossfight.spiritbowdisplay", false, getFontRenderer().getStringWidth("Spirit Bow Destruction: 2m 00s"), getFontRenderer().FONT_HEIGHT);
+        super("Dungeon.Bossfight.Floor 4", "Display Spirit bow timer", "Displays how long until spirit bow gets destroyed", "bossfight.spiritbowdisplay");
         getStyles().add(new TextStyle("title", new AColor(0x00, 0xAA,0xAA,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("separator", new AColor(0x55, 0x55,0x55,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("time", new AColor(0x55, 0xFF,0xFF,255), new AColor(0, 0,0,0), false));
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonCurrentRoomSecrets.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonCurrentRoomSecrets.java
index 257f571b..5b408f5f 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonCurrentRoomSecrets.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonCurrentRoomSecrets.java
@@ -34,7 +34,7 @@ import java.util.List;
 
 public class FeatureDungeonCurrentRoomSecrets extends TextHUDFeature {
     public FeatureDungeonCurrentRoomSecrets() {
-        super("Dungeon.HUDs", "Display # Secrets in current room", "Display what your actionbar says", "dungeon.stats.secretsroom", true, getFontRenderer().getStringWidth("Secrets In Room: 8/8"), getFontRenderer().FONT_HEIGHT);
+        super("Dungeon.HUDs", "Display # Secrets in current room", "Display what your actionbar says", "dungeon.stats.secretsroom");
         this.setEnabled(false);
         getStyles().add(new TextStyle("title", new AColor(0x00, 0xAA,0xAA,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("separator", new AColor(0x55, 0x55,0x55,255), new AColor(0, 0,0,0), false));
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonDeaths.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonDeaths.java
index f2fdaaf1..3b961cef 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonDeaths.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonDeaths.java
@@ -26,7 +26,6 @@ import kr.syeyoung.dungeonsguide.mod.config.types.AColor;
 import kr.syeyoung.dungeonsguide.mod.dungeon.DungeonContext;
 import kr.syeyoung.dungeonsguide.mod.dungeon.events.impl.DungeonDeathEvent;
 import kr.syeyoung.dungeonsguide.mod.events.annotations.DGEventHandler;
-import kr.syeyoung.dungeonsguide.mod.events.impl.DungeonEndedEvent;
 import kr.syeyoung.dungeonsguide.mod.events.impl.DungeonLeftEvent;
 import kr.syeyoung.dungeonsguide.mod.features.text.StyledText;
 import kr.syeyoung.dungeonsguide.mod.features.text.TextHUDFeature;
@@ -36,8 +35,6 @@ import kr.syeyoung.dungeonsguide.mod.parallelUniverse.tab.TabListEntry;
 import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
 import lombok.Getter;
 import net.minecraft.client.Minecraft;
-import net.minecraft.client.network.NetworkPlayerInfo;
-import net.minecraft.scoreboard.ScorePlayerTeam;
 import net.minecraft.util.ChatComponentText;
 import net.minecraftforge.client.event.ClientChatReceivedEvent;
 
@@ -47,7 +44,7 @@ import java.util.regex.Pattern;
 
 public class FeatureDungeonDeaths extends TextHUDFeature {
     public FeatureDungeonDeaths() {
-        super("Dungeon.HUDs", "Display Deaths", "Display names of player and death count in dungeon run", "dungeon.stats.deaths", false, getFontRenderer().getStringWidth("longestplayernamepos: 100"), getFontRenderer().FONT_HEIGHT * 6);
+        super("Dungeon.HUDs", "Display Deaths", "Display names of player and death count in dungeon run", "dungeon.stats.deaths");
         this.setEnabled(false);
         getStyles().add(new TextStyle("username", new AColor(0x00, 0xAA,0xAA,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("total", new AColor(0x00, 0xAA,0xAA,255), new AColor(0, 0,0,0), false));
@@ -64,11 +61,6 @@ public class FeatureDungeonDeaths extends TextHUDFeature {
         return context != null;
     }
 
-    @Override
-    public boolean doesScaleWithHeight() {
-        return false;
-    }
-
     @Override
     public List<String> getUsedTextStyle() {
         return Arrays.asList("username", "separator", "deaths", "total", "totalDeaths");
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonMap.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonMap.java
index 81462602..a087a15b 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonMap.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonMap.java
@@ -23,6 +23,7 @@ import com.google.common.collect.Ordering;
 import kr.syeyoung.dungeonsguide.mod.DungeonsGuide;
 import kr.syeyoung.dungeonsguide.mod.chat.ChatTransmitter;
 import kr.syeyoung.dungeonsguide.mod.config.types.AColor;
+import kr.syeyoung.dungeonsguide.mod.config.types.GUIPosition;
 import kr.syeyoung.dungeonsguide.mod.dungeon.DungeonContext;
 import kr.syeyoung.dungeonsguide.mod.dungeon.map.DungeonRoomScaffoldParser;
 import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
@@ -32,6 +33,7 @@ import kr.syeyoung.dungeonsguide.mod.events.impl.DungeonEndedEvent;
 import kr.syeyoung.dungeonsguide.mod.events.impl.DungeonStartedEvent;
 import kr.syeyoung.dungeonsguide.mod.features.FeatureParameter;
 import kr.syeyoung.dungeonsguide.mod.features.RawRenderingGuiFeature;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Size;
 import kr.syeyoung.dungeonsguide.mod.parallelUniverse.tab.TabList;
 import kr.syeyoung.dungeonsguide.mod.parallelUniverse.tab.TabListEntry;
 import kr.syeyoung.dungeonsguide.mod.utils.RenderUtils;
@@ -131,18 +133,19 @@ public class FeatureDungeonMap extends RawRenderingGuiFeature {
         DungeonRoomScaffoldParser mapProcessor = context.getScaffoldParser();
 
         MapData mapData = mapProcessor.getLatestMapData();
-        Rectangle featureRect = getFeatureRect().getRectangle();
-        Gui.drawRect(0, 0, featureRect.width, featureRect.height, RenderUtils.getColorAt(featureRect.x, featureRect.y, backgroudColor));
+        GUIPosition featureSize = getFeatureRect();
+        // TODO: redo chroma
+        Gui.drawRect(0, 0, featureSize.getWidth().intValue(), featureSize.getHeight().intValue(), RenderUtils.getColorAt(0,0, backgroudColor));
         GlStateManager.color(1, 1, 1, 1);
         GlStateManager.pushMatrix();
         if (mapData == null) {
-            Gui.drawRect(0, 0, featureRect.width, featureRect.height, 0xFFFF0000);
+            Gui.drawRect(0, 0, featureSize.getWidth().intValue(), featureSize.getHeight().intValue(), 0xFFFF0000);
         } else {
             renderMap(partialTicks, mapProcessor, mapData, context);
         }
         GlStateManager.popMatrix();
         GL11.glLineWidth(2);
-        RenderUtils.drawUnfilledBox(0, 0, featureRect.width, featureRect.height, this.<AColor>getParameter("border_color").getValue());
+        RenderUtils.drawUnfilledBox(0, 0, featureSize.getWidth().intValue(), featureSize.getHeight().intValue(), this.<AColor>getParameter("border_color").getValue());
     }
 
     @Override
@@ -152,16 +155,16 @@ public class FeatureDungeonMap extends RawRenderingGuiFeature {
             drawHUD(partialTicks);
             return;
         }
-        Rectangle featureRect = getFeatureRect().getRectangle();
-        Gui.drawRect(0, 0, featureRect.width, featureRect.height, RenderUtils.getColorAt(featureRect.x, featureRect.y, backgroudColor));
+        GUIPosition featureRect = getFeatureRect();
+        Gui.drawRect(0, 0, featureRect.getWidth().intValue(), featureRect.getWidth().intValue(), RenderUtils.getColorAt(0,0, backgroudColor));
         FontRenderer fr = getFontRenderer();
 
         GlStateManager.enableBlend();
         GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
         GlStateManager.tryBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
-        fr.drawString("Please join a dungeon to see preview", featureRect.width / 2 - fr.getStringWidth("Please join a dungeon to see preview") / 2, featureRect.height / 2 - fr.FONT_HEIGHT / 2, 0xFFFFFFFF);
+        fr.drawString("Please join a dungeon to see preview", featureRect.getWidth().intValue() / 2 - fr.getStringWidth("Please join a dungeon to see preview") / 2, featureRect.getWidth().intValue() / 2 - fr.FONT_HEIGHT / 2, 0xFFFFFFFF);
         GL11.glLineWidth(2);
-        RenderUtils.drawUnfilledBox(0, 0, featureRect.width, featureRect.height, this.<AColor>getParameter("border_color").getValue());
+        RenderUtils.drawUnfilledBox(0, 0, featureRect.getWidth().intValue(), featureRect.getWidth().intValue(), this.<AColor>getParameter("border_color").getValue());
     }
 
     public void renderMap(float partialTicks, DungeonRoomScaffoldParser mapProcessor, MapData mapData, DungeonContext context) {
@@ -169,8 +172,8 @@ public class FeatureDungeonMap extends RawRenderingGuiFeature {
 
         float postScale = this.centerMapOnPlayer ? postscaleOfMap : 1;
 
-        Rectangle featureRect = getFeatureRect().getRectangle();
-        int width = featureRect.width;
+        GUIPosition featureRect = getFeatureRect();
+        int width = featureRect.getWidth().intValue();
 
         float scale = shouldScale ? width / 128.0f : 1;
 
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonMilestone.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonMilestone.java
index 7fcb9c06..0db654c4 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonMilestone.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonMilestone.java
@@ -25,7 +25,6 @@ import kr.syeyoung.dungeonsguide.mod.chat.ChatTransmitter;
 import kr.syeyoung.dungeonsguide.mod.config.types.AColor;
 import kr.syeyoung.dungeonsguide.mod.dungeon.DungeonContext;
 import kr.syeyoung.dungeonsguide.mod.events.annotations.DGEventHandler;
-import kr.syeyoung.dungeonsguide.mod.events.impl.DungeonEndedEvent;
 import kr.syeyoung.dungeonsguide.mod.events.impl.DungeonLeftEvent;
 import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
 import kr.syeyoung.dungeonsguide.mod.features.text.StyledText;
@@ -35,9 +34,6 @@ import kr.syeyoung.dungeonsguide.mod.parallelUniverse.tab.TabList;
 import kr.syeyoung.dungeonsguide.mod.parallelUniverse.tab.TabListEntry;
 import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
 import lombok.Getter;
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.network.NetworkPlayerInfo;
-import net.minecraft.scoreboard.ScorePlayerTeam;
 import net.minecraft.util.ChatComponentText;
 import net.minecraftforge.client.event.ClientChatReceivedEvent;
 
@@ -48,7 +44,7 @@ import java.util.regex.Pattern;
 
 public class FeatureDungeonMilestone extends TextHUDFeature {
     public FeatureDungeonMilestone() {
-        super("Dungeon.HUDs", "Display Current Class Milestone", "Display current class milestone of yourself", "dungeon.stats.milestone", true, getFontRenderer().getStringWidth("Milestone: 12"), getFontRenderer().FONT_HEIGHT);
+        super("Dungeon.HUDs", "Display Current Class Milestone", "Display current class milestone of yourself", "dungeon.stats.milestone");
         this.setEnabled(false);
         getStyles().add(new TextStyle("title", new AColor(0x00, 0xAA,0xAA,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("separator", new AColor(0x55, 0x55,0x55,255), new AColor(0, 0,0,0), false));
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonRealTime.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonRealTime.java
index 804bd1ee..832d4f8c 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonRealTime.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonRealTime.java
@@ -34,7 +34,7 @@ import java.util.List;
 
 public class FeatureDungeonRealTime extends TextHUDFeature {
     public FeatureDungeonRealTime() {
-        super("Dungeon.HUDs", "Display Real Time-Dungeon Time", "Display how much real time has passed since dungeon run started", "dungeon.stats.realtime", true, getFontRenderer().getStringWidth("Time(Real): 59m 59s"), getFontRenderer().FONT_HEIGHT);
+        super("Dungeon.HUDs", "Display Real Time-Dungeon Time", "Display how much real time has passed since dungeon run started", "dungeon.stats.realtime");
         this.setEnabled(false);
         getStyles().add(new TextStyle("title", new AColor(0x00, 0xAA,0xAA,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("discriminator", new AColor(0xAA,0xAA,0xAA,255), new AColor(0, 0,0,0), false));
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonRoomName.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonRoomName.java
index 0e12fe34..ed006124 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonRoomName.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonRoomName.java
@@ -37,7 +37,7 @@ import java.util.List;
 
 public class FeatureDungeonRoomName extends TextHUDFeature {
     public FeatureDungeonRoomName() {
-        super("Dungeon.HUDs", "Display name of the room you are in", "Display name of the room you are in", "dungeon.roomname", false, getFontRenderer().getStringWidth("You're in puzzle-tictactoe"), getFontRenderer().FONT_HEIGHT);
+        super("Dungeon.HUDs", "Display name of the room you are in", "Display name of the room you are in", "dungeon.roomname");
         getStyles().add(new TextStyle("in", new AColor(0x00, 0xAA,0xAA,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("roomname", new AColor(0x55, 0xFF,0xFF,255), new AColor(0, 0,0,0), false));
     }
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonSBTime.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonSBTime.java
index dfe67f9e..909bdbaa 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonSBTime.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonSBTime.java
@@ -41,7 +41,7 @@ public class FeatureDungeonSBTime extends TextHUDFeature {
     private final SkyblockStatus skyblockStatus = DungeonsGuide.getDungeonsGuide().getSkyblockStatus();
 
     public FeatureDungeonSBTime() {
-        super("Dungeon.HUDs", "Display Ingame Dungeon Time", "Display how much time skyblock thinks has passed since dungeon run started", "dungeon.stats.igtime", true, getFontRenderer().getStringWidth("Time(IG): 1h 59m 59s"), getFontRenderer().FONT_HEIGHT);
+        super("Dungeon.HUDs", "Display Ingame Dungeon Time", "Display how much time skyblock thinks has passed since dungeon run started", "dungeon.stats.igtime");
         this.setEnabled(false);
         getStyles().add(new TextStyle("title", new AColor(0x00, 0xAA,0xAA,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("discriminator", new AColor(0xAA,0xAA,0xAA,255), new AColor(0, 0,0,0), false));
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonScore.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonScore.java
index 3897a8a5..0926bdb9 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonScore.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonScore.java
@@ -48,7 +48,7 @@ import java.util.concurrent.ExecutionException;
 
 public class FeatureDungeonScore extends TextHUDFeature {
     public FeatureDungeonScore() {
-        super("Dungeon.HUDs", "Display Current Score", "Calculate and Display current score\nThis data is from pure calculation and can be different from actual score.", "dungeon.stats.score", false, 200, getFontRenderer().FONT_HEIGHT * 4);
+        super("Dungeon.HUDs", "Display Current Score", "Calculate and Display current score\nThis data is from pure calculation and can be different from actual score.", "dungeon.stats.score");
         this.setEnabled(false);
         addParameter("verbose", new FeatureParameter<Boolean>("verbose", "Show each score instead of sum", "Skill: 100 Explore: 58 S->S+(5 tombs) instead of Score: 305", true, "boolean"));
 
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonSecrets.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonSecrets.java
index 5bc642ac..da9553a9 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonSecrets.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonSecrets.java
@@ -37,7 +37,7 @@ import java.util.List;
 
 public class FeatureDungeonSecrets extends TextHUDFeature {
     public FeatureDungeonSecrets() {
-        super("Dungeon.HUDs", "Display Total # of Secrets", "Display how much total secrets have been found in a dungeon run.\n+ sign means DG does not know the correct number, but it's somewhere above that number.", "dungeon.stats.secrets", true, getFontRenderer().getStringWidth("Secrets: 999/999+ of 999+"), getFontRenderer().FONT_HEIGHT);
+        super("Dungeon.HUDs", "Display Total # of Secrets", "Display how much total secrets have been found in a dungeon run.\n+ sign means DG does not know the correct number, but it's somewhere above that number.", "dungeon.stats.secrets");
         this.setEnabled(false);
         getStyles().add(new TextStyle("title", new AColor(0x00, 0xAA,0xAA,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("separator", new AColor(0x55, 0x55,0x55,255), new AColor(0, 0,0,0), false));
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonTombs.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonTombs.java
index 72a09dd7..f62d755f 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonTombs.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureDungeonTombs.java
@@ -28,9 +28,6 @@ import kr.syeyoung.dungeonsguide.mod.features.text.TextStyle;
 import kr.syeyoung.dungeonsguide.mod.parallelUniverse.tab.TabList;
 import kr.syeyoung.dungeonsguide.mod.parallelUniverse.tab.TabListEntry;
 import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
-import net.minecraft.client.Minecraft;
-import net.minecraft.client.network.NetworkPlayerInfo;
-import net.minecraft.scoreboard.ScorePlayerTeam;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -38,7 +35,7 @@ import java.util.List;
 
 public class FeatureDungeonTombs extends TextHUDFeature {
     public FeatureDungeonTombs() {
-        super("Dungeon.HUDs", "Display # of Crypts", "Display how much total crypts have been blown up in a dungeon run", "dungeon.stats.tombs", true, getFontRenderer().getStringWidth("Crypts: 42"), getFontRenderer().FONT_HEIGHT);
+        super("Dungeon.HUDs", "Display # of Crypts", "Display how much total crypts have been blown up in a dungeon run", "dungeon.stats.tombs");
         this.setEnabled(false);
         getStyles().add(new TextStyle("title", new AColor(0x00, 0xAA,0xAA,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("separator", new AColor(0x55, 0x55,0x55,255), new AColor(0, 0,0,0), false));
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureWarnLowHealth.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureWarnLowHealth.java
index bfbab9f3..3396b8dd 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureWarnLowHealth.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureWarnLowHealth.java
@@ -30,10 +30,6 @@ import kr.syeyoung.dungeonsguide.mod.parallelUniverse.scoreboard.Objective;
 import kr.syeyoung.dungeonsguide.mod.parallelUniverse.scoreboard.Score;
 import kr.syeyoung.dungeonsguide.mod.parallelUniverse.scoreboard.ScoreboardManager;
 import kr.syeyoung.dungeonsguide.mod.utils.TextUtils;
-import net.minecraft.client.Minecraft;
-import net.minecraft.scoreboard.ScoreObjective;
-import net.minecraft.scoreboard.ScorePlayerTeam;
-import net.minecraft.scoreboard.Scoreboard;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -42,7 +38,7 @@ import java.util.List;
 
 public class FeatureWarnLowHealth extends TextHUDFeature {
     public FeatureWarnLowHealth() {
-        super("Dungeon.Teammates", "Low Health Warning", "Warn if someone is on low health", "dungeon.lowhealthwarn", false, 500, 20);
+        super("Dungeon.Teammates", "Low Health Warning", "Warn if someone is on low health", "dungeon.lowhealthwarn");
         addParameter("threshold", new FeatureParameter<Integer>("threshold", "Health Threshold", "Health Threshold for this feature to be toggled. default to 500", 500, "integer"));
         getStyles().add(new TextStyle("title", new AColor(0x00, 0xAA,0xAA,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("separator", new AColor(0x55, 0x55,0x55,255), new AColor(0, 0,0,0), false));
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureWatcherWarning.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureWatcherWarning.java
index da8908f2..71241ff3 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureWatcherWarning.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/dungeon/FeatureWatcherWarning.java
@@ -25,7 +25,6 @@ import kr.syeyoung.dungeonsguide.mod.config.types.AColor;
 import kr.syeyoung.dungeonsguide.mod.dungeon.DungeonContext;
 import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
 import kr.syeyoung.dungeonsguide.mod.events.annotations.DGEventHandler;
-import kr.syeyoung.dungeonsguide.mod.events.impl.DungeonEndedEvent;
 import kr.syeyoung.dungeonsguide.mod.events.impl.DungeonLeftEvent;
 import kr.syeyoung.dungeonsguide.mod.features.text.StyledText;
 import kr.syeyoung.dungeonsguide.mod.features.text.TextHUDFeature;
@@ -40,7 +39,7 @@ import java.util.UUID;
 public class FeatureWatcherWarning extends TextHUDFeature  {
 
     public FeatureWatcherWarning() {
-        super("Dungeon.Blood Room","Watcher Spawn Alert", "Alert when watcher says 'That will be enough for now'", "dungen.watcherwarn", true, getFontRenderer().getStringWidth("Watcher finished spawning all mobs!"), getFontRenderer().FONT_HEIGHT);
+        super("Dungeon.Blood Room","Watcher Spawn Alert", "Alert when watcher says 'That will be enough for now'", "dungen.watcherwarn");
         getStyles().add(new TextStyle("warning", new AColor(0xFF, 0x69,0x17,255), new AColor(0, 0,0,0), false));
         setEnabled(false);
     }
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/etc/FeatureCooldownCounter.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/etc/FeatureCooldownCounter.java
index 1360db60..e879e45c 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/etc/FeatureCooldownCounter.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/etc/FeatureCooldownCounter.java
@@ -35,7 +35,7 @@ import java.util.List;
 
 public class FeatureCooldownCounter extends TextHUDFeature {
     public FeatureCooldownCounter() {
-        super("Dungeon", "Dungeon Cooldown Counter", "Counts 10 seconds after leaving dungeon", "qol.cooldown", true, getFontRenderer().getStringWidth("Cooldown: 10s "), getFontRenderer().FONT_HEIGHT);
+        super("Dungeon", "Dungeon Cooldown Counter", "Counts 10 seconds after leaving dungeon", "qol.cooldown");
         getStyles().add(new TextStyle("title", new AColor(0x00, 0xAA,0xAA,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("separator", new AColor(0x55, 0x55,0x55,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("number", new AColor(0x55, 0xFF,0xFF,255), new AColor(0, 0,0,0), false));
@@ -74,11 +74,6 @@ public class FeatureCooldownCounter extends TextHUDFeature {
         return actualBit;
     }
 
-    @Override
-    public boolean doesScaleWithHeight() {
-        return true;
-    }
-
     @DGEventHandler
     public void onDungeonQuit(DungeonLeftEvent event) {
         leftDungeonTime = System.currentTimeMillis();
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/etc/ability/FeatureAbilityCooldown.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/etc/ability/FeatureAbilityCooldown.java
index 33241613..68d4bf8b 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/etc/ability/FeatureAbilityCooldown.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/etc/ability/FeatureAbilityCooldown.java
@@ -42,7 +42,7 @@ import java.util.regex.Pattern;
 public class FeatureAbilityCooldown extends TextHUDFeature {
 
     public FeatureAbilityCooldown() {
-        super("Misc", "View Ability Cooldowns", "A handy hud for viewing cooldown abilities", "etc.abilitycd2", false, 100, getFontRenderer().FONT_HEIGHT * 5);
+        super("Misc", "View Ability Cooldowns", "A handy hud for viewing cooldown abilities", "etc.abilitycd2");
         getStyles().add(new TextStyle("abilityname", new AColor(0x00, 0xAA,0xAA,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("separator", new AColor(0x55, 0x55,0x55,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("number", new AColor(0x55, 0xFF,0xFF,255), new AColor(0, 0,0,0), false));
@@ -57,11 +57,6 @@ public class FeatureAbilityCooldown extends TextHUDFeature {
         return SkyblockStatus.isOnSkyblock() && (!this.<Boolean>getParameter("disable").getValue() || (this.<Boolean>getParameter("disable").getValue() && SkyblockStatus.isOnSkyblock()));
     }
 
-    @Override
-    public boolean doesScaleWithHeight() {
-        return false;
-    }
-
     @Override
     public List<String> getUsedTextStyle() {
         return Arrays.asList("abilityname", "separator", "number", "unit", "ready");
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/party/FeaturePartyList.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/party/FeaturePartyList.java
index 5618ae05..229bcfaf 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/party/FeaturePartyList.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/party/FeaturePartyList.java
@@ -32,7 +32,7 @@ import java.util.List;
 
 public class FeaturePartyList extends TextHUDFeature {
     public FeaturePartyList() {
-        super("Party","Party List", "Party List as GUI", "party.list", false, getFontRenderer().getStringWidth("Watcher finished spawning all mobs!"), getFontRenderer().FONT_HEIGHT*4);
+        super("Party","Party List", "Party List as GUI", "party.list");
         getStyles().add(new TextStyle("name", new AColor(0x00, 0xAA,0xAA,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("separator", new AColor(0x55, 0x55,0x55,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("player", new AColor(0x55, 0xFF,0xFF,255), new AColor(0, 0,0,0), false));
@@ -69,11 +69,6 @@ public class FeaturePartyList extends TextHUDFeature {
         return dummyText;
     }
 
-    @Override
-    public boolean doesScaleWithHeight() {
-        return false;
-    }
-
     @Override
     public List<StyledText> getText() {
         PartyContext pc = PartyManager.INSTANCE.getPartyContext();
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/party/FeaturePartyReady.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/party/FeaturePartyReady.java
index d899fe18..f061188b 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/party/FeaturePartyReady.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/party/FeaturePartyReady.java
@@ -35,7 +35,7 @@ import java.util.*;
 
 public class FeaturePartyReady extends TextHUDFeature {
     public FeaturePartyReady() {
-        super("Party","Party Ready List", "Check if your party member have said r or not", "party.readylist", false, getFontRenderer().getStringWidth("Watcher finished spawning all mobs!"), getFontRenderer().FONT_HEIGHT*4);
+        super("Party","Party Ready List", "Check if your party member have said r or not", "party.readylist");
         getStyles().add(new TextStyle("player", new AColor(0x00, 0xAA,0xAA,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("separator", new AColor(0x55, 0x55,0x55,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("ready", new AColor(0x55, 0xFF,0xFF,255), new AColor(0, 0,0,0), false));
@@ -83,11 +83,6 @@ public class FeaturePartyReady extends TextHUDFeature {
         return dummyText;
     }
 
-    @Override
-    public boolean doesScaleWithHeight() {
-        return false;
-    }
-
     private Set<String> ready = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
     private Map<String, String> terminal = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
 
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/secret/FeatureActions.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/secret/FeatureActions.java
index 4bf5642a..0622c683 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/secret/FeatureActions.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/secret/FeatureActions.java
@@ -40,7 +40,7 @@ import java.util.List;
 
 public class FeatureActions extends TextHUDFeature {
     public FeatureActions() {
-        super("Dungeon.Secrets", "Action Viewer", "View List of actions that needs to be taken", "secret.actionview", false, 200, getFontRenderer().FONT_HEIGHT * 10);
+        super("Dungeon.Secrets", "Action Viewer", "View List of actions that needs to be taken", "secret.actionview");
 
         getStyles().add(new TextStyle("pathfinding", new AColor(0x00, 0xAA,0xAA,255), new AColor(0, 0,0,0), false));
         getStyles().add(new TextStyle("mechanic", new AColor(0x55, 0xFF,0x55,255), new AColor(0, 0,0,0), false));
@@ -54,11 +54,6 @@ public class FeatureActions extends TextHUDFeature {
     }
 
 
-    @Override
-    public boolean doesScaleWithHeight() {
-        return false;
-    }
-
     @Override
     public boolean isHUDViewable() {
         if (!SkyblockStatus.isOnDungeon()) return false;
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/secret/FeatureSoulRoomWarning.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/secret/FeatureSoulRoomWarning.java
index cc41d233..3ccba58e 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/secret/FeatureSoulRoomWarning.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/secret/FeatureSoulRoomWarning.java
@@ -59,7 +59,7 @@ import java.util.function.Predicate;
 public class FeatureSoulRoomWarning extends TextHUDFeature {
 
     public FeatureSoulRoomWarning() {
-        super("Dungeon.HUDs","Secret Soul Alert", "Alert if there is an fairy soul in the room", "secret.fairysoulwarn", true, getFontRenderer().getStringWidth("There is a fairy soul in this room!"), getFontRenderer().FONT_HEIGHT);
+        super("Dungeon.HUDs","Secret Soul Alert", "Alert if there is an fairy soul in the room", "secret.fairysoulwarn");
         getStyles().add(new TextStyle("warning", new AColor(0xFF, 0x69,0x17,255), new AColor(0, 0,0,0), false));
 
         addParameter("roomuids", new FeatureParameter("roomuids", "Disabled room Names", "Disable for these rooms", new ArrayList<>(), "stringlist"));
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/secret/mechanicbrowser/FeatureMechanicBrowse.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/secret/mechanicbrowser/FeatureMechanicBrowse.java
index b5e67a5d..573c274e 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/secret/mechanicbrowser/FeatureMechanicBrowse.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/secret/mechanicbrowser/FeatureMechanicBrowse.java
@@ -22,6 +22,7 @@ package kr.syeyoung.dungeonsguide.mod.features.impl.secret.mechanicbrowser;
 import kr.syeyoung.dungeonsguide.mod.DungeonsGuide;
 import kr.syeyoung.dungeonsguide.mod.SkyblockStatus;
 import kr.syeyoung.dungeonsguide.mod.config.guiconfig.location.GuiGuiLocationConfig;
+import kr.syeyoung.dungeonsguide.mod.config.types.GUIPosition;
 import kr.syeyoung.dungeonsguide.mod.dungeon.DungeonContext;
 import kr.syeyoung.dungeonsguide.mod.dungeon.actions.tree.ActionRoute;
 import kr.syeyoung.dungeonsguide.mod.dungeon.roomfinder.DungeonRoom;
@@ -33,7 +34,8 @@ import kr.syeyoung.dungeonsguide.mod.features.RawRenderingGuiFeature;
 import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
 import kr.syeyoung.dungeonsguide.mod.gui.elements.MFloatSelectionButton;
 import kr.syeyoung.dungeonsguide.mod.gui.elements.MPassiveLabelAndElement;
-import kr.syeyoung.dungeonsguide.mod.overlay.GUIRectanglePositioner;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Size;
+import kr.syeyoung.dungeonsguide.mod.overlay.GUIRectPositioner;
 import kr.syeyoung.dungeonsguide.mod.overlay.OverlayManager;
 import kr.syeyoung.dungeonsguide.mod.overlay.OverlayType;
 import kr.syeyoung.dungeonsguide.mod.overlay.OverlayWidget;
@@ -77,8 +79,8 @@ public class FeatureMechanicBrowse extends RawRenderingGuiFeature {
         double scale = FeatureMechanicBrowse.this.<Float>getParameter("scale").getValue();
         GlStateManager.scale(scale, scale, 1.0);
 
-        Dimension bigDim = getFeatureRect().getRectangleNoScale().getSize();
-        Dimension effectiveDim = new Dimension((int) (bigDim.width / scale),(int)( bigDim.height / scale));
+        GUIPosition bigDim = getFeatureRect();
+        Dimension effectiveDim = new Dimension((int) (bigDim.getWidth() / scale),(int)( bigDim.getHeight() / scale));
 
         FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
         Gui.drawRect(0, 0, effectiveDim.width, fr.FONT_HEIGHT + 4, 0xFF444444);
@@ -108,8 +110,8 @@ public class FeatureMechanicBrowse extends RawRenderingGuiFeature {
         double scale = FeatureMechanicBrowse.this.<Float>getParameter("scale").getValue();
         GlStateManager.scale(scale, scale, 1.0);
 
-        Dimension bigDim = getFeatureRect().getRectangleNoScale().getSize();
-        Dimension effectiveDim = new Dimension((int) (bigDim.width / scale),(int)( bigDim.height / scale));
+        GUIPosition bigDim = getFeatureRect();
+        Dimension effectiveDim = new Dimension((int) (bigDim.getWidth() / scale),(int)( bigDim.getHeight() / scale));
 
         FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
         Gui.drawRect(0, 0, effectiveDim.width, fr.FONT_HEIGHT + 4, 0xFF444444);
@@ -199,7 +201,7 @@ public class FeatureMechanicBrowse extends RawRenderingGuiFeature {
                     OverlayManager.getInstance().removeOverlay(lastOpen);
                 widget = new OverlayWidget(
                     mechanicBrowser = new WidgetMechanicBrowser(dungeonRoomOpt.get()),
-                    OverlayType.OVER_CHAT, new GUIRectanglePositioner(this::getFeatureRect));
+                    OverlayType.OVER_CHAT, new GUIRectPositioner(this::getFeatureRect));
             }
         }
         if (mechanicBrowser != null)
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/text/TextHUDFeature.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/text/TextHUDFeature.java
index 7debd1f0..5e1c9554 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/text/TextHUDFeature.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/text/TextHUDFeature.java
@@ -25,6 +25,7 @@ import kr.syeyoung.dungeonsguide.mod.config.guiconfig.MFeatureEdit;
 import kr.syeyoung.dungeonsguide.mod.config.guiconfig.MParameterEdit;
 import kr.syeyoung.dungeonsguide.mod.config.guiconfig.RootConfigPanel;
 import kr.syeyoung.dungeonsguide.mod.config.guiconfig.location.GuiGuiLocationConfig;
+import kr.syeyoung.dungeonsguide.mod.config.guiconfig.location2.MarkerProvider;
 import kr.syeyoung.dungeonsguide.mod.config.types.AColor;
 import kr.syeyoung.dungeonsguide.mod.events.annotations.DGEventHandler;
 import kr.syeyoung.dungeonsguide.mod.events.impl.DGTickEvent;
@@ -34,13 +35,18 @@ import kr.syeyoung.dungeonsguide.mod.gui.MPanel;
 import kr.syeyoung.dungeonsguide.mod.gui.elements.MFloatSelectionButton;
 import kr.syeyoung.dungeonsguide.mod.gui.elements.MPassiveLabelAndElement;
 import kr.syeyoung.dungeonsguide.mod.gui.elements.MStringSelectionButton;
+import kr.syeyoung.dungeonsguide.mod.guiv2.DomElement;
+import kr.syeyoung.dungeonsguide.mod.guiv2.Widget;
 import kr.syeyoung.dungeonsguide.mod.guiv2.elements.richtext.BreakWord;
 import kr.syeyoung.dungeonsguide.mod.guiv2.elements.richtext.RichText;
 import kr.syeyoung.dungeonsguide.mod.guiv2.elements.richtext.TextSpan;
 import kr.syeyoung.dungeonsguide.mod.guiv2.elements.richtext.styles.ParentDelegatingTextStyle;
-import kr.syeyoung.dungeonsguide.mod.overlay.GUIRectanglePositioner;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Position;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Rect;
+import kr.syeyoung.dungeonsguide.mod.overlay.GUIRectPositioner;
 import kr.syeyoung.dungeonsguide.mod.overlay.OverlayType;
 import kr.syeyoung.dungeonsguide.mod.overlay.OverlayWidget;
+import lombok.RequiredArgsConstructor;
 import net.minecraft.client.Minecraft;
 import net.minecraft.client.gui.FontRenderer;
 import net.minecraft.client.renderer.GlStateManager;
@@ -48,8 +54,8 @@ import net.minecraft.client.renderer.GlStateManager;
 import java.util.*;
 
 public abstract class TextHUDFeature extends AbstractHUDFeature implements StyledTextProvider {
-    protected TextHUDFeature(String category, String name, String description, String key, boolean keepRatio, int width, int height) {
-        super(category, name, description, key, keepRatio, width, height);
+    protected TextHUDFeature(String category, String name, String description, String key) {
+        super(category, name, description, key);
         addParameter("textStylesNEW", new FeatureParameter<List<TextStyle>>("textStylesNEW", "", "", new ArrayList<TextStyle>(), "list_textStyle"));
         addParameter("alignment", new FeatureParameter<String>("alignment", "Alignment", "Alignment", "LEFT", "string", (change) -> {
             richText.setAlign(
@@ -69,11 +75,11 @@ public abstract class TextHUDFeature extends AbstractHUDFeature implements Style
     private final RichText richText = new RichText(new TextSpan(
             ParentDelegatingTextStyle.ofDefault(),
             ""
-    ), BreakWord.WORD, true, RichText.TextAlign.LEFT);
+    ), BreakWord.WORD, false, RichText.TextAlign.LEFT);
 
     @Override
     public OverlayWidget instantiateWidget() {
-        return new OverlayWidget(richText, OverlayType.UNDER_CHAT, new GUIRectanglePositioner(this::getFeatureRect));
+        return new OverlayWidget(richText, OverlayType.UNDER_CHAT, new GUIRectPositioner(this::getFeatureRect));
     }
 
     private Map<String, ParentDelegatingTextStyle> builtTextStyles = new HashMap<>();
@@ -86,12 +92,7 @@ public abstract class TextHUDFeature extends AbstractHUDFeature implements Style
                 List<StyledText> asd = getText();
 
                 ParentDelegatingTextStyle defaultStyle = ParentDelegatingTextStyle.ofDefault();
-                if (doesScaleWithHeight()) {
-                    if (getWidget() == null || getWidget().getDomElement() == null || getWidget().getDomElement().getSize() == null) return;
-                    defaultStyle.setSize(getFeatureRect().getRectangleNoScale().getHeight() / countLines(asd));
-                } else {
-                    defaultStyle.setSize((double) (this.<Float>getParameter("scale").getValue() * 8));
-                }
+                defaultStyle.setSize((double) (this.<Float>getParameter("scale").getValue() * 8));
 
                 TextSpan span = new TextSpan(defaultStyle, "");
 
@@ -111,26 +112,78 @@ public abstract class TextHUDFeature extends AbstractHUDFeature implements Style
         return Minecraft.getMinecraft().fontRendererObj;
     }
 
-    public boolean doesScaleWithHeight() {
-        return true;
-    }
-
     @Override
     public void drawDemo(float partialTicks) {
         List<StyledText> asd = getDummyText();
-        double scale = 1;
-        if (doesScaleWithHeight()) {
-            FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
-            scale = getFeatureRect().getRectangle().getHeight() / (fr.FONT_HEIGHT* countLines(asd));
-        } else {
-            scale = this.<Float>getParameter("scale").getValue();
-        }
+        double scale = this.<Float>getParameter("scale").getValue();
         GlStateManager.scale(scale, scale, 0);
 
-        StyledTextRenderer.drawTextWithStylesAssociated(asd, 0, 0, (int) (Math.abs(getFeatureRect().getWidth())/scale), getStylesMap(),
+        StyledTextRenderer.drawTextWithStylesAssociated(asd, 0, 0, 100, getStylesMap(),
                 StyledTextRenderer.Alignment.valueOf(TextHUDFeature.this.<String>getParameter("alignment").getValue()));
     }
 
+    @RequiredArgsConstructor
+    public static class TextHUDDemo extends Widget implements MarkerProvider {
+        public final TextHUDFeature hudFeature;
+        @Override
+        public List<Position> getMarkers() {
+            String change = hudFeature.<String>getParameter("alignment").getValue();
+            Rect relBound = getDomElement().getRelativeBound();
+            if (change.equals("LEFT")) {
+                return Arrays.asList(
+                        new Position(0, 0),
+                        new Position(0, relBound.getHeight())
+                );
+            } else if (change.equals("CENTER")) {
+                return Arrays.asList(
+                        new Position(relBound.getWidth() /2, 0),
+                        new Position(relBound.getWidth() /2, relBound.getHeight())
+                );
+            } else if (change.equals("RIGHT")) {
+                return Arrays.asList(
+                        new Position(relBound.getWidth(), 0),
+                        new Position(relBound.getWidth(), relBound.getHeight())
+                );
+            }
+            return null;
+        }
+
+        @Override
+        public List<Widget> build(DomElement buildContext) {
+            List<StyledText> asd = hudFeature.getDummyText();
+
+            RichText richText = new RichText(new TextSpan(
+                    ParentDelegatingTextStyle.ofDefault(),
+                    ""
+            ), BreakWord.WORD, false, RichText.TextAlign.LEFT);
+            String change = hudFeature.<String>getParameter("alignment").getValue();
+            richText.setAlign(
+                    change.equals("LEFT") ? RichText.TextAlign.LEFT :
+                            change.equals("CENTER") ? RichText.TextAlign.CENTER :
+                                    change.equals("RIGHT") ? RichText.TextAlign.RIGHT : RichText.TextAlign.LEFT
+            );
+
+            ParentDelegatingTextStyle defaultStyle = ParentDelegatingTextStyle.ofDefault();
+            defaultStyle.setSize((double) (hudFeature.<Float>getParameter("scale").getValue() * 8));
+
+            TextSpan span = new TextSpan(defaultStyle, "");
+
+            for (StyledText styledText : asd) {
+                TextStyle style = hudFeature.getStylesMap().get(styledText.getGroup());
+                TextSpan textSpan = new TextSpan(style.getLinked(), styledText.getText());
+                span.addChild(textSpan);
+            }
+            richText.setRootSpan(span);
+
+            return Collections.singletonList(richText);
+        }
+    }
+
+    @Override
+    public Widget instantiateDemoWidget() {
+        return new TextHUDDemo(this);
+    }
+
     public int countLines(List<StyledText> texts) {
         StringBuilder things = new StringBuilder();
         for (StyledText text : texts) {
@@ -212,13 +265,11 @@ public abstract class TextHUDFeature extends AbstractHUDFeature implements Style
         });
 
         mPanels.add(new MPassiveLabelAndElement("Alignment", mStringSelectionButton));
-        if (!doesScaleWithHeight()) {
-            mPanels.add(new MPassiveLabelAndElement("Scale", new MFloatSelectionButton(TextHUDFeature.this.<Float>getParameter("scale").getValue()) {{
-                setOnUpdate(() ->{
-                    TextHUDFeature.this.<Float>getParameter("scale").setValue(this.getData());
-                }); }
-            }));
-        }
+        mPanels.add(new MPassiveLabelAndElement("Scale", new MFloatSelectionButton(TextHUDFeature.this.<Float>getParameter("scale").getValue()) {{
+            setOnUpdate(() ->{
+                TextHUDFeature.this.<Float>getParameter("scale").setValue(this.getData());
+            }); }
+        }));
 
         return mPanels;
     }
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/DomElement.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/DomElement.java
index 46390e66..f35536be 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/DomElement.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/DomElement.java
@@ -227,23 +227,24 @@ public class DomElement {
 
 
     private boolean wasMouseIn = false;
-    public boolean mouseMoved0(int absMouseX, int absMouseY, double relMouseX0, double relMouseY0) {
+    public boolean mouseMoved0(int absMouseX, int absMouseY, double relMouseX0, double relMouseY0, boolean withinbound) {
         if (absBounds == null) return false;
-        if (!absBounds.contains(absMouseX, absMouseY)) {
+        boolean isIn = absBounds.contains(absMouseX, absMouseY) && withinbound;
+        if (!isIn) {
             if (wasMouseIn) widget.mouseExited(absMouseX, absMouseY, relMouseX0, relMouseY0);
-            wasMouseIn = false;
         } else {
             if (!wasMouseIn) widget.mouseEntered(absMouseX, absMouseY, relMouseX0, relMouseY0);
-            wasMouseIn = true;
         }
+        wasMouseIn = isIn;
+
         for (DomElement childComponent  : children) {
             Position transformed = renderer.transformPoint(childComponent, new Position(relMouseX0, relMouseY0));
 
-            if (childComponent.mouseMoved0(absMouseX, absMouseY,  transformed.x, transformed.getY())) {
+            if (childComponent.mouseMoved0(absMouseX, absMouseY,  transformed.x, transformed.getY(), isIn)) {
                 return true;
             }
         }
-        if (wasMouseIn)
+        if (isIn)
             return widget.mouseMoved(absMouseX, absMouseY, relMouseX0, relMouseY0);
         return false;
     }
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/GuiScreenAdapter.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/GuiScreenAdapter.java
index 902b92c1..907b77ae 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/GuiScreenAdapter.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/GuiScreenAdapter.java
@@ -192,7 +192,7 @@ public class GuiScreenAdapter extends GuiScreen {
     public void mouseMove(int mouseX, int mouseY) {
         try {
             view.mouseMoved0(mouseX, mouseY
-                    , mouseX, mouseY);
+                    , mouseX, mouseY, true);
         } catch (Throwable e) {
             if (e.getMessage() == null || !e.getMessage().contains("hack to stop"))
                 e.printStackTrace();
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/GlobalHUDScale.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/GlobalHUDScale.java
new file mode 100644
index 00000000..1feab6e3
--- /dev/null
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/GlobalHUDScale.java
@@ -0,0 +1,124 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2023  cyoung06 (syeyoung)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.guiv2.elements;
+
+import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
+import kr.syeyoung.dungeonsguide.mod.guiv2.BindableAttribute;
+import kr.syeyoung.dungeonsguide.mod.guiv2.DomElement;
+import kr.syeyoung.dungeonsguide.mod.guiv2.Widget;
+import kr.syeyoung.dungeonsguide.mod.guiv2.layouter.Layouter;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.ConstraintBox;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Position;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Rect;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Size;
+import kr.syeyoung.dungeonsguide.mod.guiv2.renderer.Renderer;
+import kr.syeyoung.dungeonsguide.mod.guiv2.renderer.RenderingContext;
+import kr.syeyoung.dungeonsguide.mod.guiv2.xml.annotations.Export;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.ScaledResolution;
+import net.minecraft.client.renderer.GlStateManager;
+
+import java.util.Collections;
+import java.util.List;
+
+public class GlobalHUDScale extends Widget implements Layouter, Renderer {
+    
+    private final Widget widget;
+    public GlobalHUDScale(Widget widget) {
+        this.widget = widget;
+        scale = getScale();
+    }
+
+
+    private double getScale() {
+        boolean useMc = FeatureRegistry.GLOBAL_HUD_SCALE.<Boolean>getParameter("mc").getValue();
+        if (useMc) return (double) new ScaledResolution(Minecraft.getMinecraft()).getScaleFactor();
+        else return FeatureRegistry.GLOBAL_HUD_SCALE.<Float>getParameter("scale").getValue();
+    }
+    
+    private double scale;
+
+
+    @Override
+    public List<Widget> build(DomElement buildContext) {
+        return Collections.singletonList(widget);
+    }
+    @Override
+    public Size layout(DomElement buildContext, ConstraintBox constraintBox) {
+        this.scale = getScale();
+        DomElement child = buildContext.getChildren().get(0);
+        Size dims = child.getLayouter().layout(child, new ConstraintBox(
+                (constraintBox.getMinWidth() / scale),
+                (constraintBox.getMaxWidth() / scale),
+                (constraintBox.getMinHeight() / scale),
+                (constraintBox.getMaxHeight() / scale)
+        ));
+        child.setRelativeBound(new Rect(0,0,
+                (dims.getWidth() * scale),
+                (dims.getHeight() * scale)));
+        child.setSize(new Size(dims.getWidth(), dims.getHeight()));
+
+        return new Size(dims.getWidth() * scale, dims.getHeight() * scale);
+    }
+
+    @Override
+    public double getMaxIntrinsicHeight(DomElement buildContext, double width) {
+        DomElement child = buildContext.getChildren().get(0);
+        return child.getLayouter().getMaxIntrinsicHeight(child, width / scale) * scale;
+    }
+
+    @Override
+    public double getMaxIntrinsicWidth(DomElement buildContext, double height) {
+        DomElement child = buildContext.getChildren().get(0);
+        return child.getLayouter().getMaxIntrinsicWidth(child, height / scale) * scale;
+    }
+
+    @Override
+    public Position transformPoint(DomElement element, Position pos) {
+        Rect elementRect = element.getRelativeBound();
+        double relX = pos.getX() - elementRect.getX();
+        double relY = pos.getY() - elementRect.getY();
+        return new Position(relX / scale, relY / scale);
+    }
+
+
+    @Override
+    public void doRender(int absMouseX, int absMouseY, double relMouseX, double relMouseY, float partialTicks, RenderingContext context, DomElement buildContext) {
+        DomElement value = buildContext.getChildren().get(0);
+
+        Rect original = value.getRelativeBound();
+        GlStateManager.translate(original.getX(), original.getY(), 0);
+        GlStateManager.scale(scale, scale, 1);
+
+        double absXScale = buildContext.getAbsBounds().getWidth() / buildContext.getSize().getWidth();
+        double absYScale = buildContext.getAbsBounds().getHeight() / buildContext.getSize().getHeight();
+
+        Rect elementABSBound = new Rect(
+                (buildContext.getAbsBounds().getX() + original.getX() * absXScale),
+                (buildContext.getAbsBounds().getY() + original.getY() * absYScale),
+                (original.getWidth() * absXScale),
+                (original.getHeight() * absYScale)
+        );
+        value.setAbsBounds(elementABSBound);
+
+        value.getRenderer().doRender(absMouseX, absMouseY,
+                (relMouseX - original.getX())  / scale,
+                (relMouseY - original.getY()) / scale, partialTicks, context, value);
+    }
+}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/RoundRect.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/RoundRect.java
index a4e94f1f..d4e6d501 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/RoundRect.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/guiv2/elements/RoundRect.java
@@ -65,7 +65,7 @@ public class RoundRect extends AnnotatedExportOnlyWidget {
         public void doRender(int absMouseX, int absMouseY, double relMouseX, double relMouseY, float partialTicks, RenderingContext renderingContext, DomElement buildContext) {
             ShaderProgram shaderProgram = ShaderManager.getShader("shaders/roundrect");
             shaderProgram.useShader();
-            shaderProgram.uploadUniform("radius", radius.getValue().floatValue());
+            shaderProgram.uploadUniform("radius", (float)(radius.getValue() * buildContext.getAbsBounds().getWidth() / buildContext.getSize().getWidth()));
             shaderProgram.uploadUniform("halfSize", (float) buildContext.getAbsBounds().getWidth()/2, (float) buildContext.getAbsBounds().getHeight()/2);
             shaderProgram.uploadUniform("centerPos",
                     (float) (buildContext.getAbsBounds().getX()+buildContext.getAbsBounds().getWidth()/2),
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/overlay/GUIRectPositioner.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/overlay/GUIRectPositioner.java
new file mode 100644
index 00000000..bd16bd6f
--- /dev/null
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/overlay/GUIRectPositioner.java
@@ -0,0 +1,40 @@
+/*
+ * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+ * Copyright (C) 2023  cyoung06 (syeyoung)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+package kr.syeyoung.dungeonsguide.mod.overlay;
+
+import kr.syeyoung.dungeonsguide.mod.config.types.GUIPosition;
+import kr.syeyoung.dungeonsguide.mod.guiv2.DomElement;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.ConstraintBox;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Rect;
+import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Size;
+import lombok.RequiredArgsConstructor;
+
+import java.util.function.Supplier;
+
+@RequiredArgsConstructor
+public class GUIRectPositioner implements Positioner {
+    public final Supplier<GUIPosition> rectSupplier;
+
+    @Override
+    public Rect position(DomElement domElement, double screenWidth, double screenHeight) {
+        GUIPosition posSize = rectSupplier.get();
+        Size size = domElement.getLayouter().layout(domElement, new ConstraintBox(0, screenWidth, 0, screenHeight));
+        return posSize.position(screenWidth, screenHeight, size);
+    }
+}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/overlay/GUIRectanglePositioner.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/overlay/GUIRectanglePositioner.java
deleted file mode 100644
index 55920c81..00000000
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/overlay/GUIRectanglePositioner.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
- * Copyright (C) 2023  cyoung06 (syeyoung)
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-package kr.syeyoung.dungeonsguide.mod.overlay;
-
-import kr.syeyoung.dungeonsguide.mod.config.types.GUIRectangle;
-import kr.syeyoung.dungeonsguide.mod.guiv2.DomElement;
-import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.ConstraintBox;
-import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Rect;
-import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.Size;
-import lombok.RequiredArgsConstructor;
-import net.minecraft.client.Minecraft;
-
-import java.awt.*;
-import java.util.function.Supplier;
-
-@RequiredArgsConstructor
-public class GUIRectanglePositioner implements Positioner {
-    public final Supplier<GUIRectangle> rectSupplier;
-
-    @Override
-    public Rect position(DomElement domElement, double screenWidth, double screenHeight) {
-        GUIRectangle posSize = rectSupplier.get();
-
-        double x = posSize.getX(), y = posSize.getY();
-        x = x * screenWidth / Minecraft.getMinecraft().displayWidth;
-        y = y * screenHeight / Minecraft.getMinecraft().displayHeight;
-        if (Math.abs(x) > screenWidth / 2) {
-            x = x < 0 ? -screenWidth/2 : screenWidth/2;
-        }
-        if (Math.abs(y) > screenHeight/ 2) {
-            y = y < 0 ? -screenHeight/2 : screenHeight/2;
-        }
-
-
-
-        double realX = (int) (x < 0 ? screenWidth + x : x);
-        double realY = (int) (y < 0 ? screenHeight + y : y);
-
-        Size size = domElement.getLayouter().layout(domElement,
-                new ConstraintBox(Math.abs(posSize.getWidth()),
-                        Math.abs(posSize.getWidth()),
-                        Math.abs(posSize.getHeight()),
-                        Math.abs(posSize.getHeight())));
-        return new Rect(Math.min(realX + posSize.getWidth(), realX), Math.min(realY + posSize.getHeight(), realY),
-                Math.abs(posSize.getWidth()), Math.abs(posSize.getHeight()));
-    }
-}
diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/overlay/OverlayManager.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/overlay/OverlayManager.java
index dcfa033f..a3c99ae4 100644
--- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/overlay/OverlayManager.java
+++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/overlay/OverlayManager.java
@@ -20,6 +20,7 @@ package kr.syeyoung.dungeonsguide.mod.overlay;
 
 import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry;
 import kr.syeyoung.dungeonsguide.mod.guiv2.RootDom;
+import kr.syeyoung.dungeonsguide.mod.guiv2.elements.GlobalHUDScale;
 import kr.syeyoung.dungeonsguide.mod.guiv2.elements.Scaler;
 import kr.syeyoung.dungeonsguide.mod.guiv2.elements.popups.PopupMgr;
 import kr.syeyoung.dungeonsguide.mod.guiv2.primitive.ConstraintBox;
@@ -64,7 +65,6 @@ public class OverlayManager {
 
     public static final String OVERLAY_TYPE_KEY = "OVERLAY_TYPE";
 
-    private Scaler scaler;
     private OverlayManager() {
         this.mc = Minecraft.getMinecraft();
 
@@ -72,24 +72,15 @@ public class OverlayManager {
         popupMgr.child.setValue(root);
 
 
-        scaler = new Scaler();
-        scaler.child.setValue(popupMgr);
-        scaler.scale.setValue(getScale());
 
-        view = new RootDom(scaler);
+        view = new RootDom(new GlobalHUDScale(popupMgr));
         guiResize(null);
         view.setMounted(true);
     }
 
-    private double getScale() {
-        boolean useMc = FeatureRegistry.GLOBAL_HUD_SCALE.<Boolean>getParameter("mc").getValue();
-        if (useMc) return (double) new ScaledResolution(Minecraft.getMinecraft()).getScaleFactor();
-        else return FeatureRegistry.GLOBAL_HUD_SCALE.<Float>getParameter("scale").getValue();
-    }
     @SubscribeEvent()
     public void guiResize(GuiScreenEvent.InitGuiEvent.Post post){
         try {
-            scaler.scale.setValue(getScale());
             view.setRelativeBound(new Rect(0,0, Minecraft.getMinecraft().displayWidth, Minecraft.getMinecraft().displayHeight));
             view.setAbsBounds(new Rect(0,0, Minecraft.getMinecraft().displayWidth, Minecraft.getMinecraft().displayHeight));
             view.setSize(new Size(Minecraft.getMinecraft().displayWidth, Minecraft.getMinecraft().displayHeight));
@@ -220,7 +211,7 @@ public class OverlayManager {
     private void mouseMove(int mouseX, int mouseY) {
         try {
             view.mouseMoved0(mouseX, mouseY
-                    , mouseX, mouseY);
+                    , mouseX, mouseY, true);
         } catch (Throwable e) {
             if (e.getMessage() == null || !e.getMessage().contains("hack to stop"))
                 e.printStackTrace();
diff --git a/mod/src/main/resources/assets/dungeonsguide/gui/config/hudconfig.gui b/mod/src/main/resources/assets/dungeonsguide/gui/config/hudconfig.gui
new file mode 100644
index 00000000..9d0cdf32
--- /dev/null
+++ b/mod/src/main/resources/assets/dungeonsguide/gui/config/hudconfig.gui
@@ -0,0 +1,28 @@
+<!--
+  ~ Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+  ~ Copyright (C) 2023  cyoung06 (syeyoung)
+  ~
+  ~ This program is free software: you can redistribute it and/or modify
+  ~ it under the terms of the GNU Affero General Public License as published
+  ~ by the Free Software Foundation, either version 3 of the License, or
+  ~ (at your option) any later version.
+  ~
+  ~ This program is distributed in the hope that it will be useful,
+  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+  ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  ~ GNU Affero General Public License for more details.
+  ~
+  ~ You should have received a copy of the GNU Affero General Public License
+  ~ along with this program.  If not, see <https://www.gnu.org/licenses/>.
+  -->
+
+<bgcolor backgroundColor="0x64000000">
+    <stack>
+        <PopupManager>
+            <slot bind:child="movestuff"/>
+        </PopupManager>
+        <align vAlign="CENTER" hAlign="CENTER">
+            <Text text="Right Click On Elements to Open Popup Menu" color="#FFFFFFFF"/>
+        </align>
+    </stack>
+</bgcolor>
\ No newline at end of file
diff --git a/mod/src/main/resources/assets/dungeonsguide/gui/config/popupmenu.gui b/mod/src/main/resources/assets/dungeonsguide/gui/config/popupmenu.gui
new file mode 100644
index 00000000..5210cab6
--- /dev/null
+++ b/mod/src/main/resources/assets/dungeonsguide/gui/config/popupmenu.gui
@@ -0,0 +1,49 @@
+<!--
+  ~ Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod
+  ~ Copyright (C) 2023  cyoung06 (syeyoung)
+  ~
+  ~ This program is free software: you can redistribute it and/or modify
+  ~ it under the terms of the GNU Affero General Public License as published
+  ~ by the Free Software Foundation, either version 3 of the License, or
+  ~ (at your option) any later version.
+  ~
+  ~ This program is distributed in the hope that it will be useful,
+  ~ but WITHOUT ANY WARRANTY; without even the implied warranty of
+  ~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  ~ GNU Affero General Public License for more details.
+  ~
+  ~ You should have received a copy of the GNU Affero General Public License
+  ~ along with this program.  If not, see <https://www.gnu.org/licenses/>.
+  -->
+<UnconstrainedBox>
+
+        <size width="200">
+            <RoundRect radius="5" backgroundColor="#FF121212">
+                <padding top="5" bottom="5" left="5" right="5">
+                    <col mainAlign="START" crossAlign="STRETCH">
+                        <ColorButton disabled="false"
+                                     backgroundColor="#FF005500"          textColor="#FF777777"
+                                     hoveredBackgroundColor="#FF009900"   hoveredTextColor="#FF777777"
+                                     disabledBackgroundColor="#FF444444"  disabledTextColor="#FF777777"
+                                     pressedBackgroundColor="#FF00F00F"   pressedTextColor="#FF777777"
+                                     text="lol1"
+                        />
+                        <ColorButton disabled="false"
+                                     backgroundColor="#FF005500"          textColor="#FF777777"
+                                     hoveredBackgroundColor="#FF009900"   hoveredTextColor="#FF777777"
+                                     disabledBackgroundColor="#FF444444"  disabledTextColor="#FF777777"
+                                     pressedBackgroundColor="#FF00F00F"   pressedTextColor="#FF777777"
+                                     text="lol2"
+                        />
+                        <ColorButton disabled="false"
+                                     backgroundColor="#FF005500"          textColor="#FF777777"
+                                     hoveredBackgroundColor="#FF009900"   hoveredTextColor="#FF777777"
+                                     disabledBackgroundColor="#FF444444"  disabledTextColor="#FF777777"
+                                     pressedBackgroundColor="#FF00F00F"   pressedTextColor="#FF777777"
+                                     text="lol3"
+                        />
+                    </col>
+                </padding>
+            </RoundRect>
+        </size>
+</UnconstrainedBox>
\ No newline at end of file
-- 
cgit