diff --git a/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp b/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp
index 945013a9905234d8eb807745bea34e04c8456b31..fc014c5adab046771815191a4c1e997602dca519 100644
--- a/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp
+++ b/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.cpp
@@ -22,10 +22,10 @@
 
 #include "ArVizWidgetController.h"
 
-#include <ArmarXCore/observers/variant/Variant.h>
-
 #include <SimoxUtility/algorithm/string/string_tools.h>
 
+#include <ArmarXCore/observers/variant/Variant.h>
+
 #include <QLineEdit>
 #include <QMessageBox>
 #include <QTimer>
@@ -93,7 +93,6 @@ namespace armarx
         connect(this, &This::disconnectGui, this, &This::onDisconnectGui, Qt::QueuedConnection);
 
         // Layer info tree.
-
         connect(widget.layerTree, &QTreeWidget::currentItemChanged, this, &This::updateSelectedLayer);
 
         connect(widget.layerInfoTreeGroupBox, &QGroupBox::toggled, &layerInfoTree, &LayerInfoTree::setEnabled);
@@ -105,7 +104,6 @@ namespace armarx
         layerInfoTree.setEnabled(widget.layerInfoTreeGroupBox->isChecked());
         layerInfoTree.registerVisualizerCallbacks(visualizer);
 
-
         // We need a callback from the visualizer, when the layers have changed
         // So we can update the tree accordingly
         visualizer.layersChangedCallback = [this](std::vector<viz::CoinLayerID> const & layers)
@@ -113,6 +111,12 @@ namespace armarx
             layersChanged(layers);
         };
 
+        // Arviz Profile tree.
+        arvizeProfileLayerWidget = new ArvizProfileManagerWidget();
+        widget.verticalLayout->addWidget(arvizeProfileLayerWidget);
+        connect(arvizeProfileLayerWidget, &ArvizProfileManagerWidget::publishUpdate, this, &This::updateLayersFromProfile);
+        connect(arvizeProfileLayerWidget, &ArvizProfileManagerWidget::fetchUpdate, this, &This::updateLayers);
+
         replayTimer->start(33);
     }
 
@@ -167,6 +171,38 @@ namespace armarx
         emit disconnectGui();
     }
 
+    void ArVizWidgetController::updateLayers()
+    {
+        // Update shown/hidden layers
+        layerTreeChanged(nullptr, 0);
+    }
+
+    void ArVizWidgetController::updateLayersFromProfile()
+    {
+        {
+            QSignalBlocker blocker(widget.layerTree);
+
+            // Iterate over all items and activate/deactivate layers accordingly
+            for (int compIndex = 0; compIndex < widget.layerTree->topLevelItemCount(); ++compIndex)
+            {
+                QTreeWidgetItem* componentItem = widget.layerTree->topLevelItem(compIndex);
+                bool parentChecked = true;
+                const std::string component = componentItem->text(0).toStdString();
+                for (int layerIndex = 0; layerIndex < componentItem->childCount(); ++layerIndex)
+                {
+                    QTreeWidgetItem* layerItem = componentItem->child(layerIndex);
+                    const std::string layer = layerItem->text(0).toStdString();
+                    const viz::CoinLayerID layerID(component, layer);
+                    const bool visible = not arvizeProfileLayerWidget->isHidden(layerID);
+                    layerItem->setCheckState(0, visible ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
+                    parentChecked &= visible;
+                    visualizer.showLayer(layerID, visible);
+                }
+                componentItem->setCheckState(0, parentChecked ? Qt::CheckState::Checked : Qt::CheckState::Unchecked);
+            }
+        }
+    }
+
     void ArVizWidgetController::onConnectGui()
     {
         onRefreshRecordings();
@@ -194,6 +230,8 @@ namespace armarx
             Qt::CheckState componentCheck = componentItem->checkState(0);
             int layerCount = componentItem->childCount();
 
+            arvizeProfileLayerWidget->update(component, componentCheck == Qt::Checked);
+
             if (componentItem == item)
             {
                 // The parent was selected or deselected, so all children should be set accordingly
@@ -208,7 +246,6 @@ namespace armarx
                 }
                 return;
             }
-
             for (int layerIndex = 0; layerIndex < layerCount; ++layerIndex)
             {
                 QTreeWidgetItem* layerItem = componentItem->child(layerIndex);
@@ -217,6 +254,9 @@ namespace armarx
                 ARMARX_VERBOSE << "Layer: " << layer << ", Visible: " << layerVisible;
 
                 viz::CoinLayerID layerID(component, layer);
+
+                arvizeProfileLayerWidget->update(layerID, layerVisible);
+
                 visualizer.showLayer(layerID, layerVisible);
             }
         }
@@ -261,10 +301,10 @@ namespace armarx
                 if (iter == currentComponents.end())
                 {
                     // Create a new item
+                    QSignalBlocker blocker(tree); // otherwise added as unchecked and directly updated
                     currentItem = new QTreeWidgetItem(tree);
                     currentItem->setText(0, QString::fromStdString(component));
-                    // A new item is visible by default
-                    currentItem->setCheckState(0, Qt::Checked);
+                    currentItem->setCheckState(0, arvizeProfileLayerWidget->isHidden(component) ? Qt::Unchecked : Qt::Checked);
 
                     componentWasNew = true;
                 }
@@ -286,8 +326,7 @@ namespace armarx
                 std::string const& layer = entry.second;
                 QTreeWidgetItem* layerItem = new QTreeWidgetItem;
                 layerItem->setText(0, QString::fromStdString(layer));
-                // A new item is visible by default
-                layerItem->setCheckState(0, Qt::Checked);
+                layerItem->setCheckState(0, arvizeProfileLayerWidget->isHidden(entry) ? Qt::Unchecked : Qt::Checked);
 
                 if (currentItem)
                 {
@@ -308,7 +347,11 @@ namespace armarx
             }
             else
             {
-                // Item exists already ==> nothing to be done
+                // Item exists already ==> make sure that it is not shown if necessary
+                if (arvizeProfileLayerWidget->isHidden(iter->first) or iter->second->checkState(0) == Qt::Unchecked)
+                {
+                    visualizer.showLayer(iter->first, false);
+                }
             }
         }
     }
@@ -398,8 +441,7 @@ namespace armarx
 
         widget.layerTree->blockSignals(false);
 
-        // Update shown/hidden layers
-        layerTreeChanged(nullptr, 0);
+        updateLayers();
     }
 
     void ArVizWidgetController::showFilteredLayers(bool visible)
@@ -422,8 +464,7 @@ namespace armarx
 
         widget.layerTree->blockSignals(false);
 
-        // Update shown/hidden layers
-        layerTreeChanged(nullptr, 0);
+        updateLayers();
     }
 
     void ArVizWidgetController::onDeselectElement()
diff --git a/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.h b/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.h
index cb10e285bee2e0b69497a1032703ca2aa5b5462e..065d04253da98d4c84c9d6f96313b094cfd95237 100644
--- a/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.h
+++ b/source/RobotAPI/gui-plugins/ArViz/ArVizWidgetController.h
@@ -21,6 +21,8 @@
  */
 #pragma once
 
+#include <unordered_set>
+
 #include <RobotAPI/gui-plugins/ArViz/ui_ArVizWidget.h>
 
 #include <RobotAPI/components/ArViz/Coin/Visualizer.h>
@@ -34,6 +36,7 @@
 #include <ArmarXCore/core/system/ImportExportComponent.h>
 
 #include "LayerInfoTree.h"
+#include "ArvizProfileManagerWidget.h"
 
 
 namespace armarx
@@ -106,8 +109,10 @@ namespace armarx
         void onGetBatchAsync(viz::data::RecordingBatch const& batch);
 
 
-    public slots:
+    private slots:
         /* QT slot declarations */
+        void updateLayers();
+        void updateLayersFromProfile();
 
     signals:
         /* QT signal declarations */
@@ -224,6 +229,8 @@ namespace armarx
 
         std::vector<double> timings;
 
