diff --git a/examples/sdl3_renderer/CMakeLists.txt b/examples/sdl3_renderer/CMakeLists.txt
new file mode 100644
index 0000000..9ac0733
--- /dev/null
+++ b/examples/sdl3_renderer/CMakeLists.txt
@@ -0,0 +1,47 @@
+cmake_minimum_required(VERSION 3.27)
+
+# Project setup
+project(clay_sdl3_renderer C)
+set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g -Wall -Werror")
+set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3")
+
+include(FetchContent)
+set(FETCHCONTENT_QUIET FALSE)
+
+# Download SDL3
+FetchContent_Declare(
+	SDL
+	GIT_REPOSITORY https://github.com/libsdl-org/SDL.git
+	GIT_TAG preview-3.1.6
+	GIT_SHALLOW TRUE
+	GIT_PROGRESS TRUE
+)
+message(STATUS "Using SDL via FetchContent")
+FetchContent_MakeAvailable(SDL)
+set_property(DIRECTORY "${sdl_SOURCE_DIR}" PROPERTY EXCLUDE_FROM_ALL TRUE)
+
+# Download SDL_ttf
+FetchContent_Declare(
+	SDL_ttf
+	GIT_REPOSITORY https://github.com/libsdl-org/SDL_ttf.git
+	GIT_TAG main # Slightly risky to use main branch, but it's the only one available
+	GIT_SHALLOW TRUE
+	GIT_PROGRESS TRUE
+)
+message(STATUS "Using SDL_ttf via FetchContent")
+FetchContent_MakeAvailable(SDL_ttf)
+set_property(DIRECTORY "${sdl_ttf_SOURCE_DIR}" PROPERTY EXCLUDE_FROM_ALL TRUE)
+
+# Example executable
+add_executable(${PROJECT_NAME} main.c)
+target_link_libraries(${PROJECT_NAME} PRIVATE
+	SDL3::SDL3
+	SDL3_ttf::SDL3_ttf
+)
+
+add_custom_command(
+	TARGET ${PROJECT_NAME} POST_BUILD
+	COMMAND ${CMAKE_COMMAND} -E copy_directory
+		${CMAKE_CURRENT_SOURCE_DIR}/resources
+		${CMAKE_CURRENT_BINARY_DIR}/resources
+)
diff --git a/examples/sdl3_renderer/main.c b/examples/sdl3_renderer/main.c
new file mode 100644
index 0000000..d982cec
--- /dev/null
+++ b/examples/sdl3_renderer/main.c
@@ -0,0 +1,215 @@
+#define SDL_MAIN_USE_CALLBACKS
+#include <SDL3/SDL_main.h>
+#include <SDL3/SDL.h>
+#include <SDL3_ttf/SDL_ttf.h>
+
+#define CLAY_IMPLEMENTATION
+#include "../../clay.h"
+
+static const Uint32 FONT_ID = 0;
+
+static const Clay_Color COLOR_ORANGE    = (Clay_Color) {225, 138, 50, 255};
+static const Clay_Color COLOR_BLUE      = (Clay_Color) {111, 173, 162, 255};
+static const Clay_Color COLOR_LIGHT     = (Clay_Color) {224, 215, 210, 255};
+
+typedef struct app_state {
+    SDL_Window *window;
+    SDL_Renderer *renderer;
+} AppState;
+
+/* This needs to be global because the "MeasureText" callback doesn't have a
+ * user data parameter */
+static TTF_Font *gFonts[1];
+
+static inline Clay_Dimensions SDL_MeasureText(Clay_String *text, Clay_TextElementConfig *config)
+{
+    TTF_Font *font = gFonts[config->fontId];
+    int width, height;
+
+    if (!TTF_GetStringSize(font, text->chars, text->length, &width, &height)) {
+        SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to measure text: %s", SDL_GetError());
+    }
+
+    return (Clay_Dimensions) { (float) width, (float) height };
+}
+
+static void Label(Clay_String text)
+{
+    CLAY(CLAY_LAYOUT({ .padding = {16, 8} }), CLAY_RECTANGLE({ .color = Clay_Hovered() ? COLOR_BLUE : COLOR_ORANGE })) {
+        CLAY_TEXT(text, CLAY_TEXT_CONFIG({
+           .textColor = { 255, 255, 255, 255 },
+           .fontId = FONT_ID,
+           .fontSize = 24,
+        }));
+   }
+}
+
+static Clay_RenderCommandArray Clay_CreateLayout()
+{
+    Clay_BeginLayout();
+    CLAY(CLAY_ID("MainContent"),
+        CLAY_LAYOUT({
+            .sizing = {
+                .width = CLAY_SIZING_GROW(),
+                .height = CLAY_SIZING_GROW(),
+            },
+            .childAlignment = {
+                .x = CLAY_ALIGN_X_CENTER,
+                .y = CLAY_ALIGN_Y_CENTER,
+            },
+            .childGap = 10,
+            .padding = { 10, 10 },
+            .layoutDirection = CLAY_TOP_TO_BOTTOM,
+        }),
+        CLAY_RECTANGLE({
+            .color = COLOR_LIGHT,
+        })
+    ) {
+        Label(CLAY_STRING("Button 1"));
+        Label(CLAY_STRING("Button 2"));
+        Label(CLAY_STRING("Button 3"));
+    }
+    return Clay_EndLayout();
+}
+
+static void SDL_RenderClayCommands(SDL_Renderer *renderer, Clay_RenderCommandArray *rcommands)
+{
+    for (size_t i = 0; i < rcommands->length; i++) {
+        Clay_RenderCommand *rcmd = Clay_RenderCommandArray_Get(rcommands, i);
+        Clay_BoundingBox bounding_box = rcmd->boundingBox;
+        SDL_FRect rect = { bounding_box.x, bounding_box.y, bounding_box.width, bounding_box.height };
+
+        switch (rcmd->commandType) {
+            case CLAY_RENDER_COMMAND_TYPE_RECTANGLE: {
+                Clay_RectangleElementConfig *config = rcmd->config.rectangleElementConfig;
+                Clay_Color color = config->color;
+                SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
+                SDL_RenderFillRect(renderer, &rect);
+            } break;
+            case CLAY_RENDER_COMMAND_TYPE_TEXT: {
+                Clay_TextElementConfig *config = rcmd->config.textElementConfig;
+                Clay_String *text = &rcmd->text;
+                SDL_Color color = { config->textColor.r, config->textColor.g, config->textColor.b, config->textColor.a };
+
+                TTF_Font *font = gFonts[config->fontId];
+                SDL_Surface *surface = TTF_RenderText_Blended(font, text->chars, text->length, color);
+                SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
+                SDL_RenderTexture(renderer, texture, NULL, &rect);
+
+                SDL_DestroySurface(surface);
+                SDL_DestroyTexture(texture);
+            } break;
+            default:
+                SDL_Log("Unknown render command type: %d", rcmd->commandType);
+        }
+    }
+}
+
+SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
+{
+    (void) argc;
+    (void) argv;
+
+    if (!TTF_Init()) {
+        return SDL_APP_FAILURE;
+    }
+
+    AppState *state = SDL_calloc(1, sizeof(AppState));
+    if (!state) {
+        return SDL_APP_FAILURE;
+    }
+    *appstate = state;
+
+    if (!SDL_CreateWindowAndRenderer("Clay Demo", 640, 480, 0, &state->window, &state->renderer)) {
+        SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to create window and renderer: %s", SDL_GetError());
+        return SDL_APP_FAILURE;
+    }
+    SDL_SetWindowResizable(state->window, true);
+
+    TTF_Font *font = TTF_OpenFont("resources/Roboto-Regular.ttf", 24);
+    if (!font) {
+        SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to load font: %s", SDL_GetError());
+        return SDL_APP_FAILURE;
+    }
+
+    gFonts[FONT_ID] = font;
+
+    /* Initialize Clay */
+    uint64_t totalMemorySize = Clay_MinMemorySize();
+    Clay_Arena clayMemory = (Clay_Arena) {
+        .label = CLAY_STRING("Clay Memory Arena"),
+        .memory = SDL_malloc(totalMemorySize),
+        .capacity = totalMemorySize
+    };
+
+    int width, height;
+    SDL_GetWindowSize(state->window, &width, &height);
+    Clay_SetMeasureTextFunction(SDL_MeasureText);
+    Clay_Initialize(clayMemory, (Clay_Dimensions) { (float) width, (float) height });
+
+    *appstate = state;
+    return SDL_APP_CONTINUE;
+}
+
+SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
+{
+    SDL_AppResult ret_val = SDL_APP_CONTINUE;
+
+    switch (event->type) {
+        case SDL_EVENT_QUIT:
+            ret_val = SDL_APP_SUCCESS;
+            break;
+        case SDL_EVENT_WINDOW_RESIZED:
+            Clay_SetLayoutDimensions((Clay_Dimensions) { (float) event->window.data1, (float) event->window.data2 });
+            break;
+        case SDL_EVENT_MOUSE_MOTION:
+            Clay_SetPointerState((Clay_Vector2) { event->motion.x, event->motion.y },
+                                 event->motion.state & SDL_BUTTON_LEFT);
+            break;
+        case SDL_EVENT_MOUSE_WHEEL:
+            Clay_UpdateScrollContainers(true, (Clay_Vector2) { event->motion.xrel, event->motion.yrel }, 0.01f);
+            break;
+        default:
+            break;
+    };
+
+    return ret_val;
+}
+
+SDL_AppResult SDL_AppIterate(void *appstate)
+{
+    AppState *state = appstate;
+
+    Clay_RenderCommandArray render_commands = Clay_CreateLayout();
+
+    SDL_SetRenderDrawColor(state->renderer, 0, 0, 0, 255);
+    SDL_RenderClear(state->renderer);
+
+    SDL_RenderClayCommands(state->renderer, &render_commands);
+
+    SDL_RenderPresent(state->renderer);
+
+    return SDL_APP_CONTINUE;
+}
+
+void SDL_AppQuit(void *appstate, SDL_AppResult result)
+{
+    (void) result;
+
+    if (result != SDL_APP_SUCCESS) {
+        SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Application failed to run");
+    }
+
+    AppState *state = appstate;
+
+    if (state) {
+        if (state->renderer)
+            SDL_DestroyRenderer(state->renderer);
+
+        if (state->window)
+            SDL_DestroyWindow(state->window);
+
+        SDL_free(state);
+    }
+    TTF_Quit();
+}
diff --git a/examples/sdl3_renderer/resources/Roboto-Regular.ttf b/examples/sdl3_renderer/resources/Roboto-Regular.ttf
new file mode 100644
index 0000000..ddf4bfa
Binary files /dev/null and b/examples/sdl3_renderer/resources/Roboto-Regular.ttf differ