# Forge Debug Lines

> Add immediate-mode debug line drawing to an SDL GPU project. Render colored lines, grids, axes, circles, and wireframe boxes with world-space (depth-tested) and overlay (always-on-top) modes. Use when someone needs diagnostic visualization, debug drawing, or wireframe rendering in SDL3 GPU.

- **Type:** Skill
- **Install:** `agentstack add skill-nebulavenus-forge-gpu-forge-debug-lines`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [Nebulavenus](https://agentstack.voostack.com/s/nebulavenus)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** Zlib
- **Upstream author:** [Nebulavenus](https://github.com/Nebulavenus)
- **Source:** https://github.com/Nebulavenus/forge-gpu/tree/main/.claude/skills/forge-debug-lines

## Install

```sh
agentstack add skill-nebulavenus-forge-gpu-forge-debug-lines
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Debug Lines — Immediate-Mode Debug Drawing

This skill adds a lightweight debug drawing system to any SDL GPU project.
It uses `SDL_GPU_PRIMITIVETYPE_LINELIST` with a dynamic vertex buffer updated
every frame via the immediate-mode pattern: reset, accumulate, upload, draw.

## When to use

- Visualizing positions, bounds, directions, or other spatial data
- Drawing coordinate-axis gizmos (RGB = XYZ)
- Rendering wireframe bounding boxes for physics or collision debugging
- Drawing circles to show radii, influence zones, or trigger areas
- Adding an always-visible overlay for diagnostic indicators
- Any per-frame debug visualization that changes based on game state

## Key API calls (ordered)

1. `SDL_CreateGPUGraphicsPipeline` — create two pipelines (depth ON / depth OFF)
   with `SDL_GPU_PRIMITIVETYPE_LINELIST` and `SDL_GPU_CULLMODE_NONE`
2. `SDL_CreateGPUBuffer` — pre-allocate GPU vertex buffer for max vertices
3. `SDL_CreateGPUTransferBuffer` — pre-allocate upload staging buffer
4. `SDL_MapGPUTransferBuffer` / `SDL_UnmapGPUTransferBuffer` — map, copy, unmap each frame
5. `SDL_UploadToGPUBuffer` — copy pass to transfer data to GPU
6. `SDL_PushGPUVertexUniformData` — push VP matrix
7. `SDL_DrawGPUPrimitives` — draw world lines, then overlay lines with first_vertex offset

## Common mistakes

- **Forgetting to reset vertex counts each frame.** The immediate-mode pattern
  requires `world_count = 0; overlay_count = 0;` at the start of every frame,
  otherwise vertices accumulate and the buffer overflows.
- **Using TRIANGLELIST primitive type.** Debug lines use `LINELIST` — every pair
  of vertices is a separate line segment. There are no faces, no indices.
- **Enabling back-face culling.** Lines have no face orientation.  Always use
  `SDL_GPU_CULLMODE_NONE` for line pipelines.
- **Creating separate GPU buffers for world and overlay.** Both can share one
  buffer — use `first_vertex` offset in the draw call to select the region.
- **Forgetting the copy pass before drawing.** The transfer buffer upload
  requires `SDL_BeginGPUCopyPass` / `SDL_UploadToGPUBuffer` /
  `SDL_EndGPUCopyPass` / `SDL_SubmitGPUCommandBuffer` before the render pass.

## Code template

### Vertex format

```c
typedef struct DebugVertex {
    vec3 position;   /* 12 bytes — world-space position */
    vec4 color;      /* 16 bytes — RGBA color           */
} DebugVertex;       /* 28 bytes total                  */

#define DEBUG_VERTEX_PITCH 28
#define MAX_DEBUG_VERTICES 65536
```

### Pipeline creation

```c
/* Vertex layout: position (float3) + color (float4) */
SDL_GPUVertexAttribute attrs[2];
SDL_zero(attrs);
attrs[0].location = 0;
attrs[0].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3;
attrs[0].offset = offsetof(DebugVertex, position);
attrs[1].location = 1;
attrs[1].format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT4;
attrs[1].offset = offsetof(DebugVertex, color);

SDL_GPUGraphicsPipelineCreateInfo pipe;
SDL_zero(pipe);
pipe.primitive_type = SDL_GPU_PRIMITIVETYPE_LINELIST;
pipe.rasterizer_state.cull_mode = SDL_GPU_CULLMODE_NONE;

/* World-space pipeline: depth test ON */
pipe.depth_stencil_state.enable_depth_test = true;
pipe.depth_stencil_state.enable_depth_write = true;
pipe.depth_stencil_state.compare_op = SDL_GPU_COMPAREOP_LESS_OR_EQUAL;
line_pipeline = SDL_CreateGPUGraphicsPipeline(device, &pipe);

/* Overlay pipeline: depth test OFF */
pipe.depth_stencil_state.enable_depth_test = false;
pipe.depth_stencil_state.enable_depth_write = false;
overlay_pipeline = SDL_CreateGPUGraphicsPipeline(device, &pipe);
```

### Per-frame upload and draw

```c
/* 1. Reset counts */
state->world_count = 0;
state->overlay_count = 0;

/* 2. Accumulate debug shapes */
debug_grid(state, 20, 1.0f, gray);
debug_axes(state, origin, 2.0f, true);   /* overlay */
debug_box_wireframe(state, min, max, orange, false);

/* 3. Upload (map → copy → unmap → copy pass) */
void *mapped = SDL_MapGPUTransferBuffer(device, transfer_buf, true);
SDL_memcpy(mapped, vertices, total * sizeof(DebugVertex));
SDL_UnmapGPUTransferBuffer(device, transfer_buf);
/* ... copy pass to GPU buffer ... */

/* 4. Draw */
if (world_count > 0) {
    SDL_BindGPUGraphicsPipeline(pass, line_pipeline);
    SDL_DrawGPUPrimitives(pass, world_count, 1, 0, 0);
}
if (overlay_count > 0) {
    SDL_BindGPUGraphicsPipeline(pass, overlay_pipeline);
    SDL_DrawGPUPrimitives(pass, overlay_count, 1, world_count, 0);
}
```

### Debug shape helpers

```c
/* Single line segment (2 vertices) */
static void debug_line(state, vec3 start, vec3 end, vec4 color, bool overlay);

/* Ground grid on XZ plane */
static void debug_grid(state, int half_size, float spacing, vec4 color);

/* Coordinate axes: red=X, green=Y, blue=Z (6 vertices) */
static void debug_axes(state, vec3 origin, float size, bool overlay);

/* Circle from line segments (2 × segments vertices) */
static void debug_circle(state, vec3 center, float radius, vec3 normal,
                          vec4 color, int segments, bool overlay);

/* Wireframe AABB (24 vertices = 12 edges) */
static void debug_box_wireframe(state, vec3 min_pt, vec3 max_pt,
                                 vec4 color, bool overlay);
```

### Shader (HLSL)

```hlsl
/* Vertex shader — transform position, pass through color */
cbuffer DebugUniforms : register(b0, space1)
{
    column_major float4x4 view_projection;
};

struct VSInput  { float3 position : TEXCOORD0; float4 color : TEXCOORD1; };
struct VSOutput { float4 clip_pos : SV_Position; float4 color : TEXCOORD0; };

VSOutput main(VSInput input) {
    VSOutput output;
    output.clip_pos = mul(view_projection, float4(input.position, 1.0));
    output.color = input.color;
    return output;
}

/* Fragment shader — pass-through color */
float4 main(PSInput input) : SV_Target { return input.color; }
```

## Lesson reference

See [Lesson 19 — Debug Lines](../../../lessons/gpu/19-debug-lines/) for the
full implementation with detailed comments explaining every step.

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [Nebulavenus](https://github.com/Nebulavenus)
- **Source:** [Nebulavenus/forge-gpu](https://github.com/Nebulavenus/forge-gpu)
- **License:** Zlib

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-nebulavenus-forge-gpu-forge-debug-lines
- Seller: https://agentstack.voostack.com/s/nebulavenus
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
