home / skills / bbeierle12 / skill-mcp-claude / shader-sdf
This skill generates and explains signed distance function shaders for 2D/3D shapes, blending, repetition, and raymarching to create procedural visuals.
npx playbooks add skill bbeierle12/skill-mcp-claude --skill shader-sdfReview the files below or copy the command above to add this skill to your agents.
---
name: shader-sdf
description: Signed Distance Functions (SDFs) in GLSL—2D/3D shape primitives, boolean operations (union, intersection, subtraction), smooth blending, repetition, and raymarching fundamentals. Use when creating procedural shapes, text effects, smooth morphing, or raymarched 3D scenes.
---
# Shader SDFs
Signed Distance Functions return the distance from a point to a shape's surface. Negative = inside, positive = outside, zero = on surface.
## Quick Start
```glsl
// 2D circle SDF
float sdCircle(vec2 p, float r) {
return length(p) - r;
}
// Usage
float d = sdCircle(uv - 0.5, 0.3);
// Render
vec3 color = d < 0.0 ? vec3(1.0) : vec3(0.0); // Hard edge
vec3 color = vec3(smoothstep(0.01, 0.0, d)); // Soft edge
vec3 color = vec3(smoothstep(0.02, 0.0, abs(d))); // Outline
```
## 2D Primitives
### Circle
```glsl
float sdCircle(vec2 p, float r) {
return length(p) - r;
}
```
### Box
```glsl
float sdBox(vec2 p, vec2 b) {
vec2 d = abs(p) - b;
return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0);
}
```
### Rounded Box
```glsl
float sdRoundedBox(vec2 p, vec2 b, float r) {
vec2 d = abs(p) - b + r;
return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0) - r;
}
```
### Line Segment
```glsl
float sdSegment(vec2 p, vec2 a, vec2 b) {
vec2 pa = p - a;
vec2 ba = b - a;
float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
return length(pa - ba * h);
}
```
### Triangle
```glsl
float sdTriangle(vec2 p, vec2 p0, vec2 p1, vec2 p2) {
vec2 e0 = p1 - p0, e1 = p2 - p1, e2 = p0 - p2;
vec2 v0 = p - p0, v1 = p - p1, v2 = p - p2;
vec2 pq0 = v0 - e0 * clamp(dot(v0, e0) / dot(e0, e0), 0.0, 1.0);
vec2 pq1 = v1 - e1 * clamp(dot(v1, e1) / dot(e1, e1), 0.0, 1.0);
vec2 pq2 = v2 - e2 * clamp(dot(v2, e2) / dot(e2, e2), 0.0, 1.0);
float s = sign(e0.x * e2.y - e0.y * e2.x);
vec2 d = min(min(
vec2(dot(pq0, pq0), s * (v0.x * e0.y - v0.y * e0.x)),
vec2(dot(pq1, pq1), s * (v1.x * e1.y - v1.y * e1.x))),
vec2(dot(pq2, pq2), s * (v2.x * e2.y - v2.y * e2.x)));
return -sqrt(d.x) * sign(d.y);
}
```
### Ring
```glsl
float sdRing(vec2 p, float r, float thickness) {
return abs(length(p) - r) - thickness;
}
```
### Polygon (N-sided)
```glsl
float sdPolygon(vec2 p, float r, int n) {
float a = atan(p.x, p.y) + 3.141592;
float s = 6.283185 / float(n);
return cos(floor(0.5 + a / s) * s - a) * length(p) - r;
}
```
### Star
```glsl
float sdStar(vec2 p, float r, int n, float m) {
float an = 3.141592 / float(n);
float en = 3.141592 / m;
vec2 acs = vec2(cos(an), sin(an));
vec2 ecs = vec2(cos(en), sin(en));
float bn = mod(atan(p.x, p.y), 2.0 * an) - an;
p = length(p) * vec2(cos(bn), abs(sin(bn)));
p -= r * acs;
p += ecs * clamp(-dot(p, ecs), 0.0, r * acs.y / ecs.y);
return length(p) * sign(p.x);
}
```
## 3D Primitives
### Sphere
```glsl
float sdSphere(vec3 p, float r) {
return length(p) - r;
}
```
### Box
```glsl
float sdBox(vec3 p, vec3 b) {
vec3 q = abs(p) - b;
return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0);
}
```
### Rounded Box
```glsl
float sdRoundBox(vec3 p, vec3 b, float r) {
vec3 q = abs(p) - b;
return length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0) - r;
}
```
### Cylinder
```glsl
float sdCylinder(vec3 p, float h, float r) {
vec2 d = abs(vec2(length(p.xz), p.y)) - vec2(r, h);
return min(max(d.x, d.y), 0.0) + length(max(d, 0.0));
}
```
### Torus
```glsl
float sdTorus(vec3 p, vec2 t) {
vec2 q = vec2(length(p.xz) - t.x, p.y);
return length(q) - t.y;
}
```
### Cone
```glsl
float sdCone(vec3 p, vec2 c, float h) {
vec2 q = h * vec2(c.x / c.y, -1.0);
vec2 w = vec2(length(p.xz), p.y);
vec2 a = w - q * clamp(dot(w, q) / dot(q, q), 0.0, 1.0);
vec2 b = w - q * vec2(clamp(w.x / q.x, 0.0, 1.0), 1.0);
float k = sign(q.y);
float d = min(dot(a, a), dot(b, b));
float s = max(k * (w.x * q.y - w.y * q.x), k * (w.y - q.y));
return sqrt(d) * sign(s);
}
```
### Capsule
```glsl
float sdCapsule(vec3 p, vec3 a, vec3 b, float r) {
vec3 pa = p - a, ba = b - a;
float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0);
return length(pa - ba * h) - r;
}
```
### Plane
```glsl
float sdPlane(vec3 p, vec3 n, float h) {
return dot(p, n) + h;
}
```
## Boolean Operations
### Union (OR)
```glsl
float opUnion(float d1, float d2) {
return min(d1, d2);
}
```
### Intersection (AND)
```glsl
float opIntersection(float d1, float d2) {
return max(d1, d2);
}
```
### Subtraction (NOT)
```glsl
float opSubtraction(float d1, float d2) {
return max(-d1, d2);
}
```
### Smooth Union
```glsl
float opSmoothUnion(float d1, float d2, float k) {
float h = clamp(0.5 + 0.5 * (d2 - d1) / k, 0.0, 1.0);
return mix(d2, d1, h) - k * h * (1.0 - h);
}
```
### Smooth Intersection
```glsl
float opSmoothIntersection(float d1, float d2, float k) {
float h = clamp(0.5 - 0.5 * (d2 - d1) / k, 0.0, 1.0);
return mix(d2, d1, h) + k * h * (1.0 - h);
}
```
### Smooth Subtraction
```glsl
float opSmoothSubtraction(float d1, float d2, float k) {
float h = clamp(0.5 - 0.5 * (d2 + d1) / k, 0.0, 1.0);
return mix(d2, -d1, h) + k * h * (1.0 - h);
}
```
## Transformations
### Translation
```glsl
// Move shape by offset
float d = sdCircle(p - offset, r);
```
### Rotation (2D)
```glsl
mat2 rot2D(float a) {
float s = sin(a), c = cos(a);
return mat2(c, -s, s, c);
}
// Rotate point around origin
vec2 rotatedP = rot2D(angle) * p;
float d = sdBox(rotatedP, size);
```
### Rotation (3D)
```glsl
mat3 rotateX(float a) {
float s = sin(a), c = cos(a);
return mat3(1, 0, 0, 0, c, -s, 0, s, c);
}
mat3 rotateY(float a) {
float s = sin(a), c = cos(a);
return mat3(c, 0, s, 0, 1, 0, -s, 0, c);
}
mat3 rotateZ(float a) {
float s = sin(a), c = cos(a);
return mat3(c, -s, 0, s, c, 0, 0, 0, 1);
}
```
### Scale
```glsl
// Scale shape
float d = sdCircle(p / scale, r) * scale;
```
### Symmetry
```glsl
// Mirror across Y axis
p.x = abs(p.x);
float d = sdCircle(p - vec2(0.3, 0.0), 0.1);
```
## Domain Operations
### Repetition (Infinite)
```glsl
float opRepeat(vec2 p, vec2 spacing) {
vec2 q = mod(p + spacing * 0.5, spacing) - spacing * 0.5;
return sdCircle(q, 0.1);
}
```
### Repetition (Limited)
```glsl
float opRepeatLimited(vec3 p, float spacing, vec3 count) {
vec3 q = p - spacing * clamp(round(p / spacing), -count, count);
return sdSphere(q, 0.1);
}
```
### Twist
```glsl
float opTwist(vec3 p, float k) {
float c = cos(k * p.y);
float s = sin(k * p.y);
mat2 m = mat2(c, -s, s, c);
vec3 q = vec3(m * p.xz, p.y);
return sdBox(q, vec3(0.5));
}
```
### Bend
```glsl
float opBend(vec3 p, float k) {
float c = cos(k * p.x);
float s = sin(k * p.x);
mat2 m = mat2(c, -s, s, c);
vec3 q = vec3(m * p.xy, p.z);
return sdBox(q, vec3(0.5));
}
```
### Onion (Hollow)
```glsl
float opOnion(float d, float thickness) {
return abs(d) - thickness;
}
```
### Round
```glsl
float opRound(float d, float r) {
return d - r;
}
```
## 2D Rendering Techniques
### Anti-aliased Edge
```glsl
float aa = fwidth(d) * 1.5;
float mask = smoothstep(aa, -aa, d);
```
### Outline
```glsl
float outline = smoothstep(thickness + aa, thickness - aa, abs(d));
```
### Glow
```glsl
float glow = exp(-d * falloff);
```
### Drop Shadow
```glsl
float shadow = smoothstep(0.0, blur, sdShape(p - shadowOffset));
```
## 3D Raymarching (Basic)
```glsl
float map(vec3 p) {
float d = sdSphere(p, 1.0);
d = opSmoothUnion(d, sdBox(p - vec3(1.0, 0.0, 0.0), vec3(0.5)), 0.2);
return d;
}
vec3 calcNormal(vec3 p) {
vec2 e = vec2(0.001, 0.0);
return normalize(vec3(
map(p + e.xyy) - map(p - e.xyy),
map(p + e.yxy) - map(p - e.yxy),
map(p + e.yyx) - map(p - e.yyx)
));
}
float raymarch(vec3 ro, vec3 rd) {
float t = 0.0;
for (int i = 0; i < 100; i++) {
vec3 p = ro + rd * t;
float d = map(p);
if (d < 0.001) break;
if (t > 100.0) break;
t += d;
}
return t;
}
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
vec2 uv = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;
vec3 ro = vec3(0.0, 0.0, 3.0); // Ray origin
vec3 rd = normalize(vec3(uv, -1.0)); // Ray direction
float t = raymarch(ro, rd);
vec3 color = vec3(0.0);
if (t < 100.0) {
vec3 p = ro + rd * t;
vec3 n = calcNormal(p);
vec3 light = normalize(vec3(1.0, 1.0, 1.0));
float diff = max(dot(n, light), 0.0);
color = vec3(diff);
}
fragColor = vec4(color, 1.0);
}
```
## File Structure
```
shader-sdf/
├── SKILL.md
├── references/
│ ├── 2d-primitives.md # All 2D shapes
│ ├── 3d-primitives.md # All 3D shapes
│ └── operations.md # All operations
└── scripts/
├── primitives/
│ ├── 2d.glsl # 2D shape functions
│ └── 3d.glsl # 3D shape functions
├── operations.glsl # Boolean & domain ops
└── examples/
├── logo.glsl # 2D logo example
└── raymarch.glsl # 3D raymarching example
```
## Reference
- `references/2d-primitives.md` — Complete 2D shape library
- `references/3d-primitives.md` — Complete 3D shape library
- `references/operations.md` — All boolean and domain operations
This skill provides a compact GLSL toolkit for building Signed Distance Functions (SDFs) for 2D and 3D. It includes common shape primitives, boolean ops (union, intersection, subtraction), smooth blends, domain transforms (repeat, twist, bend), and a basic raymarching example for rendering. Use it to rapidly prototype procedural shapes, text effects, smooth morphs, and raymarched scenes.
Each function returns a signed distance: negative inside, positive outside, zero on the surface. Primitives (circle, box, sphere, torus, etc.) compute distance fields for single shapes. Operators combine or modify those fields: boolean ops pick min/max, smooth ops blend with a control parameter, and domain ops repeat or deform space before evaluating a primitive. The raymarch loop steps along a ray by the distance value from the map function and resolves surface normals via numerical gradient sampling.
How do I get soft edges and outlines?
Use smoothstep with fwidth(d) for anti-aliased edges and smoothstep on abs(d) to create outlines; adjust thresholds for thickness.
When should I use smooth unions instead of plain min()?
Use smooth unions when you want soft joins or rounded blends between shapes; tune the k parameter to control blend radius.