100% client-side — your files never leave your device.
🌐 Live Demo · 🚀 Self-Hosting · 📡 API Reference · 🐛 Report Bug
Built with ❤️ by Bhautik Bavadiya (Yesbhautik) · YBX Labs
| Feature | Description |
|---|---|
| 🖼️ GIF Output | Animated GIF with full transparency support and configurable dimensions |
| 💬 Telegram Emoji | VP9 WebM at 100×100px, within Telegram's 256 KB limit |
| 🏷️ Telegram Sticker | VP9 WebM with 512px longest side, auto-scaled aspect ratio |
| 🔗 Aspect Ratio Lock | Auto-syncs width/height to maintain original proportions |
| 🎨 Full Animation Support | CSS @keyframes + SMIL <animate> — opacity, transforms, stroke-dasharray, filters, colours |
| 🔒 Complete Privacy | All processing runs in-browser — zero uploads, zero tracking, zero data collection |
| ⚡ Instant Processing | No server queues — conversion starts immediately on your CPU |
| 🌍 Self-Hostable | Pure static site — deploy anywhere with zero dependencies |
| 🧵 Web Workers | GIF encoding runs in background threads for smooth UX |
TGmoji is built with privacy as a core principle, not an afterthought.
| Concern | TGmoji's Answer |
|---|---|
| File uploads | ❌ None. Your files stay on your device. |
| Server processing | ❌ There is no server. All conversion runs in your browser's JavaScript engine. |
| Data collection | ❌ Zero analytics, zero cookies, zero tracking pixels. |
| Network requests | Only loads the page itself. No API calls during conversion. |
| Source code | Fully open source (MIT). Audit it yourself. |
Why does this matter? Many online converters upload your files to remote servers for processing. Your SVGs may contain proprietary designs, brand assets, or sensitive artwork. With TGmoji, your intellectual property never leaves your machine.
Visit tgmoji.ybxlabs.com — no installation needed.
git clone https://github.com/yesbhautik/tgmoji.git
cd tgmoji
npm run devOpen http://localhost:3000. That's it — no npm install, no build step, no environment variables.
| Platform | Deploy |
|---|---|
| Vercel | |
| Netlify | |
| Cloudflare Pages | Deploy to Cloudflare — select repo, output dir: public/ |
| GitHub Pages | Settings → Pages → Source: main branch, /public folder |
TGmoji is a purely static site — index.html, style.css, app.js, converter.js, and gif.worker.js. There are no build steps, no server-side code, no databases, and no environment variables.
- Any HTTP server that can serve static files (Nginx, Apache, Caddy, Python, Node.js, etc.)
- No runtime dependencies — no Node.js, no Docker, no FFmpeg, no Chromium
server {
listen 80;
server_name tgmoji.example.com;
root /var/www/tgmoji/public;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
# Cache static assets aggressively
location ~* \.(js|css|woff2|svg)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
}# Deploy files
git clone https://github.com/yesbhautik/tgmoji.git /var/www/tgmoji
sudo systemctl reload nginx<VirtualHost *:80>
ServerName tgmoji.example.com
DocumentRoot /var/www/tgmoji/public
<Directory /var/www/tgmoji/public>
AllowOverride None
Require all granted
</Directory>
</VirtualHost>tgmoji.example.com {
root * /var/www/tgmoji/public
file_server
}
git clone https://github.com/yesbhautik/tgmoji.git
cd tgmoji/public
python3 -m http.server 8000Option A — Pull pre-built image from GHCR:
docker pull ghcr.io/yesbhautik/tgmoji:latest
docker run -d -p 8080:80 --name tgmoji ghcr.io/yesbhautik/tgmoji:latestOpen http://localhost:8080.
Option B — Docker Compose:
git clone https://github.com/yesbhautik/tgmoji.git
cd tgmoji
docker compose up -dOption C — Build locally:
git clone https://github.com/yesbhautik/tgmoji.git
cd tgmoji
docker build -t tgmoji .
docker run -d -p 8080:80 --name tgmoji tgmojiImage details:
nginx:alpinebase (~7 MB), multi-arch (amd64+arm64), includes healthcheck, security headers, and gzip compression.
TGmoji includes ready-to-use Cloudflare config files (wrangler.toml, public/_headers, public/_routes.json).
Option A — Cloudflare Dashboard:
- Go to Cloudflare Dashboard → Workers & Pages → Create
- Connect your GitHub repo
- Build settings:
- Build command: (leave empty)
- Build output directory:
public/
- Deploy
Option B — Wrangler CLI:
# Install wrangler
npm install -g wrangler
# Authenticate
wrangler login
# Deploy directly
wrangler pages deploy public/ --project-name=tgmojiOption C — GitHub Actions CI/CD:
Create .github/workflows/cloudflare-pages.yml:
name: Deploy to Cloudflare Pages
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: pages deploy public/ --project-name=tgmojiNote: Add
CLOUDFLARE_API_TOKENandCLOUDFLARE_ACCOUNT_IDas GitHub secrets.
See the full Deployment Guide for all platforms and detailed Cloudflare configuration.
All platforms above support custom domains with automatic SSL. For self-hosted Nginx/Apache, use Let's Encrypt with Certbot:
sudo certbot --nginx -d tgmoji.example.com┌──────────────────────────────────────────────────────────┐
│ Your Browser │
│ │
│ ┌────────────┐ ┌───────────────────────────────┐ │
│ │ Upload SVG │──▶│ Iframe Renderer │ │
│ └────────────┘ │ CSS @keyframes + SMIL │ │
│ │ Web Animations API seek │ │
│ └────────────┬──────────────────┘ │
│ │ │
│ ┌────────────▼──────────────────┐ │
│ │ Canvas Capture │ │
│ │ getComputedStyle → clone │ │
│ │ XMLSerializer → Blob → img │ │
│ └────────────┬──────────────────┘ │
│ │ │
│ ┌───────────────────┼────────────────┐ │
│ │ │ │ │
│ ┌─────────▼──────┐ ┌────────▼──────┐ ┌──────▼───┐ │
│ │ gif.js │ │ MediaRecorder │ │ Sticker │ │
│ │ (Web Workers) │ │ (VP9 WebM) │ │ 512px │ │
│ └────────┬───────┘ └──────┬────────┘ └─────┬────┘ │
│ │ │ │ │
│ ┌────────▼──────────────────▼─────────────────▼──────┐ │
│ │ Download as Blob │ │
│ └────────────────────────────────────────────────────┘. │
└──────────────────────────────────────────────────────────┘
- Iframe rendering — The SVG is loaded inside a hidden
<iframe>with full CSS and SMIL support - Time control — CSS animations are paused and seeked via the Web Animations API (
document.getAnimations()→pause()→ setcurrentTime). SMIL animations useSVGSVGElement.setCurrentTime() - Style capture — At each frame,
getComputedStyle()is called on every animated element and the computed values (opacity, filter, stroke-dasharray, etc.) are inlined asstyleattributes on a deep clone - Serialization — The styled clone (with
<style>and<animate>elements removed) is serialized viaXMLSerializer, converted to a Blob URL, loaded as an<img>, and drawn to<canvas> - Encoding — Frames are encoded to GIF (gif.js Web Workers) and/or WebM (MediaRecorder VP9)
tgmoji/
├── public/ # Everything served to the browser
│ ├── index.html # Main page (SEO + structured data + FAQ schema)
│ ├── app.js # UI logic & event handlers
│ ├── converter.js # Client-side conversion engine
│ ├── gif.worker.js # gif.js Web Worker (local copy)
│ ├── style.css # Design system & styles
│ ├── _headers # Cloudflare Pages headers config
│ └── _routes.json # Cloudflare Pages routing config
│
├── .github/workflows/
│ └── docker-build.yml # CI/CD: build & push Docker image to GHCR
│
├── docs/ # Documentation
│ ├── API.md # Client-side API reference
│ └── DEPLOYMENT.md # Platform deployment guide
│
├── Dockerfile # Docker image (nginx:alpine)
├── docker-compose.yml # Docker Compose config
├── nginx.conf # Nginx config for Docker container
├── .dockerignore # Docker build context exclusions
├── wrangler.toml # Cloudflare Pages/Workers config
├── vercel.json # Vercel config
├── netlify.toml # Netlify config
├── package.json # Dev server script (npx serve)
├── CONTRIBUTING.md # Contribution guidelines
├── LICENSE # MIT License
└── README.md # This file
- Upload — Drop or browse for an animated SVG
- Configure — Set dimensions, FPS, duration, and output formats
- Convert — The browser:
- Embeds the SVG in a sandboxed iframe
- Pauses & seeks CSS/SMIL animations frame-by-frame
- Inlines computed styles and captures to canvas
- Encodes GIF (gif.js workers) and WebM (MediaRecorder VP9)
- Download — Files are in-memory Blobs — nothing is uploaded
| Browser | GIF | WebM (Emoji/Sticker) |
|---|---|---|
| Chrome / Edge | ✅ | ✅ |
| Firefox | ✅ | ✅ |
| Safari | ✅ |
Safari users can still generate animated GIFs. WebM requires Chrome, Firefox, or Edge.
| Format | Size | Dimensions | Duration | Codec |
|---|---|---|---|---|
| Emoji | ≤256 KB | 100×100 px | ≤3 sec | VP9 WebM |
| Sticker | ≤256 KB | 512px longest side | ≤3 sec | VP9 WebM |
See CONTRIBUTING.md for guidelines.
git clone https://github.com/yesbhautik/tgmoji.git
cd tgmoji
npm run dev # http://localhost:3000MIT License — see LICENSE for details.
- gif.js — GIF encoding with Web Workers
- Web Animations API — CSS animation timeline control
- MediaRecorder API — WebM VP9 encoding
- Canvas API — Frame rendering and pixel manipulation
Made with ❤️ by Bhautik Bavadiya (Yesbhautik) · YBX Labs