The difference between good docs and great docs is often how media is handled. Bad: blurry screenshots from arbitrary zoom levels, hero videos that autoplay loudly, "see the image below" with no fallback for readers who can't. Good: purposeful media that carries information prose can't, annotated for clarity, captioned for scannability, alt-texted for accessibility + LLM ingestion.
This guide covers the media discipline for docs.
When to use media
UI screenshots — yes
Any step that says "click the X in the Y of the dashboard" should have a screenshot showing where. Prose alone forces the reader to hunt.
Architecture diagrams — yes
System overviews, data flow, request lifecycles. One diagram can replace five paragraphs. Use Mermaid for maintainability.
Short videos / GIFs — sometimes
Interactions that can't be captured in a single screenshot (drag-and-drop, hover-reveal, animation timing). Keep under 15 seconds. Always pair with prose fallback.
Decorative hero images — rarely
Only when the image is the product (a design tool, a data visualisation product). Otherwise cut — hero images delay first-paint and agents can't see them anyway.
Screenshot discipline
Capture
Browser zoom 100% + device pixel ratio @2x — retina-sharp on modern displays.
Same browser, same OS, same theme across the whole docs site. Mixed Safari / Firefox / macOS / Windows chrome is distracting.
Crop to the relevant UI. Full-window screenshots are 1400×900 of which 10% is useful. Crop to 600×400 of the dashboard panel being discussed.
Hide personal data — your real email, your real API keys, your real customers' names. Use
demo@acme.comandsk_test_demo....Consistent window chrome — either keep the browser title bar / URL bar visible (if URL is informative) or hide entirely (distracting). Pick one and stick with it.
Recommended tools:
| Tool | Good for |
| macOS Cmd+Shift+4, Space | Window capture with shadow, @2x |
| CleanShot X | Annotation + cropping + scrolling capture |
| Shottr | Free alternative, fewer annotation features |
| Flameshot | Cross-platform OSS |
Annotation
Annotate only what the reader needs to find. Arrows, numbered circles, red outlines around the specific clickable area. Don't annotate the whole screenshot — it defeats the purpose.
❌ Arrow 1 → Settings. Arrow 2 → General. Arrow 3 → Save. Arrow 4 → ...
(Seven arrows across the whole screenshot.)
✅ Arrow → "Custom domains" section in the Settings sidebar.
(One arrow, one focus point, one prose step.)Colour choice: high-contrast red (#DC2626) or yellow (#EAB308) against most UI. Avoid green (reads as "success") or purple (too subtle).
Where the file lives
Two places work, and the choice matters more than it looks.
In your repo, under public/. The file is versioned with the page that uses
it, and <Image> runs it through the image optimizer: the reader gets a resized
AVIF or WebP sized to their screen, not the file you committed. A 340KB
screenshot can reach a phone as about 40KB without you doing anything.
On a CDN or object store, as an https:// URL. Nothing enters your repo. No
push waits on the upload, no clone re-downloads it, and the file can be replaced
without a commit.
An external URL is served as-is. Next.js does not optimize images it doesn't
host — a 3MB PNG behind an https:// URL arrives as 3MB, on every device. The
optimizer is the thing you give up, so the size you upload is the size readers
pay for.
Which one depends on the file:
| File | Put it | Why |
| Screenshots, diagrams, icons | public/ | Small enough that Git doesn't care, and optimization is free |
Video (.mp4, .webm) | CDN | Video never goes through the optimizer, so public/ costs repo weight and returns nothing |
| Anything over a few MB | CDN | See below |
| Assets you already host | CDN | No reason to copy them into the repo |
The reason to keep large binaries out of Git is that they never leave. Git stores each version of a binary in full — it can't diff them — so a 5MB video replaced three times is 15MB in the history of every clone, forever, including the versions nobody uses. Deleting the file doesn't shrink it. Text files don't behave this way, which is why a repo of pure MDX stays small for years.
That weight is paid on every git clone, every CI checkout, and every sync,
because a sync fetches the whole repository — a 200MB media folder is
re-downloaded when you fix a typo in one page.
Sizing
Target dimensions for common slots in NookDocs layouts:
| Use case | Dimensions | File size |
| Inline full-width | 1600 × 900 (16:9) | <200KB |
| Inline narrow (next to text) | 800 × 600 | <80KB |
| Hero / section break | 1600 × 900 or 1200 × 600 | <250KB |
| Small inline (icon-size) | 200 × 200 | <30KB |
These are firm for external URLs, where the number you upload is the number
the reader downloads. Under public/ they are a guide to keeping the repo light
— the optimizer is already handling what reaches the browser, so a retina
screenshot landing somewhat over is not a problem worth solving twice.
Compress before committing:
PNG → TinyPNG (free up to 20/month, retains transparency).
JPG → 85% quality in most tools; 70% is usually the sweet spot between size + quality.
WebP → modern replacement, 25-35% smaller than JPG at same quality. Supported in all modern browsers.
# Bulk compress a directory
find ./images -name "*.png" -exec pngquant --ext .png --force {} \;
find ./images -name "*.jpg" -exec jpegoptim --max=85 {} \;Alt text that works
Alt text serves three audiences:
Screen reader users — hear the alt text read aloud.
Users on slow connections — see alt text while the image loads (or if it fails).
LLMs ingesting the page — can't see the image, extract meaning from alt + surrounding prose.
Good alt text names what the image shows + why it's in the doc.
❌ alt="screenshot.png"
❌ alt="dashboard"
❌ alt="Image of the dashboard"
✅ alt="Custom Domains panel in Settings showing docs.acme.com verified with a green check"
✅ alt="Mermaid diagram: request flow from browser through CDN to origin, with cached response returning in 15ms"
✅ alt="Code editor sidebar showing _snippets folder expanded with three mdx files inside"Rules of thumb:
Name what the image shows, not the image type. "Image of X" is noise — screen readers already announce "image".
Mention the key UI element or data point. If the screenshot shows the "Save" button, name it.
Be as short as possible while being specific. ~8-15 words is usually right.
Decorative images get
alt="". Empty alt = screen reader skips. Missing alt = screen reader reads the filename.
Captions
Captions serve sighted readers — they reinforce what the image shows AND what to do with it:
<Frame caption="After adding a custom domain, the entry flips to 'Verified' once DNS propagates. Typical: 30-60 seconds.">

</Frame>Alt text names the content. Caption explains the implication. Together they cover both "what is this showing me" and "so what".
Diagrams — prefer Mermaid
Diagrams render as images when you ship PNG / SVG. Mermaid diagrams render as live SVG from Markdown-like source — which means:
Searchable text (SEO + accessibility).
Version-controlled source —
git diffshows what changed in the diagram.Editable in-repo — update without round-tripping through a design tool.
Automatically theme-aware — respects light / dark mode via NookDocs's theme tokens.
<Mermaid>
```mermaid
sequenceDiagram
Browser->>CDN: GET /docs/quickstart
CDN->>Origin: cache miss, fetch
Origin-->>CDN: HTML + headers
CDN-->>Browser: HTML (cached 5 min)
```
</Mermaid>Use PNG/SVG only when:
The diagram is too complex for Mermaid syntax (hand-drawn, annotated with multiple overlays).
You need photo-real elements (product screenshots composited into a flow).
Video + animation
Video is tempting for "show the interaction" cases but carries real costs: file size, auto-play UX debates, screen reader + accessibility overhead, LLM invisibility.
Rules for when to use:
≤15 seconds — anything longer, split into smaller clips or use static screenshots with numbered steps.
Silent — no voiceover. Users reading docs are often in shared workspaces. The doc's prose carries narration.
No autoplay — reader presses play. Exception: ultra-short GIFs (under 3 seconds) documenting a single interaction.
Provide transcript or caption — describe what happens in prose either above or below the video. LLMs + screen readers need this; sighted users benefit too.
Formats:
| Format | Best for | Caveats |
| MP4 (H.264) | Longer demos (5-15s) | Needs <video> element. Supports audio if you ever need it. |
| GIF | Micro-interactions (<3s) | Huge files. Prefer MP4 + poster image for anything over 2s. |
| WebM | Same as MP4 | Smaller than MP4. Browsers auto-fall back to MP4 via <source> chain. |
| APNG | High-fidelity short animations | Limited tooling. Rarely worth the effort. |
Embed with the <Video> component:
<Video
src="/videos/custom-domain-setup.mp4"
poster="/images/custom-domain-setup-poster.png"
caption="Adding a CNAME record in Cloudflare, pasting the target into Acme dashboard, and watching the verification flip green."
/>Third-party embeds
YouTube, Loom, Vimeo — use the <Embed> component:
<Embed
src="https://www.youtube.com/embed/dQw4w9WgXcQ"
title="Walkthrough: Setting up a custom domain"
/>NookDocs whitelists YouTube, Loom, Vimeo, Figma, CodePen, and StackBlitz. Other origins render as a notice with a link to the external resource (avoids XSS from untrusted iframes).
Loom vs YouTube:
Loom — internal demos, quick walkthroughs, no publishing to YouTube. Loom handles the loading / hosting.
YouTube — evergreen content, marketing videos, anything you want to rank in YouTube search. More control over thumbnails + end screens.
Media organisation in the repo
docs/
images/
features/
copy-for-llms-dropdown.png
copy-for-llms-menu-open.png
api/
rate-limit-headers.png
concepts/
architecture-overview.svg
videos/
custom-domain-setup.mp4Conventions:
Organise by doc path, not by media type.
images/features/copy-for-llms.pngbeatsimages/screenshots/copy-for-llms.png.Lowercase, hyphenated filenames.
custom-domain-setup.pngbeatsCustomDomainSetup.png.No version numbers in filenames. If the screenshot gets updated, replace in place — Git tracks the history.
Reference with absolute paths in MDX:
/images/features/custom-domain.png. Relative paths break when the page moves.
Image optimisation at serve time
NookDocs doesn't yet ship Next.js <Image> auto-optimisation (lazy loading, responsive srcset, modern format delivery) for user-repo images — they serve as-is from /api/assets/<path>. Compress before committing.
Roadmap: /images/<path>?w=800&q=85 responsive URLs with on-the-fly resize. Until then, ship the right size at commit time.
Common media mistakes
Related
Accessibility — alt text + contrast requirements
Style and tone — prose that accompanies media
Frame component — the wrapper for annotated images
Image component — light/dark variants + sizing props
Video component — the embed wrapper
Mermaid component — inline diagram source