This is a LLM roleplay app that's a combination of Character.ai and TikTok. Character messages have "memories" attached to them. A memory is a video related to a specific message the character sent. For example, a memory might show a chocolate cake and the character mentions chocolate cakes in its reply.
We thought that adding videos inside LLM roleplay will make the app more engaging vs Character.ai.
After testing the app with a couple dozen students, we discovered the following:
🎨 UI Needs a Revamp
- Instead of tons of characters on the homepage, show ONE character at a time. The current UI is overwhelming
- Take inspiration from TikTok: have the initial character memory/video autoplay in the background
- Fullscreen on mobile
- Centered on desktop
- Overlay the chat history on top of the memory/video
📝 Message Length Matters
- Initial character messages must be short
- Reading long blocks of text feels like work (a problem that plagues most if not all roleplay apps)
🎤 Voice Input is Key
- Add STT: people don't wanna type long messages
- It's much more convenient to talk
👀 Most Users Don't Want Anime
- Most people don't care about anime characters. All users that sent at least one message gravitated toward general or relatable characters such as College Boyfriend, Senior Girl and Vampire Student
- Copying what character.ai did or the cargo-cult that followed is a mistake. It won't result in a mass market hit tho you might be able to build a niche (and potentially profitable) product
We got really high engagement from a couple users (15-30 minute sessions) but decided to pivot to a voice-first concept that we believe is more relatable, novel and has long-term defensibility. We don't think this app will meaningfully differentiate from existing roleplay platforms, even with all the changes mentioned above.
We believe in learning in public. We didn't hit PMF, but it helped us figure out what doesn't work in LLM consumer UX. We're open-sourcing the code in case it helps others building in this space — feel free to fork, remix, or reach out.
There are a couple other repos you need in order to run the whole project:
- This one takes care of the main API you're gonna call from the frontend
- (Optional) This is the user waitlisting logic running on Redis
- Framework: Next.js 14
- Language: TypeScript
- Package Manager: Bun
- Deployment: Cloudflare Pages
- Database & Auth: Supabase
- OTP: Resend for email, Twilio for phone
- Analytics: Mixpanel
- UI Components:
- Radix UI
- Tailwind
- Form Handling:
- React Hook Form
- Formik
- Zod for validation
- State Management:
- Zustand
- Immer for immutable state updates
- Data Fetching:
- tRPC
- Virtualization:
- react-virtua for chat history and sessions list
- Text Editor:
- Tiptap
- Internationalization:
- next-intl
- formatjs/intl-localematcher
All the Supabase scripts you need are in the sql directory.
The application is organized into feature modules under src/features/:
- auth/: Authentication and user management
- chat/: Chat interface and message handling
- media/: Video (memories) management
- sessions/: Chat session management
- sidebar/: Application sidebar
- language/: Internationalization
- feedback/: User feedback modal
The app uses RAG as follows:
- Takes the latest message from the user and the last message sent by a character
- Call the API that creates embeddings and calls Supabase
- Matching videos above the similarity threshold are retrieved
- The AI character uses details from matched video descriptions in its new message
- Call the inference API to check if the new reply includes details mentioned in the retrieved video descriptions
- Download every video whose description was used by the character and attach it as a memory to the message
Both the chat history and session lists in the sidebar use react-virtua for virtualization.
- Node.js 18+
- Bun package manager
- Cloudflare account
- Supabase account
- Mixpanel account
- Clean existing dependencies:
- Install dependencies:
The app will be available at http://localhost:3000. Note that you must add the Opengraph image, sidebar-logo and the app icon in public prior to running the app. Moreover, there are a couple TODO to solve throughout the app in order to run it smoothly.
- Build the application:
- Deploy to Cloudflare Pages:
The following environment variables need to be configured:
- Supabase configuration
- Mixpanel token
- Inference and main API keys
We use Mixpanel for analytics and record the following:
- User engagement (clicks, scrolls etc)
- Chat session creation & sent messages
- Video watch time and whether a user replays specific videos
- Error monitoring
- Session replays
- ESLint with multiple plugins:
- @typescript-eslint
- eslint-plugin-react
- eslint-plugin-import
- eslint-plugin-jsx-a11y
- eslint-plugin-react-hooks
- eslint-plugin-tailwindcss
- Prettier for code formatting
- Husky for git hooks
- Strict TypeScript configuration
- Zod for runtime type validation
- Type-safe API calls with tRPC
- Fork the repository
- Create a feature branch
- Make your changes
- Run linting and formatting:
- Submit a pull request
- dev: Start development server
- build: Build for production
- start: Start production server
- lint: Run ESLint
- format: Run Prettier
- format-and-lint: Format and lint code
- analyze: Analyze bundle size
- cf:preview: Preview prod deployment on Cloudflare Pages
- cf:deploy: Deploy to Cloudflare Pages
Tags: LLM, AI Characters, Character AI, TikTok, Retrieval Augmented Generation, RAG, Mixpanel, Roleplay, Supabase, Next.js, Bun, TypeScript