Marduk is a high-performance, low-level Retained Mode OOP Toolkit written in Modern C++ (C++20). It is designed to be the foundational engine for building custom Desktop Environments, UI Frameworks, and graphics-intensive native applications.
Unlike traditional UI frameworks that force you to use pre-built components (like Buttons or TextFields), Marduk provides the raw, unopinionated primitives: Hardware-Accelerated Rendering, Flexbox Layout, and Event Routing. It acts as a "Framework Factory," giving developers absolute control over every pixel while eliminating the boilerplate of setting up graphics contexts.
- Raw Skia Power (GPU Accelerated): Direct, zero-overhead access to the Skia Graphics Engine. You can extract the raw
SkCanvas*to draw complex paths, GLSL Shaders (SkRuntimeEffect), gradients, and particles at 60+ FPS. - Integrated Anu Flexbox Layout: Forget manual
x, ycoordinate math. Marduk integrates the Anu Flexbox engine directly into itsRenderObjecttree. Build responsive, complex layouts that automatically adapt to window resizing. - Zero-Boilerplate Setup: Say goodbye to the headache of initializing SDL, setting up OpenGL/Vulkan contexts, and managing OS event loops. Marduk handles the windowing and context lifecycle out of the box.
- Retained Mode Efficiency: Utilizes a persistent
RenderObjectscene graph. State mutations (like changing a color or size) use targetedmarkNeedsLayout()andmarkNeedsPaint()signals, ensuring the CPU/GPU only recalculates what actually changed, rather than rebuilding the entire tree. - Precise Event Routing: Built-in Hit Testing traversing the scene graph, delivering precise mouse, scroll, and pointer events exactly to the affected low-level
RenderObject.
- Desktop Environments (DEs): Perfect for building components like custom Taskbars, Docks, or interactive Live Wallpapers (e.g.,
AetherDesktop), where you need bare-metal graphics performance and low memory footprint. - Building New UI Frameworks: Want to build the next React Native, Flutter, or Qt? Use Marduk as your foundation. Build your "Virtual DOM" or "Widget Tree" in C++, Rust, or Python, and let Marduk handle the heavy lifting of Layout and Rendering.
- High-Performance Custom Apps: Ideal for software that demands custom UI paradigms, such as Video Editors, Audio Workstations (DAWs), or 2D Game Editors, where standard OS controls are too restrictive or too slow.
Marduk does not ship with Button, Checkbox, or TextField. If it did, it would be imposing a specific design language and architecture on you. Instead, Marduk gives you RenderBox and RenderFlex. You inherit from them, grab the SkCanvas, and draw your own completely unique components.
Because there is no intermediate "Declarative Widget" layer diffing in the background, you are communicating almost directly with the GPU. When you build with Marduk, you are writing code that is as close to the metal as a graphics engine, but with the convenience of Flexbox and structured event handling.
#include "marduk/app/app.hpp"
#include "marduk/tree/render_object.hpp"
#include "marduk/rendering/canvas.hpp"
// Raw Skia includes
#include <include/core/SkCanvas.h>
#include <include/core/SkPaint.h>
#include <include/core/SkShader.h>
#include <include/effects/SkGradientShader.h>
#include <include/core/SkPath.h>
using namespace marduk;
// A custom RenderObject that uses raw Skia for advanced drawing
class RenderSkiaBox : public RenderBox {
public:
void paint(PaintContext& ctx) override {
// 1. Get raw Skia canvas
SkCanvas* sk_canvas = static_cast<SkCanvas*>(ctx.canvas.getNativeHandle());
// 2. Define the bounds based on the layout computed by Anu
SkRect rect = SkRect::MakeXYWH(ctx.offset.x, ctx.offset.y, size().width, size().height);
// 3. Create a beautiful gradient shader
SkColor colors[] = { 0xFFFF0055, 0xFF5500FF }; // Pink to Purple
SkPoint points[] = {
SkPoint::Make(rect.left(), rect.top()),
SkPoint::Make(rect.right(), rect.bottom())
};
SkPaint sk_paint;
sk_paint.setShader(SkGradientShader::MakeLinear(
points, colors, nullptr, 2, SkTileMode::kClamp
));
// Draw the background with the gradient
sk_canvas->drawRect(rect, sk_paint);
// 4. Draw a custom shape (a star) using SkPath
SkPath star_path;
float center_x = rect.centerX();
float center_y = rect.centerY();
float R = std::min(rect.width(), rect.height()) * 0.4f; // outer radius
float r = R * 0.4f; // inner radius
star_path.moveTo(center_x, center_y - R);
for (int i = 1; i < 10; ++i) {
float angle = i * (3.14159265f / 5.0f);
float radius = (i % 2 == 0) ? R : r;
star_path.lineTo(
center_x + radius * std::sin(angle),
center_y - radius * std::cos(angle)
);
}
star_path.close();
SkPaint star_paint;
star_paint.setColor(SK_ColorWHITE);
star_paint.setAntiAlias(true);
star_paint.setStyle(SkPaint::kFill_Style);
// Draw the star!
sk_canvas->drawPath(star_path, star_paint);
}
};
int main(int argc, char** argv) {
AppConfig config{
.title = "Marduk - Raw Skia Integration",
.width = 800,
.height = 600,
.clear_color = 0xFF121212 // Very dark gray
};
// Use Anu Flexbox for layout
auto root = std::make_shared<RenderFlex>();
root->setFlexDirection(FlexDirection::Column);
root->setMainAxisAlignment(MainAxisAlign::Center);
root->setCrossAxisAlignment(CrossAxisAlign::Center);
// Create our custom Skia box
auto skia_box = new RenderSkiaBox();
// Set layout constraints directly on the Anu node
ANUNodeStyleSetWidth(skia_box->anuNode(), 300);
ANUNodeStyleSetHeight(skia_box->anuNode(), 300);
// You can even add margins via Anu!
ANUNodeStyleSetMargin(skia_box->anuNode(), ANUEdgeAll, 50);
root->addChild(skia_box);
return marduk::runApp(root, config);
}
meson setup build
meson compile -C build