Skip to main content
vibld

Template

Scanwell

A single-screen QR code studio that encodes nine content types (links, text, Wi-Fi, email, SMS, and hosted files such as images, PDFs and audio) and lets the user style and download the result. It can serve as a free lead-magnet tool for a business, or as a white-label utility for agencies and small SaaS builders.

Branded QR code studio · App · Small tools and apps · front-end app (local state)

Who it is for

  • Solo founders offering a free marketing tool
  • Shops and restaurants printing codes for signage and menus
  • Agencies white-labelling a generator for clients
  • Makers of micro-SaaS products

Layout

  1. Three-pane workspace, no global header
  2. Left pane: 'Select QR type' vertical list of nine large tiles, each with a pastel illustrated thumbnail and label; active tile tinted indigo with border
  3. Center card: live preview with large QR on a warm paper gradient, pill 'Download QR code' button + copy icon, then the type-specific input form (e.g. Website URL) and helper text
  4. Right pane: 'Style your QR' with Theme cards (Paper/Midnight/Pastel), Pattern tiles (5 shapes), QR color and background swatch rows plus custom picker, Download Size segmented cards (Social/Card/Print)
  5. Mobile: collapses to a single column with a dropdown type selector

Palette

clean, playful, tactile, approachable, crafted. A tidy tool with soft pastel thumbnails that make a utility feel designed.

  • background#fafafa
  • card#ffffff
  • text#262626
  • accent / focus blue#256af4
  • selected tint (indigo wash)#eef2ff
  • QR ink (warm brown)#3b2f26
  • border#e6e6e6

Every checked pair, measured again

SampleWhereRatioNeeds
Aabody text on background14.50:14.5:1
Aatext on card15.13:14.5:1
Aahelper text on card4.74:14.5:1
Aatext on selected indigo wash13.53:14.5:1
Aawhite label on accent button4.72:14.5:1
focus ring on white4.72:13:1
focus ring / selected border on indigo wash4.22:13:1
input and tile border on card3.41:13:1
AaQR ink on paper gradient start11.37:14.5:1
AaQR ink on paper gradient end10.49: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. 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

Display
Satoshi Medium 20px section titles, sentence case (Satoshi is not on Google Fonts; a vibld project loads Plus Jakarta Sans)
Body
Satoshi 16px body, 14px tile labels and helper text (Satoshi is not on Google Fonts; a vibld project loads Plus Jakarta Sans)

One friendly geometric sans; hierarchy is minimal because the QR itself is the hero.

Spacing and imagery

Three columns (~270 / 450 / 380px) with wide gutters; center card 24px radius with soft shadow; option tiles 12px radius; comfortable 16-24px padding.

Pastel 3D-ish mini illustrations for each QR type (browser window, Wi-Fi card, envelope, chat bubble, landscape, PDF, music note, phone); theme swatches as mesh-gradient orbs; pattern previews as tiny QR fragments.

Components

  • QR type selector list with illustrated tiles
  • Live preview card
  • Themed QR canvas
  • Download pill button with state feedback
  • Copy-to-clipboard icon button
  • Type-specific forms (URL, text, Wi-Fi, email, SMS, file upload, app store)
  • Theme preset cards
  • Pattern shape tiles
  • Color swatch rows + custom hex picker
  • Download size segmented cards
  • File dropzone for image/PDF/MP3
  • Toasts

Interactions

  • QR re-renders live as the user types
  • Switching type preserves each type's own inputs
  • Selected tile/card gets indigo wash and border
  • Download button disabled until content is valid, then shows success check
  • Copy image to clipboard with toast
  • Custom color picker popover
  • File upload with progress, type and size validation
  • Responsive collapse to dropdown on mobile

Data

  • QrState{type, contentByType: Record<type, fields>, theme, pattern, fg, bg, size}
  • WifiFields{ssid, password, security WPA|WEP|nopass, hidden}
  • EmailFields{to, subject, body}
  • SmsFields{phone, message}
  • UploadedAsset{id, path, mime, bytes, public_url, created_at} (storage)
  • UploadLog{ip_hash, created_at} for rate limiting

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 a template'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 templates)
- 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.
### Goal
Build **Scanwell**, a one-page QR studio that a small business can put on its site as a free tool. Visitors pick a content type, fill in a short form, style the code, and download a crisp PNG.

### Stack
React 18 + TypeScript + Vite, Tailwind CSS, shadcn/ui (Radix: ToggleGroup, Popover, Select, Tabs) and lucide-react. Use `qr-code-styling` (or `qrcode` plus custom SVG rendering) for dot patterns, react-colorful for the custom picker, react-hook-form + zod for each type's form, react-dropzone for uploads, and Sonner for toasts. Use Supabase only for file types (image, PDF, audio): a Storage bucket and an Edge Function that validates the upload, rate-limits it and returns a public URL to encode. Everything else runs client-side.

