Skip to main content
vibld

Template

Bellfound

A shared todo list that responds instantly, keeps working offline and shows other people's changes live. It is a reference starter for local-first sync: mutations are applied optimistically on the client, pushed to a server, and every client pulls the canonical state when poked. The UI is intentionally the familiar todo pattern so the sync architecture is the star.

Offline-first realtime shared todo list starter · App · Small tools and apps · full-stack app (auth + DB)

A mock-up of the homepage, drawn from this design’s layout, palette and typefaces. A build follows the full prompt below.

Add app screens

Pick up to 6 screens, such as a dashboard, settings or an empty state. Each is built in this design’s own palette and typefaces, with its states and guardrails.

Account setup
Add edit
Analytics
Appearance
Calendar
Chat
Checklist
Checkout
Confirmation
Dashboard
Delete account
Details
Discovery questions
Empty state
Flowchart
Import export
Inbox
Integrations
Invite team
Loading
Login
Onboarding
Plans
Playground
Product tour
Referral
Search
Settings
Share
Sign up
Success
Table
Team members
Text editor
Upgrade
Usage
Verification
Welcome

Start from this templateRead the build prompt

Typefaces

Georama has a clean neo-grotesk 200 that looks refined at 80px and a steady regular for the list, so the textbook todo app stays calm and utilitarian.

  • GeoramaHeadings: title 80px 200
  • GeoramaBody: todo labels and input 20px 400 (italic placeholder), footer 16px 400, tabular counts

Patterns

  • classic single-card todo list with oversized light-weight title
  • new-item input as the card's first row with toggle-all chevron
  • circular checkbox rows with strike-through on complete
  • footer bar: items-left count, All/Active/Completed filter, clear completed
  • stacked-paper shadow under card
  • optimistic mutations with background sync
  • realtime multi-user updates via poke + pull
  • offline queue with sync status indicator

States it is designed for

  • Empty list: only the input row; footer hidden
  • All completed: '0 items left' and Clear completed visible
  • Offline: pill turns amber 'Offline, changes saved locally'
  • Syncing: pill spinner; conflicts resolved server-side and UI rebased
  • Push rejected (validation): row reverts with an inline error toast
  • Initial load from local cache before network (instant paint)
  • Very long todo text wraps within the row; very long lists stay performant (virtualise beyond 500)

Who it is for

  • developers learning local-first or realtime sync
  • teams prototyping collaborative list features
  • small groups sharing a simple checklist

Layout

  1. Pale grey canvas; centred column max 550px
  2. Title: 80px extra-light wordmark-style heading in muted red, centred above the card
  3. Card: first row is a toggle-all chevron and a large italic-placeholder input; below it, todo rows (round checkbox, label, delete x on hover); hairline dividers
  4. Card footer: 'N items left' left, All/Active/Completed filter links centred (selected has a thin red outline), 'Clear completed' right
  5. Two faux paper layers peek beneath the card (stacked shadows)
  6. Small sync status pill fixed bottom-right (Synced / Syncing / Offline) and presence avatars top-right (added)
  7. Info footer below card: 'Double-click to edit', list share link
  8. Mobile: full-width card, title shrinks to 64px, footer wraps to two lines

Palette

Familiar, calm and utilitarian. It is a textbook todo app, so attention goes to how fast and resilient it feels.

  • canvas#f5f5f5
  • card surface#ffffff
  • primary text#111111
  • secondary text#484848
  • placeholder / completed text#757575
  • title red#b83f45
  • selected filter outline / focus#ce4646
  • checkbox ring / input border#949494
  • checkmark green#3ea491
  • hairline divider (decorative)#e6e6e6

Every checked pair, measured again

SampleWhereRatioNeeds
Aatodo text on card18.88:14.5:1
Aasecondary footer text9.15:14.5:1
Aaplaceholder / completed text4.61:14.5:1
title red on canvas5.02:13:1
selected filter outline4.58:13:1
checkbox ring on card3.03:13:1
checkmark green on card3.03:13: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
Georama 200 at 80px for the title (a light grotesk similar to the observed neo-grotesk); weight 200 is acceptable only because it is 24px+
Body
Georama 400 at 20px for todo labels and the input (placeholder italic), 16px footer text at weight 400

