[object Object]

← back to Quadrille Showroom

auto-save: 2026-06-28T16:15:32 (1 files) — LIQUID-UI-SPEC.md

c38484d5a0872f3ef851c262087b8efd4c19b82e · 2026-06-28 16:15:34 -0700 · Steve Abrams

Files touched

Diff

commit c38484d5a0872f3ef851c262087b8efd4c19b82e
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sun Jun 28 16:15:34 2026 -0700

    auto-save: 2026-06-28T16:15:32 (1 files) — LIQUID-UI-SPEC.md
---
 LIQUID-UI-SPEC.md | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 89 insertions(+)

diff --git a/LIQUID-UI-SPEC.md b/LIQUID-UI-SPEC.md
new file mode 100644
index 0000000..f807eed
--- /dev/null
+++ b/LIQUID-UI-SPEC.md
@@ -0,0 +1,89 @@
+# LIQUID-UI-SPEC — Quadrille Showroom HUD elevation (Figma + 21st-dev sourced)
+
+Source: 21st.dev "liquid glass" component inspiration (SVG-displacement technique) + Figma
+(team::1520578458021404621, authenticated). Goal: kill the "juvenile" HUD — replace flat
+chips / basic top bar / plain spec card with a **liquid-glass luxury** system that stays
+**Phillip-Jeffries-grade** and **senior-usable**, WITHOUT tanking FPS over the live WebGL canvas.
+
+## The hard performance rule (read first)
+The showroom canvas re-renders every frame. A full SVG `feDisplacementMap` `backdrop-filter`
+composited over it **every frame** will wreck FPS (Steve's "maximize FPS" rule). Therefore:
+
+- **Tier 1 — always-on HUD (top bar, chips, slider rail):** CSS-only frosted glass.
+  `backdrop-filter: blur(14px) saturate(140%)` + translucent fill + 1px hairline + inset
+  specular highlight. Cheap, steady 60fps. This is the default for anything persistently visible.
+- **Tier 2 — liquid refraction (the "wow"):** the real SVG `feTurbulence → feDisplacementMap`
+  glass, applied ONLY to **static / hover / open moments** — the spec card when it opens, a chip
+  on `:hover`/`:focus`, the slider thumb on grab. No per-frame cost because the underlying scene
+  is paused or the element is transient. NEVER put Tier 2 on a per-frame-updating full-width bar.
+
+## Design tokens (drop into showroom.css `:root`)
+```css
+:root{
+  --glass-fill: rgba(22,22,24,0.46);          /* smoked, not white — luxury reads dark */
+  --glass-fill-hi: rgba(255,255,255,0.06);    /* faint top sheen layer */
+  --glass-stroke: rgba(255,255,255,0.14);     /* 1px hairline */
+  --glass-blur: 14px;
+  --glass-sat: 140%;
+  --glass-shadow: 0 8px 30px rgba(0,0,0,0.38), 0 -10px 24px inset rgba(255,255,255,0.05);
+  --ink: #ece9e3;            /* warm off-white text */
+  --ink-dim: rgba(236,233,227,0.62);
+  --accent: #b9935a;         /* brushed-brass, the ONE metal accent */
+  --font-display: "Cormorant Garamond", "Times New Roman", serif;  /* thin luxury display */
+  --font-ui: -apple-system, "Helvetica Neue", system-ui, sans-serif;
+  --tr: 420ms cubic-bezier(.22,.61,.36,1);    /* slow morph, never snappy */
+}
+```
+
+## Tier 1 — frosted glass base (top bar, chips, slider rail)
+```css
+.glass{
+  background: linear-gradient(var(--glass-fill-hi), transparent 60%), var(--glass-fill);
+  -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-sat));
+  backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-sat));
+  border: 1px solid var(--glass-stroke);
+  border-radius: 16px;
+  box-shadow: var(--glass-shadow);
+  color: var(--ink);
+}
+/* Top bar: thin, letter-spaced display wordmark left, controls right, generous padding. */
+/* Version/theme chips: pill .glass, ink-dim default, brass underline + ink on active;
+   morph the active indicator with --tr (transform, not width-jump). */
+/* Open-angle slider: .glass rail, brass thumb, value label in --font-display. */
+```
+
+## Tier 2 — liquid refraction (spec card open / chip hover only)
+Inject ONE shared SVG filter once (hidden `<svg>` at end of body), reference via class:
+```html
+<svg width="0" height="0" style="position:absolute"><defs>
+  <filter id="liquid" x="-20%" y="-20%" width="140%" height="140%">
+    <feTurbulence type="fractalNoise" baseFrequency="0.001 0.005" numOctaves="2" seed="7" result="noise"/>
+    <feGaussianBlur in="noise" stdDeviation="3" result="soft"/>
+    <feDisplacementMap in="SourceGraphic" in2="soft" scale="60" xChannelSelector="R" yChannelSelector="G"/>
+  </filter>
+</defs></svg>
+```
+```css
+.liquid:hover, .spec-card.open{
+  -webkit-backdrop-filter: blur(10px) url(#liquid);
+  backdrop-filter: blur(10px) url(#liquid);   /* scale kept modest (60) so refraction is elegant, not warped */
+}
+@media (prefers-reduced-motion: reduce){ .liquid:hover,.spec-card.open{ backdrop-filter: blur(12px) saturate(140%);} }
+```
+Note: `scale=200` (the 21st source) is too much for a UI panel — it smears text. Use **scale 40–70**.
+Gate Tier 2 behind a feature flag + an FPS check: if measured FPS < 55 with it on, fall back to Tier 1.
+
+## Senior-usable guardrails (do NOT regress)
+- Min 16px UI text, 18px+ for the spec card body; hit targets ≥ 44px.
+- Contrast: ink on smoked glass must clear APCA Lc ≥ 60 (run hero-readability-auditor on a screenshot).
+- Motion slow (--tr ~420ms); respect prefers-reduced-motion (drop Tier 2 + shorten morphs).
+- The big guided buttons (Prev / Auto-Tour / Next / All Designs) keep their large size — just reskin to .glass.
+
+## Where it lands (next officer slice, AFTER geometry Slice 1 commits)
+- `public/css/showroom.css` — tokens + `.glass` + `.liquid` + chip/topbar/slider/spec-card reskin.
+- `public/js/showroom.js` / `versions.js` — add the hidden `<svg>` filter once; add `.glass`/`.liquid`
+  classes to the HUD nodes; FPS-gate Tier 2. (Officer is sole editor — do NOT touch while Slice 1 runs.)
+- Verify with /screenrecord (5 combos) + /cta (Chrome+Safari — WebKit's `backdrop-filter: url()`
+  support is the #1 risk; Tier 1 blur is safe, Tier 2 url-filter must be WebKit-tested) → /contrarian gate.
+```
+```

← 1fbedd2 Slice 1 (A+B+C): 14x14 room, fixed-centre yaw-spin camera (c  ·  back to Quadrille Showroom  ·  Slice 1: open-angle slider (qh_open_angle, 45° default, 20-9 37affeb →