Glassmorphism Generator — Swift source
Create frosted-glass CSS - backdrop-blur, translucent background, subtle border, and soft shadow - with a copy-ready snippet and live preview.
This is the Swift implementation — the same logic the interactive tool runs, in a shareable, citable form.
// =============================================================================
// Glassmorphism.swift — CosmoDev polyglot showcase port of the
// `glassmorphism-generator` tool
// -----------------------------------------------------------------------------
// Language : Swift (5.9, standard library only)
// Source: ported from src/lib/glassmorphism.ts (the canonical, live
// TypeScript lib); mirrors
// src/tool-sources/glassmorphism-generator/{python.py,rust.rs}
// License : display source — part of CosmoDev's polyglot tool pages
// (dev.cosmolabs.org). Shown verbatim alongside the JS/TS/Go/Rust/
// Python ports and the other language ports.
// -----------------------------------------------------------------------------
// Builds a frosted-glass CSS block from blur / opacity / tint / radius /
// borderOpacity (+ optional saturation). Hex tints (#rgb / #rrggbb) are
// validated by hand with ASCII hex-digit checks (no NSRegularExpression —
// stdlib only); opacity is clamped to [0,1]; the alpha channel is rounded
// with (x*100 + 0.5).rounded(.down)/100 — JS Math.round (half-up) semantics
// — and numbers render like JS template literals: String(Double) is the
// shortest round-tripping decimal, but it keeps a trailing ".0" on whole
// values, so those render through Int64 instead. The output therefore
// matches the live TypeScript lib byte-for-byte.
// =============================================================================
/// Pure glassmorphism CSS builder — deterministic, no DOM.
public enum Glassmorphism {
/// Configuration for one glassmorphism declaration block.
public struct GlassConfig: Equatable {
public var blur: Double
public var opacity: Double
public var tint: String
public var radius: Double
public var borderOpacity: Double
/// nil => 180.0 (lib default)
public var saturation: Double?
public init(blur: Double = 0.0,
opacity: Double = 0.0,
tint: String = "#ffffff",
radius: Double = 0.0,
borderOpacity: Double = 0.0,
saturation: Double? = nil) {
self.blur = blur
self.opacity = opacity
self.tint = tint
self.radius = radius
self.borderOpacity = borderOpacity
self.saturation = saturation
}
}
/// The rendered glassmorphism block plus its full CSS text.
public struct GlassCss: Equatable {
public var background: String
public var backdropFilter: String
public var webkitBackdropFilter: String
public var border: String
public var borderRadius: String
public var boxShadow: String
public var fullCss: String
}
/// Render a number like a JS template literal (10.0 -> "10", 0.3 -> "0.3").
/// String(Double) is the shortest round-tripping decimal but keeps ".0"
/// on whole values, so those render through Int64 instead (safe within
/// ±9.2e18 — far beyond any blur/radius/saturation value; beyond that we
/// fall through to Swift's exponent form rather than trap).
static func fmt(_ x: Double) -> String {
if x.rounded() == x, x.isFinite, x.magnitude < 9.2e18 {
return String(Int64(x))
}
return String(x)
}
/// True when every character is an ASCII hex digit (0-9, a-f, A-F) —
/// mirroring the Rust port's is_ascii_hexdigit, not Unicode hex digits.
static func isHexRun(_ s: Substring) -> Bool {
!s.isEmpty && s.allSatisfy { $0.isASCII && $0.isHexDigit }
}
/// The characters JS String.prototype.trim() strips, ASCII set
/// (space, tab, newline, vertical tab, form feed, carriage return) —
/// Foundation's trimmingCharacters is not part of the stdlib.
static func isJsSpace(_ c: Character) -> Bool {
c == " " || c == "\t" || c == "\n" || c == "\r"
|| c == "\u{0b}" || c == "\u{0c}"
}
/// Parse #rgb or #rrggbb into (r, g, b); nil on a bad color.
/// A 3-char hex expands each digit (e.g. "abc" -> "aabbcc"), like CSS.
/// Exactly one leading '#' is stripped, matching the lib's /^#/ replace.
public static func hexToRgb(_ hex: String) -> (r: Int, g: Int, b: Int)? {
var h = Substring(hex)
while let f = h.first, isJsSpace(f) { h = h.dropFirst() }
while let l = h.last, isJsSpace(l) { h = h.dropLast() }
if h.hasPrefix("#") {
h.removeFirst()
}
if h.count == 3 && isHexRun(h) {
// "a" -> 0xaa — each digit doubles into a pair, like CSS.
func expand(_ c: Character) -> Int {
let d = Int(String(c), radix: 16)! // guarded by isHexRun
return d * 16 + d
}
let cs = Array(h)
return (expand(cs[0]), expand(cs[1]), expand(cs[2]))
}
if h.count == 6 && isHexRun(h) {
guard let r = Int(h.prefix(2), radix: 16),
let g = Int(h.dropFirst(2).prefix(2), radix: 16),
let b = Int(h.dropFirst(4).prefix(2), radix: 16) else {
return nil
}
return (r, g, b)
}
return nil
}
/// Format rgba(), clamping + 2-decimal-rounding the alpha with JS
/// Math.round (half-up) semantics: (x*100 + 0.5).rounded(.down)/100.
public static func rgba(_ r: Int, _ g: Int, _ b: Int, _ a: Double) -> String {
let c = min(max(a, 0.0), 1.0)
return "rgba(\(r), \(g), \(b), \(fmt((c * 100.0 + 0.5).rounded(.down) / 100.0)))"
}
/// Build the full glassmorphism CSS for a config.
public static func buildGlassmorphism(_ cfg: GlassConfig) -> GlassCss {
let blur = max(cfg.blur, 0.0)
let opacity = min(max(cfg.opacity, 0.0), 1.0)
let radius = max(cfg.radius, 0.0)
let borderOpacity = min(max(cfg.borderOpacity, 0.0), 1.0)
let saturation = cfg.saturation ?? 180.0
let rgb = hexToRgb(cfg.tint) ?? (r: 255, g: 255, b: 255)
let background = rgba(rgb.r, rgb.g, rgb.b, opacity)
let backdropFilter = "blur(\(fmt(blur))px) saturate(\(fmt(saturation))%)"
let border = "1px solid \(rgba(255, 255, 255, borderOpacity))"
let borderRadius = "\(fmt(radius))px"
let boxShadow = "0 8px 32px 0 rgba(31, 38, 135, 0.37)"
let fullCss = [
"background: \(background);",
"-webkit-backdrop-filter: \(backdropFilter);",
"backdrop-filter: \(backdropFilter);",
"border-radius: \(borderRadius);",
"border: \(border);",
"box-shadow: \(boxShadow);",
].joined(separator: "\n")
// Both prefixed and unprefixed backdrop-filter carry the same value.
return GlassCss(background: background,
backdropFilter: backdropFilter,
webkitBackdropFilter: backdropFilter,
border: border,
borderRadius: borderRadius,
boxShadow: boxShadow,
fullCss: fullCss)
}
}
// Example — same config as the Python/Rust ports.
let css = Glassmorphism.buildGlassmorphism(
.init(blur: 10, opacity: 0.3, tint: "#ffffff", radius: 12, borderOpacity: 0.2))
print(css.fullCss)
Also available in 13 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →