Skip to main content
vibld

Template

Amberkey

A small tool for sending environment variables, API keys or passwords to a teammate without pasting them into chat. The text is encrypted in the browser, only ciphertext is stored, and the link self-destructs after a set number of reads or a time limit. It also serves as a starter showing client-side crypto, a key-value store and a dark marketing page.

End-to-end encrypted secret-sharing tool with expiring links · 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

Alan Sans gives terse, strong headings for the dark developer tool, and Red Hat Mono is a calm, readable mono for secrets that must be copied exactly.

  • Alan SansHeadings: headline 72px 700 at -0.025em, section headings 30px, stats 40px 700 tabular
  • Alan SansBody: body 16px/1.5 400
  • Red Hat MonoFigures and code: secrets, IDs and links 14-16px

Patterns

  • dark hero with gradient-clipped headline
  • announcement pill above headline
  • outline + inverted solid CTA pair
  • big-number stat row
  • quote cards with footer attribution strip
  • single-purpose form: textarea + inline option fields
  • client-side encryption with key in URL fragment
  • burn-after-reading / read-count limit
  • TTL input with unit select

States it is designed for

  • Empty textarea: Share disabled with hint
  • Oversized input (>32 KB): inline error
  • Encrypting / uploading: button spinner
  • Success: link, remaining reads and expiry time shown
  • Open page before reveal: warning that revealing consumes one read
  • Link expired or reads exhausted: 'This secret is gone' with no hint whether it ever existed
  • Decryption failure (wrong or missing key fragment): clear error, no retry loop
  • Clipboard blocked: fallback selectable field

Who it is for

  • developers sharing credentials with teammates
  • DevOps and platform engineers
  • agencies handing secrets to clients

Layout

  1. Top bar: wordmark left, text links right (Share, Open a link, Self-host, Source)
  2. Landing hero on near-black with subtle radial vignette: pill badge, 72px two-line headline with white-to-grey vertical gradient, muted one-paragraph explainer, outline 'Self-host' and white 'Share a secret' buttons
  3. Stats row: three centred big numbers (secrets encrypted, secrets opened, community stars) with muted labels
  4. Quote cards: three dark bordered cards with quote text and a footer strip (name, role, avatar circle)
  5. Share page: centred 640px column; 'Encrypt and share' heading; monospace textarea; row of three controls: Upload file button, Reads number field, Expires field with unit select; full-width light Share button; small legend explaining Reads and Expires
  6. Result state: generated link in a read-only field with Copy button and a QR option
  7. Open page: paste link or ID + key, Reveal button, decrypted text in a monospace block with Copy
  8. Mobile: nav links wrap under the wordmark; CTA buttons stack full width; option row stacks into three rows

Palette

Dark, terse, trustworthy. Feels like a developer tool: few words, monospace details, no decoration beyond a soft gradient.

  • canvas#0c0c0e
  • card / field surface#18181b
  • primary text#f4f4f5
  • secondary text#a1a1aa
  • muted helper text#808089
  • field / card border#646470
  • inverted button fill#fafafa
  • inverted button label#27272a
  • link / mention accent#3b82f6
  • headline gradient end#e4e4e7

Every checked pair, measured again

SampleWhereRatioNeeds
Aaprimary text on canvas17.78:14.5:1
Aasecondary text on canvas7.63:14.5:1
Aamuted helper on card4.53:14.5:1
Aainverted button label14.27:14.5:1
Aalink accent on card4.82:14.5:1
field border on card3.04:13:1
headline gradient end on canvas15.40: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
Alan Sans 700, 72px/1.0 hero with -0.025em tracking and a white-to-light-grey vertical gradient; 30px section headings
Body
Alan Sans 400 16px/1.5; secrets and links in Red Hat Mono 14px-16px

Observed explainer text was dark grey on black (2.5:1); use #a1a1aa instead. Big stats Alan Sans 700 40px with tabular numerals.

Spacing and imagery

Generous vertical rhythm: hero 160px top padding; container 1024px; share column 640px. 4px grid, control height 44px. Radius 4-6px on buttons and fields, 8px on cards. No shadows; borders define surfaces.

None except small circular avatars on quote cards; lock or key line icon allowed in the pill.

Components

  • AnnouncementPill
  • GradientHeadline
  • CTAPair (outline + inverted)
  • StatBlock
  • QuoteCard
  • SecretTextarea (monospace)
  • FileDropButton
  • NumberField (reads)
  • DurationField (value + unit select)
  • ShareResult (link field, copy, QR)
  • RevealPanel
  • InlineHelpLegend

Interactions

  • Share encrypts in the browser with AES-GCM using a fresh random key; only ciphertext and IV are sent
  • Link format: /open/{id}#{key}; the key lives in the fragment so it never reaches the server
  • Copy buttons show a check icon and 'Copied' for 2s
  • Upload file reads a .env file into the textarea locally (never uploaded in plain text)
  • Reveal decrypts on click (not on page load) so link previews in chat apps don't burn a read
  • Buttons invert on hover (outline fills, solid dims); focus ring visible on dark

Data

  • Secret{id (random 16-byte base62), ciphertext (base64), iv, reads_remaining (int, 0 = unlimited), expires_at, created_at}
  • Stats{encrypted_count, opened_count} (aggregate counters only)

Guardrails

Experience

  • Explain Reads and Expires in one line each directly under the controls
  • Default to 1 read and 24 hours; make 'unlimited' an explicit choice
  • Never auto-reveal on page load; require a deliberate click
  • After sharing, show exactly when and after how many reads the secret disappears
  • Keep the landing page to one primary action: Share a secret

Accessibility

  • Hero explainer uses #a1a1aa (7.63:1), not the observed dark grey
  • Gradient headline's lightest-to-darkest range stays above 4.5:1 on the canvas; provide it as real text
  • Textarea and option fields have visible labels, not just tiny caps inside the box
  • Field borders #646470 reach 3:1 on both canvas and card
  • Copy and reveal results announced via aria-live
  • Stat numbers have text labels read together (e.g. '20 thousand secrets encrypted')

Security

  • Encrypt client-side with the Web Crypto API (AES-GCM, 256-bit random key, unique IV); the server never sees plaintext or the key
  • Key only in the URL fragment; set Referrer-Policy: no-referrer
  • Atomic decrement-and-fetch via a security-definer RPC; delete row when reads hit zero or TTL passes
  • RLS on secrets: no direct select, insert, update or delete for anon; all access via the two RPCs
  • Rate-limit create and open by IP; cap payload size
  • No analytics or third-party scripts on share and open pages

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 **Amberkey**, a tool for sharing secrets such as environment files, API keys and one-off passwords through self-destructing links. Everything is encrypted in the sender's browser; the server stores only ciphertext and deletes it after a read limit or a time limit. The project also ships a short dark landing page that explains the model and invites people to self-host.

### Stack
Next.js (App Router) + React + TypeScript, Tailwind CSS, lucide-react, zod. The browser Web Crypto API does the encryption (AES-GCM). Supabase Postgres stores secrets, reached only through two RPC functions; a scheduled job purges expired rows. No user accounts are needed.

### Pages & layout
1. **Landing (`/`)**: top bar with wordmark and text links (Share, Open a link, Self-host, Source). Near-black hero with a faint radial vignette: pill badge ("Open source and self-hostable"), a 72px two-line headline with a white-to-light-grey gradient (for example "Send secrets that vanish"), a muted two-line explainer, outline "Self-host" and inverted white "Share a secret" buttons. Then a centred section heading, a three-stat row with big numbers, and three quote cards with a bordered footer strip (name, role, avatar). All names and numbers are invented.
2. **Share (`/share`)**: 640px column. Heading "Encrypt and share"; labelled monospace textarea; a row with Upload .env, Reads (number, default 1, 0 = unlimited) and Expires (number + unit select: minutes, hours, days; default 24 hours); full-width light Share button; a two-line legend explaining Reads and Expires. On success, swap to a result card: read-only link field, Copy, Show QR, and a summary line such as "Disappears after 1 read or in 24 hours".
3. **Open (`/open/[id]`)**: warning card "Revealing uses one read", a Reveal button, then the decrypted text in a monospace block with Copy. A gone state for expired or used links.
4. **Self-host (`/docs`)**: short prose page with numbered steps.
5. **Responsive**: nav links wrap under the wordmark; buttons stack full width; the option row becomes three stacked fields.

### Design system
- Colors: `--canvas: #0c0c0e`, `--surface: #18181b`, `--fg: #f4f4f5`, `--fg-2: #a1a1aa`, `--muted: #808089`, `--border: #646470`, `--inverted: #fafafa`, `--on-inverted: #27272a`, `--link: #3b82f6`, `--headline-end: #e4e4e7`.
- Fonts: Alan Sans 700 for the headline (72px/1.0, -0.025em) and 30px section headings; Alan Sans 400 16px/1.5 body; Red Hat Mono for secrets, IDs and links. Stats Alan Sans 700 40px with tabular numerals.
- Spacing: 4px base; hero top padding 160px; controls 44px tall; card padding 20px.
- Radius: 6px buttons and fields; 8px cards; pill fully rounded.
- Shadows: none; 1px `--border` lines separate surfaces.
- Motion: 150ms colour and opacity transitions; the result card fades in over 200ms; none under reduced motion.

### Components & interactions
AnnouncementPill, GradientHeadline, CTAPair, StatBlock, QuoteCard, SecretTextarea, FileDropButton (reads the file locally), NumberField, DurationField, ShareResult, RevealPanel, InlineHelpLegend, CopyButton. Share: generate a 256-bit key and 12-byte IV, encrypt, POST `{ciphertext, iv, reads, ttlSeconds}` to the create RPC, receive an id, and build `/open/{id}#{base64url key}`. Open: on Reveal, call the consume RPC, decrypt with the fragment key, and render as text. Reveal is never automatic, so link unfurlers in chat apps can't burn a read.

### Data & state
`secrets(id text primary key, ciphertext text, iv text, reads_remaining int, expires_at timestamptz, created_at timestamptz)`. `create_secret(ciphertext, iv, reads, ttl)` validates sizes and returns the id. `consume_secret(id)` atomically decrements `reads_remaining`, returns ciphertext and IV, and deletes the row when the count reaches zero; it returns nothing for expired or missing ids. `stats(encrypted_count, opened_count)` is updated by the RPCs. Form state is local React state.

### Accessibility
Visible labels on the textarea and every option. Legend text at least 14px in `--muted`. Headline is live text; its gradient ends stay above 3:1 as large text. Copy and reveal outcomes use a polite live region. Focus ring 2px `--link` with 2px offset. Quote cards use `<figure>` and `<figcaption>`. Stats read as one phrase each.
Verified contrast: primary text on canvas: #f4f4f5 on #0c0c0e = 17.78:1; secondary text on canvas: #a1a1aa on #0c0c0e = 7.63:1; muted helper on card: #808089 on #18181b = 4.53:1; inverted button label: #27272a on #fafafa = 14.27:1; link accent on card: #3b82f6 on #18181b = 4.82:1; field border on card: #646470 on #18181b = 3.04:1; headline gradient end on canvas: #e4e4e7 on #0c0c0e = 15.4:1.

### Security
Encryption and decryption happen only in the browser. The key travels only in the URL fragment; set `Referrer-Policy: no-referrer` and a strict CSP with no third-party scripts. RLS is enabled on `secrets` with no policies for anon or authenticated users, so direct table access is denied; only the two security-definer RPCs (owned by a least-privilege role) touch it. Cap ciphertext at 48 KB, cap TTL at 30 days, rate-limit both RPCs by IP, and purge expired rows every 10 minutes. Error messages never reveal whether an id once existed.

### Performance & SEO
Statically render the landing and docs; the share and open routes are small client bundles with no chart or animation libraries. Add `noindex` to `/open/*`. Title, description and an original OG image on the landing. Target Lighthouse 95+.

### Guardrails
- Quotes, names and stats on the landing are invented and labelled as sample content.
- Do not log request bodies anywhere.
- Name no hosting or storage vendors in UI copy.
- Acceptance criteria:
  - [ ] Network inspection shows only ciphertext leaving the browser
  - [ ] A 1-read link works once, then shows the gone state
  - [ ] TTL expiry removes the row within 10 minutes
  - [ ] A missing or wrong fragment key shows a decryption error, not garbage text
  - [ ] Every text pair on the dark canvas passes AA

Open the builderAll templatesThis palette on its own