This is what it looks like with padding, for some reason in production it's not applied, not sure why and didnt have time, first time for me that I deployed a vite app, normally I do nextjs
A multi-model AI chat interface built for the T3 Chat Cloneathon. Works with Gemini and OpenRouter models (tested with GPT-4o-mini, DeepSeek-R1, Llama-70B).
Demo: clone3chat.vercel.app
Note: Don't use real passwords - should be secure, but not fully verified.
A single page chat app that syncs messages instantly locally and across tabs using Convex, heavily inspired by Theo. Each conversation gets a URL (/chat/{id}). API keys are encrypted client-side and never leave your browser. YOU CAN MAKE STABLECOIN PAYMENTS with USDC. Theo talkin bout stablecoins.
Messages appear instantly and sync across every tab by sending only the small part that changed, not the whole list, so the UI never stalls. Behind the scenes a short-lived Redis lock stops two tabs from writing the same thread at once, while batched 100 ms streaming keeps bandwidth low and scrolling smooth. If a user goes offline the app still shows their message right away, stores it with a 60-second expiry, and reconciles safely when the connection returns unused uploads and stale temp data are cleared automatically. All timestamps come from the server, I load just the 50–100 messages in view, and the app keeps working even if Redis drops, so crashes, duplicates, and clock-skew bugs never reach the user.
- Google Gemini (free tier)
- OpenRouter: GPT-4o-mini, DeepSeek-R1, Llama-70B
- Instant cross-tab sync
- Web search via
/searchcommand - Longer web search via
/researchcommand - Image gen via
/imagecommand and Imagen 3 model (untested, but got the correct not allowed on free tier message) - Clear chat via
/clearcommand - Pay USDC via
/paycommand - File uploads (images/PDFs)
- Offline message queueing
- Gemini setup requires manual API key entry in settings
- Only tested two AI providers thoroughly
I chose Vite, because I have Convex as the backend: No need for Next.js API routes No need for SSR/SSG - Convex handles real-time data No need for middleware or server components Authentication is handled by Convex Auth. This is a client-rendered SPA, no server-side logic. Vite gives me:
- 390ms cold starts vs 4.5s with CRA
- Instant hot module replacement
- No need for SSR/SSG - Convex handles real-time data
Convex (convex/ directory) handles:
- Real-time subscriptions without WebSocket setup
- Database with reactive queries
- User auth out of the box
Redis (src/lib/redis-cache.ts) is optional:
- Reduces Convex reads by ~80% when switching threads
- Viewport caching (50 messages at a time)
- Falls back gracefully if unavailable
Message Sync (src/lib/scalable-sync-engine-v2.tsx):
// Smart sync detection - only sync significant changes
if (msg.isStreaming) {
// For streaming, sync only if content differs by >100 chars
if (!lastContent || Math.abs(msg.content.length - lastContent.length) > 100) {
hasSignificantChanges = true;
}
} else if (isStreamingRef.current.has(msgId)) {
// Was streaming, now finished - always sync
hasSignificantChanges = true;
isStreamingRef.current.delete(msgId);
}
// Debounced sync - 300ms stable, 1000ms while streaming
const syncDelay = currentlyStreaming.size > 0 ? 1000 : 300;Redis Cache (src/lib/redis-cache.ts):
// Viewport loading with error handling
const rawMessages = await getRedis().zrange(key, -VIEWPORT_SIZE, -1);
messages = (rawMessages || []).map(item => {
try {
if (typeof item === 'string') {
return JSON.parse(item);
} else if (item && typeof item === 'object') {
return item;
}
return null;
} catch (error) {
console.error('Failed to parse message:', item, error);
return null;
}
});Encryption (src/lib/crypto-utils.ts):
- AES-GCM with persistent key (not fingerprint-based)
- Key stored in localStorage survives browser updates
AI Integration (convex/ai.ts):
- Each provider has its own adapter
- Streaming responses update every chunk
- Function calling for payments (experimental)
From local testing:
- Bundle size: 497KB gzipped
- Message display: <50ms from Convex
- Memory per thread: ~200KB (50 messages)
- Redis operations: 2 per message (was 7+)
- Passwords: Auth implementation not security-audited. Use throwaway passwords.
- API Keys: Encrypted locally but physical device access could expose them.
- Fixed: Previous bug where API keys persisted between user accounts (see
SECURITY-FIX-API-KEY-ISOLATION.md)
git clone [repo]
cd c3chat
bun install
bunx convex dev
bun run devOptional Redis (.env.local):
VITE_KV_REST_API_URL=your-upstash-url
VITE_KV_REST_API_TOKEN=your-upstash-token
- Message Deduplication: Initially deduped after state updates, causing React key warnings. Fixed in
scalable-sync-engine-v2.tsx. - Browser Fingerprinting: Keys got lost on browser updates. Switched to persistent random keys.
- Excessive Redis Sync: Was syncing on every character. Now uses smart debouncing.
- Frontend: React 19, TypeScript, Vite 6
- Backend: Convex (database + functions)
- Cache: Upstash Redis (optional)
- UI: Tailwind CSS v4
- Build: Bun
- Multi-provider AI chat: OpenAI, Gemini, Anthropic, DeepSeek (via OpenRouter)
- Real-time sync: Messages appear instantly across tabs
- Voice input/output: 11+ languages with adjustable speech settings (
src/components/VoiceControls.tsx) - File attachments: Drag & drop images/PDFs with preview (
src/components/FileUpload.tsx) - Web search:
/searchcommand fetches real-time results - Code blocks: Syntax highlighting with copy button
- Encrypted API keys: Client-side AES-GCM encryption
- Command palette: Cmd/Ctrl+K for quick actions (
src/components/CommandPalette.tsx) - Dark/light themes: Persistent theme switching
- Markdown support: Tables, lists, code blocks
- Thread management: Create, delete conversations
- Mobile responsive: Works on all screen sizes
- Token tracking: See usage and costs per message (
src/components/TokenUsageBar.tsx) - AI agents: Specialized prompts (Research, Code Expert, Creative)

- Collaboration presence: See who's typing in real-time (
src/components/CollaborationPresence.tsx)
- Wallet integration: MetaMask/WalletConnect (
src/components/WalletConnect.tsx) - USDC payments:
/paycommand on Base Sepolia testnet (Gemini models only) - Get test USDC: Base Sepolia Faucet
These features have partial/no implementations or UI without backend or vice versa:
- Proper verified auth: I currently have basic Convex auth, it is supposedly secure, but there is no email verification, regex etc.
- Automated Chat Naming: Not implemented
- Thread branching: UI exists (
/branchcommand) but functionality bugged - Export conversations: Commands shown but export not implemented
- Message editing: Bugged
- Thread archiving: Not implemented
- Projects/Workspaces: Backend exists (
convex/projects.ts) but no UI - Security audit: Not conducted - use throwaway passwords
Built in a week for the T3 Chat Cloneathon.