Agent skill
forge-ui-rendering
Render the forge-gpu immediate-mode UI system on the GPU with a single draw call, font atlas texture, alpha blending, and dynamic buffer streaming. Based on Lesson 28.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/other/other/forge-ui-rendering-code-review-benchmar-coderabbit-prs2-forg
SKILL.md
Render the CPU-side immediate-mode UI (forge_ui_ctx.h, forge_ui_window.h) using the SDL GPU API. Based on GPU Lesson 28.
When to use
- You have a ForgeUiContext producing vertex/index arrays and need to draw them
- You need to render text glyphs from a font atlas with alpha blending
- You need a single-draw-call 2D UI pipeline with dynamic buffer streaming
- You want to integrate the UI track output into a GPU application
Key API calls
SDL_CreateGPUTexturewithSDL_GPU_TEXTUREFORMAT_R8_UNORM— single-channel atlasSDL_CreateGPUSampler— linear filter, clamp-to-edge for atlasSDL_CreateGPUGraphicsPipeline— alpha blend, no depth, cull noneSDL_CreateGPUTransferBuffer/SDL_MapGPUTransferBuffer— per-frame uploadSDL_UploadToGPUBuffer— copy vertex + index data via copy passSDL_PushGPUVertexUniformData— orthographic projection matrixSDL_DrawGPUIndexedPrimitives— single batched draw callforge_ui_ctx_begin/forge_ui_ctx_end— UI declaration phaseforge_ui_wctx_begin/forge_ui_wctx_end— window z-order sorting
Correct order
-
Init (once) a. Load font with
forge_ui_ttf_load, build atlas withforge_ui_atlas_buildb. Upload atlas pixels to R8_UNORM GPU texture via transfer buffer + copy pass c. Create sampler (linear, clamp-to-edge) d. Create vertex and fragment shaders from compiled HLSL bytecode e. Create pipeline: alpha blend enabled, no depth, cull none, 4x FLOAT2 vertex attrs f. Pre-allocate vertex and index GPU buffers (power-of-two sizes) g. Init ForgeUiContext and ForgeUiWindowContext -
Each frame a. Query window size and mouse state b.
forge_ui_ctx_begin— start UI declaration c. Declare windows and widgets (labels, buttons, checkboxes, sliders, text input) d.forge_ui_wctx_end/forge_ui_ctx_end— finalize vertex/index arrays e. Resize GPU buffers if needed (power-of-two growth) f. Create single transfer buffer, map, copy vertex+index data, unmap g. Copy pass: upload vertex data at offset 0, index data after h. Release transfer buffer i. Acquire swapchain, begin render pass (clear) j. Bind pipeline, vertex buffer, index buffer, atlas texture+sampler k. Push orthographic projection uniform l.SDL_DrawGPUIndexedPrimitives— one call for all UI m. End render pass, submit command buffer
Key concepts
- ForgeUiVertex is 32 bytes — 8 floats: pos(2), uv(2), color(4). Pipeline reads as 4x FLOAT2.
- White-pixel technique — solid rects use UVs pointing to a white region in the atlas where coverage = 1.0, so the fragment shader works for both text and solid geometry.
- R8_UNORM atlas — single-channel texture saves 4x memory vs RGBA8. Fragment shader reads
.ras coverage. - Orthographic projection — maps [0..W, 0..H] pixels to [-1..+1] clip space with Y flipped for top-left origin. Rebuilt every frame for automatic resize handling.
- No depth buffer — 2D UI uses painter's algorithm via z_order sorting in the window context.
- No backface culling — UI quads may have either winding order.
- Single draw call — all widgets batched into one vertex/index stream by the UI context.
Theme colors
The forge-gpu project uses a dark blue-gray palette defined in
scripts/forge_diagrams/_common.py. All UI colors follow this theme. The
key property: dark surfaces carry a strong blue tint (B/R ratio ~1.8) that
tapers toward neutral at brighter levels (~1.07 for text).
Reference palette (sRGB)
| Role | Hex | RGBA float | Used for |
|---|---|---|---|
| Background | #1a1a2e |
(0.10, 0.10, 0.18, 1.0) | Clear color |
| Surface | #252545 |
(0.14, 0.14, 0.27, 1.0) | Panel/window BG |
| Grid | #2a2a4a |
(0.16, 0.16, 0.29, 1.0) | Title bar BG |
| Accent cyan | #4fc3f7 |
(0.31, 0.76, 0.97, 1.0) | Active/focused states, cursors, borders |
| Accent orange | #ff7043 |
(1.00, 0.44, 0.26, 1.0) | Secondary highlights |
| Accent green | #66bb6a |
(0.40, 0.73, 0.42, 1.0) | Tertiary highlights |
| Accent purple | #ab47bc |
(0.67, 0.28, 0.74, 1.0) | Special elements |
| Warn yellow | #ffd54f |
(1.00, 0.84, 0.31, 1.0) | Warnings, annotations |
| Text | #e0e0f0 |
(0.88, 0.88, 0.94, 1.0) | Primary text, labels |
| Dim text | #8888aa |
(0.53, 0.53, 0.67, 1.0) | Secondary/info text |
Deriving new colors
When adding new UI elements, derive colors from the theme by maintaining the blue tint ratio for the brightness level:
- Dark (0.10–0.20 R/G): set B ≈ R × 1.7–1.8
- Medium (0.20–0.40 R/G): set B ≈ R × 1.5–1.6
- Bright (0.40–0.60 R/G): set B ≈ R × 1.3–1.4
- Near-white (0.80+ R/G): set B ≈ R × 1.05–1.15
The default widget colors in forge_ui_ctx.h and forge_ui_window.h
already follow this theme. The clear color and label colors are set per
lesson (see main.c CLEAR_R/G/B and TITLE_LABEL_R/G/B defines).
Common mistakes
- Using RGBA8 for the atlas — wastes 4x GPU memory and requires CPU-side pixel expansion. Use R8_UNORM.
- Forgetting to flip Y in the projection — without
-2.0f / height, the UI renders upside down. - Not checking SDL_SubmitGPUCommandBuffer return — must check on every path, including error paths after swapchain acquisition.
- Leaking the transfer buffer — release it after the copy pass ends, not after submit.
- Not handling the minimized window case — when swapchain texture is NULL, submit the command buffer and return.
- Fixed-size buffers — if the UI grows beyond initial capacity, you must resize. Use power-of-two growth.
- Depth testing with alpha blending — depth test would discard semi-transparent fragments. Disable it for 2D UI.
Template
#define SDL_MAIN_USE_CALLBACKS 1
#include "ui/forge_ui.h"
#include "ui/forge_ui_ctx.h"
#include "ui/forge_ui_window.h"
#include "math/forge_math.h"
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
/* Include compiled shader headers */
#include "shaders/compiled/ui_vert_spirv.h"
#include "shaders/compiled/ui_vert_dxil.h"
#include "shaders/compiled/ui_frag_spirv.h"
#include "shaders/compiled/ui_frag_dxil.h"
typedef struct UiUniforms {
mat4 projection; /* orthographic pixel-to-NDC mapping */
} UiUniforms;
typedef struct app_state {
SDL_Window *window;
SDL_GPUDevice *device;
SDL_GPUGraphicsPipeline *pipeline;
SDL_GPUTexture *atlas_texture; /* R8_UNORM font atlas */
SDL_GPUSampler *atlas_sampler; /* linear, clamp-to-edge */
SDL_GPUBuffer *vertex_buffer;
SDL_GPUBuffer *index_buffer;
Uint32 vertex_buffer_size;
Uint32 index_buffer_size;
ForgeUiFont font;
ForgeUiFontAtlas atlas;
ForgeUiContext ui_ctx;
ForgeUiWindowContext ui_wctx;
/* ... widget state ... */
} app_state;
/* Orthographic projection: top-left origin, y-down */
static mat4 ui_ortho_projection(float width, float height)
{
mat4 m = mat4_identity();
m.m[0] = 2.0f / width;
m.m[5] = -2.0f / height;
m.m[12] = -1.0f;
m.m[13] = 1.0f;
return m;
}
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?