### Pages & layout
One route with three panes:
1. **Left: type list**: nine large tiles (URL, Text, Wi-Fi, Email, SMS, Image, PDF, Audio, App link), each with a soft pastel thumbnail and label; the selected tile gets an indigo wash.
2. **Center: preview card**: the QR on a themed square, a pill Download button with a copy icon next to it, then the form for the active type with a helper line.
3. **Right: style panel**: theme cards (Paper, Midnight, Pastel), five pattern tiles, foreground and background swatch rows with a custom picker, and output size cards (500 / 800 / 1200 px).
Below 1024px, stack the panes and turn the type list into a Select.

### Design system
- Tokens: `--background: #fafafa`, `--card: #ffffff`, `--foreground: #262626`, `--accent: #256af4`, `--selected: #eef2ff`, `--border: #e6e6e6`, `--input-border: #8b8b8b`, `--muted-fg: #737373`, default ink `#3b2f26` on a paper gradient (`#f7efe4` to `#efe6da`).
- Font: Satoshi or General Sans from Fontshare, or Plus Jakarta Sans from Google Fonts as the Google-only alternative. Titles 20px medium, body 16px (line-height 1.5), labels 14px, nothing below 12px.
- Spacing on a 4px base; pane gap 48px; card padding 24px.
- Radius: preview card 24px, tiles 12px, pills fully rounded.
- Shadows: preview card `0 12px 32px -12px rgb(0 0 0 / .18)`.
- Motion: 150ms color/border transitions, and a 200ms crossfade when the QR regenerates.
- Light UI by default; the Midnight theme only restyles the QR canvas.

### Components & interactions
TypeTile (hover, selected, focus), PreviewCanvas (placeholder "Enter content to generate", error state for over-long payloads), DownloadButton (disabled, loading, success check), CopyButton (clipboard API with fallback), per-type forms (URL normalization, Wi-Fi escaping of `;,:\`), UploadDropzone (drag-over highlight, progress, rejected-file message), ThemeCard, PatternTile, SwatchRow, CustomColorPopover, SizeSelector. Keep each type's inputs in its own slice so switching types loses nothing. Warn when foreground/background contrast is too low to scan reliably.

### Data & state
Client: a single typed reducer `QrState` persisted to `localStorage`. Server: bucket `qr-uploads` with object metadata; table `upload_log(ip_hash, created_at)` for the rate limiter. Always encode with error-correction level H. Use example.com URLs and fictional Wi-Fi names in placeholders.

### Accessibility
Build the type list and theme, pattern and size groups as radio groups with arrow-key navigation. Swatches need `aria-label`s with color names, and selection must be shown by more than color (a check icon). Keep `#256af4` focus rings visible on white and on the selected wash; tile and input borders use `--input-border` so boundaries hold 3:1. Give the QR image alt text describing its content type. Every form field gets a visible label, and errors are linked with `aria-describedby`.
Verified contrast: body: #262626 on #fafafa = 14.5:1; helper: #737373 on #ffffff = 4.7:1; white on accent: #ffffff on #256af4 = 4.7:1; QR ink on paper: #3b2f26 on #f7efe4 = 11.4:1.

### Security
The upload Edge Function checks MIME type and magic bytes for PNG/JPEG/WebP/PDF/MP3, enforces a 10 MB cap, randomizes object names and allows 15 uploads per IP hash per hour. Validate all fields with zod on the client and again in the function. Only accept `https:` or `http:` URLs, never `javascript:` or `data:`. Keep the service key in the function environment only. Expire old files with a bucket lifecycle policy.

### Performance & SEO
Debounce regeneration by 100ms, lazy-load the color picker and dropzone, and render the preview as SVG with PNG rasterized only on download. Add title, meta description and OG image, and put a single H1 in the visually hidden page heading. Target Lighthouse 95+.

### Guardrails
- Write fresh copy and your own thumbnail illustrations; no app store or brand logos.
- Store uploads only as long as needed, and never log payload contents.
- Keep components small and typed; no `any`. Show upload and generation errors visibly.
- Done when: (1) all nine types produce codes that scan on iOS and Android; (2) switching types preserves inputs; (3) the three sizes download at the exact pixel dimensions; (4) invalid or oversized files are rejected server-side; (5) the whole flow works by keyboard.

Open the builderAll templatesThis palette on its own