// SloppyUniverse Logo System — v3 // ------------------------------------------------------------ // Two shapes share the same frame geometry: // • Umbrella → 4-color frame + "UNIV/ERSE" wordmark (main brand) // • Module → monochrome frame + big single letter (F, S, P, R) // Colors pulled from the module icons on the login page so everything // reads as one family. // Brand palette — aligned to module icons on the login page. const SU_COLORS = { // Umbrella quadrant colors — same hues as the modules green: "#5A7C2A", // SloppyFix (olive) navy: "#2E3CC6", // SloppyScan (royal blue) magenta: "#B63E8E", // SloppyPlan (pink/magenta) orange: "#C86A2E", // SloppyRent (terracotta) // Text / utility ink: "#0F1233", paper: "#FFFFFF", outline:"#0F1233", }; // Per-module tokens (frame color = dark variant, accent = light variant for glyph bg) const SU_MODULES = { fix: { name: "SloppyFix", letter: "F", pair: "FX", color: "#5A7C2A", tint: "#8FB055" }, scan: { name: "SloppyScan", letter: "S", pair: "SN", color: "#2E3CC6", tint: "#6A78E8" }, plan: { name: "SloppyPlan", letter: "P", pair: "PN", color: "#B63E8E", tint: "#D97AB8" }, rent: { name: "SloppyRent", letter: "R", pair: "RT", color: "#C86A2E", tint: "#E39A68" }, pay: { name: "SloppyPay", letter: "P", pair: "PY", color: "#A47913", tint: "#D9A93B" }, }; // Font presets for the module monogram. `size1/size2` are fractions of icon size. const FONT_PRESETS = { "space-grotesk": { label: "Space Grotesk 600", family: "'Space Grotesk', system-ui, sans-serif", weight: 600, size1: 0.44, size2: 0.32, ls1: "-0.02em", ls2: "-0.04em", }, "ibm-plex-mono": { label: "IBM Plex Mono 600", family: "'IBM Plex Mono', ui-monospace, monospace", weight: 600, size1: 0.44, size2: 0.30, ls1: "0", ls2: "-0.05em", }, "jetbrains-mono": { label: "JetBrains Mono 700", family: "'JetBrains Mono', ui-monospace, monospace", weight: 700, size1: 0.44, size2: 0.30, ls1: "0", ls2: "-0.05em", }, "instrument-serif": { label: "Instrument Serif", family: "'Instrument Serif', 'Times New Roman', serif", weight: 400, size1: 0.55, size2: 0.40, ls1: "-0.01em", ls2: "-0.03em", style: "italic", }, "archivo-narrow": { label: "Archivo Narrow 700", family: "'Archivo Narrow', 'Arial Narrow', sans-serif", weight: 700, size1: 0.48, size2: 0.38, ls1: "-0.02em", ls2: "-0.04em", }, "dm-mono": { label: "DM Mono 500", family: "'DM Mono', ui-monospace, monospace", weight: 500, size1: 0.44, size2: 0.30, ls1: "0", ls2: "-0.04em", }, "inter-tight": { label: "Inter Tight 700", family: "'Inter Tight', Inter, system-ui, sans-serif", weight: 700, size1: 0.46, size2: 0.34, ls1: "-0.03em", ls2: "-0.05em", }, }; // ---------------------------------------------------------------------- // FrameShape — a single filled rounded-rect frame with a top-left notch. // Exposes gradients/filters so both Umbrella and Module variants can reuse. // ---------------------------------------------------------------------- function FrameShape({ size = 240, pad = 10, thickness = 28, ro = 24, ri = 10, gap = 18, gapCenterFrac = 0.28, children, idPrefix = "f", }) { const x0 = pad, y0 = pad; const x1 = size - pad, y1 = size - pad; const ix0 = x0 + thickness, iy0 = y0 + thickness; const ix1 = x1 - thickness, iy1 = y1 - thickness; const cx = size / 2; const outer = `M ${x0 + ro} ${y0} H ${x1 - ro} A ${ro} ${ro} 0 0 1 ${x1} ${y0 + ro} V ${y1 - ro} A ${ro} ${ro} 0 0 1 ${x1 - ro} ${y1} H ${x0 + ro} A ${ro} ${ro} 0 0 1 ${x0} ${y1 - ro} V ${y0 + ro} A ${ro} ${ro} 0 0 1 ${x0 + ro} ${y0} Z`; const inner = `M ${ix0 + ri} ${iy0} H ${ix1 - ri} A ${ri} ${ri} 0 0 1 ${ix1} ${iy0 + ri} V ${iy1 - ri} A ${ri} ${ri} 0 0 1 ${ix1 - ri} ${iy1} H ${ix0 + ri} A ${ri} ${ri} 0 0 1 ${ix0} ${iy1 - ri} V ${iy0 + ri} A ${ri} ${ri} 0 0 1 ${ix0 + ri} ${iy0} Z`; const notchCx = x0 + (x1 - x0) * gapCenterFrac; const notchX0 = notchCx - gap / 2; const notchX1 = notchCx + gap / 2; return { cx, size, pad, thickness, x0, y0, x1, y1, ix0, iy0, ix1, iy1, outer, inner, notchX0, notchX1, notchY0: y0 - 4, notchY1: iy0 + 4, idPrefix, }; } // ---------------------------------------------------------------------- // UmbrellaLogo — the main SloppyUniverse mark. // 4-color frame (one color per quadrant), subtle gradient + inner highlight // for plastic depth, white UNIV/ERSE with dark outline for legibility. // ---------------------------------------------------------------------- function UmbrellaLogo({ size = 240, colors = { tl: SU_COLORS.green, tr: SU_COLORS.navy, br: SU_COLORS.orange, bl: SU_COLORS.magenta, }, idPrefix = "umb", plastic = true, onDark = false, textColor = SU_COLORS.paper, outlineColor = SU_COLORS.outline, }) { const s = size; // Everything scales from size (defaults tuned for 240). const k = s / 240; const pad = 10 * k; const thickness = 28 * k; const ro = 24 * k; const ri = 10 * k; const gap = 18 * k; const gapCenterFrac = 0.28; const outlineWidth = 3 * k; const rowHeight = 54 * k; const lineGap = 4 * k; const wordInset = 36 * k; const g = FrameShape({ size: s, pad, thickness, ro, ri, gap, gapCenterFrac, idPrefix }); const maskId = `${idPrefix}-mask`; const hiId = `${idPrefix}-hi`; const haloId = `${idPrefix}-halo`; return ( {/* Halo for dark backgrounds */} {/* White backing card behind frame — lifts off dark backgrounds */} {onDark && ( )} {/* Colored frame */} {plastic && } {plastic && } ); } function UmbrellaWordmark({ cx, cy, width, rowHeight, lineGap, color, outlineColor, outlineWidth, fontFamily = "'Archivo Black', 'Arial Black', system-ui, sans-serif", }) { const cap = rowHeight * 0.72; const topY = cy - (cap + lineGap) / 2; const bottomY = cy + (cap + lineGap) / 2; const base = { textAnchor: "middle", fontFamily, fontWeight: 900, fontSize: rowHeight, textLength: width, lengthAdjust: "spacingAndGlyphs", dominantBaseline: "middle", paintOrder: "stroke fill", stroke: outlineColor, strokeWidth: outlineWidth, strokeLinejoin: "round", }; return ( UNIV ERSE ); } // ---------------------------------------------------------------------- // ModuleIcon — same frame shape, monochrome color, single big letter. // ---------------------------------------------------------------------- function ModuleIcon({ moduleKey = "fix", size = 240, idPrefix, plastic = true, glyph, font = "inter-tight", // key into FONT_PRESETS }) { const m = SU_MODULES[moduleKey]; const label = glyph ?? m.letter; const labelLen = label.length; const twoChar = labelLen >= 2; const preset = FONT_PRESETS[font] || FONT_PRESETS["space-grotesk"]; // Fuer 3-Zeichen-Wörter (fix, pay) ~70% des 2-letter Sizes, // fuer 4-Zeichen-Wörter (scan, plan, rent) ~55%. Sonst werden die // Buchstaben breiter als der Frame. const lenScale = labelLen <= 2 ? 1.0 : (labelLen === 3 ? 0.70 : 0.55); const s = size; const prefix = idPrefix || `mod-${moduleKey}`; const pad = Math.round(s * 0.06); const thickness = Math.round(s * 0.11); const ro = Math.round(s * 0.14); const ri = Math.round(s * 0.05); const gap = Math.round(s * 0.07); const g = FrameShape({ size: s, pad, thickness, ro, ri, gap, gapCenterFrac: 0.28, idPrefix: prefix }); const maskId = `${prefix}-mask`; const hiId = `${prefix}-hi`; // Darker inner panel behind the letter const ix0 = g.ix0, iy0 = g.iy0, ix1 = g.ix1, iy1 = g.iy1; const innerR = ri; return ( {/* Dark inner panel (module color darkened) */} {/* Colored outer frame */} {plastic && } {/* Monogram — font chosen via preset. Shift slightly left for optical centering (round shapes feel right-heavy). Per-label nudge: "RT" has a vertical T-stem on the right, so push right. */} = 3 ? "-0.02em" : (twoChar ? preset.ls2 : preset.ls1)} fontStyle={preset.style || "normal"} > {label} ); } // ---------------------------------------------------------------------- // UmbrellaMono — single color variant (for print, stamping, dark BG) // ---------------------------------------------------------------------- function UmbrellaMono({ size = 240, color = SU_COLORS.ink, idPrefix = "mono" }) { return ( ); } // ---------------------------------------------------------------------- // UmbrellaLockup — horizontal mark + wordmark // ---------------------------------------------------------------------- function UmbrellaLockup({ size = 380 }) { const h = 120; const w = 420; return ( sloppy universe ); } Object.assign(window, { UmbrellaLogo, UmbrellaMono, UmbrellaLockup, ModuleIcon, SU_COLORS, SU_MODULES, FONT_PRESETS, // Legacy aliases LogoA: UmbrellaLogo, LogoB: (props) => , LogoC: UmbrellaLogo, LogoD: UmbrellaLogo, LogoE: UmbrellaLockup, LogoF: UmbrellaMono, LogoPrimary: UmbrellaLogo, LogoThin: (props) => , LogoTile: UmbrellaLogo, LogoMono: UmbrellaMono, LogoLockup: UmbrellaLockup, });