The sticker pack platform for WhatsApp β discover, create, and share animated sticker packs.
Slap is a community-driven Android app where creators upload sticker packs and users can browse, save, and export them directly to WhatsApp. Built with a modern TypeScript monorepo β Expo on the client, Elysia on the server, Cloudflare R2 for storage, and Redis for trending feeds.
- Discover β Browse trending and new sticker packs with a masonry-style grid feed
- Search β Full-text search across pack names, tags, and categories
- Pack detail β Preview all stickers in a pack; copy individual stickers to clipboard, share to WhatsApp, or save to gallery
- WhatsApp export β One-tap export of a full sticker pack to WhatsApp via
react-native-wa-stickers-animated - Upload β Creators can upload packs of up to 30 stickers (any image format; server converts to WebP at β€1.5 MB, max 1024 Γ 1024)
- Vault (Saves) β Bookmark packs for quick access later
- Profile β Public creator profiles with avatar, bio, and published packs
- Trending β Redis-cached trending algorithm based on downloads and saves
- Auth β Email OTP (Resend) and Discord OAuth via Better Auth
| Layer | Technology |
|---|---|
| Mobile | React Native 0.85 Β· Expo 56 Β· Expo Router Β· React Native Reanimated 4 |
| Styling | React Native Unistyles 3 |
| State / Data | TanStack Query 5 Β· oRPC |
| Auth | Better Auth Β· Email OTP (Resend) Β· Discord OAuth |
| Backend | Elysia Β· Bun runtime |
| API layer | oRPC (type-safe, no codegen) |
| Database | PostgreSQL (Prisma + @prisma/adapter-pg) |
| Storage | Cloudflare R2 (via aws4fetch) |
| Image processing | Sharp (server-side WebP conversion) |
| Background jobs | BullMQ + Redis |
| Trending cache | Redis |
| Monorepo | Nx + Bun workspaces |
| Package manager | Bun |
slap/
βββ apps/
β βββ native/ # Expo Android app
β β βββ app/ # Expo Router screens (file-based routing)
β β β βββ (auth)/ # Auth screens (email OTP, Discord)
β β β βββ (tabs)/ # Main tabs: Discover, Upload, Vault, Profile
β β β βββ pack/ # Pack detail screen [id].tsx
β β β βββ user/ # Public user profile [userId].tsx
β β βββ components/ # Shared UI components
β β βββ utils/ # sticker-actions, download, whatsapp helpers
β βββ server/ # Elysia HTTP server
βββ packages/
β βββ api/ # oRPC routers, image processing, queues, storage
β βββ auth/ # Better Auth configuration
β βββ db/ # Prisma schema + generated client
β βββ env/ # Type-safe env validation (@t3-oss/env-core)
β βββ config/ # Shared TypeScript / Biome configs
βββ nx.json
- Bun β₯ 1.1 β bun.sh
- Node β₯ 20 (for Expo CLI tooling)
- Android Studio + Android SDK (API 33+)
- PostgreSQL 15+ running locally (or remote)
- Redis 7+ running locally
- Cloudflare R2 bucket with public URL enabled
- Resend account for email OTP
- Discord OAuth app (optional β needed for Discord login)
git clone https://github.com/your-org/slap.git
cd slap
bun installcp apps/server/.env.example apps/server/.env| Variable | Description |
|---|---|
DATABASE_URL |
PostgreSQL connection string |
BETTER_AUTH_SECRET |
Random secret β₯ 32 chars β openssl rand -hex 32 |
BETTER_AUTH_URL |
Public URL of your backend (e.g. http://localhost:3000) |
CORS_ORIGIN |
Frontend origin (Expo dev URL or production URL) |
DISCORD_CLIENT_ID |
Discord OAuth app client ID |
DISCORD_CLIENT_SECRET |
Discord OAuth app client secret |
REDIS_URL |
Redis connection URL (default: redis://localhost:6379) |
RESEND_API_KEY |
Resend API key for sending OTP emails |
RESEND_FROM_EMAIL |
Verified sender email address |
R2_ACCOUNT_ID |
Cloudflare account ID |
R2_ACCESS_KEY_ID |
R2 API token key ID |
R2_SECRET_ACCESS_KEY |
R2 API token secret |
R2_BUCKET_NAME |
R2 bucket name (default: slap-assets) |
R2_PUBLIC_URL |
Public CDN URL for your R2 bucket |
cd packages/db
bunx prisma db push
# Optional: seed with sample data
bun run seedcd apps/server
bun run dev
# Server starts on http://localhost:3000cd apps/native
bunx expo run:androidMake sure an Android emulator is running or a physical device is connected via ADB.
Android App (Expo)
β
β oRPC (type-safe HTTP)
βΌ
Elysia Server (Bun)
β
βββ Better Auth βββΊ PostgreSQL (users, sessions)
βββ oRPC Routers βββΊ PostgreSQL (packs, stickers, saves, tags)
βββ BullMQ Worker βββΊ Redis (image-process queue)
β β
β ββββΊ Sharp (WebP conversion, resize β€1024px, β€1.5MB)
βββ Trending Worker βββΊ Redis (pre-computed trending pack IDs)
β
ββββΊ Cloudflare R2 (WebP sticker storage)
β
ββββΊ Public CDN URL (served directly to app)
Sticker upload flow:
- User selects up to 30 images (any format) in the Upload tab
- Files are sent to the server as multipart form data via oRPC
- Server enqueues each sticker into BullMQ (
image-processqueue) - Worker converts to WebP (Sharp), resizes to β€1024px, compresses to β€1.5MB
- WebP is uploaded to Cloudflare R2; public URL stored in PostgreSQL
- Pack status flips to
READYonce all stickers are processed
Trending feed flow:
- Every download and save increments counters on the pack row
- A BullMQ worker (
trending-recalc) periodically scores packs and writes ordered IDs to Redis (slap:trending:cache) - The Discover feed reads from cache; falls back to
ORDER BY downloads DESCon cache miss
| Rule | Limit |
|---|---|
| Stickers per pack | Max 30 |
| Accepted input formats | Any (JPEG, PNG, GIF, WebP, AVIF, etc.) |
| Output format | WebP (server-converted) |
| Max output dimensions | 1024 Γ 1024 px |
| Max output file size | 1.5 MB per sticker |
| Pack name | 1β80 characters |
| Pack description | Max 500 characters |
| Tags per pack | Max 12 |
The backend exposes a type-safe oRPC API. All routes are defined in packages/api/src/routers/.
appRouter
βββ healthCheck
βββ checkEmail
βββ packs list Β· get Β· search Β· create Β· trending
βββ stickers upload
βββ saves save Β· unsave Β· list
βββ download trackDownload
βββ tags list
βββ categories list
βββ profile get Β· update Β· packs
Public procedures require no authentication. Protected procedures require a valid Better Auth session cookie.
- Fork the repo and create a branch:
git checkout -b feat/your-feature - Follow conventional commits:
feat:,fix:,refactor:,docs:,chore: - Run the formatter before committing:
bunx biome check --write . - Open a PR describing the change and link any related issues
- iOS support
- Animated sticker packs (WEBP/APNG/Lottie)
- Creator analytics dashboard
- Pack collections and playlists
- In-app sticker search with visual similarity
- Push notifications for new packs from followed creators
- Deployment: Cloudflare Workers (server) + managed PostgreSQL
All rights reserved. Not open for public use at this time.