Skip to main content
vibld

Template

Ulmora

A stripped-back sign-up page for an AI assistant workspace aimed at companies. It offers name and email with a bright primary Continue (magic link or code), plus two OAuth options, and nothing else on the page.

Minimal sign-up form with OAuth alternatives · App screen: sign up · Small tools and apps · full-stack app (auth + DB)

A mock-up of the screen, drawn from its layout, palette and typefaces. A build follows the full prompt below.

Start from this screenRead the build prompt

Typefaces

The catalog's own faces. A screen composed into a template is drawn in that template's typefaces.

  • InterHeadings: Inter 600, 24px H1
  • InterBody: Inter 400/500, 16px, line-height 1.5; labels 14px 600; footnote 13px

Patterns

  • minimal centred auth column
  • filled grey inputs
  • OR divider
  • stacked OAuth buttons
  • legal footnote pinned to bottom
  • blocky geometric logomark

States it is designed for

  • Empty form
  • Invalid email inline
  • Sending code (button spinner)
  • Code screen: wrong code, expired code with resend, too many attempts lockout
  • OAuth cancelled returns with a neutral notice
  • Workspace domain already exists: offer to request to join
  • Network error

Who it is for

  • Knowledge workers trying an AI assistant workspace
  • Team admins setting up a company workspace
  • Developers who prefer signing up with a code-host account

Layout

  1. Blank white page, single 360px column centred horizontally, top at ~16% viewport height
  2. Logomark built from a few coloured geometric blocks, then 'Sign up' H1 left-aligned
  3. First name / Last name row, Email, full-width bright blue Continue
  4. OR divider with hairlines
  5. Two outlined OAuth buttons stacked, each with provider icon
  6. 'Already have an account? Sign in' line
  7. Legal footnote centred near the bottom of the viewport
  8. Mobile: same column at 100% width minus 16px gutters; name fields stack under 360px

Palette

clean, playful-in-one-spot, efficient. A blank page with a colourful mark and a single bright action.

  • page#ffffff
  • input fill#f5f5f5
  • primary text#111418
  • muted text#5f6670
  • input border#8b919a
  • primary button#1766c2
  • link#1766c2
  • outline button border#8b919a
  • focus ring#1766c2
  • error#c42b1c
  • logo block green#3f8f4a
  • logo block red#e0452c

Every checked pair, measured again

SampleWhereRatioNeeds
Aabody text18.47:14.5:1
Aaplaceholder/muted on input fill5.32:14.5:1
Aaprimary label5.65:14.5:1
Aalink text5.65:14.5:1
input border on page3.17:13:1
focus ring on page5.65:13:1
Aaerror text5.66:14.5:1

As vibld’s tokens

The palette on the fifteen colour tokens vibld styles a project with, each text colour on the fill it is read on.

  • background
  • card
  • muted
  • primary
  • secondary
  • accent
  • destructive

Type scale

Display
Inter 600, 24px H1
Body
Inter 400/500, 16px, line-height 1.5; labels 14px 600; footnote 13px

Clean grotesk similar to the observed face; all text left-aligned except the footnote and sign-in line.

Spacing and imagery

Compact column: 12px label-to-input, 20px between fields, 40px inputs, radius 8px; OAuth buttons 40px with 12px gap; no card, no shadow.

Only the multicoloured block logomark and small provider icons; everything else is type and hairlines.

Components

  • Block logomark
  • Filled text input
  • Name pair row
  • Primary Continue button
  • OR divider
  • OAuth button (icon + label)
  • Sign-in link line
  • Legal footnote
  • Code entry screen (6 boxes)

Interactions

  • Continue sends a one-time code and moves to the code screen with the email echoed
  • OAuth buttons open the provider flow; the clicked one shows a spinner and the others disable
  • Inputs darken border on hover and show ring on focus
  • Code inputs auto-advance and accept paste of the whole code

Data

  • User{id, email, first_name, last_name, auth_provider (email|oauth_a|oauth_b)}
  • Workspace{id, name, email_domain, auto_join (bool)}
  • OtpAttempt{email_hash, attempts, locked_until}

Guardrails

Experience

  • Do not ask for a password; the one-time code is the credential
  • Keep OAuth equal in weight to each other and secondary to Continue
  • Echo the email on the code screen with an edit link
  • Put legal copy below, not as a checkbox
  • Offer 'join existing workspace' when the email domain matches an existing workspace

