Table of contents
C3 is a WCAG-compliant color contrast checker with AI-powered color suggestions, team collaboration, shareable check URLs, and freemium billing. Built with Astro SSR, React, Clerk, Neon Postgres, and Lemon Squeezy.
- Instant contrast ratio calculation (text vs background)
- WCAG AA / AAA compliance for small text, large text, and UI components
- Live color preview with dummy text rendering
- Tools panel: palette harmony generator, color history, daltonism simulation, RGB/HSL display, palette export
- 7-day shareable check URLs
- Check history (365 days)
- Permanent shareable check URLs
- Saved personal color palettes (up to 10)
- Unlimited AI color correction suggestions (3/month on Free)
- AI palette generator β full 8-role accessible color system from a brand color
- Everything in Pro
- Team workspace with up to 5 members
- Shared brand palettes
- Bulk CSV contrast checker with paginated results and PDF export
- PDF audit report export from check history
| Layer | Technology |
|---|---|
| Framework | Astro 5 (SSR, @astrojs/vercel) |
| UI | React 18 + Tailwind CSS |
| Auth | Clerk (Google/GitHub OAuth, magic link) |
| Database | Neon (Postgres, serverless HTTP driver) |
| Billing | Lemon Squeezy |
| AI | OpenAI GPT-4o-mini |
| jspdf + jspdf-autotable | |
| State | nanostores |
| Linting | ESLint + Prettier + commitlint |
| Hooks | Husky + lint-staged |
| Deploy | Vercel |
Create a .env file at the project root:
# Clerk
PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
CLERK_SECRET_KEY=sk_test_...
CLERK_WEBHOOK_SECRET=whsec_...
# Neon
DATABASE_URL=postgresql://...
# OpenAI
OPENAI_API_KEY=sk-...
# Lemon Squeezy
LEMONSQUEEZY_API_KEY=...
LEMONSQUEEZY_STORE_ID=...
LEMONSQUEEZY_WEBHOOK_SECRET=...
LEMONSQUEEZY_PRO_MONTHLY_VARIANT_ID=...
LEMONSQUEEZY_PRO_YEARLY_VARIANT_ID=...
LEMONSQUEEZY_TEAMS_MONTHLY_VARIANT_ID=...
# Cron (Vercel)
CRON_SECRET=...Clone the repository:
# with ssh
git clone git@github.com:Proskynete/color-contrast-checker.git
# with https
git clone https://github.com/Proskynete/color-contrast-checker.git
# with GitHub CLI
gh repo clone Proskynete/color-contrast-checkerInstall dependencies and start the dev server:
cd color-contrast-checker
npm install
npm run devThe app will be available at localhost:4321.
npm run db:migrateMigrations are located in src/db/migrations/. They must run in order:
| File | Description |
|---|---|
001_users.sql |
Users table |
002_teams.sql |
Teams and team_members tables |
003_checks.sql |
Contrast checks with share token |
004_palettes.sql |
Personal and team palettes |
005_ai_rate_limits.sql |
Per-user hourly AI rate limits |
007_users_lemonsqueezy.sql |
Lemon Squeezy customer/subscription IDs |
src/
βββ db/ # Neon client + migrations
βββ layouts/ # Astro layouts (landing, header, footer)
βββ lib/ # Shared server utilities
βββ pages/
β βββ api/ # API endpoints
β β βββ ai-suggest.ts
β β βββ ai-palette.ts
β β βββ checks/
β β βββ clerk/
β β βββ cron/
β β βββ lemonsqueezy/
β β βββ palettes/
β β βββ teams/
β βββ sections/ # React island components
β βββ share/ # Public share page /share/[token]
β βββ pricing.astro
β βββ index.astro
βββ store/ # nanostores (textStore, backgroundStore)
βββ types/
βββ utils/ # contrast.util.ts, color-convert.util.ts
| Method | Route | Auth | Description |
|---|---|---|---|
POST |
/api/checks |
Required | Save a contrast check |
GET |
/api/checks |
Required | Get check history |
GET |
/api/checks/[token] |
None | Get shared check |
POST |
/api/ai-suggest |
Required | AI color correction (up to 3 suggestions) |
POST |
/api/ai-palette |
Required | AI full palette generation (8 roles) |
GET/POST |
/api/palettes |
Required | List / save personal palette |
DELETE |
/api/palettes/[id] |
Required | Delete personal palette |
GET/POST |
/api/teams |
Required | Get / create team |
GET |
/api/teams/[id] |
Member | Get team details + members |
POST |
/api/teams/[id]/invite |
Owner | Invite member by email |
GET/POST |
/api/teams/[id]/palettes |
Member/Owner | List / save team palette |
DELETE |
/api/teams/[id]/palettes/[id] |
Owner | Delete team palette |
POST |
/api/lemonsqueezy/checkout |
Required | Create checkout session |
GET |
/api/lemonsqueezy/portal |
Required | Customer billing portal URL |
POST |
/api/lemonsqueezy/webhook |
β | Handle Lemon Squeezy subscription events |
POST |
/api/clerk/webhook |
β | Handle Clerk user.created events |
GET |
/api/cron/cleanup-teams |
Cron secret | Hard-delete teams frozen 30+ days |
| Feature | Free | Pro | Teams |
|---|---|---|---|
| Contrast checker | β | β | β |
| Tools panel | β | β | β |
| Shareable links | 7-day expiry | Permanent | Permanent |
| Check history | β | 365 days | 365 days |
| AI color suggestions | 3/month | Unlimited | Unlimited |
| AI palette generator | β | β | β |
| Saved palettes | β | Up to 10 | Unlimited |
| Team workspace | β | β | Up to 5 members |
| Shared brand palettes | β | β | β |
| Bulk CSV checker | β | β | β |
| PDF export | β | β | β |
- Go to c3.eduardoalvarez.dev
- Enter a text color and a background color (hex, RGB, or HSL)
- The app instantly shows the contrast ratio and WCAG compliance level
- Use "Suggest with AI" if the ratio fails β get up to 3 accessible color alternatives
- Sign in (Google / GitHub / magic link) to save checks, create shareable links, and manage palettes
- Upgrade to Pro for unlimited history and AI usage, or Teams for bulk checking and PDF reports
