Files

101 lines
3.9 KiB
Swift

#!/usr/bin/env swift
// Generiert das RemminaMac App-Icon (Dracula-Terminal) als PNG-Set + .iconset.
// Aufruf: swift scripts/RenderIcon.swift <output-dir>
// Braucht nur macOS-Bordmittel (AppKit). Kein Netzwerk, keine Deps.
import AppKit
import Foundation
let outDir = CommandLine.arguments.count > 1 ? CommandLine.arguments[1] : "/tmp/RemminaMac.iconset"
try? FileManager.default.createDirectory(atPath: outDir, withIntermediateDirectories: true)
// Dracula-Palette
func c(_ hex: String, _ alpha: CGFloat = 1) -> NSColor {
var v: UInt64 = 0
Scanner(string: hex).scanHexInt64(&v)
return NSColor(red: CGFloat((v >> 16) & 0xFF) / 255,
green: CGFloat((v >> 8) & 0xFF) / 255,
blue: CGFloat(v & 0xFF) / 255, alpha: alpha)
}
let bg1 = c("3A3D4F"), bg2 = c("23242F"), bar = c("44475A")
let green = c("50FA7B"), pink = c("FF79C6"), purple = c("BD93F9")
let red = c("FF5555"), yellow = c("F1FA8C")
func drawIcon(size: CGFloat) -> NSImage {
let img = NSImage(size: NSSize(width: size, height: size))
img.lockFocus()
let s = size / 1024.0 // Skalierung relativ zu 1024er-Master
NSGraphicsContext.current?.imageInterpolation = .high
// Hintergrund: abgerundetes Quadrat mit Verlauf
let rect = NSRect(x: 0, y: 0, width: size, height: size)
let radius = 232 * s
let path = NSBezierPath(roundedRect: rect, xRadius: radius, yRadius: radius)
let grad = NSGradient(colors: [bg1, bg2])!
grad.draw(in: path, angle: 90)
// feine Kontur
bar.withAlphaComponent(0.9).setStroke()
path.lineWidth = max(2, 6 * s)
path.stroke()
// Dezenter Glow hinter der Glyphe
let glow = NSShadow()
glow.shadowColor = purple.withAlphaComponent(0.55)
glow.shadowBlurRadius = 90 * s
glow.shadowOffset = .zero
// Traffic-Lights (Fenster-Look)
for (i, col) in [red, yellow, green].enumerated() {
let r = 40 * s
let cx = CGFloat(150 + i * 108) * s
let cy = size - 158.0 * s
col.setFill()
NSBezierPath(ovalIn: NSRect(x: cx - r, y: cy - r, width: 2 * r, height: 2 * r)).fill()
}
// Prompt „>" + Block-Cursor (Menlo Bold)
let fontSize: CGFloat = 470 * s
let font: NSFont = NSFont(name: "Menlo-Bold", size: fontSize)
?? NSFont.monospacedSystemFont(ofSize: fontSize, weight: .bold)
let attrs: [NSAttributedString.Key: Any] = [.font: font, .foregroundColor: green]
let glyph = NSAttributedString(string: ">", attributes: attrs)
let gw = glyph.size()
// Cursor-Block rechts vom „>"
let gap = 44 * s
let cursorW = 128 * s, cursorH = 96 * s
let totalW = gw.width + gap + cursorW
let startX = (size - totalW) / 2
let baseY = size * 0.30
NSGraphicsContext.saveGraphicsState()
NSGraphicsContext.current?.cgContext.setShadow(offset: .zero, blur: 90 * s, color: purple.withAlphaComponent(0.55).cgColor)
glyph.draw(at: NSPoint(x: startX, y: baseY))
NSGraphicsContext.restoreGraphicsState()
let cursor = NSBezierPath(roundedRect: NSRect(x: startX + gw.width + gap, y: baseY + 30 * s, width: cursorW, height: cursorH), xRadius: 14 * s, yRadius: 14 * s)
pink.setFill()
cursor.fill()
img.unlockFocus()
return img
}
func save(_ img: NSImage, _ name: String) {
guard let tiff = img.tiffRepresentation,
let rep = NSBitmapImageRep(data: tiff),
let png = rep.representation(using: .png, properties: [:]) else {
fputs("FEHLER bei \(name)\n", stderr); exit(1)
}
try! png.write(to: URL(fileURLWithPath: "\(outDir)/\(name)"))
}
// iconset: je Größe 1x + 2x
for base in [16, 32, 128, 256, 512] {
save(drawIcon(size: CGFloat(base)), "icon_\(base)x\(base).png")
save(drawIcon(size: CGFloat(base * 2)), "icon_\(base)x\(base)@2x.png")
}
// Vorschau in groß
try? FileManager.default.createDirectory(atPath: "/tmp", withIntermediateDirectories: true)
save(drawIcon(size: 512), "RemminaMac-preview-tmp.png")
print("iconset fertig: \(outDir)")