Zum Inhalt

apple/PhysarumEngine/Sources/PresetGallery/main.swift

import Foundation
import Metal
import PhysarumEngine

// Renders every preset JSON in a directory to a thumbnail PNG (dir/thumbs/<id>.png),
// so presets can be designed and visually iterated headless. Web-JSON compatible.
// Usage: swift run PresetGallery <presets-dir> [frames] [size]

let args = CommandLine.arguments
let dir = args.count > 1 ? args[1] : "presets"
let frames = args.count > 2 ? Int(args[2]) ?? 400 : 400
let size = args.count > 3 ? Int(args[3]) ?? 512 : 512

guard let device = MTLCreateSystemDefaultDevice() else { fatalError("no Metal device") }
let lib = ShaderLibrary(device: device)
let renderer = try Renderer(device: device, library: lib, width: size, height: size)

let fm = FileManager.default
let dirURL = URL(fileURLWithPath: dir)
let thumbsURL = dirURL.appendingPathComponent("thumbs")
try? fm.createDirectory(at: thumbsURL, withIntermediateDirectories: true)

let files = ((try? fm.contentsOfDirectory(at: dirURL, includingPropertiesForKeys: nil)) ?? [])
    .filter { $0.pathExtension == "json" }
    .sorted { $0.lastPathComponent < $1.lastPathComponent }

print("rendering \(files.count) presets at \(size)×\(size), \(frames) frames")
for f in files {
    do {
        let preset = try JSONDecoder().decode(Preset.self, from: Data(contentsOf: f))
        let sim = try SimEngine(device: device, library: lib, width: size, height: size, preset: preset.params)
        // Render every frame (not just the last) so temporal feedback / echo
        // accumulates the same way the live viewer + web bake do.
        renderer.resetFeedback()
        for _ in 0..<frames {
            sim.step()
            try renderer.renderOffscreen(sim: sim, preset: preset.params)
        }
        let out = thumbsURL.appendingPathComponent("\(preset.id).png").path
        _ = try renderer.savePNG(to: out)
        print("  ✓ \(preset.id)  —  \(preset.name)")
    } catch {
        print("  ✗ \(f.lastPathComponent): \(error)")
    }
}
print("thumbs → \(thumbsURL.path)")