Theming & branding
Swap colors, fonts, and component styles across both apps. Tailwind v4 @theme tokens, the additive-display palette, the semantic-class pattern.
GlassKit uses Tailwind v4 with @theme tokens. Two surfaces, two
stylesheets, one shared design language. Rebranding for your
product takes ~10 minutes:
| File | Surface | Owns |
|---|---|---|
companion/app/globals.css | Next.js companion | Companion-side palette (dark theme, accent green) |
app/src/index.css | Vite glasses app | Imports the library stylesheet + adds AI-response glue |
packages/glasses-ui/styles.css | Library (shared) | The additive-display palette + semantic classes (.screen, .focusable, .launcher-*) |
The companion gets its own palette because it's a normal web
surface: full color, gradients, all the usual. The glasses app
inherits the additive-display palette from glasses-ui because
the optics constrain it (pure black emits no light, so the design
system has to be glowing marks on black).
The companion's tokens
Edit companion/app/globals.css:
@import "tailwindcss";
@theme {
--color-bg: #08090b;
--color-surface: #131418;
--color-surface-2: #1c1e23;
--color-ink: #f2f3f5;
--color-ink-dim: #9aa0a8;
--color-rule: #232629;
--color-rule-hover: #34383d;
--color-accent: #36e27f; /* the green CTA color */
--color-accent-ink: #04210f; /* dark text on the accent bg */
--font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
}Every --color-X token automatically becomes a Tailwind utility:
bg-bg, text-ink-dim, border-rule, bg-accent text-accent-ink,
etc. To rebrand:
Swap the accent hex. --color-accent is the primary CTA and
brand color. Pick one with good contrast against the dark surface.
Pick a matching --color-accent-ink. This is the text color that
sits ON the accent. Usually a darkened version of the accent
(don't use pure black; accent backgrounds need a tinted
foreground for harmony).
Swap the font. Replace the --font-sans value or add a
--font-display for headings (the marketing site uses
Bricolage_Grotesque via next/font/google).
That's the entire rebrand for the companion. No component edits required. Every component reads from the tokens.
The library's tokens (the glasses app)
Don't fork the library file
Override in your fork's app stylesheet by re-declaring the tokens AFTER the library import.
@import "tailwindcss";
@import "@glasskit/glasses-ui/styles.css";
/* Your override — wins because it's loaded later */
@theme {
--color-accent: #ff7e6b; /* your brand color */
--color-room: #050507; /* the dev-only "around-the-viewport" color */
}The library's defaults:
@theme {
--color-bg: #000; /* pure black — transparent on the device */
--color-ink: #f2f3f5;
--color-ink-dim: #9aa0a8;
--color-accent: #36e27f; /* phosphor green */
--color-surface: #14171c;
--color-rule: #2a2f37;
--color-room: #07080a; /* dark room around the viewport — local dev only */
--font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
}Constraints from the optics
The Meta Ray-Ban Display is additive: it adds light to what the wearer sees through the lens. That has hard implications:
Optics-driven rules
--color-bgshould stay#000. Any non-black background emits unintended light. Even very-dark gray (#0a0a0a) shows up as a faint glow on the optics.--color-accentshould be bright and saturated. Pastels and desaturated tones wash out. The default phosphor green (#36e27f) is calibrated for the display; replacement colors should be similarly bright (think CRT-style hex:#ff7e6bcoral,#5ad8ffcyan,#ffce6bamber all work).--color-inkmatters less than you'd think. Most text on the glasses app is small enough that subtle gradations don't perceptibly differ. Off-white reads cleaner than pure white.--color-roomis dev-only: it's the area AROUND the 600×600 viewport in the browser preview. Doesn't render on the device; pick whatever color makes the local preview pleasant.
The semantic classes
glasses-ui/styles.css ships a set of @apply-based classes that
every demo uses:
.glass-viewport/.glass-viewport--frame: the 600×600 container styling.screen: flex column layout for a full screen.focusable: base interactive styling + the focus ring.launcher,.launcher-grid,.launcher-card,.launcher-card__label,.launcher-card__tagline: the demo launcher.app-head,.row,.readout,.label,.dim,.cue-script,.cue-line,.cue-bar: the typography + layout classes the demos compose
These are semantic by intent: .screen doesn't mean "a flex
column with gap: 12px"; it means "the page-level layout of a
screen on the glasses." If you want a slightly different gap, you
edit glasses-ui/styles.css once and every demo updates.
The classes are public API of the library. Override carefully in your fork.
Adding your own classes
In app/src/index.css, after the library import:
@import "tailwindcss";
@import "@glasskit/glasses-ui/styles.css";
.my-special-card {
@apply rounded-md border border-rule bg-surface p-4;
}
.ai-response {
/* Existing class — extend it */
@apply m-0 min-h-[2.6em] w-full text-center leading-[1.5] text-ink;
font-size: 13px;
}Use Tailwind utilities (@apply) over custom CSS where possible.
The utilities already reference your --color-* tokens, so a
theme swap doesn't require touching individual classes.
Fonts
The companion uses next/font/google. Edit
companion/app/(web)/layout.tsx (or whichever layout you're
targeting):
import { Bricolage_Grotesque, Hanken_Grotesk } from "next/font/google";
const display = Bricolage_Grotesque({ variable: "--font-display", subsets: ["latin"], weight: ["400","600","700","800"] });
const body = Hanken_Grotesk({ variable: "--font-body", subsets: ["latin"], weight: ["400","500","600","700"] });Then in globals.css:
@theme {
--font-display: var(--font-display), ui-sans-serif, system-ui;
--font-sans: var(--font-body), ui-sans-serif, system-ui;
}next/font/google self-hosts the font files, so no CDN dependency
or layout shift.
Same --font-sans token in glasses-ui/styles.css (override in
app/src/index.css). The glasses app uses system fonts by default
to avoid an extra HTTP request; the surface is small enough that
a custom font barely shows. If you want a custom font for branding,
load it via @font-face in index.css and assign to
--font-sans.
Dark / light theme
Both apps ship dark-only by default. It's the right default for a glasses-adjacent product and matches the additive display constraint. If you want a light mode for the companion:
Move the dark tokens into @theme under a .dark selector via
@variant, OR use Tailwind v4's prefers-color-scheme media
query.
Define light tokens at the root @theme level.
Wire next-themes (already a dep) to toggle between them.
The glasses app stays dark always; additive display means there is no "light mode," only "less black."
Tokens you probably won't touch
--color-rule/--color-rule-hover: hairline dividers and card borders. Stay subtle.--color-surface/--color-surface-2: card backgrounds. Each half-step lighter than--color-bgadds visual hierarchy.--color-ink-dim: secondary text. Adjusting this changes the contrast between headlines and metadata.
Most rebrands change --color-accent + --font-* and call it
done. The architecture lets you go deeper, but the design system
is already calibrated, so fight it only if your brand actually
demands it.