Skip to content

Glassmorphism Generator — Go 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 Go implementation — the same logic the interactive tool runs, in a shareable, citable form.

// Package glassmorphism is the Go twin of CosmoDev's src/lib/glassmorphism.ts
// (dual source: the web lib is TypeScript, the CLI lib is Go — kept in
// lock-step). It builds a frosted-glass CSS declaration block from
// blur/opacity/tint/radius/border-opacity. Pure + deterministic, never panics.
// The table-driven tests in glassmorphism-generator_test.go share vectors with
// src/lib/glassmorphism.test.ts so the two implementations are held to the
// same contract.
package glassmorphism

import (
	"math"
	"regexp"
	"strconv"
	"strings"
)

// GlassConfig mirrors the GlassConfig interface in src/lib/glassmorphism.ts.
// Numeric fields are float64 so the Go zero value (0) is exactly the TS
// nullish-coalescing default (blur ?? 0, opacity ?? 0, radius ?? 0,
// borderOpacity ?? 0). Saturation is *int so the zero value (nil) means the
// TS default of 180 (saturation ?? 180) while an explicit pointer — including
// to 0 — is used verbatim. An empty or unparseable Tint falls back to white
// (#ffffff), matching the TS nullish fallback.
type GlassConfig struct {
	Blur          float64
	Opacity       float64
	Tint          string
	Radius        float64
	BorderOpacity float64
	Saturation    *int // nil → 180 (default); non-nil used verbatim
}

// RGB is the {r, g, b} triple — the Go form of hexToRgb's non-null return.
type RGB struct {
	R, G, B int
}

// GlassCss mirrors the GlassCss interface in src/lib/glassmorphism.ts.
type GlassCss struct {
	Background           string
	BackdropFilter       string
	WebkitBackdropFilter string
	Border               string
	BorderRadius         string
	BoxShadow            string
	FullCss              string
}

var (
	hex3 = regexp.MustCompile(`^[0-9a-fA-F]{3}$`)
	hex6 = regexp.MustCompile(`^[0-9a-fA-F]{6}$`)
)

// HexToRgb is the Go twin of hexToRgb() in src/lib/glassmorphism.ts. It parses
// a 3- or 6-digit hex color (with or without a leading '#', surrounding
// whitespace trimmed) into an RGB triple. The bool is false for any input that
// is not a valid 3/6-digit hex — the Go equivalent of the TS null return.
func HexToRgb(hex string) (RGB, bool) {
	h := strings.TrimPrefix(strings.TrimSpace(hex), "#")
	if hex3.MatchString(h) {
		r, _ := strconv.ParseInt(string([]byte{h[0], h[0]}), 16, 0)
		g, _ := strconv.ParseInt(string([]byte{h[1], h[1]}), 16, 0)
		b, _ := strconv.ParseInt(string([]byte{h[2], h[2]}), 16, 0)
		return RGB{int(r), int(g), int(b)}, true
	}
	if hex6.MatchString(h) {
		r, _ := strconv.ParseInt(h[0:2], 16, 0)
		g, _ := strconv.ParseInt(h[2:4], 16, 0)
		b, _ := strconv.ParseInt(h[4:6], 16, 0)
		return RGB{int(r), int(g), int(b)}, true
	}
	return RGB{}, false
}

// Rgba is the Go twin of rgba() in src/lib/glassmorphism.ts. It formats an
// rgba() color string, clamping alpha to [0, 1] and rounding both the channels
// (to integers) and the alpha (to two decimals) like the TS lib.
func Rgba(r, g, b, a float64) string {
	clamped := math.Max(0, math.Min(1, a))
	alpha := math.Round(clamped*100) / 100
	return "rgba(" + ftoi(r) + ", " + ftoi(g) + ", " + ftoi(b) + ", " + fnum(alpha) + ")"
}

// BuildGlassmorphism is the Go twin of buildGlassmorphism() in
// src/lib/glassmorphism.ts. It builds a full frosted-glass CSS declaration
// block from the config, applying the same clamps and defaults as the TS lib.
func BuildGlassmorphism(config GlassConfig) GlassCss {
	blur := math.Max(0, config.Blur)
	opacity := clamp01(config.Opacity)
	radius := math.Max(0, config.Radius)
	borderOpacity := clamp01(config.BorderOpacity)
	saturation := 180
	if config.Saturation != nil {
		saturation = *config.Saturation
	}

	rgb, ok := HexToRgb(config.Tint)
	if !ok {
		rgb = RGB{255, 255, 255}
	}

	background := Rgba(float64(rgb.R), float64(rgb.G), float64(rgb.B), opacity)
	backdropFilter := "blur(" + fnum(blur) + "px) saturate(" + strconv.Itoa(saturation) + "%)"
	border := "1px solid rgba(255, 255, 255, " + fnum(math.Round(borderOpacity*100)/100) + ")"
	borderRadius := fnum(radius) + "px"
	boxShadow := "0 8px 32px 0 rgba(31, 38, 135, 0.37)"

	fullCss := strings.Join([]string{
		"background: " + background + ";",
		"-webkit-backdrop-filter: " + backdropFilter + ";",
		"backdrop-filter: " + backdropFilter + ";",
		"border-radius: " + borderRadius + ";",
		"border: " + border + ";",
		"box-shadow: " + boxShadow + ";",
	}, "\n")

	return GlassCss{
		Background:           background,
		BackdropFilter:       backdropFilter,
		WebkitBackdropFilter: backdropFilter,
		Border:               border,
		BorderRadius:         borderRadius,
		BoxShadow:            boxShadow,
		FullCss:              fullCss,
	}
}

// clamp01 clamps v to [0, 1], mirroring Math.max(0, Math.min(1, v)).
func clamp01(v float64) float64 { return math.Max(0, math.Min(1, v)) }

// ftoi formats a channel value as an integer (Math.round-equivalent).
func ftoi(v float64) string {
	return strconv.FormatFloat(math.Round(v), 'f', -1, 64)
}

// fnum formats a number the way a JS template literal coerces it — the
// shortest decimal that round-trips ("0.5", "0.57", "1", "0", "12", "10").
func fnum(v float64) string {
	return strconv.FormatFloat(v, 'f', -1, 64)
}

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 →