Skip to main content
vibld

Template

Tuftwick

A first-step sign-up screen for an open community platform where people share models, datasets and demos. It collects only email and password on a friendly centred card, keeps the public site header visible so visitors can back out and browse, and defers profile details to a second step.

Community sign-up card on a pastel gradient · 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.

  • Source Sans 3Headings: Source Sans 3 700, 30px heading, -0.01em tracking
  • Source Sans 3Body: Source Sans 3 400/600, 16px, line-height 1.5; labels 16px 600; hint 14px

Patterns

  • centred auth card
  • soft vertical pastel gradient backdrop
  • mascot/illustration above heading
  • two-step sign-up (credentials first, profile second)
  • inline helper hint under field
  • public site header kept on auth pages
  • secondary SSO upsell link under card

States it is designed for

  • Default empty form
  • Inline validation (invalid email, password under 8 chars, email already registered with 'Log in instead' link)
  • Submitting: button shows spinner and is disabled
  • Rate-limited: banner asking to wait before retrying
  • Step 2 username taken / invalid characters
  • Success: 'Check your inbox' state with resend (cooldown timer)
  • Network error with retry
  • Signed-in user visiting /join is redirected

Who it is for

  • Developers and researchers joining an open community platform
  • Team members invited by an organisation email
  • Visitors converting from a public browsing session

Layout

  1. Sticky public header: logo + wordmark left, rounded search field, text nav links with small icons, Log in text link and dark Sign up pill right; collapses to logo + menu button under 768px
  2. Full-bleed backdrop: vertical gradient from pale periwinkle at top to warm cream at bottom
  3. Centred card (max 380px) with a round illustrated mascot overlapping the top edge
  4. Card body: bold heading, one-line muted subheading, Email field + hint, Password field, full-width neutral Next button, 'Already have an account? Log in' line
  5. Below card: small muted link line upselling single sign-on for business plans
  6. Mobile: card becomes full width with 16px gutters; header search moves into the menu sheet

Palette

friendly, open, lightweight, trustworthy. A welcoming community door rather than a corporate gate.

  • gradient top#e9ecfa
  • gradient bottom#fdf6ef
  • card surface#ffffff
  • primary text#111827
  • muted text#5b6472
  • input border#8a919e
  • neutral button fill#f3f4f6
  • dark pill#111827
  • focus ring#2563eb
  • error#c81e1e
  • success#047857

Every checked pair, measured again

SampleWhereRatioNeeds
Aabody text on card17.74:14.5:1
Aamuted hint on card5.98:14.5:1
Aabutton label on neutral button16.12:14.5:1
Aapill label on dark pill17.74:14.5:1
Aamuted footer link on gradient bottom5.58:14.5:1
input border on card3.17:13:1
focus ring on card5.17:13:1
Aaerror text on card5.74:14.5:1
Aasuccess text on card5.48: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
Source Sans 3 700, 30px heading, -0.01em tracking
Body
Source Sans 3 400/600, 16px, line-height 1.5; labels 16px 600; hint 14px

Humanist sans similar to the observed UI face; JetBrains Mono only for tokens or code snippets elsewhere in the app.

Spacing and imagery

Airy; single column centred at ~40% viewport height; card padding 24px, 16px between fields; card radius 12px, inputs and buttons 8px, header pill fully rounded; card has a 1px border plus a very soft shadow.

One round, cheerful mascot illustration (original, emoji-like) above the heading; small monochrome icons in the header nav; no photos.

Components

  • Public header with search and nav
  • Auth card with mascot badge
  • Email input with helper hint
  • Password input with show/hide toggle
  • Neutral full-width Next button
  • Log in link line
  • SSO upsell link
  • Step 2 profile form (username, full name, avatar, terms checkbox)
  • Verification-sent notice

Interactions

  • Next validates email format and password length before advancing; focus moves to the step-2 heading
  • Password show/hide toggle announces state
  • Card fades up 8px on load (disabled under reduced motion)
  • Enter submits the current step
  • Hint text links to the organisation-join explanation
  • Header search opens results page; keyboard '/' focuses it

Data

  • Profile{id (auth user id), username (unique), full_name, avatar_url, created_at, org_hint_domain}
  • SignupAttempt{email_hash, ip_hash, created_at} (for rate limiting)
  • Organisation{id, name, verified_domain}

Guardrails

Experience

  • Ask for only email and password on step one; everything else waits for step two
  • Keep the public header so people can leave without the back button
  • Show the organisation-email hint under the field, not in a tooltip
  • Never clear the password field on a server error
  • Put the log-in escape hatch inside the card, directly under the button
  • Tell users the verification email address they used and offer resend with a visible cooldown

Accessibility

  • Every input has a visible <label>; hints linked via aria-describedby
  • Errors rendered in text next to the field and announced through an aria-live region
  • Neutral Next button still meets 4.5:1 for its label and has a visible 2px focus ring
  • Mascot image has empty alt (decorative)
  • Password toggle is a button with aria-pressed and a clear label
  • Gradient backdrop never sits behind body text; text always on the white card

Security

  • Rely on Supabase Auth for hashing and email confirmation; never store passwords yourself
  • Rate-limit sign-up by IP hash and email (e.g. 5 per hour) in an Edge Function
  • Enable RLS on profiles: users select/update only their own row; usernames readable publicly via a view that exposes username and avatar only
  • Validate username against a strict pattern and reserved-word list server-side
  • Return the same message for 'already registered' after a delay to limit account enumeration where policy requires

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 **Tuftwick**, the join screen for an open community where people publish models, datasets and small demos. The page must turn a curious visitor into an account holder in under a minute: email and password on step one, profile on step two, then an email-verification notice. It should feel friendly and low-pressure, like stepping through an open door, and keep the public site one click away.

