Skip to content

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 →