+        ArvizProfileManagerWidget* arvizeProfileLayerWidget;
+
     public:
         static QIcon GetWidgetIcon()
         {
diff --git a/source/RobotAPI/gui-plugins/ArViz/ArvizProfileManagerWidget.cpp b/source/RobotAPI/gui-plugins/ArViz/ArvizProfileManagerWidget.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4af5a0fd4db95eb36733d5bcb501d1453bdfc5b6
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/ArViz/ArvizProfileManagerWidget.cpp
@@ -0,0 +1,362 @@
+#include "ArvizProfileManagerWidget.h"
+
+#include <string>
+
+#include <QVBoxLayout>
+#include <QMessageBox>
+#include <QBoxLayout>
+#include <QLabel>
+#include <QFormLayout>
+#include <QDialogButtonBox>
+#include <QPushButton>
+#include <QBoxLayout>
+#include <QRadioButton>
+
+#include <ArmarXCore/core/system/ArmarXDataPath.h>
+#include <ArmarXCore/core/logging/Logging.h>
+
+namespace armarx
+{
+
+const QString ArvizProfileManagerWidget::SETTINGS_DEFAULT_PROFILE_KEY = "defaultProfileName";
+
+
+ProfileDialog::ProfileDialog(QWidget *parent, const QString &name, bool additive, bool addDialog, bool isDefault)
+    : QDialog(parent)
+{
+    setWindowTitle(addDialog ? "Add ArViz Profile" : "Edit ArViz Profile");
+
+    // Set up UI components
+    nameInput = new QLineEdit(this);
+    nameInput->setText(name);
+
+    additiveRadioButton = new QRadioButton("Save added layers", this);
+    additiveRadioButton->setChecked(additive);
+    substractiveRadioButton = new QRadioButton("Save removed layers", this);
+    substractiveRadioButton->setChecked(not additive);
+
+    defaultCheckBox = new QCheckBox("Mark default", this);
+    defaultCheckBox->setChecked(isDefault);
+
+    // Save/Cancel buttons
+    QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Save | QDialogButtonBox::Cancel, this);
+    connect(buttonBox, &QDialogButtonBox::accepted, this, &ProfileDialog::accept);
+    connect(buttonBox, &QDialogButtonBox::rejected, this, &ProfileDialog::reject);
+    buttonBox->setCenterButtons(true);
+
+    // Delete button
+    deleteButton = new QPushButton("Delete", this);
+    connect(deleteButton, &QPushButton::clicked, this, &ProfileDialog::deleteProfile);
+
+    // Layouts
+    QFormLayout *formLayout = new QFormLayout;
+    formLayout->addRow("Profile Name:", nameInput);
+    formLayout->addRow(additiveRadioButton);
+    formLayout->addRow(substractiveRadioButton);
+    formLayout->addRow(defaultCheckBox);
+    formLayout->addRow(buttonBox);
+    formLayout->addRow(deleteButton);
+
+    setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+    setLayout(formLayout);
+    adjustSize();
+}
+
+ProfileDialog::~ProfileDialog()
+{
+}
+
+QString ProfileDialog::getName() const
+{
+    return nameInput->text();
+}
+
+bool ProfileDialog::isAdditive() const
+{
+    return additiveRadioButton->isChecked();
+}
+
+bool ProfileDialog::isDefaultProfile() const
+{
+    return defaultCheckBox->isChecked();
+}
+
+void ProfileDialog::deleteProfile()
+{
+    // Handle the profile deletion
+    emit deleteProfileSignal();
+    reject(); // Close the dialog after deletion
+}
+
+
+
+ArvizProfileManagerWidget::ArvizProfileManagerWidget(QWidget* parent) :
+    QWidget(parent), 
+    settings(QString((armarx::ArmarXDataPath::GetDefaultUserConfigPath() + "/ArvizProfileManager.conf").c_str()),
+             QSettings::NativeFormat),
+    currentProfile(Profile())
+{
+    QHBoxLayout* layout = new QHBoxLayout(this);
+
+    // Setup UI elements
+    layersComboBox = new QComboBox(this);
+    connect(layersComboBox, QOverload<int>::of(&QComboBox::activated), 
+           this, &ArvizProfileManagerWidget::onProfileSelected);
+
+    addButton = new QPushButton("Add", this);
+    editButton = new QPushButton("Edit", this);
+    saveButton = new QPushButton("Save", this);
+
+    layout->addWidget(new QLabel("ArViz Profile: "));
+    layout->addWidget(layersComboBox);
+    layout->addWidget(addButton);
+    layout->addWidget(editButton);
+    layout->addWidget(saveButton);
+
+    setLayout(layout);
+
+    connect(addButton, &QPushButton::clicked, this, &ArvizProfileManagerWidget::addProfile);
+    connect(editButton, &QPushButton::clicked, this, &ArvizProfileManagerWidget::editProfile);
+    connect(saveButton, &QPushButton::clicked, this, &ArvizProfileManagerWidget::saveCurrentProfile);
+
+    loadLayerNames();
+
+    // Load default profile
+    const QString defaultProfileName 
+        = settings.value(SETTINGS_DEFAULT_PROFILE_KEY).toString();
+    if (int i = layersComboBox->findText(defaultProfileName); i >= 0)
+    {
+        layersComboBox->setCurrentText(defaultProfileName);
+        onProfileSelected(i);
+    }
+    else
+    {
+        // Not found. Load empty profile
+        layersComboBox->setCurrentIndex(-1);
+    }
+}
+
+void ArvizProfileManagerWidget::onProfileSelected(int index) 
+{
+    if (index >= 0 and index < layersComboBox->count())
+    {
+        loadProfile(layersComboBox->itemText(index));
+        emit publishUpdate();
+    }
+}
+
+void ArvizProfileManagerWidget::saveCurrentProfile() 
+{
+    const QString name = layersComboBox->currentText();
+    if (name.isEmpty()) 
+    {
+        QMessageBox::warning(this, "Warning", "Please enter a valid name.");
+        return;
+    }
+
+    if (saveProfile(name, currentProfile)) 
+    {
+        if (layersComboBox->findText(name) == -1) 
+        {
+            layersComboBox->addItem(name);
+        }
+        layersComboBox->setCurrentText(name);
+    }
+}
+
+void ArvizProfileManagerWidget::deleteCurrentProfileSave() 
+{
+    const QString name = layersComboBox->currentText();
+    settings.remove(name);
+
+    const int index = layersComboBox->currentIndex();
+    layersComboBox->removeItem(index);
+    settings.remove(name);
+
+    if (layersComboBox->count() == 0)
+    {
+        editButton->setDisabled(true);
+        saveButton->setDisabled(true);
+    }
+
+    emit publishUpdate();
+}
+
+void ArvizProfileManagerWidget::addProfile() 
+{
+    if (dialog == nullptr || !dialog->isVisible()) 
+    {
+        const QString defaultName = "Profile";
+        const bool defaultAdditive = false;
+        QString name = defaultName;
+        unsigned int counter = 2;
+        while (layersComboBox->count() > 0 and layersComboBox->findText(name) >= 0)
+        {
+            name = defaultName + QString::fromStdString(std::to_string(counter++));
+        }
+        dialog = new ProfileDialog(this, name, defaultAdditive, true,
+                                   settings.value(SETTINGS_DEFAULT_PROFILE_KEY) == name);
+        const int result = dialog->exec();
+
+        if (result == QDialog::Accepted) 
+        {
+            if (dialog->getName().isEmpty())
+            {
+                ARMARX_WARNING << "Empty name for profile set.";
+                return;
+            }
+            if (layersComboBox->findText(dialog->getName()) >= 0)
+            {
+                ARMARX_WARNING << "Profile with name " << dialog->getName().toStdString() << " already exists!";
+                return;
+            }
+
+            if (dialog->isDefaultProfile())
+            {
+                settings.setValue(SETTINGS_DEFAULT_PROFILE_KEY, dialog->getName());
+            }
+
+            currentProfile.layers = {};
+            currentProfile.additive = dialog->isAdditive();
+            emit fetchUpdate();
+
+            saveProfile(dialog->getName(), currentProfile);
+            loadLayerNames();
+            layersComboBox->setCurrentText(dialog->getName());
+        } 
+        else 
+        {
+            // do nothing
+        }
+    } 
+    else 
+    {
+        QMessageBox::information(this, "Dialog Already Open", "The dialog is already open.");
+    }
+}
+
+void ArvizProfileManagerWidget::editProfile()
+{
+    if (layersComboBox->count() > 0)
+    {
+        if (dialog == nullptr || !dialog->isVisible()) 
+        {
+            const auto name = layersComboBox->currentText();
+            dialog = new ProfileDialog(this, name, currentProfile.additive,
+                                       false, settings.value(SETTINGS_DEFAULT_PROFILE_KEY) == name);
+            connect(dialog, &ProfileDialog::deleteProfileSignal, this, &ArvizProfileManagerWidget::deleteCurrentProfileSave);
+            const int result = dialog->exec();
+
+            if (result == QDialog::Accepted) 
+            {
+                const auto newName = dialog->getName();
+
+                if (newName.isEmpty())
+                {
+                    ARMARX_WARNING << "Empty name for profile set.";
+                    return;
+                }
+
+                if (newName != name)
+                {
+                    // Rename
+                    if (layersComboBox->findText(newName) >= 0)
+                    {
+                        ARMARX_WARNING << "Profile with name " << newName.toStdString() << " already exists!";
+                        return;
+                    }
+                    settings.remove(layersComboBox->currentText());
+                }
+
+                if (dialog->isAdditive() != currentProfile.additive)
+                {
+                    currentProfile.layers.clear();
+                    currentProfile.additive = dialog->isAdditive();
+                    emit fetchUpdate();
+                }
+
+                if (dialog->isDefaultProfile())
+                {
+                    settings.setValue(SETTINGS_DEFAULT_PROFILE_KEY, newName);
+                }
+                else if (settings.value(SETTINGS_DEFAULT_PROFILE_KEY) == name)
+                {
+                    settings.setValue(SETTINGS_DEFAULT_PROFILE_KEY, "");
+                }
+                
+                saveProfile(dialog->getName(), currentProfile);
+                loadLayerNames();
+                layersComboBox->setCurrentText(newName);
+            } 
+            else 
+            {
+                // do nothing
+            }
+        } 
+        else 
+        {
+            QMessageBox::information(this, "Dialog Already Open", "The dialog is already open.");
+        }
+    }
+}
+
+void ArvizProfileManagerWidget::loadLayerNames() 
+{
+    layersComboBox->clear();
+    for (const QString& groups : settings.childGroups()) 
+    {
+        layersComboBox->addItem(groups);
+    }
+    if (layersComboBox->count() == 0)
+    {
+        editButton->setDisabled(true);
+        saveButton->setDisabled(true);
+    }
+    else 
+    {
+        editButton->setEnabled(true);
+        saveButton->setEnabled(true);
+    }
+}
+
+void ArvizProfileManagerWidget::loadProfile(const QString& name)
+{
+    ARMARX_INFO << "Loading ArViz profile " << name.toStdString();
+
+    std::scoped_lock lock(mtx);
+    currentProfile.layers.clear();
+    
+    settings.beginGroup(name);
+    currentProfile.additive  = settings.value("additive").toBool();
+    const int size = settings.beginReadArray("layers");
+    for (int i = 0; i < size; ++i) 
+    {
+        settings.setArrayIndex(i);
+        QString first = settings.value("component").toString();
+        QString second = settings.value("layer").toString();
+        currentProfile.layers.insert({first.toStdString(), second.toStdString()});
+    }
+    settings.endArray();
+    settings.endGroup();
+    editButton->setEnabled(true);
+}
+
+bool ArvizProfileManagerWidget::saveProfile(const QString& name, const Profile& profile) 
+{
+    settings.beginGroup(name);
+    settings.setValue("additive", profile.additive);
+    settings.remove("layers");
+    settings.beginWriteArray("layers", profile.layers.size());
+    int i = 0;
+    for (const auto& pair : profile.layers)
+    {
+        settings.setArrayIndex(i++);
+        settings.setValue("component", QString::fromStdString(pair.first));
+        settings.setValue("layer", QString::fromStdString(pair.second));
+    }
+    settings.endArray();
+    settings.endGroup();
+    return true;
+}
+
+}
\ No newline at end of file
diff --git a/source/RobotAPI/gui-plugins/ArViz/ArvizProfileManagerWidget.h b/source/RobotAPI/gui-plugins/ArViz/ArvizProfileManagerWidget.h
new file mode 100644
index 0000000000000000000000000000000000000000..1f5a97151f4043c723356e6db76cb491e0479a87
--- /dev/null
+++ b/source/RobotAPI/gui-plugins/ArViz/ArvizProfileManagerWidget.h
@@ -0,0 +1,175 @@
+/*
+ * This file is part of ArmarX.
+ *
+ * ArmarX is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * ArmarX 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * @package    RobotAPI::gui-plugins::ArVizProfileManagerWidget
+ * @author     Andre Meixner ( andre dot meixner at kit dot edu )
+ * @date       2024
+ * @copyright  http://www.gnu.org/licenses/gpl-2.0.txt
+ *             GNU General Public License
+ */
+#pragma once
+
+#include <QWidget>
+#include <QDialog>
+#include <QComboBox>
+#include <QPushButton>
+#include <QLineEdit>
+#include <QSettings>
+#include <QString>
+#include <QCheckBox>
+#include <QRadioButton>
+
+#include <mutex>
+#include <qcheckbox.h>
+#include <unordered_set>
+#include <string>
+#include <utility>
+
+#include <RobotAPI/components/ArViz/Coin/Visualizer.h>
+
+namespace armarx
+{
+    struct pair_hash 
+    {
+        template <typename T1, typename T2>
+        std::size_t operator ()(const std::pair<T1, T2>& p) const 
+        {
+            auto h1 = std::hash<T1>{}(p.first);
+            auto h2 = std::hash<T2>{}(p.second);
+            return h1 ^ (h2 << 1);
+        }
+    };
+
+    using Layers = std::unordered_set<viz::CoinLayerID, pair_hash>;
+
+    struct Profile
+    {
+        Layers layers;
+        bool additive = false;
+    };
+
+
+    class ProfileDialog : public QDialog
+    {
+        Q_OBJECT
+
+    public:
+        explicit ProfileDialog(QWidget *parent = nullptr, const QString &name = "",
+                               bool additive = false, bool addDialog = true, bool isDefault = false);
+        ~ProfileDialog();
+
+        QString getName() const;
+        bool isAdditive() const;
+        bool isDefaultProfile() const;
+
+    signals:
+        void deleteProfileSignal();
+
+    private slots:
+        void deleteProfile();
+
+    private:
+        QLineEdit *nameInput;
+        QRadioButton *additiveRadioButton;
+        QRadioButton *substractiveRadioButton;
+        QPushButton *deleteButton;
+        QCheckBox *defaultCheckBox;
+    };
+
+
+    class ArvizProfileManagerWidget : public QWidget 
+    {
+        Q_OBJECT
+
+    public:
+        explicit ArvizProfileManagerWidget(QWidget* parent = nullptr);
+
+        inline void update(const viz::CoinLayerID& layerID, bool visible)
+        {
+            std::scoped_lock lock(mtx);
+
+            if (currentProfile.additive == visible)
+            {
+                currentProfile.layers.insert(layerID);
+            }
+            else if (currentProfile.layers.count(layerID) > 0)
+            {
+                currentProfile.layers.erase(layerID);
+                currentProfile.layers.erase({layerID.first, "*"});
+            }
+
+        }
+
+        inline void update(const std::string& componentName, bool visible)
+        {
+            update({componentName, "*"}, visible);
+        }
+
+        inline bool isHidden(const viz::CoinLayerID& layerID) const
+        {
+            std::scoped_lock lock(mtx);
+
+            const bool result = currentProfile.layers.count(layerID) > 0 or currentProfile.layers.count({layerID.first, "*"}) > 0;
+
+            if (currentProfile.additive)
+            {
+                return not result;
+            }
+            else 
+            {
+                return result;
+            }
+        }
+
+        inline bool isHidden(const std::string& componentName) const
+        {
+            std::scoped_lock lock(mtx);
+
+            return currentProfile.additive == (currentProfile.layers.count({componentName, "*"}) == 0);
+        }
+
+    signals:
+        void publishUpdate();
+        void fetchUpdate();
+
+    public slots:
+        void onProfileSelected(int index);
+
+    private slots:
+        void saveCurrentProfile();
+        void deleteCurrentProfileSave();
+
+        void addProfile();
+        void editProfile();
+
+    private:
+        void loadLayerNames();
+        void loadProfile(const QString& name);
+        bool saveProfile(const QString& name, const Profile& profile);
+
+        ProfileDialog* dialog = nullptr;
+        QComboBox* layersComboBox;
+        QPushButton* addButton;
+        QPushButton* editButton;
+        QPushButton* saveButton;
+        QSettings settings;
+        mutable std::mutex mtx;
+
+        Profile currentProfile;
+
+        static const QString SETTINGS_DEFAULT_PROFILE_KEY;
+    };
+
+}
diff --git a/source/RobotAPI/gui-plugins/ArViz/CMakeLists.txt b/source/RobotAPI/gui-plugins/ArViz/CMakeLists.txt
index c9f30ffe5c0d845c057bf9346ca2425e3e146832..94928007fbb4c707002d5f9347b632a32d4e5b12 100644
--- a/source/RobotAPI/gui-plugins/ArViz/CMakeLists.txt
+++ b/source/RobotAPI/gui-plugins/ArViz/CMakeLists.txt
@@ -10,6 +10,7 @@ armarx_build_if(ArmarXGui_FOUND "ArmarXGui not available")
 set(SOURCES
     ArVizGuiPlugin.cpp
     ArVizWidgetController.cpp
+    ArvizProfileManagerWidget.cpp
 
     LayerInfoTree.cpp
 )
@@ -18,6 +19,7 @@ set(SOURCES
 set(HEADERS
     ArVizGuiPlugin.h
     ArVizWidgetController.h
+    ArvizProfileManagerWidget.h
 
     LayerInfoTree.h
 )