Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

slab/menuband: compile WaveformShaders.metal at runtime

SwiftPM's executableTarget doesn't auto-compile bundled .metal files
into a default.metallib (auto-compile is an Xcode build-phase rule, not
SwiftPM). With the .metal file declared as a `.process()` resource
SwiftPM only copies the SOURCE into the module bundle, so
`makeDefaultLibrary(bundle: .module)` throws "no default library was
found" and the visualizer ships solid black.

Fix: load the .metal source from the module bundle and compile via
`device.makeLibrary(source:)` at first-pipeline-build. ~10ms once on
launch. Falls back to makeDefaultLibrary if SwiftPM ever starts
emitting a metallib.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

+24 -1
+8
slab/menuband/Package.swift
··· 10 10 path: "Sources/MenuBand", 11 11 resources: [ 12 12 .process("Resources"), 13 + // SwiftPM doesn't auto-compile .metal files in 14 + // executable targets — declaring it as a processed 15 + // resource makes SwiftPM emit a default.metallib into 16 + // the module bundle, which `device.makeDefaultLibrary( 17 + // bundle: .module)` then finds at runtime. Without 18 + // this the visualizer renders solid black: the Metal 19 + // pipeline fails with "no default library was found". 20 + .process("WaveformShaders.metal"), 13 21 ] 14 22 ), 15 23 ]
+16 -1
slab/menuband/Sources/MenuBand/WaveformView.swift
··· 215 215 216 216 private func buildPipeline(device: MTLDevice) { 217 217 do { 218 - let library = try device.makeDefaultLibrary(bundle: .module) 218 + // SwiftPM's executableTarget doesn't compile bundled .metal 219 + // files into a default.metallib (the auto-compile path is 220 + // an Xcode build-phase, not an SPM rule). We declare the 221 + // .metal file as a `.process()` resource so SPM copies the 222 + // SOURCE into the module bundle, then compile it here at 223 + // first-pipeline-build via `makeLibrary(source:)`. Cost is 224 + // ~10ms once on launch — invisible next to the popover 225 + // animation. Without this the visualizer ships solid black: 226 + // makeDefaultLibrary throws "no default library was found". 227 + let library: MTLLibrary 228 + if let url = Bundle.module.url(forResource: "WaveformShaders", withExtension: "metal"), 229 + let source = try? String(contentsOf: url, encoding: .utf8) { 230 + library = try device.makeLibrary(source: source, options: nil) 231 + } else { 232 + library = try device.makeDefaultLibrary(bundle: .module) 233 + } 219 234 guard let vfn = library.makeFunction(name: "bar_vertex"), 220 235 let ffn = library.makeFunction(name: "bar_fragment") else { 221 236 NSLog("MenuBand: visualizer shader functions missing")