Theme Studio Overview
The theme studio is where you design the hosted login experience for a downstream Blu app. It controls every pixel that a user sees during authentication — the layout, the colors, the typography, the copy on every concept screen, the logo, the background, and (if you need to reach past presets) custom CSS. One theme record drives the sign-in page, the force-reset checkpoint, every transactional email, and the branded artifacts BluAuth hands off to downstream apps.
This guide is the entry point. Subsequent guides go deep on each axis — layouts, styling tokens, concept copy, assets and backgrounds, and advanced CSS.
Who uses the theme studio
Tenant administrators with the admin role on BluAuth. You'll find the studio under /admin/themes. Each theme is scoped to one OAuth client, and each OAuth client represents one downstream Blu application. If your tenant ships three apps, you'll typically maintain three themes — though you can rebind a single theme to many clients if they share branding.
End users never touch the studio. They see the rendered result on the hosted login page at auth.blutools.io (or a tenant subdomain).
What a theme controls
A theme record is a row in the clientThemes table. Its editable surface in the studio is grouped into six panels:
| Panel | What it controls |
|---|---|
| Layout | One of five compositions — centered card, split hero, minimal, cinematic split, aurora — plus layout-specific options like aurora intensity or cinematic panel mode. |
| Colors | Primary accent, background canvas, optional surface (card) fill. Hex only. |
| Typography & Density | Font preset, field style, button style, surface style, density. |
| Copy | Theme-level heading and subheading, concept-specific overrides for login / forgot / reset / force-reset, hero eyebrow, and two hero action cards. |
| Assets | Logo upload and optional background image (framed or full-bleed). |
| Advanced CSS | An escape hatch for polish that presets don't cover. |
See the design tokens reference for the authoritative visual contract — the studio's presets are tuned against it.
The concept × mode matrix
A "concept" is one of the auth-flow screens; a "mode" is the interaction state inside that concept. Copy and affordances vary across this matrix:
| Concept | Mode(s) | Route | What it does |
|---|---|---|---|
login | signin, signup | /login | Primary entry. Toggles between sign in and sign up. |
forgot-password | forgot | /forgot-password | Request a reset link by email. |
reset-password | reset | /reset-password?token=... | Set a new password using a token from email. |
force-reset | reset | /reset-password (with requirePasswordReset) | Admin-triggered mandatory reset before a user can continue. |
verify-email | — | /verify-email | Confirms a new email address. |
error | error | Any concept, on failure | Renders an inline error state. |
Every layout renders every concept — you don't design per-concept layouts. You design one layout and it adapts to whatever concept the router resolves.
The workflow
A typical session in the studio looks like this:
1. Pick a layout
Open /admin/themes/:id. The Layout selector is the top-most control because it changes the most. See the layouts guide for the taxonomy. Don't agonize — you can swap layouts at any time with no data loss. Each layout reads the same theme fields; some fields simply render differently (or not at all) depending on the layout.
2. Set colors and typography
Drop in your Primary Color and Background Color first. If you want a specific card tint that isn't derived from the background, flip on Apply custom surface tint and set Surface Color. Then pick a Font Family Preset, Surface Style, Field Style, Button Style, and Density. The styling tokens guide explains what each of these drives.
3. Write copy
Under Copy, override the default headings. At minimum, set a Heading Text that names your tenant or app. Optionally override per-concept headings — if your tenant uses different voice for forgot/reset flows, this is where you set that. See the concept copy guide.
4. Upload assets
Drop in a logo (under 512 KB, SVG preferred). If you want a background image, set a mode (Framed or Full Bleed) and upload one (under 5 MB). See the assets guide.
5. Preview
The preview pane on the right renders the exact HostedLoginSurface component the production login page uses, against your in-flight draft. Use the viewport toggle above the preview to switch between desktop and mobile. Mobile preview shrinks the embedded frame to a phone-aspect container — useful for catching hero card collapse and the narrow-form behaviors specific to split-hero and cinematic-split.
You can also change the concept the preview renders (login vs forgot vs reset vs force-reset) to verify your concept-specific copy.
6. Save
Click Save. Your draft is persisted to the clientThemes row; the preview reflects exactly what users will see. Saves are atomic — every field you touched writes in one transaction. If the save fails (rare — usually a KMS transient if you just uploaded an asset), the studio keeps your local edits so you can retry.
7. Deploy
BluAuth's staging environment deploys automatically from main. Production deploys on merge as well. Expect your saved theme to land on staging within a few minutes of the save completing — no rebuild required, because theme reads hit Postgres and are cached in Valkey with a short TTL.
Reset & discard
The studio has two ways to abandon in-flight edits:
- Discard — drops your local draft and re-hydrates from the saved row. Use when you want to start over but keep the saved theme.
- Reset to defaults — overwrites the saved row with
HOSTED_LOGIN_THEME_DEFAULTS. Destructive. Confirmation required.
There is no undo history beyond the current session. If you need to roll back a saved theme, restore it from the clientThemes audit trail (see /admin/audit).
The staging preview reservation
BluAuth reserves the theme ID "preview" for ad-hoc staging previews. If you need to share a work-in-progress theme with a stakeholder without saving it to a real client, export your draft to the preview slot and share the /login?theme=preview URL. The preview slot is wiped on every deploy, so it's not a place to store anything you care about.
How themes resolve at runtime
At request time, BluAuth determines the effective theme in this order:
- The OAuth client carried in the request (via
client_slug,client_id, or referral context) has a bound theme. - If no client is identified, the default service theme (marked
isDefaultin the admin UI) is used. - Any unset field falls back to
HOSTED_LOGIN_THEME_DEFAULTSin code — so a theme never renders half-blank.
The same resolution runs server-side for email rendering. Every email goes through resolveEmailTheme(clientId) so invitation, password reset, and welcome emails match the recipient's tenant brand.
Preview vs production
The studio's preview pane renders inside an embedded container sized to the preview frame. The markup is identical to production, but some viewport-dependent styles — most notably min-height: 100dvh on cinematic-split --height-full — behave differently inside the embedded frame. That's expected. Verify those behaviors by opening the saved theme in a real browser window using the Open in new tab action at the top of the studio.
Next steps
- Layouts — pick the right composition for your brand.
- Styling tokens — what every color, font, and preset does.
- Concept copy — tailor each auth-flow screen.
- Assets and backgrounds — logo and background image sizing.
- Advanced CSS — when and how to use the escape hatch.
- Design tokens — the authoritative visual contract the presets target.