Meme generator app, when the builder is general-purpose
Every other guide on this topic ranks meme apps you can download. This one is about a different question: what happens when you point a general-purpose AI app builder at the request "build me a meme generator", and why the answer is shaped by five things already baked into the sandbox image before the first character of your prompt.
The pages that currently rank for this answer the wrong question
The existing playbooks for this topic are catalogs. Mematic for iPhone. Imgflip on the web. Canva for templated quickness. Supermeme.ai and MemeFast for "type a sentence, get a meme". All real, all good at what they do, all answering the same prompt: which meme app should I download? That works if your need is a one-off image with a top and bottom caption on a stock template, and it loses if you want a meme generator that is yours: your fonts, your watermark, your library, your domain, your database, your team channel.
The general-builder answer is different in shape. You do not pick from a list. You describe what the app should do, and a sandbox writes the code. Whether that route is interesting depends entirely on what is already inside the sandbox. If the sandbox is empty, you spend the first hour installing things. If the sandbox is heavy in the right places, the meme generator is a one-evening project that ends with a real codebase you own.
On mk0r the sandbox is heavy in five specific places, and that is what makes this question worth a page of its own.
What is on disk before you type
All five of these come from the same file: docker/e2b/e2b.Dockerfile. They are pre-installed at template build time, so every fresh sandbox boots with them already present. The sandbox is not a blank Linux box; it is a workshop laid out for this kind of work.
- Chromium and ffmpeg. Line 28 of the Dockerfile installs them in a single apt-get along with
fonts-liberation libgbm1 libnss3 libxss1. The browser is what you preview in. ffmpeg is what makes a meme into a GIF or a video. - Playwright MCP. Line 53 installs
@playwright/mcp@0.0.70globally. The agent can drive the browser: navigate, click, type, screenshot. That is how you get a clean server-side PNG of a finished meme without trusting browser-canvas exports across phone operating systems. - A Vite + React + TS scaffold. Line 70 runs
npm create vite@latest . -- --template react-ts. The dev server is already running on port 5173 with HMR by the time the first prompt arrives. You do not wait fornpm install. - Tailwind v4. Line 72 installs
tailwindcss @tailwindcss/vite. The styling layer is wired before the first component exists. - Resend, Neon, PostHog. These are not in the Dockerfile. They are added per-session by the service-provisioning step (see
src/core/service-provisioning) and listed in/app/CLAUDE.mdlines 41-46 with their env vars already populated. Email out, database in, analytics on, no API keys to paste.
“chromium fonts-liberation libgbm1 libnss3 libnss3-tools libxss1 ffmpeg”
docker/e2b/e2b.Dockerfile
What "build me a meme generator" actually triggers
From the moment you hit enter to the moment the first canvas paints, here is the path. Most of it is inside the sandbox; the only thing crossing back to your screen is the screencast.
Inside the sandbox
Open mk0r and start typing
No account, no signup, no card. The Firestore-backed pool in src/core/e2b.ts hands you a sandbox that has been pre-warmed for about 2.5 seconds. Inside it, /app already exists.
The agent reads three files first
The system prompt at src/core/e2b.ts line 148 (Vite + React + TS + Tailwind v4), /app/CLAUDE.md (which files to edit), and the existing src/App.tsx. Those three set the path of least resistance: write a React component, import it from App.tsx.
It writes src/components/MemeStudio.tsx
A canvas, a file input, two text fields, a download button. The dev server is already up at port 5173 with HMR. The first paint appears in the in-VM Chromium at port 9222 within seconds.
You watch it render in real time
The screencast is wired through proxy.js on port 3000 (see docker/e2b/files/opt/proxy.js). What you see is the actual Chromium running inside the sandbox, not a server-rendered preview.
You iterate with sentences
Sticker library. Watermark. Drag-to-position text. Click-to-add-text. Replace canvas with server-side Playwright PNG. Save to Neon. Email via Resend. Each step is one more prompt against the same /app project.
What the V1 component looks like
The first version is small enough to read in one go. The agent will land somewhere close to this on the first prompt. Stripe-style stroke around the white text is the Impact-on-photo look that everyone reads as "meme" instantly. Copy this if you are curious; or skip ahead, ask mk0r for it, and read what it actually shipped.
Two things to notice. The font stack is Impact, "Arial Black", sans-serif because the sandbox shipped fonts-liberation on Dockerfile line 28, which gives Liberation Sans Bold as the cross-platform stand-in for Arial Black; if you want real Impact you install it as one more package. And the canvas is capped at 1080px wide because most social uploads downscale anything bigger anyway, so you save the round-trip time.
The render pipeline once it grows up
The V1 above renders client-side with the canvas API. That is fine for fast preview. If you care about a clean output (consistent cross-browser anti-aliasing, no scrollbar artifacts, predictable font metrics), you move the final render to headless Chromium. Each box below is one more piece the sandbox already has.
Meme render pipeline (V2)
Image upload
fileInput, blob URL, img tag
Canvas paint
drawImage, fillText with stroke
Headless Chromium
Playwright screenshot at 2x DPR
Postgres row
INSERT INTO memes via Neon
Email or share
Resend, or signed URL
The whole loop, in messages
One way to see how unusual this shape is: lay out the actors that actually move bytes during a single "make a meme and email it to me" round-trip. None of them require you to paste an API key. None of them are external services you log into. They were all inside the sandbox before you sent the first character.
One prompt, five actors
Where Chromium earns its place specifically
Client-side canvas works on every modern browser, but the output varies. Safari on iOS rasterizes text differently from Chrome on Android. Some desktop Chromium versions leave a half-pixel gap at the top of the canvas. Phones in low-power mode downscale before export. Memes that look perfect during preview can ship 720px instead of 1080px because the user's phone decided to save memory.
The pre-installed Playwright path skips that uncertainty. The agent navigates the in-VM Chromium to the dev-server preview, sets the viewport, fills the form, and calls page.locator("canvas").screenshot({ deviceScaleFactor: 2 }). The PNG comes back as bytes, ready for Resend or for an INSERT into Neon. The browser doing the render is the same one your tests would run against, on the same OS, with the same fonts. Output stops being a coin flip.
None of the existing meme apps offer this. They cannot, because they are not running their own headless browser. The closest you get without building it yourself is exporting through a server-side tool you wired up with three keys and a card. Inside this sandbox, the same keys are already there.
Where the same sandbox closes the loop
A meme generator alone is half a product. The other half is what you do with the meme: save it for later, share it with friends, blast it to a mailing list, hang it in a Slack channel. Each of those needs storage and an outbound channel. On mk0r, both already exist as listed services in /app/CLAUDE.md:
- Storage. Neon Postgres on line 44 with
DATABASE_URLalready in .env. One prompt toCREATE TABLE memes, one prompt to insert on save. The PNG can live as a base64 column for small volumes or in object storage with a URL row for larger ones. - Email. Resend on line 45 with
RESEND_API_KEYandRESEND_AUDIENCE_IDalready set. "Email me my last meme every Friday" is one cron entry plus one resend call. - Analytics. PostHog on line 43 with
VITE_POSTHOG_KEYalready wired into the Vite env. So you know which template actually got used and which caption length wins.
None of these are integrations you set up. They are services present in the project the moment it exists. The closest analogue in the catalog-of-meme-apps world is Imgflip Pro plus a Mailchimp account plus a Postgres provider plus an analytics tool. Three credit cards, four dashboards. Or the build-it-yourself path, where it is one sandbox.
Where the existing meme apps still win
For most one-off meme needs, downloading Mematic or opening Imgflip beats every other option. Their template libraries have been curated for years. Their mobile UIs have been polished against tens of millions of users. Their distribution channels (Imgflip's gallery, Canva's social-share buttons) are already where people look. If you want to caption a stock template and post it to Twitter in 30 seconds, do that.
The from-a-prompt path beats them on three specific axes. Custom templates and fonts that are part of the build, not a paid upgrade. Private memes that never leave a database you control. Workflows that wire memes into other systems (a daily email, a Slack endpoint, a calendar reminder, a webhook from a build that failed). On all three, an app you wrote in your sandbox wins, and the App Store apps cannot compete because they were never meant to extend that far.
Both paths are valid. The mistake is asking a from-a-prompt builder to compete on first-meme time and judging it for losing. It loses on that axis on purpose. It buys you the rest.
Honest limits
The first version of a meme generator is one component and a canvas. A serious one is bigger: drag-to-position text, sticker search, brand-logo lock, undo history, EXIF orientation handling, face detection for caption auto-placement, animated GIF output with ffmpeg, watermarking, an admin page to manage the template library. Each of those is one prompt away, but they compound. By the time you have all of them, the project is a small but real full-stack app that needs the same diligence as anything else: a bug list, a real auth story if you put it on the public internet, a deploy plan.
What you do not get is "I built it once and never touched it again". That is what an App Store app is for. The from-a-prompt path is for the case where the marginal feature you need is not on the App Store, or where you specifically want to own the codebase. Pick the side honestly.
Want a teardown of your meme-generator prompt?
Fifteen minutes. Bring an idea, leave with a working V1 and a list of the next three prompts.
Frequently asked questions
Why would I build a meme generator instead of just using one?
If your need is a quick one-off image with a top and bottom caption on a stock template, a download from the App Store is faster. If you want anything past that (your own template library, your own font, a brand watermark, a private database of memes you and your friends made, an email of the day, an export-to-GIF flow, an internal Slack endpoint), the existing apps stop short. Building your own from a prompt costs minutes, not days, when the sandbox already has Chromium and Postgres on disk. The trade is between picking from a list and owning the codebase.
What does mk0r actually generate when I ask for a meme generator?
It writes a React component (usually `src/components/MemeStudio.tsx` or similar) into the pre-existing Vite scaffold at /app and imports it from src/App.tsx. The first version uses an HTML5 canvas plus a fileInput and two text fields, plus the standard Impact font stack with white fill and black stroke. It hot-reloads in the in-VM Chromium so you see it within 5 seconds. From there you iterate: add a sticker library, add a brand watermark, switch the renderer to a server-side path, add export buttons. Each change is one more sentence.
Where does the Chromium part actually come in?
Two places, with different jobs. First, the dev-server preview shows up in the in-VM Chromium because that is the browser the sandbox runs at port 9222 with CDP enabled (see docker/e2b/e2b.Dockerfile line 23 and the proxy.js entry on port 3000). Second, the agent can use Playwright via the MCP server installed at line 53 (`@playwright/mcp@0.0.70`) to navigate to the running app, fill in the form, and screenshot the canvas at 2x device pixel ratio. That second path is where you get a clean PNG without trusting browser canvas exports across phone OSes. Most meme apps do not give you that path because they are not running their own headless browser.
What is the role of ffmpeg here?
Two things. Animated meme output as GIF (canvas frames concatenated, palette generated, compressed) and video memes (drop a clip in, overlay text, export an MP4 with the captions burned in). ffmpeg is on disk because docker/e2b/e2b.Dockerfile line 28 installs it next to chromium. The agent shells out with execSync('ffmpeg ...') from a small Node script. None of the App Store meme apps let you write your own ffmpeg invocation; they hard-code the export pipeline.
Can the same sandbox actually save and share the memes?
Yes, that is what the pre-provisioned services list inside /app/CLAUDE.md is for. Line 44 lists Neon Postgres with DATABASE_URL already in .env, so the agent can `CREATE TABLE memes (id, image_url, caption, created_at)` and start writing rows with no setup. Line 45 lists Resend with RESEND_API_KEY already set, so a 'meme of the day' email is one prompt away. Line 43 has PostHog wired for event tracking. None of these need an account, a credit card, or a copy-paste-the-key step. They were provisioned the moment the project was created.
How is this different from Imgflip, Mematic, or Canva?
Those are products. They each bring a curated template library, a polished mobile UI, and a built-in distribution channel (Imgflip's gallery, Canva's social-share). They beat any from-scratch build on first-meme time and on template variety. The thing they cannot do is be your private meme app. You do not own the codebase, you cannot host it on your own domain, you cannot extend the editor with your own fonts and logos baked in, you cannot wire it into your team's database. A built-with-mk0r app is yours to keep, host, and extend. Pick the tool whose ceiling matches your need.
How long does the first version take?
Roughly under a minute for the canvas-only V1 once the sandbox is warm. The pre-warmed pool is in src/core/e2b.ts (Firestore-backed, the file describes a ~2.5s template boot at the comment near line 8). After the agent reads the CLAUDE.md files and the Vite project state, generating the MemeStudio component and importing it into App.tsx is a small edit. The longer pieces come later: server-side rendering, sticker libraries, export-to-GIF, login.
Do I need to know any code to build this?
Not for V1. The first useful meme generator is a single React component with a file input, two text fields, a canvas, and a download button. The agent writes all of that. You read the result, run it in the in-VM browser, and ask for changes in plain words. You will hit a code-shaped wall when you want behavior that is hard to describe in a sentence (e.g. 'snap text to the bottom edge of the detected face' or 'preserve EXIF orientation across iOS uploads'). At that wall, having a working codebase to read beats a black-box editor.
What is a realistic first prompt?
Something like: 'Build a meme generator. Component at src/components/MemeStudio.tsx, imported from src/App.tsx. File input for the image, two text fields for top and bottom caption, render on an HTML5 canvas at the image's natural width up to 1080px wide. Use a white-fill black-stroke Impact-stack font, 8% of the canvas height. Add a download button that exports the canvas as a PNG named meme.png. Then open the dev preview in the in-VM browser and screenshot the result.' Eight sentences, one round trip, working V1.
Can I deploy the result?
Yes. The codebase is a normal Vite + React + TypeScript project. `npm run build` produces a dist/ folder you can host anywhere static (Cloud Run, Netlify, Cloudflare Pages, an S3 bucket). If your meme generator wants a server (database, email, image processing) you keep the same agent and ask it to build a small Node server next to the React app, or split it into a Next.js project on a second prompt. The mk0r repo is open source on GitHub at github.com/m13v/appmaker if you want to inspect or self-host the builder itself.
Adjacent reading
Single HTML File App
When the meme generator needs to be one .html file you can drop on a USB stick, here is the override prompt that flips the sandbox out of multi-file React mode.
HTML Email Generator
If your meme generator emails the meme of the day, this is what you have to know about Outlook and Gmail before you press send.
AI App Builder No Code
The general shape of mk0r in one read. Quick mode versus VM mode and how each one handles a project larger than a single component.