# Meme Generator > A meme generator that separates the picture from the words. Describe an idea; a writing run > returns the captions and a paintable scene, an image run paints original artwork with no > lettering in it, and the caption is then typeset onto the picture on a canvas in the browser. Live at https://meme-generator.skillsafe.ai/ · API tutorial at /api.html · the exact writing guide the app sends to the model is served verbatim at /plan-prompt.js ## What it does The app makes one meme at a time, in four layouts: - **Top line, bottom line** — one picture, a line across the top and a line across the bottom in heavy outlined type. Two caption slots, 70 characters each. - **Caption above the picture** — one sentence in a plain band above an untouched picture. One slot, 200 characters. - **Two panels compared** — one picture painted as a left/right diptych, each half with its own label bar, plus an optional heading. Three slots. - **Labelled scene** — one picture with two to four label chips placed at corners the user chooses, plus an optional heading. Five slots. Seven art looks (photographic, flat vector, gouache, 3D render, pencil sketch, retro print, pixel art) and six tones (deadpan, absurd, exasperated, fond, overexcited, bleak but cheerful). The look steers the picture; the tone steers only the words and is never sent to the renderer. ## The one design decision everything follows from **The captions are not part of the generated image.** The art brief explicitly forbids words, letters, numbers, captions, speech bubbles, logos, watermarks, signatures and borders inside the picture. The caption is then typeset on a canvas in the browser. That is not a stylistic preference. An image model cannot reliably spell, cannot be held to a character limit, and cannot be edited after the fact. Typesetting in the browser makes the words correct, sized to fit, identical in every browser, and free to change as many times as the user likes after the picture has been paid for — including switching to one of the alternative caption sets the writing run returned, moving a label to a different corner, or turning capitals off. ## What it will not do, and why **It does not reproduce famous meme photographs.** Those are copyrighted pictures and most of the famous ones are photographs of real people who never agreed to be a punchline for a decade. What is not anybody's property is the *rhetorical shape* — reject one thing and prefer another, compare expectation with reality, label the parts of a scene, put a calm line over a disaster. Naming a template blocks the run and offers a one-click rebuild into the app's own layout for that shape, cutting the borrowed name out of the text and leaving the rest of the user's words untouched. The same applies to characters somebody else owns. **It refuses five things outright**, in the browser, before any credit is reserved, quoting the exact words that caused the refusal: 1. harassment and pile-ons — the machinery of aiming a crowd at a person 2. contempt aimed at a group of people for what they are 3. a meme aimed at a real, named individual — the app does not try to sort public figures from private ones, because it cannot do that reliably in a browser and the cost of getting it wrong falls on the person with no platform 4. sexual or suggestive content 5. anything sexual, suggestive or hostile involving a child The guard reads every field the user controls — the idea, the scene and every caption slot — not just the first box, because putting the offending part in a caption is the obvious evasion. **Two limits, stated rather than hidden.** The guard is structural: it reads the shape of a request, so it catches the clear cases and a coded or implicit version can get past it. And it runs **in the page**. A client driving the API directly is not behind it; there, only the model's own refusals in the system prompt apply. Those are two different checks, not one, and neither is described here as more than it is. **The guard ships no slur lexicon**, deliberately: a word list puts the words in the bundle, ages badly, catches reclaimed usage, and is defeated by one changed letter. The hate rules are structural instead — a protected characteristic named together with a dehumanising or contemptuous frame. The model that writes the captions refuses independently, and the app says plainly that these are two different checks rather than one. ## The two runs **Writing run** (the app's own text model). Input fields: `task` (always `"plan"`), `guide` (the full text of /plan-prompt.js), `idea`, `format`, `want` (the layout's slot list with each slot's character limit) and `tone`. Returns one JSON object: `title`, `lines` (an array of `{slot, text}`), `alts` (two alternative caption sets), `scene`, `why`. A refusal instead returns `{refused: true, reason}`. **Painting run** (an image model, reached with a `$model` override). Input is exactly two fields, `instruction` and `$model` — every additional key would be concatenated into the text the renderer sees and painted into the picture as literal words. The instruction is the compiled brief: an originality clause, the scene, the layout's composition requirement, the art look, and the clause forbidding lettering. Output is one 1024×1024 picture returned as base64. Pricing is quoted at the button as the *reserve* for both runs added together, with the addition shown rather than the sum alone, and read from the platform's own `/estimate` at page load rather than repeated from documentation. Costs are shown in US dollars; 10,000 credits is $1. The image leg reserves **$0.27** (2,652 credits on `gpt-image-2`, confirmed against `/estimate`) and the caption leg is a small token-priced text run. The settled charge varies picture to picture against an identical reserve, so the app never quotes a settled price. ## What is free Choosing a layout, writing captions by hand, the caption lint, the content guard, the compiled brief, typesetting over a browser-drawn plate, the PNG export, and a bundled example that replays four real writing runs — one per layout plus the refusal branch. No account needed for any of it. ## Storage Memes are saved to a declared `memes` collection on the user's account, with a localStorage mirror for instant paint and for signed-out use. Rows carry every word but no image bytes; the picture is an `ss.files` id fetched back as a fresh signed URL on reopen. Past memes are searchable by meaning. Re-captioning a reopened meme is free; repainting it is not. ## Not affiliated Independent. Not connected to, endorsed by, or derived from any other site or service of a similar name.