Glassmorphism Generator — Ruby 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 Ruby implementation — the same logic the interactive tool runs, in a shareable, citable form.
# =============================================================================
# glassmorphism_generator.rb — CosmoDev polyglot showcase port of the
# `glassmorphism-generator` tool
# -----------------------------------------------------------------------------
# Language : Ruby (3.2, 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 /
# border_opacity (+ optional saturation). Hex tints (#rgb / #rrggbb) are
# matched with anchored stdlib regexes; opacity is clamped to [0,1]; the
# alpha channel is rounded with floor(x*100 + 0.5)/100 — JS Math.round
# (half-up) semantics, NOT Float#round's banker's behavior on ties — so the
# output matches the live TypeScript lib byte-for-byte. Numbers render like
# JS template literals (10.0 -> "10", 0.3 -> "0.3"): Float#to_s is the
# shortest round-tripping decimal, but it keeps ".0" on whole values, so
# those render as Integers instead.
# =============================================================================
module GlassmorphismGenerator
# Configuration for one glassmorphism declaration block.
Config = Struct.new(
:blur, :opacity, :tint, :radius, :border_opacity, :saturation,
keyword_init: true
) do
def initialize(blur: 0.0, opacity: 0.0, tint: '#ffffff', radius: 0.0,
border_opacity: 0.0, saturation: nil)
super
end
end
# The rendered glassmorphism block plus its full CSS text.
Css = Struct.new(
:background, :backdrop_filter, :webkit_backdrop_filter,
:border, :border_radius, :box_shadow, :full_css,
keyword_init: true
)
HEX3 = /\A[0-9a-fA-F]{3}\z/
HEX6 = /\A[0-9a-fA-F]{6}\z/
class << self
# Parse a #rgb or #rrggbb hex color into [r, g, b]; nil 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.
def hex_to_rgb(hex_color)
h = hex_color.to_s.strip
h = h[1..] if h.start_with?('#')
if HEX3.match?(h)
[(h[0] * 2).to_i(16), (h[1] * 2).to_i(16), (h[2] * 2).to_i(16)]
elsif HEX6.match?(h)
[h[0, 2].to_i(16), h[2, 2].to_i(16), h[4, 2].to_i(16)]
end
end
# Format an rgba() string, clamping + 2-decimal-rounding the alpha.
def rgba(r, g, b, a)
format('rgba(%<r>d, %<g>d, %<b>d, %<alpha>s)',
r: r, g: g, b: b, alpha: alpha(a))
end
# Build the full glassmorphism CSS for a Config.
def build_glassmorphism(cfg)
blur = [cfg.blur.to_f, 0.0].max
opacity = cfg.opacity.to_f.clamp(0.0, 1.0)
radius = [cfg.radius.to_f, 0.0].max
border_opacity = cfg.border_opacity.to_f.clamp(0.0, 1.0)
saturation = cfg.saturation.nil? ? 180.0 : cfg.saturation.to_f
r, g, b = hex_to_rgb(cfg.tint) || [255, 255, 255]
background = rgba(r, g, b, opacity)
backdrop_filter = format('blur(%<b>spx) saturate(%<s>s%%)',
b: fmt_num(blur), s: fmt_num(saturation))
border = "1px solid #{rgba(255, 255, 255, border_opacity)}"
border_radius = "#{fmt_num(radius)}px"
box_shadow = '0 8px 32px 0 rgba(31, 38, 135, 0.37)'
full_css = [
"background: #{background};",
"-webkit-backdrop-filter: #{backdrop_filter};",
"backdrop-filter: #{backdrop_filter};",
"border-radius: #{border_radius};",
"border: #{border};",
"box-shadow: #{box_shadow};"
].join("\n")
# Both prefixed and unprefixed backdrop-filter carry the same value.
Css.new(background: background, backdrop_filter: backdrop_filter,
webkit_backdrop_filter: backdrop_filter, border: border,
border_radius: border_radius, box_shadow: box_shadow,
full_css: full_css)
end
private
# Render a number like a JS template literal (10.0 -> '10', 0.3 -> '0.3').
def fmt_num(x)
x = Float(x)
return x.to_i.to_s if x == x.truncate && x.finite?
x.to_s
end
# Clamp to [0,1], round with JS Math.round (half-up), and render.
def alpha(a)
c = a.to_f.clamp(0.0, 1.0)
fmt_num((c * 100.0 + 0.5).floor / 100.0)
end
end
end
if $PROGRAM_NAME == __FILE__
cfg = GlassmorphismGenerator::Config.new(
blur: 10, opacity: 0.3, tint: '#ffffff', radius: 12, border_opacity: 0.2
)
puts GlassmorphismGenerator.build_glassmorphism(cfg).full_css
end
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 →