### 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/password sign-up with confirmation email). A Supabase Edge Function handles rate limiting and username checks.

### Pages & layout
1. **App shell (public)**: sticky 56px header with logo and wordmark, a rounded search input (max 320px), text links with small leading icons (Models, Datasets, Demos, Docs, Pricing), a Log in text link and a dark Sign up pill. Under 768px collapse links and search into a sheet opened by a menu button.
2. **/join step 1**: full-height backdrop with a vertical gradient from `--grad-top` to `--grad-bottom`. Centred 380px card starting ~80px below the header, with an original round mascot badge overlapping its top edge. Heading 'Create your account', one muted subheading line, Email (with a hint about using a work email to find your organisation), Password (show/hide), full-width neutral Next button, and 'Already a member? Log in'. Under the card a small muted line: 'Need single sign-on? See business plans'.
3. **/join step 2**: same card; username (live availability check), full name, optional avatar upload, terms checkbox, Create account button, Back link.
4. **/join/check-email**: mascot, 'Check your inbox', the address used, Resend button with 60s cooldown, 'Wrong address? Start over'.

### Design system
- Colors: `--grad-top: #e9ecfa` (gradient top), `--grad-bottom: #fdf6ef` (gradient bottom), `--card: #ffffff` (card surface), `--fg: #111827` (primary text), `--muted: #5b6472` (muted text), `--input-border: #8a919e` (input border), `--btn: #f3f4f6` (neutral button fill), `--pill: #111827` (dark pill), `--ring: #2563eb` (focus ring), `--danger: #c81e1e` (error), `--success: #047857` (success).
- Fonts: Source Sans 3 (400, 600, 700) for everything; heading 30px/1.2 700; body 16px/1.5; hint 14px; JetBrains Mono for code only.
- Spacing: 4px base; card padding 24px; 16px field gap; 24px between header and first field.
- Radius: card 12px, inputs and buttons 8px, pill 9999px.
- Shadows: card `0 1px 2px rgb(17 24 39 / 0.06)` plus 1px `#e5e7eb` border.
- Motion: 200ms ease-out fade-up for the card; step transitions slide 12px; all disabled under prefers-reduced-motion.

### Components & interactions
`PublicHeader`, `AuthCard` (mascot slot, title, subtitle, children), `TextField` (label, hint, error, aria wiring), `PasswordField` (toggle button with aria-pressed), `NeutralButton` (loading spinner, disabled), `UsernameField` (debounced availability check with 'Checking...', 'Available', 'Taken' text + icon), `AvatarDrop` (image only, 2MB), `ResendButton` (countdown). Next validates locally with zod, then calls sign-up; on success move focus to the step-2 heading. Enter submits. Keep the password in memory only while the form is mounted.

### Data & state
Tables: `profiles(id uuid pk references auth.users, username citext unique, full_name, avatar_url, created_at)`, `organisations(id, name, verified_domain)`, `signup_attempts(id, email_hash, ip_hash, created_at)`. Step state lives in the URL (`?step=2`) and react-hook-form; a partially completed step 2 is restored from the session if the user reloads. Mock mode: seed three taken usernames to demo the conflict state.

### Accessibility
Visible labels on every field and hints tied with `aria-describedby`. Errors appear as text beside the field and in a polite live region; the first invalid field receives focus on submit. The mascot is decorative (`alt=""`). The neutral Next button keeps a dark label and a 2px `--ring` focus outline offset 2px. Resend countdown is announced once, not every second. Honour reduced motion.
Verified contrast: body text on card: #111827 on #ffffff = 17.74:1; muted hint on card: #5b6472 on #ffffff = 5.98:1; button label on neutral button: #111827 on #f3f4f6 = 16.12:1; pill label on dark pill: #ffffff on #111827 = 17.74:1; muted footer link on gradient bottom: #5b6472 on #fdf6ef = 5.58:1; input border on card: #8a919e on #ffffff = 3.17:1; focus ring on card: #2563eb on #ffffff = 5.17:1; error text on card: #c81e1e on #ffffff = 5.74:1; success text on card: #047857 on #ffffff = 5.48:1.

### Security
Use Supabase Auth for credentials and confirmation links. RLS on `profiles`: `select` own row for authenticated users, a public view exposes only `username, avatar_url`; `insert`/`update` only where `id = auth.uid()`. `signup_attempts` has no client policies; only the Edge Function (service role, server-side secret) writes it. Rate-limit sign-ups and resends per IP and email hash. Validate usernames with zod plus a server-side reserved list. Avatar uploads: image MIME check, 2MB cap, stored under the user's folder in a storage bucket with owner-only write.

### Performance & SEO
Auth routes ship without the app bundle; lazy-load the avatar cropper. Preload Source Sans 3 400/700 only. `noindex` on step 2 and check-email; the join page has a clear title and description. LCP under 1.5s on 4G.

### Guardrails
- Use an original mascot and invented wordmark; do not reproduce any real logo or character.
- Write fresh, generic microcopy.
- Collect no fields beyond email, password, username and name.
- No dark patterns: terms checkbox unticked by default, marketing opt-in separate and optional.

Acceptance criteria:
- [ ] Step 1 rejects bad email and short password inline
- [ ] Username conflict shows text + icon and suggests alternatives
- [ ] Check-email screen shows the address and enforces resend cooldown
- [ ] RLS prevents reading another user's full profile
- [ ] Keyboard-only sign-up works end to end

Open the builderAll templatesThis palette on its own