Template
Moonstitch
A short onboarding step in a tool that builds public expert profile pages. The user chooses whether their page renders in light or dark mode by picking between two large preview cards, then creates the profile. It is a single, reversible decision presented with a visual preview rather than a toggle.
Onboarding theme picker for a public profile page · App screen: appearance · 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.
- Plus Jakarta SansHeadings: Plus Jakarta Sans 700, 36px, tracking -0.02em for the step title
- Plus Jakarta SansBody: Plus Jakarta Sans 400, 16px/1.5 subtitle; card captions 16px 600; button 16px 500
Patterns
- centred single-choice step
- large preview radio cards with corner checkbox
- schematic mini-page previews
- gradient primary CTA
- beta pill beside wordmark
- top-right logout text link
States it is designed for
- default (light preselected)
- dark selected
- creating profile (button spinner)
- creation failed banner with retry
- handle collision detected server-side (route back to handle step)
- user's system prefers dark (dark preselected)
Who it is for
- consultants and coaches
- independent experts building a personal page
- creators setting up a link-in-bio style profile
Layout
- Top bar: wordmark with small beta pill left, Log out text link right (accent colour)
- Centre stack: large title, one-line subtitle
- Choice row: two ~180x160 cards side by side (light preview, dark preview), each with a checkbox in the top-left corner, a mini page drawing and a bold caption
- CTA: 200px gradient button centred below
- Below 480px cards stack vertically at full width; CTA becomes full-width and sticky
Palette
Friendly, modern, low-stakes. A soft gradient button adds a touch of personality to an otherwise monochrome step.
- surface
#ffffff - text
#1c1d2e - muted
#52525b - card
#f4f4f4 - card-selected
#e2e2e5 - selected-border
#24263f - accent
#5850a9 - accent-tint
#ece9fb - gradient-start
#3d55c9 - gradient-end
#6b3fd4 - checkbox-border
#85858f - dark-preview
#24263f
Every checked pair, measured again
| Sample | Where | Ratio | Needs |
|---|---|---|---|
| Aa | title text on white | 16.61:1 | 4.5:1 |
| Aa | muted subtitle on white | 7.73:1 | 4.5:1 |
| Aa | CTA label at gradient start | 6.29:1 | 4.5:1 |
| Aa | CTA label at gradient end | 6.39:1 | 4.5:1 |
| Aa | logout link on white | 6.70:1 | 4.5:1 |
| Aa | beta pill text on tint | 5.62:1 | 4.5:1 |
| selected card border on white | 14.75:1 | 3:1 | |
| checkbox border on card | 3.32:1 | 3:1 | |
| Aa | caption on selected card | 12.85: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. Marked tokens are solved from the palette, because no swatch held that role at 4.5:1.
- background
- card
- muted
- primary
- secondary
- accent
- destructive *
Type scale
- Display
- Plus Jakarta Sans 700, 36px, tracking -0.02em for the step title
- Body
- Plus Jakarta Sans 400, 16px/1.5 subtitle; card captions 16px 600; button 16px 500
Similar to the observed geometric grotesk. Beta pill 12px 500.
Spacing and imagery
Airy; 8px base; 48px between title block and cards; 16px card gap; cards 12px padding; radius 12px cards, 8px inner preview, 10px button; selected card has a 1.5px dark border; no shadows.
Schematic previews drawn with CSS: avatar circle, name bar in accent, grey text lines, two small button bars.
Components
- wordmark with beta pill
- logout link
- preview radio card
- corner checkbox indicator
- gradient CTA button
- step progress dots (optional)
Interactions
- Clicking anywhere on a card selects it; arrow keys switch between cards
- Selected card darkens background, shows border and a checked box in 150ms
- CTA shows spinner then routes to the new profile editor
- Hovering the unselected card lifts its background one step
- The chosen theme can be changed later; helper text says so
Data
Profile{id, user_id, handle, theme (light|dark), created_at}OnboardingState{user_id, step, completed_at}
Guardrails
Experience
- Show real previews, not just words
- Preselect based on the user's OS preference
- Say the choice can be changed later
- Keep one primary action
- Keep log out reachable but visually quiet
Accessibility
- Cards form a radio group with captions as accessible names
- Checked state shown by checkbox tick and border, not colour alone
- Gradient button text meets 4.5:1 at both gradient ends
- Previews are decorative (aria-hidden)
- Focus ring visible around the whole card
Security
- RLS: profile rows editable only by their owner
- Theme validated against the enum server-side
- Profile creation RPC checks onboarding prerequisites and handle uniqueness atomically
- Log out clears the session and cached queries
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 **Moonstitch**, the 'pick a style' step of onboarding for a tool that creates public expert profile pages. The user chooses light or dark rendering for their page from two preview cards and presses 'Build my page'.
### Stack
React 18 + TypeScript + Vite, Tailwind CSS, shadcn/ui (RadioGroup primitives, Button), lucide-react, Motion for the card state, TanStack Query for the create mutation, Supabase Auth and Postgres.
### Pages & layout
1. **/onboarding/style** (this screen): top bar with wordmark + 'Beta' pill, 'Log out' link. Title 'Pick a look', subtitle 'Choose how visitors will see your page.' Two cards: 'Light' and 'Dark' each with a mini page (avatar, accent name bar, two grey lines, two small buttons). Helper line 'You can switch this any time in settings.' Gradient button 'Build my page'.
2. Previous step (handle) and next destination (profile editor) as stubs.
3. Mobile: cards stack, sticky full-width CTA with 16px margins.
### Design system
- Colors: `--surface: #ffffff`, `--text: #1c1d2e`, `--muted: #52525b`, `--card: #f4f4f4`, `--card-selected: #e2e2e5`, `--selected-border: #24263f`, `--accent: #5850a9`, `--accent-tint: #ece9fb`, `--gradient-start: #3d55c9`, `--gradient-end: #6b3fd4`, `--checkbox-border: #85858f`, `--dark-preview: #24263f`.
- Fonts: Plus Jakarta Sans (similar to observed geometric grotesk). Title 36px/700 -0.02em; subtitle 16px/1.5; captions 16px/600.
- Spacing: 8px base; generous vertical rhythm (24/48px).
- Radius: cards 12px, previews 8px, button 10px.
- Gradient: `linear-gradient(90deg, var(--gradient-start), var(--gradient-end))`.
- Motion: 150ms selection; button press scale 0.98; none under reduced motion.
### Components & interactions
`OnboardingTopBar` (Wordmark, BetaPill, LogoutLink), `StepHeader`, `ThemeChoiceCard` (radio input visually replaced by a checkbox-style box, CSS preview, caption), `GradientButton` (loading state). Hover on the unselected card changes background to `--card-selected` at 50%.
### Data & state
`profiles(id, user_id unique, handle, theme check in ('light','dark'), created_at)`, `onboarding_state(user_id, step, completed_at)`. Local state holds the choice; `create_profile(theme)` RPC finalises onboarding. Preselect via `matchMedia('(prefers-color-scheme: dark)')`.
### Accessibility
Native radio inputs inside labels (visually styled). Arrow keys switch selection. The whole card shows a 2px focus ring. White button text passes at both gradient ends. Page title announces the step ('Step 3 of 3: Pick a look').
Verified contrast: title text on white: #1c1d2e on #ffffff = 16.61:1; muted subtitle on white: #52525b on #ffffff = 7.73:1; CTA label at gradient start: #ffffff on #3d55c9 = 6.29:1; CTA label at gradient end: #ffffff on #6b3fd4 = 6.39:1; logout link on white: #5850a9 on #ffffff = 6.7:1; beta pill text on tint: #5850a9 on #ece9fb = 5.62:1; selected card border on white: #24263f on #ffffff = 14.75:1; checkbox border on card: #85858f on #f4f4f4 = 3.32:1; caption on selected card: #1c1d2e on #e2e2e5 = 12.85:1.
### Security
RLS on `profiles`: select public (published pages only via a view), insert/update where `user_id = auth.uid()`. `create_profile` is security definer, checks prior steps and handle uniqueness atomically. Enum check constraint on theme.
### Performance & SEO
Tiny route; previews are pure CSS. Prefetch the profile editor chunk after selection. Noindex.
### Guardrails
- Invented wordmark and copy
- One primary action only
- Do not lock the choice
- Typed code, clear errors
- Acceptance criteria: (1) selection works by mouse, touch and arrow keys; (2) dark is preselected on dark-mode devices; (3) Create my page stores the theme and routes onward; (4) RLS prevents editing others' profiles; (5) works at 390px.