Accessibility

  • Filled inputs also carry a 3:1 border so the field edge is visible
  • OR divider text is not the only separator (aria-hidden hairlines)
  • OAuth buttons have text labels, icons are decorative
  • Code boxes are one labelled input group with autocomplete=one-time-code
  • Focus lands on the first code box when the code screen opens

Security

  • Supabase Auth email OTP with 10-minute expiry and 5-attempt lockout
  • OAuth redirect URLs allow-listed; state parameter verified
  • RLS: users read/update own row; workspace membership checked before auto-join
  • Rate-limit code sends per email and IP
  • Do not reveal whether an email exists before the code step

Build prompt

The baseline every prompt in the catalog assumes, then this design’s own ten sections, from goal to guardrails.

The baseline
### How to use these prompts
Paste an entry's build prompt into your coding agent as the first message. Each prompt names its own stack, tokens and acceptance criteria; the rules below apply to all of them and can be prepended once per project.

### Engineering baseline
- TypeScript strict mode, no `any`, small typed components, feature folders, and one source of truth for design tokens (CSS variables consumed by Tailwind).
- Validate every input with a shared zod schema on the client and again on the server or edge function. Never trust client-side checks alone.
- Show loading, empty and error states for every async view. Surface errors in plain language with a retry, and log details to the console in development only.
- Keep secrets out of the bundle. Only publishable keys (for example a Supabase anon key) belong in client code; service-role keys, API keys and webhooks live in server or edge-function environment variables.

### Data and auth baseline (full-stack entries)
- Enable Row Level Security on every table before inserting data. Default-deny, then add owner-scoped policies (`auth.uid() = user_id`) and explicit role checks for admin views.
- Store roles in a separate table checked by a security-definer function, never in a user-editable profile field.
- Upload files to private storage buckets with size and MIME limits, and serve them through signed URLs.
- Rate-limit public endpoints (forms, auth, AI calls) and add a honeypot field or captcha to anonymous forms.
- Take payments through a hosted checkout and verify webhooks by signature. Never handle raw card data.

### Accessibility and UX baseline
- Target WCAG 2.2 AA: 4.5:1 contrast for normal text and 3:1 for large text, input borders, focus rings and meaningful icons or chart lines. Every palette in this catalog lists its verified pairs; re-check with a contrast tool after any colour change.
- Keep body text at 16px or larger with 1.5 line height, nothing below 12px, no light weights under 24px, and uppercase only for short labels.
- Give every interactive element a visible focus ring, full keyboard support, semantic landmarks, labelled form fields, and alt text on meaningful images.
- Respect `prefers-reduced-motion` for every animation. Give drag-and-drop and carousels keyboard and button alternatives.
- Build mobile-first and test at 375px, 768px and 1280px.

### Content guardrails
- Use original copy, fictional sample data and placeholder or licensed imagery. Do not reuse another product's name, logo, screenshots or marketing text.
- Label demo testimonials and metrics as samples. Collect the minimum personal data the feature needs.

### SaaS screen baseline
- Design every screen for its full set of states: first-run empty, loading skeleton, partial data, error with retry, permission-denied, and success feedback. Each entry lists the states its screen needs.
- Keep destructive actions (delete, revoke, downgrade, remove member) behind a confirmation that names the object, and prefer undo over a second dialog where the action is reversible.
- Enforce authorisation on the server for every action a screen exposes. Hiding a button is not access control; check the role again in the API or RLS policy.
- Never show secrets (API keys, tokens) in full after creation. Show them once, then mask them, and offer rotate and revoke.
- Keep the app shell (navigation, workspace switcher, account menu) consistent across screens, and preserve filters, sort and scroll position when the user navigates back.
### Goal
Build **Ulmora**'s sign-up page for an AI assistant workspace used by whole companies. One narrow column: name, work email, a bright Continue that emails a one-time code, and two OAuth alternatives. Nothing competes for attention except a small multicoloured logomark.

### Stack
React 18 + TypeScript + Vite, Tailwind CSS, shadcn/ui (Radix primitives) and lucide-react icons. TanStack Query for server state, react-hook-form + zod for forms, date-fns for dates. Supabase for Auth, Postgres and Row Level Security (email OTP plus two OAuth providers configured generically as 'Provider A' and 'Provider B').

### Pages & layout
1. **/signup**: white page; 360px column centred horizontally, starting ~16vh from top. Logomark (four coloured rectangles and circles composed into an abstract mark, original), H1 'Sign up', First/Last name row, Email, Continue (full width, `--primary`), OR divider, two outlined OAuth buttons, 'Already have an account? Sign in'. Legal footnote ('By creating an account you agree to the Terms and Privacy Policy') fixed 24px from the viewport bottom on tall screens, in flow on short ones.
2. **/signup/code**: same column; 'Check your email', echoed address with Edit link, six-box code input, Verify button, Resend with 30s cooldown.
3. **/signup/workspace**: if the email domain matches a workspace with auto-join, offer 'Join Acme Labs' (invented) or 'Create a new workspace'.
4. Mobile: name row stacks below 360px; footnote in flow.

### Design system
- Colors: `--bg: #ffffff` (page), `--field: #f5f5f5` (input fill), `--fg: #111418` (primary text), `--muted: #5f6670` (muted text), `--input-border: #8b919a` (input border), `--primary: #1766c2` (primary button), `--link: #1766c2` (link), `--outline: #8b919a` (outline button border), `--ring: #1766c2` (focus ring), `--danger: #c42b1c` (error), `--logo-green: #3f8f4a` (logo block green), `--logo-red: #e0452c` (logo block red).
- Fonts: Inter 400/500/600; H1 24px/1.3 600; labels 14px 600; body 16px/1.5; footnote 13px.
- Spacing: 4px base; 20px between fields; column width 360px.
- Radius: 8px inputs and buttons.
- Shadows: none; outline buttons use a 1px `--outline` border.
- Motion: 150ms border-colour transitions; code screen slides in 8px; none under reduced motion.

### Components & interactions
`BlockLogo` (inline, decorative), `FilledInput` (grey fill plus 1px 3:1 border, darker on hover, `--ring` 2px on focus), `NameRow`, `PrimaryButton` (spinner), `OrDivider`, `OAuthButton` (icon, label, loading), `OtpInput` (6 boxes, paste support, `autocomplete=one-time-code`), `ResendLink` (cooldown), `WorkspaceMatchCard`. When one OAuth button is loading, disable the other and Continue.

### Data & state
`users(id = auth.uid(), email, first_name, last_name, auth_provider)`, `workspaces(id, name, email_domain unique, auto_join bool)`, `memberships(workspace_id, user_id, role enum owner|admin|member)`, `otp_attempts(email_hash, attempts, locked_until)`. Seed one workspace with auto-join on for the matching-domain demo.

### Accessibility
Labels above inputs; placeholders are examples only. Errors inline and in a polite live region. Code input group labelled 'Verification code', with each box `aria-label='Digit n of 6'`. OAuth icons `aria-hidden`. Focus moves to the H1 of each new step.
Verified contrast: body text: #111418 on #ffffff = 18.47:1; placeholder/muted on input fill: #5f6670 on #f5f5f5 = 5.32:1; primary label: #ffffff on #1766c2 = 5.65:1; link text: #1766c2 on #ffffff = 5.65:1; input border on page: #8b919a on #ffffff = 3.17:1; focus ring on page: #1766c2 on #ffffff = 5.65:1; error text: #c42b1c on #ffffff = 5.66:1.

### Security
Email OTP with 10-minute expiry, 5 wrong tries lock for 15 minutes (tracked server-side only; `otp_attempts` has no client policies). OAuth redirect allow-list and state checks. RLS: `users` own row only; `workspaces` select only for members, except an RPC `find_workspace_for_domain` returning name and id for the verified domain after login; `memberships` insert only via that RPC for auto-join workspaces. Rate-limit sends per IP and email.

### Performance & SEO
Static route, no heavy dependencies; inline the SVG logomark. `noindex` code and workspace steps. First load under 60KB JS.

### Guardrails
- Draw an original logomark; don't echo any real brand's shapes.
- Label OAuth providers generically in mocks.
- No password field on this flow.
- Invent any sample workspace names.

Acceptance criteria:
- [ ] Continue sends a code and shows the code screen
- [ ] Pasting a 6-digit code fills all boxes
- [ ] Lockout after 5 wrong attempts is enforced server-side
- [ ] Domain match offers join or create
- [ ] All contrast pairs pass

Open the builderAll templatesThis palette on its own