
Metal Graphics
- 1 installs
- Updated January 17, 2026
- alejandrolaborda/agent-tools
metal-graphics is a skill that provides Apple Metal GPU rendering code for games, covering the render pipeline, MTKView, shaders, textures, and MetalFX upscaling in Swift.
About
This skill provides Apple Metal GPU graphics code for games, covering MTKView setup, the render pipeline, shaders, and MetalFX upscaling. A developer uses it when building 3D rendering for an iOS or macOS game in Swift, with ready patterns for the renderer, Metal Shading Language shaders, vertex descriptors, uniforms, matrices, and textures. It focuses on the graphics pipeline scaffolding rather than full game logic.
- Provides Metal GPU rendering setup: MTKView, render pipeline, renderer, and depth state in Swift
- Includes Metal Shading Language vertex and fragment shaders, vertex descriptors, and uniforms
- Covers matrices, textures, sampler state, and MetalFX upscaling for game rendering
Metal Graphics by the numbers
- 1 all-time installs (skills.sh)
- Ranked #218 of 247 Game Development skills by installs in the Skillselion catalog
- Data as of Jul 7, 2026 (Skillselion catalog sync)
metal-graphics capabilities & compatibility
- Capabilities
- metal rendering · shader authoring · game graphics
- Use cases
- frontend
- Platforms
- macOS
- Pricing
- Free
What metal-graphics says it does
Metal GPU graphics for games - render pipeline, shaders, MTKView, MetalFX upscaling. Triggers on Metal, GPU, graphics, shaders, render pipeline, MTKView, game rendering, 3D graphics.
vertex VertexOut vertex_main(VertexIn in [[stage_in]], constant Uniforms &u [[buffer(1)]]) {
npx skills add https://github.com/alejandrolaborda/agent-tools --skill metal-graphicsAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| Last updated | January 17, 2026 |
| Repository | alejandrolaborda/agent-tools ↗ |
What it does
Set up Metal GPU rendering (MTKView, pipeline, shaders, textures) for an iOS or macOS game in Swift.
Who is it for?
Building the Metal GPU rendering pipeline and shaders for an iOS or macOS game in Swift.
Skip if: Non-Apple graphics APIs, full game logic, or platforms without Metal support.
When should I use this skill?
When working on Metal, GPU, shaders, the render pipeline, MTKView, or 3D game rendering on Apple platforms.
What you get
Provides working MTKView, renderer, MSL shaders, vertex descriptors, matrices, and texture-loading code.
- MTKView setup code
- Metal renderer
- MSL vertex/fragment shaders
By the numbers
- colorPixelFormat .bgra8Unorm
- depthStencilPixelFormat .depth32Float
Files
Metal Graphics
MTKView Setup
// UIKit
class GameViewController: UIViewController {
var metalView: MTKView!
var renderer: Renderer!
override func viewDidLoad() {
super.viewDidLoad()
guard let device = MTLCreateSystemDefaultDevice() else { fatalError("Metal not supported") }
metalView = MTKView(frame: view.bounds, device: device)
metalView.colorPixelFormat = .bgra8Unorm
metalView.depthStencilPixelFormat = .depth32Float
view.addSubview(metalView)
renderer = Renderer(metalView: metalView)
metalView.delegate = renderer
}
}
// SwiftUI
struct MetalView: UIViewRepresentable {
func makeUIView(context: Context) -> MTKView {
let device = MTLCreateSystemDefaultDevice()!
let view = MTKView()
view.device = device
view.colorPixelFormat = .bgra8Unorm
view.depthStencilPixelFormat = .depth32Float
context.coordinator.renderer = Renderer(metalView: view)
view.delegate = context.coordinator.renderer
return view
}
func updateUIView(_ uiView: MTKView, context: Context) {}
func makeCoordinator() -> Coordinator { Coordinator() }
class Coordinator { var renderer: Renderer? }
}Renderer
class Renderer: NSObject, MTKViewDelegate {
let device: MTLDevice
let commandQueue: MTLCommandQueue
var pipelineState: MTLRenderPipelineState!
var depthState: MTLDepthStencilState!
init(metalView: MTKView) {
device = metalView.device!
commandQueue = device.makeCommandQueue()!
super.init()
let library = device.makeDefaultLibrary()!
let desc = MTLRenderPipelineDescriptor()
desc.vertexFunction = library.makeFunction(name: "vertex_main")
desc.fragmentFunction = library.makeFunction(name: "fragment_main")
desc.colorAttachments[0].pixelFormat = metalView.colorPixelFormat
desc.depthAttachmentPixelFormat = metalView.depthStencilPixelFormat
pipelineState = try! device.makeRenderPipelineState(descriptor: desc)
let depthDesc = MTLDepthStencilDescriptor()
depthDesc.depthCompareFunction = .less
depthDesc.isDepthWriteEnabled = true
depthState = device.makeDepthStencilState(descriptor: depthDesc)
}
func mtkView(_ view: MTKView, drawableSizeWillChange size: CGSize) {}
func draw(in view: MTKView) {
guard let drawable = view.currentDrawable,
let desc = view.currentRenderPassDescriptor else { return }
let cmd = commandQueue.makeCommandBuffer()!
let enc = cmd.makeRenderCommandEncoder(descriptor: desc)!
enc.setRenderPipelineState(pipelineState)
enc.setDepthStencilState(depthState)
// Draw calls here
enc.endEncoding()
cmd.present(drawable)
cmd.commit()
}
}Shaders (Metal Shading Language)
#include <metal_stdlib>
using namespace metal;
struct VertexIn {
float3 position [[attribute(0)]];
float4 color [[attribute(1)]];
float2 texCoord [[attribute(2)]];
};
struct VertexOut {
float4 position [[position]];
float4 color;
float2 texCoord;
};
struct Uniforms {
float4x4 modelMatrix;
float4x4 viewMatrix;
float4x4 projectionMatrix;
};
vertex VertexOut vertex_main(VertexIn in [[stage_in]], constant Uniforms &u [[buffer(1)]]) {
VertexOut out;
out.position = u.projectionMatrix * u.viewMatrix * u.modelMatrix * float4(in.position, 1.0);
out.color = in.color;
out.texCoord = in.texCoord;
return out;
}
fragment float4 fragment_main(VertexOut in [[stage_in]], texture2d<float> tex [[texture(0)]], sampler s [[sampler(0)]]) {
return tex.sample(s, in.texCoord) * in.color;
}Vertex Data
struct Vertex {
var position: SIMD3<Float>
var color: SIMD4<Float>
var texCoord: SIMD2<Float>
}
func buildVertexDescriptor() -> MTLVertexDescriptor {
let d = MTLVertexDescriptor()
d.attributes[0].format = .float3; d.attributes[0].offset = 0; d.attributes[0].bufferIndex = 0
d.attributes[1].format = .float4; d.attributes[1].offset = MemoryLayout<SIMD3<Float>>.stride; d.attributes[1].bufferIndex = 0
d.attributes[2].format = .float2; d.attributes[2].offset = MemoryLayout<SIMD3<Float>>.stride + MemoryLayout<SIMD4<Float>>.stride; d.attributes[2].bufferIndex = 0
d.layouts[0].stride = MemoryLayout<Vertex>.stride
return d
}
// Use .stride not .size for buffer lengths (alignment)
let buffer = device.makeBuffer(bytes: vertices, length: MemoryLayout<Vertex>.stride * vertices.count, options: .storageModeShared)!Uniforms & Matrices
struct Uniforms { var modelMatrix, viewMatrix, projectionMatrix: float4x4 }
encoder.setVertexBytes(&uniforms, length: MemoryLayout<Uniforms>.stride, index: 1)
extension float4x4 {
static var identity: float4x4 { matrix_identity_float4x4 }
init(translation t: SIMD3<Float>) { self = float4x4([[1,0,0,0],[0,1,0,0],[0,0,1,0],[t.x,t.y,t.z,1]]) }
init(rotationY a: Float) { let c=cos(a),s=sin(a); self = float4x4([[c,0,-s,0],[0,1,0,0],[s,0,c,0],[0,0,0,1]]) }
static func perspective(fov: Float, aspect: Float, near: Float, far: Float) -> float4x4 {
let y=1/tan(fov*0.5), x=y/aspect, z=far/(near-far)
return float4x4([[x,0,0,0],[0,y,0,0],[0,0,z,-1],[0,0,z*near,0]])
}
}Textures
func loadTexture(_ name: String) -> MTLTexture? {
try? MTKTextureLoader(device: device).newTexture(name: name, scaleFactor: 1, bundle: nil, options: [.generateMipmaps: true])
}
func samplerState() -> MTLSamplerState {
let d = MTLSamplerDescriptor()
d.minFilter = .linear; d.magFilter = .linear; d.mipFilter = .linear
return device.makeSamplerState(descriptor: d)!
}
encoder.setFragmentTexture(texture, index: 0)
encoder.setFragmentSamplerState(sampler, index: 0)Draw Commands
encoder.setVertexBuffer(vertexBuffer, offset: 0, index: 0)
encoder.drawPrimitives(type: .triangle, vertexStart: 0, vertexCount: 3)
encoder.drawIndexedPrimitives(type: .triangle, indexCount: count, indexType: .uint16, indexBuffer: indexBuffer, indexBufferOffset: 0)
encoder.drawIndexedPrimitives(type: .triangle, indexCount: count, indexType: .uint16, indexBuffer: indexBuffer, indexBufferOffset: 0, instanceCount: 100)MetalFX Upscaling
import MetalFX
// Spatial (simpler, no motion vectors)
let desc = MTLFXSpatialScalerDescriptor()
desc.inputWidth = 1920; desc.inputHeight = 1080
desc.outputWidth = 3840; desc.outputHeight = 2160
desc.colorTextureFormat = .bgra8Unorm; desc.outputTextureFormat = .bgra8Unorm
let upscaler = desc.makeSpatialScaler(device: device)!
upscaler.colorTexture = inputTex; upscaler.outputTexture = outputTex
upscaler.encode(commandBuffer: cmd)
// Temporal (better quality, needs motion vectors + depth)
let tdesc = MTLFXTemporalScalerDescriptor()
tdesc.inputWidth = 1920; tdesc.inputHeight = 1080
tdesc.outputWidth = 3840; tdesc.outputHeight = 2160
tdesc.colorTextureFormat = .bgra8Unorm; tdesc.depthTextureFormat = .depth32Float
tdesc.motionTextureFormat = .rg16Float; tdesc.outputTextureFormat = .bgra8Unorm
let temporal = tdesc.makeTemporalScaler(device: device)!
temporal.colorTexture = color; temporal.depthTexture = depth; temporal.motionTexture = motion
temporal.outputTexture = output; temporal.jitterOffsetX = jx; temporal.jitterOffsetY = jy
temporal.encode(commandBuffer: cmd)Frame Timing
var lastTime: CFTimeInterval = 0
func draw(in view: MTKView) {
let now = CACurrentMediaTime()
let dt = Float(now - lastTime); lastTime = now
update(deltaTime: dt)
render(in: view)
}
metalView.preferredFramesPerSecond = 60 // or 30 for demanding gamesStorage Modes
.storageModeShared- CPU writes, GPU reads.storageModePrivate- GPU only (faster)- Triple-buffer with shared for streaming data
MCP Integration
Context7: /websites/developer_apple - Query "Metal tvOS", "MTKView", "MetalFX upscaling"
Serena: find_symbol "MTKViewDelegate" - Renderer setup; search_for_pattern "makeRenderPipelineState" - Pipeline config
Sources
Official
- https://developer.apple.com/metal/ - Metal Overview
- https://developer.apple.com/documentation/metal - Metal Framework
- https://developer.apple.com/documentation/metalkit - MetalKit Framework
- https://developer.apple.com/documentation/metalfx - MetalFX Framework
Core APIs
- https://developer.apple.com/documentation/metal/mtldevice - MTLDevice
- https://developer.apple.com/documentation/metalkit/mtkview - MTKView
- https://developer.apple.com/documentation/metal/mtlrenderpipelinestate - Pipeline State
- https://developer.apple.com/documentation/metal/mtlbuffer - Buffers
MetalFX
- https://developer.apple.com/documentation/metalfx/mtlfxspatialscaler - Spatial Upscaling
- https://developer.apple.com/documentation/metalfx/mtlfxtemporalscaler - Temporal Upscaling
Shading Language
- https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf - MSL Spec
WWDC
- https://developer.apple.com/videos/play/wwdc2025/ - Metal 4 (2025)
- https://developer.apple.com/videos/play/wwdc2022/10103/ - MetalFX Upscaling (2022)
Tutorials
- https://metalbyexample.com/ - Metal by Example
- https://www.kodeco.com/books/metal-by-tutorials - Metal by Tutorials
Version
- Metal 4 / tvOS SDK 18.2 (Jan 2026)
MCP
- Context7: /websites/developer_apple_metal
Related skills
FAQ
What does metal-graphics cover?
Metal GPU graphics for games: MTKView setup, the render pipeline, a renderer, Metal Shading Language shaders, vertex descriptors, uniforms, matrices, textures, and MetalFX upscaling.
What platforms is it for?
Apple platforms using Metal, with UIKit and SwiftUI MTKView examples in Swift.