Skip to content

frontic/mintlify-shots

Repository files navigation

mintlify-shots

A <Screenshot> directive for Mintlify MDX, backed by Playwright. Captures a light + dark PNG pair for every directive and rewrites the <Frame> block that follows it. Idempotent. Stays in sync as your app's UI evolves.

<!-- you write this -->
<Screenshot
  name="api/playground"
  caption="API Playground — testing a Search Listing"
  alt="API Playground dialog with request config on the left and JSON response on the right"
  width="640px"
/>

<!-- pnpm shots fills in this -->
<Frame caption="API Playground — testing a Search Listing">
  <img src="/images/api/playground-light.png" className="dark:hidden block max-w-... mx-auto" style={{ maxWidth: "640px" }} alt="..." />
  <img src="/images/api/playground-dark.png"  className="hidden dark:block max-w-... mx-auto" style={{ maxWidth: "640px" }} alt="..." />
</Frame>

Why

Maintaining light + dark screenshots by hand is tedious enough that most docs skip dark mode entirely. This kit makes them a one-liner and keeps them honest: when the UI changes, you re-run pnpm shots --force and the PNGs catch up — no manual editing of <Frame> blocks, no drifting alt text, no out-of-sync captions.

What's in the box

  • <Screenshot> directive — plain MDX, no React component to install
  • pnpm shots CLI — finds directives, runs the matching Playwright tests, writes the Frame blocks
  • Playwright fixtureshot(), theme, waitForReady(), plus an appInit hook for app-specific setup
  • Two-theme runner — every test runs once per colorScheme, producing the light/dark pair
  • Auth flowpnpm shots:login opens a headful browser, captures storageState, reuses it on every later run

Setup (≈ 5 minutes)

  1. Copy the kit into your Mintlify docs repo — these files transfer as-is:

    scripts/                  shots/fixtures.ts        screenshots.config.ts
    shots/helpers.ts          playwright.config.ts     tsconfig.json
    shots/example.spec.ts     .env.example
    
  2. Install dev dependencies in your docs repo:

    pnpm add -D @playwright/test dotenv fast-glob tsx typescript @types/node
    pnpm exec playwright install chromium
  3. Add the scripts to your package.json:

    "scripts": {
      "shots": "tsx scripts/screenshots.ts",
      "shots:force": "tsx scripts/screenshots.ts --force",
      "shots:login": "tsx scripts/screenshots.ts --login"
    }
  4. Configure your app's URL — copy .env.example to .env and edit:

    APP_BASE_URL=https://app.example.com
    APP_LOGIN_URL=/login           # only if your app is gated
  5. Write your first directive and test:

    {/* in any .mdx file */}
    <Screenshot name="getting-started/dashboard" caption="The dashboard" alt="..." />
    // shots/getting-started.spec.ts
    import { test, waitForReady } from "./fixtures";
    
    test("getting-started/dashboard", async ({ page, shot }) => {
      await page.goto("/dashboard");
      await waitForReady(page);
      await shot();
    });
  6. Run it:

    pnpm shots:login    # one-time, only if your app needs auth
    pnpm shots          # captures missing pairs and rewrites <Frame> blocks

That's it. Deploy your docs and you've got synced light/dark screenshots.

Per-app setup

Apps usually need a tiny amount of pre-test setup — pin a tenant cookie, hide a transient banner, seed localStorage. Use the fixture's appInit hook for this. See shots/README.md for the recipe.

How it works

Read docs/how-it-works.md for the architecture and lifecycle of a shot. Read shots/README.md for authoring conventions and CLI options. If you use Claude Code, .claude/skills/docs-screenshots/SKILL.md is a copy of the skill our team uses to add and audit shots — drop it into your repo's .claude/skills/ and Claude will pick it up.

CLI reference

pnpm shots                                  # only tests with missing PNG pairs
pnpm shots --force                          # recapture everything
pnpm shots --force --name section/stem      # recapture one shot
pnpm shots --file path/to/page.mdx          # scope to one MDX file
pnpm shots --no-sync                        # capture without rewriting <Frame> blocks
pnpm shots --dry-run                        # show what would run, don't run it
pnpm shots --login                          # capture storageState for a gated app

Limitations & non-goals

  • Playwright-only. No Cypress, no Puppeteer.
  • No NPM package. This is a starter kit you copy into your repo. Easy to customize, no upgrade churn — but no npm update either.
  • No image optimization. PNGs are saved at 2× DPR (1440 × 900 → 2880 × 1800). Add a build-time optimizer (Mintlify's image pipeline, sharp, etc.) if you need it.
  • No CI helpers. Wire it into your own pipeline as needed; the CLI exits non-zero on failure.

License & posture

MIT — copyright Frontic. This is a snapshot of the tool we use internally; PRs welcome but no SLA. See CONTRIBUTING.md. Originally built for the Frontic docs.

About

A starter kit that turns a <Screenshot name="..." /> directive in your MDX into a maintained light/dark image pair. A single Playwright test captures both themes; a CLI rewrites the <Frame> block beside the directive, escapes captions, applies sizing, and stays idempotent run-to-run.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors