Skip to content

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

// =============================================================================
//  glassmorphism-generator.cpp — CosmoDev polyglot showcase port of the
//  `glassmorphism-generator` tool
//  -----------------------------------------------------------------------------
//  Language : C++ (C++17, 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
//  validated by hand with std::isxdigit (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
//  are rendered via std::to_chars with no format argument, the shortest
//  round-tripping decimal (10.0 -> "10", 0.3 -> "0.3"), which is exactly how
//  JavaScript template literals render them. The output therefore matches the
//  live TypeScript lib byte-for-byte.
// =============================================================================

#include <algorithm>
#include <cctype>
#include <charconv>
#include <cmath>
#include <iostream>
#include <optional>
#include <string>
#include <string_view>
#include <tuple>

namespace glassmorphism {

/// Configuration for one glassmorphism declaration block.
struct GlassConfig {
    double blur = 0.0;
    double opacity = 0.0;
    std::string tint = "#ffffff";
    double radius = 0.0;
    double border_opacity = 0.0;
    std::optional<double> saturation;  // nullopt => 180.0 (lib default)
};

/// The rendered glassmorphism block plus its full CSS text.
struct GlassCss {
    std::string background;
    std::string backdrop_filter;
    std::string webkit_backdrop_filter;
    std::string border;
    std::string border_radius;
    std::string box_shadow;
    std::string full_css;
};

/// Render a double the way JavaScript's template literal does — shortest
/// round-tripping decimal, no trailing ".0" on whole numbers. std::to_chars
/// with no format argument is precisely that: 10.0 -> "10", 0.3 -> "0.3".
inline std::string format_number(double x)
{
    char buf[32];
    auto res = std::to_chars(buf, buf + sizeof buf, x);
    return std::string(buf, res.ptr);
}

/// True when every character of `s` is an ASCII hex digit (0-9, a-f, A-F).
inline bool is_hex_run(std::string_view s)
{
    return !s.empty() && std::all_of(s.begin(), s.end(), [](char c) {
        unsigned char u = static_cast<unsigned char>(c);
        return std::isxdigit(u) != 0;
    });
}

/// Parse a run of ASCII hex digits into its integer value (base 16).
inline int parse_hex(std::string_view s)
{
    int v = 0;
    for (char c : s) {
        unsigned char u = static_cast<unsigned char>(c);
        int d = std::isdigit(u) != 0 ? u - '0'
                                      : std::tolower(u) - 'a' + 10;
        v = v * 16 + d;
    }
    return v;
}

/// Parse #rgb or #rrggbb into (r, g, b); std::nullopt 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.
inline std::optional<std::tuple<int, int, int>> hex_to_rgb(std::string_view hex)
{
    // Trim ASCII whitespace first — the set JS String.prototype.trim() strips.
    constexpr const char* kWs = " \t\n\r\f\v";
    if (hex.find_first_not_of(kWs) == std::string_view::npos) {
        return std::nullopt;
    }
    auto s = hex.substr(hex.find_first_not_of(kWs),
                        hex.find_last_not_of(kWs) - hex.find_first_not_of(kWs) + 1);
    if (!s.empty() && s.front() == '#') {
        s.remove_prefix(1);
    }
    if (s.size() == 3 && is_hex_run(s)) {
        // "a" -> 0xaa — each digit doubles into a pair, like CSS.
        auto expand = [&](size_t i) { return parse_hex(s.substr(i, 1)) * 16 + parse_hex(s.substr(i, 1)); };
        return std::tuple(expand(0), expand(1), expand(2));
    }
    if (s.size() == 6 && is_hex_run(s)) {
        return std::tuple(parse_hex(s.substr(0, 2)), parse_hex(s.substr(2, 2)),
                          parse_hex(s.substr(4, 2)));
    }
    return std::nullopt;
}

/// Format rgba(), clamping + 2-decimal-rounding the alpha with JS Math.round
/// (half-up) semantics: floor(x*100 + 0.5)/100.
inline std::string rgba(int r, int g, int b, double a)
{
    double c = std::min(std::max(a, 0.0), 1.0);
    return "rgba(" + std::to_string(r) + ", " + std::to_string(g) + ", " +
           std::to_string(b) + ", " +
           format_number(std::floor(c * 100.0 + 0.5) / 100.0) + ")";
}

/// Build the full glassmorphism CSS for a config.
inline GlassCss build(const GlassConfig& cfg)
{
    const double blur = std::max(cfg.blur, 0.0);
    const double opacity = std::min(std::max(cfg.opacity, 0.0), 1.0);
    const double radius = std::max(cfg.radius, 0.0);
    const double border_opacity = std::min(std::max(cfg.border_opacity, 0.0), 1.0);
    const double saturation = cfg.saturation.value_or(180.0);
    auto [r, g, b] = hex_to_rgb(cfg.tint).value_or(std::make_tuple(255, 255, 255));

    GlassCss css;
    css.background = rgba(r, g, b, opacity);
    css.backdrop_filter = "blur(" + format_number(blur) + "px) saturate(" +
                          format_number(saturation) + "%)";
    css.border = "1px solid " + rgba(255, 255, 255, border_opacity);
    css.border_radius = format_number(radius) + "px";
    css.box_shadow = "0 8px 32px 0 rgba(31, 38, 135, 0.37)";
    // Both prefixed and unprefixed backdrop-filter carry the same value.
    css.webkit_backdrop_filter = css.backdrop_filter;

    css.full_css = "background: " + css.background + ";\n"
                   "-webkit-backdrop-filter: " + css.backdrop_filter + ";\n"
                   "backdrop-filter: " + css.backdrop_filter + ";\n"
                   "border-radius: " + css.border_radius + ";\n"
                   "border: " + css.border + ";\n"
                   "box-shadow: " + css.box_shadow + ";";
    return css;
}

}  // namespace glassmorphism

int main()
{
    glassmorphism::GlassConfig cfg;
    cfg.blur = 10.0;
    cfg.opacity = 0.3;
    cfg.tint = "#ffffff";
    cfg.radius = 12.0;
    cfg.border_opacity = 0.2;
    std::cout << glassmorphism::build(cfg).full_css << '\n';
    return 0;
}

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 →