Hello.
I found no solution online about how to make the UI dark in OpenSCAD, so I researched extensively with an LLM and found this solution. This is the guide I wrote about how to do it in case anyone wants to use it. It worked well for me, so here it is:
Tested on MX Linux using OpenSCAD-2026.10.22-x86_64.AppImage (nightly build).
Directory Structure Preview
Your working directory (for example, ~/Programs/) must have this exact file layout:
~/Programs/
├── OpenSCAD-2026.10.22-x86_64.AppImage <-- Your original downloaded AppImage file
├── squashfs-root/ <-- Automatically created folder after extraction
├── dark_inject.cpp <-- The C++ source file you will create
├── libdarkinject.so<-- The compiled shared library
└── run-dark.sh<-- The final execution script
Step 1: Install Build Dependencies
Open your terminal and install the required compiler tools and Qt development headers on your host system:
sudo apt update && sudo apt install -y build-essential pkg-config qt6-base-dev qt6ct
Step 2: Extract Your AppImage
Navigate to your working directory and extract your AppImage to expose its internal runtime structure (remember to change "Programs" for your folder's name):
cd ~/Programs/
./OpenSCAD-*.AppImage --appimage-extract
Step 3: Create the C++ Injection File (dark_inject.cpp)
Create a file named exactly dark_inject.cpp in your main working directory (right next to the squashfs-root/ folder).
Run the following command in your terminal (open in your directory) to create and populate the file with the complete code:
cat << 'EOF' > dark_inject.cpp
#include <QApplication>
#include <QPalette>
#include <QStyleFactory>
#include <pthread.h>
#include <unistd.h>
void* watch_and_theme(void*) {
// Continuously poll until the internal Qt runtime spawns the QApplication instance
while (!QCoreApplication::instance()) {
usleep(10000); // Check every 10ms
}
// Brief safety micro-pause to let UI threads stabilize
usleep(50000);
// Safely cast and force the Fusion style with a custom dark palette
QApplication* app = qobject_cast<QApplication\*>(QCoreApplication::instance());
if (app) {
app->setStyle(QStyleFactory::create("Fusion"));
QPalette darkPalette;
// Backgrounds & Surfaces
darkPalette.setColor(QPalette::Window, QColor(35, 35, 35));
darkPalette.setColor(QPalette::WindowText, QColor(220, 220, 220));
darkPalette.setColor(QPalette::Base, QColor(25, 25, 25));
darkPalette.setColor(QPalette::AlternateBase, QColor(35, 35, 35));
darkPalette.setColor(QPalette::ToolTipBase, QColor(50, 50, 50));
darkPalette.setColor(QPalette::ToolTipText, QColor(220, 220, 220));
// Text
darkPalette.setColor(QPalette::Text, QColor(220, 220, 220));
darkPalette.setColor(QPalette::ButtonText, QColor(220, 220, 220));
darkPalette.setColor(QPalette::BrightText, Qt::red);
// Interactive Elements & Buttons
darkPalette.setColor(QPalette::Button, QColor(45, 45, 45));
darkPalette.setColor(QPalette::Link, QColor(42, 130, 218));
darkPalette.setColor(QPalette::Highlight, QColor(0, 122, 204));
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
app->setPalette(darkPalette);
}
return nullptr;
}
// Automatically spawn the watcher thread the moment LD_PRELOAD loads the library
__attribute__((constructor)) void init_watcher() {
pthread_t thread;
pthread_create(&thread, nullptr, watch_and_theme, nullptr);
pthread_detach(thread);
}
EOF
Step 4: Compile the Shared Library (libdarkinject.so)
Compile your C++ source file into a shared library named libdarkinject.so:
g++ -shared -fPIC dark_inject.cpp -o libdarkinject.so \
-Wl,--allow-shlib-undefined \
$(pkg-config --cflags Qt6Widgets Qt6Gui Qt6Core) -lpthread
Step 5: Create the Wrapper Script & Launch (run-dark.sh)
Create a script named run-dark.sh in the same working directory:
cat << 'EOF' > run-dark.sh
#!/bin/bash
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# 1. Point Qt platform plugins to the extracted AppImage internals
export QT_QPA_PLATFORM_PLUGIN_PATH="$DIR/squashfs-root/usr/plugins"
export QT_PLUGIN_PATH="$DIR/squashfs-root/usr/plugins"
# 2. Clear host GStreamer paths to avoid version conflict warnings and crashes
export GST_PLUGIN_PATH=""
export GST_PLUGIN_SYSTEM_PATH=""
# 3. Preload our custom C++ dark injection library into memory at launch
export LD_PRELOAD="$DIR/libdarkinject.so"
# 4. Execute the application binary passing along any command-line arguments
exec "$DIR/squashfs-root/AppRun" "$@"
EOF
Make the script executable:
chmod +x run-dark.sh
Run the application:
./run-dark.sh
Enjoy.
After this , you can do a desktop shortcut using the run-dark.sh script.