Glassmorphism Generator — Kotlin 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 Kotlin implementation — the same logic the interactive tool runs, in a shareable, citable form.
// =============================================================================
// Glassmorphism.kt — CosmoDev polyglot showcase port of the
// `glassmorphism-generator` tool
// -----------------------------------------------------------------------------
// Language : Kotlin (1.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 (no regex — stdlib only); opacity is clamped to [0,1];
// the alpha channel is rounded with floor(x*100 + 0.5)/100 — JS Math.round
// (half-up) semantics — and numbers render like JS template literals:
// Double.toString is already the shortest round-tripping decimal, but it
// keeps a trailing ".0" on whole values, so those go through toLong()
// instead. The output therefore matches the live TypeScript lib
// byte-for-byte.
// =============================================================================
package com.cosmolabs.cosmodev
import kotlin.math.abs
import kotlin.math.floor
import kotlin.math.max
import kotlin.math.min
/** Configuration for one glassmorphism declaration block. */
data class GlassConfig(
val blur: Double = 0.0,
val opacity: Double = 0.0,
val tint: String = "#ffffff",
val radius: Double = 0.0,
val borderOpacity: Double = 0.0,
val saturation: Double? = null, // null => 180.0 (lib default)
)
/** The rendered glassmorphism block plus its full CSS text. */
data class GlassCss(
val background: String,
val backdropFilter: String,
val webkitBackdropFilter: String,
val border: String,
val borderRadius: String,
val boxShadow: String,
val fullCss: String,
)
/** Pure glassmorphism CSS builder — deterministic, no DOM. */
object Glassmorphism {
/** True when the character is an ASCII hex digit (0-9, a-f, A-F). */
private fun isHexDigit(c: Char): Boolean =
c in '0'..'9' || c in 'a'..'f' || c in 'A'..'F'
/** True when every character is an ASCII hex digit. */
private fun isHexRun(s: String): Boolean =
s.isNotEmpty() && s.all(::isHexDigit)
/** Parse a run of hex digits into its value (base 16). */
private fun parseHex(s: String): Int = s.toInt(16)
/**
* Render a number like a JS template literal (10.0 -> "10", 0.3 -> "0.3").
* Double.toString is the shortest round-tripping decimal but keeps ".0"
* on whole values, so those render through toLong() instead (safe within
* ±9.2e18 — far beyond any blur/radius/saturation value).
*/
private fun fmt(x: Double): String =
if (x == floor(x) && !x.isInfinite() && abs(x) < 9.2e18) {
x.toLong().toString()
} else {
x.toString()
}
/**
* Parse a #rgb or #rrggbb hex color into (r, g, b); null if invalid.
* A 3-char hex expands each digit (e.g. "abc" -> "aabbcc"), like CSS.
* Exactly one leading '#' is stripped, matching the lib's /^#/ replace.
*/
fun hexToRgb(hexColor: String?): Triple<Int, Int, Int>? {
var h = hexColor?.trim() ?: ""
if (h.startsWith("#")) h = h.substring(1)
if (h.length == 3 && isHexRun(h)) {
// "a" -> 0xaa — each digit doubles into a pair, like CSS.
fun expand(c: Char): Int {
val d = c.digitToInt(16)
return d * 16 + d
}
return Triple(expand(h[0]), expand(h[1]), expand(h[2]))
}
if (h.length == 6 && isHexRun(h)) {
return Triple(parseHex(h.substring(0, 2)),
parseHex(h.substring(2, 4)),
parseHex(h.substring(4, 6)))
}
return null
}
/** Clamp to [0,1], round with JS Math.round (half-up), and render. */
private fun alpha(a: Double): String {
val c = min(1.0, max(0.0, a))
return fmt(floor(c * 100.0 + 0.5) / 100.0)
}
/** Format rgba(), clamping + 2-decimal-rounding the alpha. */
fun rgba(r: Int, g: Int, b: Int, a: Double): String =
"rgba($r, $g, $b, ${alpha(a)})"
/** Build the full glassmorphism CSS for a config. */
fun buildGlassmorphism(cfg: GlassConfig): GlassCss {
val blur = max(0.0, cfg.blur)
val opacity = min(1.0, max(0.0, cfg.opacity))
val radius = max(0.0, cfg.radius)
val borderOpacity = min(1.0, max(0.0, cfg.borderOpacity))
val saturation = cfg.saturation ?: 180.0
val (r, g, b) = hexToRgb(cfg.tint) ?: Triple(255, 255, 255)
val background = rgba(r, g, b, opacity)
val backdropFilter = "blur(${fmt(blur)}px) saturate(${fmt(saturation)}%)"
val border = "1px solid ${rgba(255, 255, 255, borderOpacity)}"
val borderRadius = "${fmt(radius)}px"
val boxShadow = "0 8px 32px 0 rgba(31, 38, 135, 0.37)"
val fullCss = listOf(
"background: $background;",
"-webkit-backdrop-filter: $backdropFilter;",
"backdrop-filter: $backdropFilter;",
"border-radius: $borderRadius;",
"border: $border;",
"box-shadow: $boxShadow;",
).joinToString("\n")
// Both prefixed and unprefixed backdrop-filter carry the same value.
return GlassCss(background, backdropFilter, backdropFilter, border,
borderRadius, boxShadow, fullCss)
}
}
fun main() {
val css = Glassmorphism.buildGlassmorphism(
GlassConfig(blur = 10.0, opacity = 0.3, tint = "#ffffff",
radius = 12.0, borderOpacity = 0.2))
println(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 →