A self-contained HTML file means the images travel inside it, not as links. The prompt wording that makes an AI base64-encode assets on the first pass — plus the size budget, what to inline, and what to leave alone.
You ask the AI for a one-file landing page. It hands you clean HTML with the CSS in a <style> block and the JavaScript inline. Looks self-contained. You email it, the recipient opens it, and where the product shots and the logo should be, there are gray broken-image boxes.
The markup was fine. The pictures weren't in it. The <img> tags still pointed at https://cdn.example.com/hero.png or at a ./images/logo.svg that lived next to the file on your machine and nowhere else. When the model heard "self-contained," it inlined the code and left the assets as links — because that's the normal web convention, and the model defaults to normal.
A file is only truly self-contained when the bytes of every image travel inside it. That's what base64 inlining does, and getting it on the first pass is a wording problem, not a code one.
A normal image tag is a reference: <img src="hero.png"> tells the browser to go fetch a separate file. If that file isn't reachable — wrong network, blocked CDN, the folder didn't come along — you get a broken box.
A base64 data URI is the bytes themselves, written as text, sitting inside the src:
<img src="data:image/png;base64,iVBORw0KGgoAAAANS...">
There's no fetch. The browser decodes the text back into a PNG and draws it. It works offline, behind a corporate firewall, on a plane, in an email preview pane — anywhere the HTML itself can open, the image is already there. That's the property you're buying: the picture can't fail to load, because there's nothing to load.
The trade is size. Base64 is a way of writing binary data using only safe text characters, and it costs about 33% in bloat — a 900KB photo becomes roughly 1.2MB of text in the file. For a few interface images that's nothing. For a 40-image gallery it's the difference between a sane file and a 60MB monster. So the prompt has to do two jobs: get the form right, and respect the budget.
"Make it self-contained" is too abstract — the model satisfies it by inlining code and calls it done. Name the assets explicitly and name the form you want:
Embed every image directly in the HTML. No
<img src>may start withhttp://,https://,//, or a relative path like./orimages/. Each raster image (PNG, JPG, WebP) must be a base64 data URI inline in thesrc. Each icon or logo that's vector should be inline<svg>markup, not base64. After you finish, scan everysrcandurl()and confirm none of them point at an external or local file.
Three things make this work where a vague ask fails:
http, //, and the sneaky relative path. The relative path is the one a generic prompt always misses, because it looks local and self-contained but isn't.src and url() attributes catches the straggler in a second pass it's good at.The same logic extends past images. Web fonts are the other asset that silently phones home — a @font-face pointing at Google or a CDN breaks the same way an image does. If the look depends on a specific font, add: base64-encode the WOFF2 and inline it via @font-face; otherwise use a system font stack.
The fastest way to know the inlining worked is to open the file somewhere it can't cheat — a network that doesn't have your CDN cached. Drop the HTML at a private link in under a minute and open it on your phone: if an image is still a link, you'll see the broken box immediately. No card, no account, and on the free tier the link self-destructs in 7 days.
The mistake in the other direction is asking the model to base64 everything, then watching it produce a 50MB file that chokes the email and times out the browser. A good prompt sets the budget:
Inline assets under ~200KB each as base64. For anything larger — a big hero, a photo gallery, video — first downscale and compress to web sizes; if the total still pushes the file past a few MB, flag it and list which assets are the heavy ones so I can decide. Never inline video; reference it or drop it.
This hands the model a threshold instead of an absolute, and asks it to report the heavy assets rather than silently bloat the file. You stay in control of the size/portability trade instead of discovering it after the send fails.
A rough hierarchy worth pasting into the prompt: inline SVG for icons and logos; base64 for the handful of raster images the layout truly needs; compress-then-base64 for one hero; leave galleries and video as a host's job.
Inlining wins when the deliverable is one page, one recipient, one moment — a proposal, a report, a landing snapshot, a deck. The whole thing arrives intact and renders anywhere.
It's the wrong tool when the content is genuinely media-heavy or genuinely live. A 200-photo portfolio doesn't belong in a single base64 blob; that's a real site, and a static host like Netlify or Vercel serving cached, separate image files is faster for every visitor. Anything that needs a server — uploads, a database, auth, video streaming — is past what any single file can do, base64 or not; that's a backend job, and those platforms are the right call. Inlining is for the static slice: the self-contained page that has to survive being emailed, opened offline, or sent through a network you don't control.
When that's the job, the base64 file is exactly right — and it pairs naturally with a private, unguessable link so the one self-contained file lands somewhere you decide who sees, rather than a public deploy the search engines index. If the page came out of a chat tool, the same inlining prompt cleans up an AI artifact before you hand it over.
If you remember nothing else: a self-contained file is one where the images are inside it, not linked from it. The prompt that gets there names the failure modes (http, //, relative paths), splits raster from vector (base64 the PNGs, inline the SVGs), and sets a size budget so the model compresses instead of bloating. Then open it once on a network that can't cheat — if every picture shows up offline, it's truly self-contained.
AI gives you a dark mode that flashes white, forgets the toggle, and hardcodes one shade of gray everywhere. The token-first prompt that makes theming survive in a single self-contained HTML file.
Most AI-built HTML looks right on screen and breaks the moment someone hits Ctrl+P. The exact prompt clauses, CSS hooks, and a ninety-second verification pass that make a page export to PDF cleanly the first time.
A multi-page site usually means a router and a server. Prompt patterns that give you real pages — Home, Pricing, About — inside one self-contained file or one ZIP you can drop at a private link.
miinideck turns a single HTML file into an unguessable link with optional password and expiry. Default-private, never indexed.