{"slug": "open-source-free-meme-generator-friendly-for-ai-agents-and-humans", "title": "Open-source free meme generator, friendly for AI agents and humans", "summary": "A free, open-source meme generator running entirely on Cloudflare Workers launched with an in-browser editor covering 450+ templates and a URL-based API that renders memes on the fly via GET /images/{template}/{top}/{bottom}.png. The serverless TypeScript Worker uses WASM image codecs and static assets at the edge, and includes an /agents page plus /llms.txt guide for AI agents alongside server-rendered template pages with structured data and a sitemap. The project requires no signup, no origin server, and no image storage, and supports PNG, JPG, animated GIF, and WebP output.", "body_md": "A free meme generator that runs entirely on [Cloudflare Workers](https://workers.cloudflare.com):\nan in-browser editor for 450+ templates, plus a URL-based API where every meme is just a link.\n\n- **Editor pages** : one page per template with draggable, individually styled text boxes,\nyour own image layers, custom backgrounds, undo/redo, and PNG/JPG export. No signup, no\nserver round-trips while you edit.\n- **Meme API** :`GET /images/{template}/{top}/{bottom}.png` renders a meme on the fly, with\nfonts, colors, styles, overlays, custom backgrounds, and animated GIF/WebP output.\nInteractive docs live at`/docs` .\n- **Built for search** : every template page is server-rendered with a description of the\nmeme, alternate names, tags, structured data, social cards, and a sitemap.\n- **Serverless** : TypeScript Worker, WASM image codecs, static assets at the edge. No\norigin server, no image storage, nothing to babysit.\n\n```\nGET  /images/buzz/memes/memes_everywhere.png\nGET  /images/ds/small_file/high_quality.jpg?style=maga&width=800\nGET  /images/oprah/you_get/animated_text.gif\nPOST /images  {\"template_id\": \"fry\", \"text\": [\"not sure if\", \"or just\"]}\n```\n\nEvery template has a human-facing, SEO-friendly editor page rendered by `src/views/editor.ts`:\n\n| Route | Purpose | \n|---|---|\n| `/` | Index of all templates with search ( `/?q=` also works server-side) | \n| `/memes/{slug}` | Canvas editor for one template (name-based; old ids and slugs redirect) | \n| `/agents` ,`/llms.txt` | Guide for AI agents, as a page and as raw markdown ( `src/docs/agents.ts` ) | \n| `/privacy` | What the site collects ( `src/views/privacy.ts` ); update it when that changes | \n| `/sitemap.xml` | Lists the index and every editor page | \n| `/robots.txt` | Allows crawling of the pages, disallows the JSON API paths, links the sitemap | \n| `/static/*` | Stylesheet and scripts ( `assets/static/` , cache-busted with`?v=<version>` ) | \n| `/assets/templates/{id}/{f}` | Raw template images used by the editor canvas | \n| `/assets/fonts/{file}` | Font files loaded by the editor with the `FontFace` API | \n| `/proxy/image?url=` | Fetches a remote image (10 MB max, images only) so the canvas can use it | \n\nThe editor (`assets/static/editor.js`) runs entirely in the browser, imgflip-style:\n\n- Text boxes start where the template defines them; drag to move, corner handles to resize, top handle to rotate (Shift snaps to 15°), arrow keys to nudge.\n- Every text box has its own font, size (automatic fit or manual), color, outline color and width, alignment, vertical alignment, case, opacity and rotation.\n- Add as many text boxes as you like, add your own images as layers (upload or URL, with flip and opacity), reorder and duplicate layers, and replace the background with an uploaded image or a blank canvas of any size. Alternate template styles are selectable.\n- Undo/redo (Ctrl+Z / Ctrl+Y), delete key, double-click a box to edit its text.\n- Export as PNG or JPG at full resolution, copy the image to the clipboard, or copy an editor link that restores the text layers (the state lives in the URL hash).\n\nEach page is server-rendered with a unique title, meta description, canonical URL, Open\nGraph and Twitter Card tags (the example meme is the social image), JSON-LD (`WebSite`\nwith `SearchAction`, `WebPage`, `ImageObject`, `BreadcrumbList`), an `<h1>`, descriptive\ncopy, the template's source link, keyword links, and related templates. Without JavaScript\na `<noscript>` form posts to `POST /images` instead.\n\nThe site name in titles and social cards comes from the `SITE_NAME` variable.\n\nThe site is installable: `/manifest.webmanifest` (icons generated by\n`npx tsx scripts/build-icons.ts` into `assets/static/icons/`), a service worker at `/sw.js`\n(`assets/static/sw.js`, its cache name bound to the asset content hash so every deploy\nrefreshes caches), and an `/offline` fallback page. The worker serves pages network-first\nwith an offline fallback, and caches static assets, fonts, template images, and the last\n80 rendered memes cache-first. On phones, `assets/static/pwa.js` shows a closeable\n\"Install\" banner: Chrome/Android use the native prompt, iOS gets \"Share → Add to Home\nScreen\" instructions; dismissal is remembered for 14 days and the banner never shows once\nthe app is installed.\n\nEvery template page explains what the meme is, where it comes from, its alternate names,\nand related tags, so people can find a template by describing it rather than knowing its\nname. The search on `/` (and `?q=`) matches names, aliases, keywords, tags, example text,\nand the description; multi-word queries require every word to match.\n\n- `data/descriptions.json` is fetched from each template's Know Your Meme entry by`npm run fetch:descriptions` (short About/Origin excerpts, tags, alternate names). It\nonly refetches missing or failed entries; pass`--force` to refresh everything.\n- `data/descriptions.manual.json` holds hand-written entries for templates without a Know\nYour Meme source; these override fetched data. Add an entry here for any new template.\n- `scripts/build-templates.ts` merges both into the manifest and warns about templates\nthat still lack a description.\n\nKnow Your Meme excerpts are short, attributed, and linked; write original copy in the manual file when you want fully unique page text.\n\nRequirements: Node 20+, a Cloudflare account for deployment.\n\n```\nnpm install\nnpm run dev          # http://localhost:8787 (runs the template build first)\nnpm test             # vitest inside the Workers runtime\nnpm run typecheck\nnpm run deploy       # wrangler deploy (uploads the Worker + ~90 MB of template assets)\n```\n\nCloudflare's free plan limits Workers to 10 ms of CPU per request, which is not enough\nto render images. Deploy on the Workers Paid plan; `wrangler.jsonc` sets a 30 s CPU limit.\n\nVariables are defined in `wrangler.jsonc` (`vars`). Secrets go through `wrangler secret put`\nor a local `.dev.vars` file (see `.dev.vars.example`).\n\n| Variable | Purpose | \n|---|---|\n| `SITE_NAME` | Name used on the web pages and social cards ( `Memegenscript` ) | \n| `DEBUG` | `\"true\"` draws text/overlay boxes, enables`/test` , disables caching | \n| `DOMAIN` | Host used in absolute URLs (defaults to the request's own origin) | \n| `DEFAULT_STATIC_EXTENSION` | Extension used when none is requested ( `png` ) | \n| `DEFAULT_ANIMATED_EXTENSION` | Extension for animated templates ( `gif` ) | \n| `CACHE_TTL` | Seconds to keep rendered images in the edge cache ( `0` disables) | \n| `REMOTE_TRACKING_URL` | Optional memecomplete backend for API keys, tokens, search, tracking | \n| `REMOTE_TRACKING_ERRORS_LIMIT` | Errors before request tracking turns itself off ( `10` ) | \n\nThe API began as a TypeScript port of [memegen](https://github.com/jacebrowning/memegen)\n(Python), whose template library it still uses; the editor, pages, search, and design are\noriginal. The table shows what replaced each Python-era dependency:\n\n| Concern | Originally (memegen, Python) | Memegenscript | \n|---|---|---|\n| HTTP | Sanic | Worker `fetch` handler + ordered regex router (`src/router.ts` ) | \n| Template metadata | `templates/*/config.yml` via datafiles | Same YAML, compiled to `src/generated/templates.json` at build | \n| Template images, fonts | Local filesystem | Workers Static Assets ( `assets/` , read via the`ASSETS` binding) | \n| Text measurement & glyphs | Pillow + FreeType | opentype.js ( `src/images/layout.ts` ) | \n| Rasterizing text/overlays | Pillow `ImageDraw` | SVG built in `src/images/layer.ts` , rendered by resvg (wasm) | \n| Resize, blur, compositing | Pillow | Pure TypeScript ( `src/images/raster.ts` ) | \n| PNG / JPEG / WebP codecs | Pillow, `webp` | jSquash wasm codecs | \n| GIF | Pillow | gifuct-js (decode) + gifenc (encode) | \n| Animated WebP | `webp` package | Per-frame encode + hand-written ANMF muxer ( `src/images/webp.ts` ) | \n| Emoji | `emoji` + pilmoji (Twemoji) | emojilib aliases + Twemoji images ( `src/utils/emoji.ts` ) | \n| `style: mock` text | spongemock (seeded `random` ) | MT19937 port with CPython seeding ( `src/utils/mt19937.ts` ) | \n| Rendered image cache | `images/` directory on disk | Cache API ( `caches.default` ), keyed by request URL | \n| Custom backgrounds/overlays | Downloaded to `templates/_custom-<sha1>/` | Downloaded on demand, cached with the Cache API | \n\nRequest flow for `GET /images/{template}/{text}.{ext}`:\n\n1. `src/views/images.ts` normalizes the slug and handles redirects (style, watermark, tokens).\n2. `src/views/helpers.ts#renderImageResponse` resolves the template, validates every\nparameter and picks the status code exactly like the Python view.\n3. `src/images/render.ts` decodes the background, resizes it, renders the foreground layer\n(overlays + text) once per distinct animation state, pads/watermarks, and encodes.\n\nDrop a directory into `assets/templates/<id>/` with a `config.yml` and a `default.png`\n(or `.jpg`/`.gif`), exactly as in the Python project. Extra images in the directory become\n`style=` options. The manifest is rebuilt automatically by `npm run dev`, `npm test` and\n`npm run deploy` (or run `npm run build:templates`).\n\nThe full guide lives in [docs/guide.md](https://github.com/terryds/memegenscript/blob/main/docs/guide.md) and the client notes in\n[docs/clients.md](https://github.com/terryds/memegenscript/blob/main/docs/clients.md). Everything from the original README applies:\n\n- Formats: `.png` ,`.jpg` ,`.gif` ,`.webp` (GIF/WebP animate the text on static backgrounds)\n- `width` /`height` (both → padded to exact size),`layout=top` ,`font=<id|alias>`\n- `color=<line1>,<line2>` (names or hex,`#` optional),`style=<name>` or`style=<url>[,<url>]`\n- `background=<url>` with`template_id=custom` ,`center` ,`scale` ,`frames` ,`start` ,`stop`\n- Special characters in paths: `_` /`-` → space,`__` →`_` ,`--` →`-` ,`~q ~a ~p ~h ~s ~b ~l ~g ~n` ,`''` →`\"`\n- Emoji as characters or `:aliases:`\n\n- Text is rasterized from vector outlines instead of FreeType bitmaps, so glyph shapes and antialiasing differ very slightly; layout, wrapping and font-size selection use the same algorithms and produce the same line breaks.\n- GIF output is quantized without dithering (gifenc), so gradients band a little more.\n- Hebrew text is laid out left-to-right (no bidi shaping), as Pillow does without libraqm.\n- EXIF orientation of custom JPEG backgrounds is not applied.\n- Bugsnag error reporting is not wired up; errors go to Workers logs (observability is on).\n- `DEBUG` mode does not write new template config files to disk (there is no disk).\n- `/` serves the template index page instead of redirecting to`/docs` .\n\n```\nassets/            templates/, fonts/, static/  (served by Workers Static Assets)\nscripts/           build-templates.ts → src/generated/templates.json\nsrc/index.ts       routes + CORS + error handling\nsrc/views/         one module per Sanic blueprint\nsrc/models/        Template, Text, Overlay, Font\nsrc/images/        codecs, raster ops, text layout, SVG layer, render pipeline\nsrc/utils/         slug codec, urls, colors, emoji, remote tracking, sha1, mt19937\nsrc/docs/          OpenAPI document + Swagger UI page\ntest/              vitest (runs inside workerd via @cloudflare/vitest-pool-workers)\n```\n\nMIT. Portions of the API and the template library come from\n[memegen](https://github.com/jacebrowning/memegen) by Jace Browning (MIT); see\n`LICENSE.txt`. Template images belong to their respective owners. Font licenses are in\n`assets/fonts/`. Meme descriptions quote short, attributed excerpts from Know Your Meme.", "url": "https://wpnews.pro/news/open-source-free-meme-generator-friendly-for-ai-agents-and-humans", "canonical_source": "https://github.com/terryds/memegenscript", "published_at": "2026-09-20 01:35:45+00:00", "updated_at": "2026-09-20 01:53:47.942907+00:00", "lang": "en", "topics": ["ai-agents", "structured-data", "generative-engine-optimization", "ai-tools", "developer-tools"], "entities": ["Cloudflare Workers", "TypeScript", "WebAssembly", "imgflip"], "alternates": {"html": "https://wpnews.pro/news/open-source-free-meme-generator-friendly-for-ai-agents-and-humans", "markdown": "https://wpnews.pro/news/open-source-free-meme-generator-friendly-for-ai-agents-and-humans.md", "text": "https://wpnews.pro/news/open-source-free-meme-generator-friendly-for-ai-agents-and-humans.txt", "jsonld": "https://wpnews.pro/news/open-source-free-meme-generator-friendly-for-ai-agents-and-humans.jsonld"}}