Telegram Custom Emoji Mosaic · git:20260803.915e4ed · 2026-08-03 · sha256 d18170a2511911ff
Telegram Custom Emoji Mosaic git:20260803.915e4edA
Immutable. This exact content never changes and is served at /api/v1/blob/d18170a2511911ff.
--- id: telegram-custom-emoji-mosaic name: Telegram Custom Emoji Mosaic summary: >- Turn any image into a real Telegram mosaic built from Premium custom emoji: pick a grid that preserves the original aspect ratio, slice it into 100×100 WEBP tiles, create a custom_emoji set through the Bot API, and send the whole picture as one message ready to paste into a post. type: skill author: kisa recommended: true added: 2026-08-02 tags: [telegram, custom-emoji, image-processing, bot-api, media] source: https://core.telegram.org/bots/api#createnewstickerset reminder: >- The deliverable is a real Telegram message made of custom emoji — never a ZIP, a preview render, or a folder of tiles. Pick the grid from the image's aspect ratio, never force 10×10. Never add blur, letterbox bars, backgrounds, or visible crop unless the user asks. Verify through the API before reporting success. description: >- Use when the user wants an image posted to Telegram as a custom-emoji mosaic — an emoji "painting" for a channel post — or asks to turn a picture into custom emoji, build an emoji pack from an image, or make an emoji banner. license: MIT --- # Telegram Custom Emoji Mosaic ## Overview This skill turns a single image into a **genuine Telegram mosaic assembled from Premium custom emoji**. The agent slices the picture, publishes the tiles as a real `custom_emoji` sticker set through the Bot API, and sends the reassembled picture as one message the user can forward or paste straight into a channel post. Input: PNG, JPEG or WEBP. Output: a Telegram message plus a shareable pack link. ## Requirements - Telegram Bot API token (read at runtime from the environment) - **Telegram Premium on the bot owner's account** — without it custom emoji cannot be sent - `ffmpeg` - Python 3 with `requests` The user must have opened a dialog with the bot beforehand. A bot cannot write first. ## The main principle **The finished result is a real message made of custom emoji.** Not a ZIP, not a preview, not a set of files. The WEBP tiles are an intermediate artifact and nothing more. A run that produces tiles but no sent message is a failed run, and must be reported as failed. The skill does not add blur, side bars, a background, or noticeable crop without asking. When the proportions nearly match a suitable grid, only a minimal symmetric crop of a few pixels is allowed. ## Grid selection — do not force a square The skill analyses the image's proportions and picks a grid of up to 100 custom emoji. It does **not** push every picture into a 10×10 square. It chooses the row and column counts that preserve the original composition most accurately. | Source shape | Grid | Emoji used | |---|---|---| | square | 10×10 | 100 | | vertical 4:5 | 8×10 | 80 | | horizontal ≈ 14:6 | 14×6 | 84 | Search for the `columns × rows <= 100` pair that minimises the aspect-ratio error against the source, then build the canvas at `columns*100 × rows*100` so every tile lands exactly on a 100×100 boundary. ## Telegram limits — all of them bind at once - **Maximum 100 custom emoji in a single message.** This is the hard ceiling on grid size. - Up to **50 emoji** may be passed when the set is first created; the rest are added with `addStickerToSet`. - The emoji-pack size limit does **not** lift the 100-per-message limit. They are separate constraints and both apply. - Every static custom emoji must be exactly **100×100 px**. - The bot owner needs Telegram Premium. - The user must have started a dialog with the bot first. ## Procedure 1. Read the source image's dimensions. 2. Find the grid `columns × rows <= 100` with the smallest aspect-ratio error. 3. Build the final canvas at `columns*100 × rows*100`. 4. Slice it into WEBP tiles in row-major order. 5. Verify the file count, tile dimensions, and the visual reconstruction before uploading. 6. Upload the tiles via `uploadStickerFile`. 7. Create the `custom_emoji` set, then add the remaining tiles with `addStickerToSet`. 8. Collect the `custom_emoji_id` for every tile. 9. Assemble the message with correct **UTF-16 offsets** for each entity. 10. Send the finished mosaic to the user. 11. Verify through the API: emoji count, pack type, and the sent message. Step 9 is where implementations usually break. Telegram entity offsets are counted in UTF-16 code units, not Python characters — a placeholder emoji outside the BMP occupies two units. Compute offsets against the UTF-16 encoding of the message text, or the mosaic renders scrambled. ## Pack naming The visible pack title is built from **the owner's channel handle plus a short content id**: ``` <channel handle> <8-char id> ``` For example, for the channel `@deployladeploy`: ``` @deployladeploy 239c234b ``` Derive the id from the **first eight characters of a hash of the content**. This gives a short unique name and makes re-runs idempotent instead of breeding duplicate packs — the same image yields the same id. When installing this skill for someone else, substitute their own channel handle. The handle is the brand carrier on every pack the bot publishes, so it should be configured once at install time rather than hardcoded per run. ## Definition of done The work counts as finished **only** when all of the following hold: - Telegram returned a real `message_id`; - the pack type is `custom_emoji`; - the emoji count matches the tile count; - every `custom_emoji_id` exists and is unique; - the sent message came back with the expected number of `custom_emoji` entities; - `https://t.me/addemoji/<set_name>` opens and shows the correct title. Anything less is an incomplete run. Report it as such — do not present tiles as a result. ## Security The bot token is read at runtime from a protected environment only. It is never printed to logs, never echoed into a reply, and never written into any artifact handed back to the user.