Telemorph converts animated images such as GIF, animated WebP, and APNG into VP9 WebM files suitable for Telegram video stickers and custom emoji.
- Sticker profile: 512px canvas or variable height, up to 3 seconds and 30 FPS
- Emoji profile: 100×100, up to 3 seconds and 30 FPS
- VP9 with alpha (
yuva420p) - Automatic CRF selection for a target file size
- Live per-attempt encoding progress
- Direct input-to-WebM conversion with no ImageMagick or intermediate PNG files
Download the archive for your platform from GitHub Releases and extract it. Release archives contain:
- the self-contained Telemorph executable;
- pinned
ffmpegandffprobeexecutables; - third-party license notices.
No .NET runtime, ImageMagick, FFmpeg, or ffprobe installation is required for these archives.
Run the built-in diagnostic after extraction:
telemorph --doctorWhen running from source, FFmpeg and ffprobe must be available on PATH, or
provided with --ffmpeg and --ffprobe.
Requires the .NET 10 SDK:
dotnet build src/Telemorph.slnx -c Release
dotnet test src/Telemorph.slnx -c ReleaseRun from source:
dotnet run --project src/Telemorph.App -- input.gif --stickertelemorph <input> [options]Common options:
--output, -o <path>— output WebM path.--sticker, -s— 512px Telegram sticker profile; this is the default.--emoji, -e— 100×100 Telegram custom emoji profile.--crf, -c <0..51>— starting VP9 CRF; default38.--fps, -f <value>— maximum output FPS; default30.--duration, -d <seconds>— maximum duration; default3.--max-size-kb <KiB>— target maximum size; default256.--max-attempts <count>— maximum CRF search attempts; default6.--no-optimize— perform a single encode even if it exceeds the target size.--fit-duration— speed up a long animation instead of cutting it.--variable-height— make one sticker side 512px and preserve the other side.--threads, -t <count>— number of encoder threads.--no-row-mt— disable libvpx row-based multithreading.--no-overwrite— fail if the requested output already exists.--ffmpeg <path>/--ffprobe <path>— override bundled tools.--doctor— verify the media toolchain andlibvpx-vp9.
Examples:
telemorph animation.gif
telemorph animation.webp --emoji
telemorph long.gif --sticker --fit-duration
telemorph noisy.gif --max-size-kb 200 --max-attempts 8
telemorph input.gif --no-optimize --crf 42The initial CRF is treated as the preferred quality. Telemorph:
- probes the source;
- creates a conversion plan;
- encodes directly from the source with FFmpeg;
- probes and validates the resulting WebM;
- if the file is too large, searches higher CRF values for the smallest quality reduction that meets the requested limit.
Every attempt is written to a temporary WebM. The requested output path is replaced only after structural validation succeeds. A successful result is checked for VP9, alpha metadata, dimensions, duration, FPS, and file size.
In an interactive terminal, Telemorph shows an in-place FFmpeg progress bar for each CRF attempt and then records its resulting size. When output is redirected to a file or CI log, progress automatically switches to stable line-by-line messages without terminal control characters.
If CRF 51 still cannot meet the limit, conversion fails without leaving a partially validated output. Reduce FPS, duration, or visual complexity in that case.
The core conversion flow is intentionally split into independent stages:
FfmpegProbe
→ ConversionPlanner
→ FfmpegEncoder
→ OutputValidator
→ ConversionOptimizer
ConversionPipeline coordinates these stages. ImageMagick is not used.
FFmpeg receives the original animation directly, while ffprobe supplies source
metadata and validates every encoded candidate.
Pull requests from dev to main run formatting checks, a warnings-as-errors
build, and the full test suite. Pushing or merging a commit into main does not
create release binaries.
Publishing a GitHub Release starts the release workflow from that release's tag and produces self-contained builds for:
win-x64win-arm64linux-x64linux-arm64osx-arm64
FFmpeg and ffprobe are restored from exact npm dependency versions using the
committed lockfile. The Windows ARM64 release uses a pinned BtbN x64 media
backend through Windows 11 ARM emulation because the native build lacks
libvpx-vp9; its archive has an explicit SHA-256 check. The tools are copied
under tools/<RID>/, checked with telemorph --doctor, and exercised by a
transparent APNG-to-VP9 WebM smoke test before an archive is uploaded.
See third-party notices for FFmpeg licensing and source information.
I used Telemorph to convert some of my favorite 7TV emojis into Telegram video emojis and create my own 7TV emoji pack.
I also used it to convert several Tenor GIFs into Telegram stickers for my shitpost sticker pack.
I recommend using the @Stickers mini app to create a new sticker or emoji pack and upload your
.webmvideo stickers or emojis to it.
PRs are welcome. Please keep the code style consistent with the existing files. If you add options, mirror them in this README.