The observed 14px weight-300 body is raised to 16px/400. Use tabular numerals for the items-left count.

Spacing and imagery

Compact list: rows 58px tall with 16px horizontal padding; card has no radius; footer 40px. Shadows: card `0 2px 4px rgb(0 0 0 / 0.2), 0 25px 50px rgb(0 0 0 / 0.1)` plus two offset paper layers. Filter chips radius 3px.

None; only a chevron, round checkboxes, a delete cross and tiny presence avatars (initials).

Components

  • TitleWordmark
  • NewTodoInput with ToggleAll
  • TodoRow (checkbox, label, inline editor, delete)
  • FilterLinks (All, Active, Completed)
  • ItemsLeftCounter
  • ClearCompletedButton
  • SyncStatusPill
  • PresenceAvatars
  • ShareListButton

Interactions

  • Enter in the input adds a todo instantly (optimistic) and clears the field
  • Clicking the circle toggles done with a check animation and strike-through
  • Double-click (or Enter on a focused row) edits inline; Enter saves, Escape cancels, blank deletes
  • Delete cross appears on row hover and on focus
  • Changes from other users appear within ~100ms with a brief highlight
  • Filters change the URL hash (#/active, #/completed)
  • While offline, mutations queue locally and flush on reconnect

Data

  • List{id, owner_id, name, created_at}
  • ListMember{list_id, user_id, role (owner|editor|viewer)}
  • Todo{id, list_id, text (<= 500), completed (bool), sort (float), version (int), updated_at, deleted (bool)}
  • ClientGroup{id, user_id, cvr_version}
  • Client{id, client_group_id, last_mutation_id}

Guardrails

Experience

  • Never block input on network; every action applies locally first
  • Always show sync state; never silently lose an edit
  • Keep the todo pattern familiar: same keyboard behaviour as users expect
  • Clear completed must be undoable for 5 seconds
  • Show who else is viewing the list

Accessibility

  • Placeholder and completed text use #757575 (4.61:1) instead of the observed light grey
  • Checkboxes are real checkbox inputs with the todo text as label
  • Delete button is visible on focus, not only on hover, and labelled 'Delete {todo}'
  • Filters are links with aria-current on the active one
  • Remote changes announced politely (e.g. 'Sam completed Buy tape')
  • Body text 16px+ at weight 400; the 200-weight title is decorative-size only

Security

  • RLS on todos and lists: select/insert/update where list_id in the caller's list_members; viewers read-only
  • Mutations validated server-side with zod (text length, ids are UUIDs, list membership) before applying
  • Push/pull endpoints require an authenticated session; client ids bound to the user
  • Rate-limit push per client group
  • Share links grant editor role only after the recipient signs in; tokens are single-use and expire

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 **Bellfound**, a shared todo list that feels instant, keeps working offline and shows collaborators' changes live. The UI deliberately follows the familiar single-card todo pattern; the point of the project is its local-first sync layer, which applies mutations optimistically, pushes them to the server, and pulls canonical state whenever the server pokes clients.

### Stack
Next.js (App Router) + React + TypeScript, Tailwind CSS and zod. Supabase provides Auth, Postgres and Realtime (a broadcast channel used only as a "poke"). The client keeps an IndexedDB-backed store with a pending mutation queue, a push endpoint (`/api/push`) and a pull endpoint (`/api/pull`) that follows a client-view-record / row-version approach. No third-party sync SDK is required.

### Pages & layout
1. **List (`/l/[listId]`)**: pale grey canvas and a centred 550px column. An 80px extra-light red title ("chores"), then a white card: the first row has a toggle-all chevron and a big input with an italic placeholder ("What needs doing?"); todo rows have a round checkbox, label and a delete cross on hover or focus. The footer shows items left, All/Active/Completed filters (the active one has a thin red outline) and Clear completed. Two offset paper layers sit beneath the card. Presence avatars sit top-right and a sync pill bottom-right.
2. **Home (`/`)**: sign in, then your lists and a New list button.
3. **Responsive**: the card goes full width with a 64px title and the footer wraps onto two lines.

### Design system
- Colors: `--canvas: #f5f5f5`, `--card: #ffffff`, `--fg: #111111`, `--fg-2: #484848`, `--muted: #757575` (placeholder and completed), `--title: #b83f45`, `--focus: #ce4646`, `--control: #949494` (checkbox ring, input border), `--check: #3ea491`, `--hairline: #e6e6e6` (decorative).
- Fonts: Georama; title 200 at 80px (allowed because of its size); labels and input 400 at 20px; footer 400 at 16px; tabular numerals for counts.
- Spacing: rows 58px; row padding 16px; footer 40px.
- Radius: none on the card; filter outline 3px; pills 999px.
- Shadows: card `0 2px 4px rgb(0 0 0 / 0.2), 0 25px 50px rgb(0 0 0 / 0.1)`; paper layers offset 4px and 8px.
- Motion: 150ms check draw; a 600ms background flash on rows changed remotely; none under reduced motion.

### Components & interactions
TitleWordmark, NewTodoInput, ToggleAll, TodoRow (real checkbox, double-click or Enter to edit, Escape cancels, a blank save deletes), DeleteButton, FilterLinks (hash routes), ItemsLeftCounter, ClearCompletedButton (Undo toast for 5s), SyncStatusPill (Synced, Syncing, Offline), PresenceAvatars (from Realtime presence), ShareListButton. All mutations (`createTodo`, `updateTodo`, `deleteTodo`, `toggleAll`, `clearCompleted`) run locally first and queue for push.

### Data & state
Tables: `lists(id, owner_id, name, created_at)`, `list_members(list_id, user_id, role)`, `todos(id uuid, list_id, text, completed, sort float8, version int, deleted bool, updated_at)`, `client_groups(id, user_id, cvr_version)`, `clients(id, client_group_id, last_mutation_id)`. Push applies each mutation in a transaction, bumps `version`, records `last_mutation_id` and broadcasts a poke on `list:{id}`. Pull diffs against the client's last view and returns puts and deletes plus `lastMutationIDChanges`. The client rebases pending mutations on top of pulled state.

### Accessibility
Each checkbox is labelled by its todo text. The delete button reads "Delete {text}" and shows on focus. The inline editor keeps focus and announces "Editing". Filters use `aria-current`. Remote changes and sync status go to a polite live region. The focus ring is 2px `--focus`. Text is 16px or larger at weight 400.
Verified contrast: todo text on card: #111111 on #ffffff = 18.88:1; secondary footer text: #484848 on #ffffff = 9.15:1; placeholder / completed text: #757575 on #ffffff = 4.61:1; title red on canvas: #b83f45 on #f5f5f5 = 5.02:1; selected filter outline: #ce4646 on #ffffff = 4.58:1; checkbox ring on card: #949494 on #ffffff = 3.03:1; checkmark green on card: #3ea491 on #ffffff = 3.03:1.

### Security
RLS on `lists`, `list_members` and `todos`: select only when the caller is a member; insert and update only for owner or editor; delete of lists by owner only. `clients` and `client_groups` are accessible only to their `user_id`. Push validates every mutation with zod (UUIDs, text 500 characters at most, list membership) and rejects unknown mutation names. Push and pull require a session and bind client groups to the user. Rate-limit push per client group. Share links create single-use, expiring invite tokens.

### Performance & SEO
The first paint comes from the local cache with no spinner. Pull batches are capped at 1,000 rows. Virtualise lists over 500 rows. Pokes carry no data. All app routes are `noindex`.

### Guardrails
- Keep the UI minimal; don't add features that obscure the sync demo.
- Seed lists with invented tasks ("Water the ferns", "Book the van").
- No vendor names in UI copy.
- Acceptance criteria:
  - [ ] Two browsers see each other's edits within a second
  - [ ] Going offline, making 10 edits, and reconnecting loses nothing
  - [ ] Non-members get empty pulls and rejected pushes
  - [ ] Keyboard-only add, edit, toggle, delete and filter all work
  - [ ] Placeholder and completed text meet 4.5:1

Open the builderAll templatesThis palette on its own