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
- 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
- Full-bleed backdrop: vertical gradient from pale periwinkle at top to warm cream at bottom
- Centred card (max 380px) with a round illustrated mascot overlapping the top edge
- 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
- Below card: small muted link line upselling single sign-on for business plans
- 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
| Sample | Where | Ratio | Needs |
|---|---|---|---|
| Aa | body text on card | 17.74:1 | 4.5:1 |
| Aa | muted hint on card | 5.98:1 | 4.5:1 |
| Aa | button label on neutral button | 16.12:1 | 4.5:1 |
| Aa | pill label on dark pill | 17.74:1 | 4.5:1 |
| Aa | muted footer link on gradient bottom | 5.58:1 | 4.5:1 |
| input border on card | 3.17:1 | 3:1 | |
| focus ring on card | 5.17:1 | 3:1 | |
| Aa | error text on card | 5.74:1 | 4.5:1 |
| Aa | success text on card | 5.48:1 | 4.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