diff --git a/loader/include/Geode/ui/General.hpp b/loader/include/Geode/ui/General.hpp
index 941e2dbf..e8b6acbc 100644
--- a/loader/include/Geode/ui/General.hpp
+++ b/loader/include/Geode/ui/General.hpp
@@ -11,12 +11,64 @@ namespace geode {
      */
     GEODE_DLL cocos2d::CCSprite* createLayerBG();
 
+    enum class SideArt {
+        BottomLeft   = 0b0001,
+        BottomRight  = 0b0010,
+        TopLeft      = 0b0100,
+        TopRight     = 0b1000,
+        Bottom       = 0b0011,
+        Top          = 0b1100,
+        All          = 0b1111,
+    };
+    constexpr SideArt operator|(SideArt a, SideArt b) {
+        return static_cast<SideArt>(static_cast<int>(a) | static_cast<int>(b));
+    }
+    constexpr bool operator&(SideArt a, SideArt b) {
+        return static_cast<bool>(static_cast<int>(a) & static_cast<int>(b));
+    }
+
+    /**
+     * Add side art (corner pieces) for a layer
+     * @param to Layer to add corner pieces to
+     * @param sides Which corners to populate; by default, populates all
+     * @param useAnchorLayout If true, `to` is given an `AnchorLayout` and the 
+     * corners' positions are dynamically updated
+     */
+    GEODE_DLL void addSideArt(cocos2d::CCNode* to, SideArt sides = SideArt::All, bool useAnchorLayout = false);
+
     /**
      * Add the rounded comment borders to a node
+     * @note Use the `ListBorders` class for increased control
      */
     GEODE_DLL void addListBorders(
         cocos2d::CCNode* to,
         cocos2d::CCPoint const& center,
         cocos2d::CCSize const& size
     );
+    
+    class GEODE_DLL ListBorders : public cocos2d::CCNode {
+    protected:
+        cocos2d::extension::CCScale9Sprite* m_top = nullptr;
+        cocos2d::extension::CCScale9Sprite* m_bottom = nullptr;
+        cocos2d::CCSprite* m_left = nullptr;
+        cocos2d::CCSprite* m_right = nullptr;
+        float m_topPadding = 7.5f;
+        float m_bottomPadding = 7.5f;
+    
+        bool init();
+
+    public:
+        static ListBorders* create();
+
+        void setSpriteFrames(const char* topAndBottom, const char* sides, float topPadding = 7.5f);
+        void setSprites(
+            cocos2d::extension::CCScale9Sprite* top,
+            cocos2d::extension::CCScale9Sprite* bottom,
+            cocos2d::CCSprite* left,
+            cocos2d::CCSprite* right,
+            float topPadding = 7.5f,
+            float bottomPadding = 7.5f
+        );
+        void setContentSize(cocos2d::CCSize const& size) override;
+    };
 }
diff --git a/loader/src/ui/nodes/General.cpp b/loader/src/ui/nodes/General.cpp
index b5163d29..df8f524c 100644
--- a/loader/src/ui/nodes/General.cpp
+++ b/loader/src/ui/nodes/General.cpp
@@ -18,6 +18,29 @@ CCSprite* geode::createLayerBG() {
     return bg;
 }
 
+void geode::addSideArt(CCNode* to, SideArt sides, bool useAnchorLayout) {
+    if (sides & SideArt::BottomLeft) {
+        auto spr = CCSprite::createWithSpriteFrameName("GJ_sideArt_001.png");
+        to->addChildAtPosition(spr, Anchor::BottomLeft, ccp(35, 35), useAnchorLayout);
+    }
+    if (sides & SideArt::BottomRight) {
+        auto spr = CCSprite::createWithSpriteFrameName("GJ_sideArt_001.png");
+        spr->setFlipX(true);
+        to->addChildAtPosition(spr, Anchor::BottomRight, ccp(-35, 35), useAnchorLayout);
+    }
+    if (sides & SideArt::TopLeft) {
+        auto spr = CCSprite::createWithSpriteFrameName("GJ_sideArt_001.png");
+        spr->setFlipY(true);
+        to->addChildAtPosition(spr, Anchor::TopLeft, ccp(35, -35), useAnchorLayout);
+    }
+    if (sides & SideArt::TopRight) {
+        auto spr = CCSprite::createWithSpriteFrameName("GJ_sideArt_001.png");
+        spr->setFlipX(true);
+        spr->setFlipY(true);
+        to->addChildAtPosition(spr, Anchor::TopRight, ccp(-35, -35), useAnchorLayout);
+    }
+}
+
 void geode::addListBorders(CCNode* to, CCPoint const& center, CCSize const& size) {
     // if the size is 346.f, the top aligns perfectly by default :3
     if (size.width == 346.f) {
@@ -89,3 +112,73 @@ void geode::addListBorders(CCNode* to, CCPoint const& center, CCSize const& size
     });
     to->addChild(layerRightSpr);
 }
+
+bool ListBorders::init() {
+    if (!CCNode::init())
+        return false;
+    
+    this->setAnchorPoint({ .5f, .5f });
+    this->setSpriteFrames("GJ_commentTop_001.png", "GJ_commentSide_001.png");
+
+    return true;
+}
+
+ListBorders* ListBorders::create() {
+    auto ret = new ListBorders();
+    if (ret && ret->init()) {
+        ret->autorelease();
+        return ret;
+    }
+    CC_SAFE_DELETE(ret);
+    return nullptr;
+}
+
+void ListBorders::setSpriteFrames(const char* topAndBottom, const char* side, float topPadding) {
+    this->setSprites(
+        CCScale9Sprite::createWithSpriteFrameName(topAndBottom),
+        CCScale9Sprite::createWithSpriteFrameName(topAndBottom),
+        CCSprite::createWithSpriteFrameName(side),
+        CCSprite::createWithSpriteFrameName(side),
+        topPadding,
+        topPadding
+    );
+    m_bottom->setScaleY(-1);
+    m_right->setFlipX(true);
+}
+void ListBorders::setSprites(
+    CCScale9Sprite* top, CCScale9Sprite* bottom,
+    CCSprite* left, CCSprite* right,
+    float topPadding, float bottomPadding
+) {
+    if (m_top) m_top->removeFromParent();
+    if (m_bottom) m_bottom->removeFromParent();
+    if (m_left) m_left->removeFromParent();
+    if (m_right) m_right->removeFromParent();
+
+    m_top = top;
+    this->addChildAtPosition(m_top, Anchor::Top, ccp(0, -m_top->getScaledContentHeight() / 3));
+
+    m_bottom = bottom;
+    this->addChildAtPosition(m_bottom, Anchor::Bottom, ccp(0, m_bottom->getScaledContentHeight() / 3));
+
+    m_left = left;
+    this->addChildAtPosition(m_left, Anchor::Left, ccp(0, 0));
+
+    m_right = right;
+    this->addChildAtPosition(m_right, Anchor::Right, ccp(0, 0));
+
+    m_topPadding = topPadding;
+    m_bottomPadding = bottomPadding;
+
+    this->setContentSize(m_obContentSize);
+}
+void ListBorders::setContentSize(CCSize const& size) {
+    CCNode::setContentSize(size);
+    this->updateLayout();
+
+    m_top->setContentWidth(size.width + m_topPadding);
+    m_bottom->setContentWidth(size.width + m_bottomPadding);
+    auto height = m_top->getContentHeight() * 0.75 + m_bottom->getContentHeight() * 0.75;
+    m_left->setScaleY((size.height - height) / m_left->getContentHeight());
+    m_right->setScaleY((size.height - height) / m_right->getContentHeight());
+}