Object oriented MVC framework for SDL3 and C.
Zlib license.
ObjectivelyMVC is a cross-platform user interface framework for SDL3 and C. It is geared towards building high-quality, modern user interfaces within video games. It is built on Objectively and ObjectivelyGPU.
- Cross-platform works on Android, iOS, macOS, Linux and Windows
- Does not hijack your main loop — your game owns the window, GPU device, and events; you call it each frame
- Complete widget set: Button, Checkbox, Slider, Select, TextView, TableView, CollectionView, TabView, PageView, and more
- Programmatic or JSON-driven layouts for declarative, data-driven UI
- Fully themable via a CSS-inspired Selector / Style / Stylesheet system
- High-DPI / Retina ready — high-density display detection with SDL_ttf TrueType font rendering
- Object oriented MVC in C via Objectively, without imposing C++
Describe an entire interface in JSON and inflate it with a single call — outlets bind the named Views straight into your controller:
Outlet outlets[] = MakeOutlets(
MakeOutlet("apply", &this->apply),
MakeOutlet("slider", &this->slider)
);
View *panel = $$(View, viewWithResourceName, "Settings.json", outlets);
$(self->view, addSubview, panel);
this->apply->delegate.didClick = didClickApply;And ObjectivelyMVC never hijacks your main loop. Your game owns the window, the GPU device and the events; you simply hand it each event and a frame to draw into:
$(windowController, respondToEvent, &event);
...
$(windowController, render);Read this before writing any View code. Layout is driven by the Selector / Style / Stylesheet system, not by assigning fields in C. Getting this backwards is the single most common way to waste an afternoon.
Attributes documented @styled in the headers — alignment, autoresizingMask, padding,
frame.w / frame.h (as width / height), minSize, maxSize, pointerEvents,
backgroundColor, borderWidth, visibility, StackView::axis, StackView::spacing and the
rest — are bound from the computed Style by View::applyStyle on every theme application.
Anything assigned in C is silently overwritten the next time the theme is applied, which is to say
almost immediately:
/* WRONG: overwritten by the next applyStyle, which binds `axis` from the computed style */
stackView->axis = StackViewAxisHorizontal;
((View *) stackView)->alignment = ViewAlignmentBottomCenter;/* RIGHT */
MyControlsView {
alignment: bottom-center;
axis: horizontal;
}Assign in C only what is not styled: delegates, data source callbacks, model values
(Slider::min / max / value) and structure (addSubview). To target a view from CSS, give it
a class with $(view, addClassName, "myClass"), or an identifier, and select on that.
Assets/stylesheet.css is always in the Theme, and its rules apply to your views whether you
expect them to or not. The defaults that most often surprise:
| Rule | Consequence |
|---|---|
StackView { axis: vertical } |
A stack is vertical unless your CSS says otherwise |
Button { min-width: 100; padding: 8 8 8 8 } |
An icon button is at least 100px wide until min-width is overruled |
Control { min-height: 32 } |
...and at least 32px tall, likewise |
StackView { autoresizing-mask: contain } |
Stacks size to their content; most other views do not |
Setting width alone does not shrink a Button: min-width clamps it. Override both.
A View with autoresizing-mask: none is exactly its frame. contain sizes it to fit its
subviews, fill expands it to its superview, and width / height do one axis each. A container
left at none with no explicit size is 0x0, and its subviews are then laid out from that empty
box: they appear to scatter, or to spill outside their parent, rather than simply not drawing.
View::hitTest descends into subviews before consulting a view's own pointerEvents, so a child
with pointer-events: auto is clickable inside a parent with pointer-events: none, exactly as in
CSS.
View::stylesheet is added to the window's Theme when the view moves to a window, and that Theme
is window-global: once attached, its rules apply to every view in the window, including views
created afterwards. A view built programmatically in a hierarchy that never loaded a stylesheet is
styled by the defaults above and nothing else.
Consult the Installation guide for dependencies, building, and linking.
Consult the User Guide to build your first interface — fonts, views and controls, JSON layout, theming, and resource loading.
Browse the API Documentation to explore the library.
- Hello creates a window and renders a themed menu over a 3D scene using JSON layout — walked through in the Guide.
- Objectively is the object oriented framework ObjectivelyMVC is built on.
- ObjectivelyGPU is the graphics framework ObjectivelyMVC renders with.
- Quetoo is a free first-person shooter that uses ObjectivelyMVC for its in-game user interface.



