20 years Weta/Pixar experience in real-time graphics, Metal shaders, and visual effects. Expert in MSL shaders, PBR rendering, tile-based deferred rendering (TBDR), and GPU debugging. Activate on 'Metal shader', 'MSL', 'compute shader', 'vertex shader', 'fragment shader', 'PBR', 'ray tracing', 'tile shader', 'GPU profiling', 'Apple GPU'. NOT for WebGL/GLSL (different architecture), general OpenGL (deprecated on Apple), CUDA (NVIDIA only), or CPU-side rendering optimization.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
20 years Weta/Pixar experience in real-time graphics, Metal shaders, and visual effects. Expert in MSL shaders, PBR rendering, tile-based deferred rendering (TBDR), and GPU debugging. Activate on 'Metal shader', 'MSL', 'compute shader', 'vertex shader', 'fragment shader', 'PBR', 'ray tracing', 'tile shader', 'GPU profiling', 'Apple GPU'. NOT for WebGL/GLSL (different architecture), general OpenGL (deprecated on Apple), CUDA (NVIDIA only), or CPU-side rendering optimization.
{"category":"Frontend & UI","tags":["metal","shaders","gpu","graphics","apple"],"provenance":{"kind":"first-party","owners":["port-daddy"]},"pairs-with":[{"skill":"gpui-shaders","reason":"gpui renders its custom widgets through Metal shaders on macOS; this skill supplies the MSL/TBDR expertise those shaders need."},{"skill":"metal-text-pipeline","reason":"Text rendering pipelines share the same precision/TBDR trade-offs (half vs float, tile memory) this skill's decision matrices cover."},{"skill":"vello-parley-rendering","reason":"GPU vector-graphics rendering needs the same bandwidth/occupancy discipline for compute and tile shaders."},{"skill":"rust-gpui-motion","reason":"Animated gpui UI often drives per-frame shader parameters; this skill's failure modes (branch divergence, register pressure) apply directly."}],"io-contract":{"kind":"deliverable","consumes":["[Truncated]","[Truncated]"],"produces":["[Truncated]","[Truncated]"]}}
Metal Shader Expert
20+ years Weta/Pixar experience specializing in Metal shaders, real-time rendering, and creative visual effects. Expert in Apple's Tile-Based Deferred Rendering (TBDR) architecture.
Decision Points
Shader Type Selection Matrix
Massive parallel data processing:
If data-independent operations → Compute shader (threadgroup size = data size)
If per-pixel operations with neighbor access → Tile shader
If simple per-vertex transformations → Vertex shader
If per-pixel lighting/materials → Fragment shader
Memory access patterns:
If reading multiple textures per pixel → Fragment shader (tile cache optimized)
If writing to multiple render targets → Fragment shader with [[color(n)]]
If sharing data between nearby threads → Tile shader with threadgroup memory
If sequential processing → Compute shader with atomic operations
If ALU-limited (heavy computation) → Compute shader (more threads)
If geometry-limited → Vertex shader with instancing/amplification
Memory/Precision Trade-off Decision Tree
Input: Variable type needed
├── Position/depth calculations?
│ └── YES: Use `float` (32-bit precision required)
├── Color/normal calculations?
│ ├── HDR/wide gamut? → `float`
│ └── Standard range? → `half` (saves 50% registers)
├── Iteration counters/indices?
│ └── Use `uint16_t` or `ushort` when possible
└── Temporary calculations?
├── Intermediate precision needed? → `float`
└── Display-bound result? → `half`
TBDR Architecture Decisions
Render target strategy:
If intermediate data not needed after pass → Memoryless texture (MTLStorageModeMemoryless)
If ping-ponging between targets → Use tile shader to avoid store/load
If multiple render targets → Group related data to minimize bandwidth
Failure Modes
1. "Bandwidth Bandit" - Excessive Memory Traffic
Detection: Frame debugger shows high memory bandwidth, low ALU utilization
Symptoms: Multiple texture fetches per fragment, storing unnecessary render targets
Fix: Use tile shaders for multi-pass effects, memoryless targets for intermediate data
// BAD: Multiple passes with full store/load
float4 pass1_result = sample_texture(tex1, uv);
// Store to render target, then load in next pass
// GOOD: Tile shader keeps data in tile memory
threadgroup float4 tile_data[64];
// Process multiple steps without memory round-trip
2. "Register Pressure Cascade" - Poor Data Type Choices
Detection: GPU occupancy drops below 50%, register spilling in shader profiler
Symptoms: Using float4 everywhere, large intermediate arrays
Fix: Use half for display-bound calculations, pack data efficiently
Detection: Fragment shader shows low efficiency in GPU profiler
Symptoms:if/else statements based on material properties or uniforms
Fix: Use function constants for compile-time specialization
// BAD: Runtime branching
if (material.has_normal_map) { /* complex normal mapping */ }
// GOOD: Function constant
constant bool has_normal_map [[function_constant(0)]];
if (has_normal_map) { /* branch eliminated at compile time */ }
Detection: Memory bandwidth higher than expected, register usage at 100%
Symptoms:float used for colors, normals, and other display-bound values
Fix: Default to half, upgrade only when precision artifacts appear
Detection: Ray tracing performance significantly below expectations
Symptoms: Using intersection query API instead of intersector
Fix: Use intersector API with explicit result handling for hardware alignment
Worked Examples
Example 1: PBR Fragment Shader Optimization
Initial novice implementation:
fragment float4 pbr_fragment(VertexOut in [[stage_in]],
constant Material& material [[buffer(0)]],
texture2d<float> albedo_tex [[texture(0)]]) {
float4 albedo = albedo_tex.sample(sampler, in.uv);
float3 normal = normalize(in.normal);
// ... complex BRDF calculation using float everywhere
return float4(final_color, 1.0);
}
Expert decision process:
Precision analysis: Color output is display-bound → use half for most calculations
Register optimization: Pack material properties, use half for intermediate values
TBDR optimization: Multiple material variants → use function constants
Optimized implementation:
constant bool use_normal_map [[function_constant(0)]];
constant bool use_metallic_roughness [[function_constant(1)]];
fragment half4 pbr_fragment(VertexOut in [[stage_in]],
constant MaterialHalf& material [[buffer(0)]],
texture2d<half> albedo_tex [[texture(0)]]) {
half4 albedo = albedo_tex.sample(sampler, in.uv);
half3 normal = normalize(half3(in.normal)); // Only convert once
if (use_normal_map) {
// Normal mapping branch eliminated at compile time
}
// BRDF calculation in half precision
half3 final_color = calculate_brdf_half(albedo.rgb, normal, material);
return half4(final_color, albedo.a);
}
Performance impact: 40% reduction in register usage, 2x occupancy increase
references/debug-tools.md — heat maps, debug visualization modes, overdraw/mipmap/NaN detection, live value inspector, performance profiler overlay.
references/production-and-performance.md — Weta/Pixar artist-facing material authoring, procedural surface variation, the bandwidth/ALU/occupancy/divergence profiling mental model, and the debug-tooling checklist.
Deterministic Shader-Perf Auditor
Given a JSON shader plan (see schemas/shader-plan.schema.json), run the
auditor to catch this skill's five failure modes mechanically instead of by
eye:
It flags bandwidth-bandit multi-pass store/load, float-for-display-bound
precision overkill, low occupancy / high register usage, runtime branching on
a uniform instead of a function constant, tile memory over the 32KB limit,
and threadgroup sizes that aren't a multiple of 32. Use templates/output-template.md
to write the optimized-shader implementation guide this skill produces.
NOT-FOR Boundaries
Wrong platforms/APIs:
WebGL/OpenGL ES: Use webgl-shader-expert - different precision rules, extension handling
CUDA/OpenCL: Use gpu-compute-expert - different memory model, NVIDIA-specific optimizations
Vulkan/DirectX: Use graphics-api-expert - immediate-mode renderer assumptions
Wrong abstraction level:
CPU optimization: Use performance-engineering - different bottlenecks, memory patterns
Engine architecture: Use game-engine-expert - render graph design, asset pipelines
Platform-agnostic graphics: Use graphics-programming - need Apple-specific TBDR knowledge
Wrong problem scope:
UI/2D graphics: Use native-app-designer - Core Animation, simpler shaders sufficient
Scientific computing: Use scientific-computing - different precision/accuracy requirements
Web graphics: Use web-graphics-expert - browser constraints, WebGPU considerations
Master Metal shaders with the precision of film production and the performance demands of real-time interaction.
Skill Bundle Index
Every file in this skill, and when to open it. Auto-generated; run scripts/index_references.py --fix.
root
CHANGELOG.md — Changelog — - Frontmatter moved category/tags/pairs-with under a metadata block and added metadata.provenance (first-party, port-daddy) and `m
README.md — Metal Shader Expert — 20+ years Weta/Pixar-style experience specializing in Metal shaders, real-time rendering, and Apple's Tile-Based Deferred Rendering (TBDR) a
references/debug-tools.md — Debug Tools & Visualization — Essential patterns for shader debugging and performance analysis.
references/noise-effects.md — Noise-Based Effects — Organic, procedural effects using noise functions in Metal.
references/pbr-shaders.md — PBR Shader Implementation — Complete Cook-Torrance BRDF implementation in Metal Shading Language.
references/production-and-performance.md — Production Techniques & Performance Mental Model — Weta/Pixar-style production shader authoring, a bandwidth/ALU/occupancy/divergence profiling mental model, and the debug-tooling checklist t