@starter-series/shotkit
v1.1.1
Published
Capture Chrome Web Store + social promo assets (screenshots, promo images, demo video) from a built browser extension with Playwright.
Maintainers
Readme
shotkit
Capture store + social promo assets from a built browser extension — with Playwright.
Screenshots · promo images · demo screencast · listing copy. One command.
English | 한국어
Part of Starter Series — reusable tooling, not just clone-templates.
shotkitis the first capability extracted into an installable package so any repo (and any agent) can use it without copy-paste.
Status & Scope
- Currently implemented — A Playwright capture engine (build → launch the built extension via
launchPersistentContext(--load-extension)→ drive scenes → screenshot → caption/disclaimer band → promo tile from HTML → demowebm→ listing copy fromSTORE_LISTING.md), a CLI (shotkit) with an agent contract (--jsonmachine output, optionalpathargument,0/1/2exit codes), size presets for both audiences (CWS1280×800/440×280, SNS1200×675/1200×630/1080×1080), a path-traversal-safe localhost fixture server, a programmatic API (capture()), a Claude Code skill (skills/capture/), an AGENTS.md run-block so any shell-having coding agent can invoke it, and the npm package@starter-series/shotkit. Consumed bybrowser-extension-starterandskillBridge. - Planned — a capture-in-CI GitHub Action (run the capture under
xvfbon the official Playwright image and uploadstore-assets/as an artifact — zero local browser); a listing in thestarter-seriesplugin marketplace; video editing (webm → mp4, trim, captions) for SNS. - Design intent — One engine, many surfaces — matched to the tool's nature. shotkit is a heavy, file-producing build tool, so its surfaces are CLI (+
--json), skill, and CI — not MCP (see Non-goals). Captures are deterministic (login-free fixtures, frozen data) and the run doubles as a real-bundle smoke test — a screenshot only appears if that feature rendered from the shipped code. Trademark-safe by construction: a disclaimer band is composited onto every shot. - Non-goals — An MCP server (dropped by design: agents with a shell get a better contract from
--json+ the skill, without MCP's per-session context cost; nothing here is a fast structured query). Removing the per-repo scene config (which screens are your money shots is irreducible intent — it lives in yourshotkit.config.js). A general-purpose video editor (v1 records a clean screencast; editing is Planned). A hosted service (file-touching capture is local by nature). - Redacted — none. Ships no private data, credentials, or third-party identifiers.
Install
npm i -D @starter-series/shotkit
npx playwright install chromium # one-time: the browser shotkit drivesZero-install in any repo that has a config:
npx @starter-series/shotkitLoading an MV3 extension requires a headed Chromium — runs headed locally, under
xvfb-runin CI. SetHEADED=0to force headless (not recommended for extensions).
Usage
Add a shotkit.config.js (the per-repo seam — see the contract below), then:
shotkit # produce everything into outDir
shotkit --scene 01-feature # just one scene/promoTile/demo, or "description"
shotkit --no-video # skip the screencast (faster/CI)
shotkit --no-build # use an already-built bundle
shotkit ../my-extension --json # run against another checkout; JSON result on stdoutOutputs land in outDir (default store-assets/): <scene>.png, <promoTile>.png, <demo>.webm, description.md.
Agent contract (--json)
shotkit [path] --json prints exactly one JSON object to stdout (progress
logs move to stderr):
{ "ok": true, "outDir": "/abs/store-assets", "produced": ["/abs/store-assets/01-popup.png"] }Exit codes: 0 ok · 1 runtime failure (stderr carries {"ok":false,"error":…}) ·
2 usage / no config found. Drop-in agent wiring: the run-block in
AGENTS.md (read by Claude Code, Codex, Cursor, Gemini CLI, …) and
the skills/capture/ skill (Agent Skills format —
copy the folder into any compatible tool's skills directory).
Config contract (shotkit.config.js)
const { serveDirectory, stageExtension, patchManifestForLocalhost } = require('@starter-series/shotkit');
module.exports = {
build: 'npm run build', // run first → real-bundle smoke test (optional)
prepareExtension: () => '<unpacked dir>', // dir to --load-extension (often a patched temp copy)
outDir: 'store-assets',
disclaimer: 'Unofficial · not affiliated with …', // composited onto every shot (optional)
description: { from: 'store-assets/STORE_LISTING.md' }, // → description.md (optional)
async setup({ context, extensionId, flags }) { // e.g. start a fixture server / stubs
return { env: { baseUrl }, teardown: async () => {} };
},
scenes: [
{ name: '01-feature', preset: 'cws-screenshot', caption: 'What this shows',
async run({ page, context, extensionId, env, baseUrl, flags }) {
await page.goto(`${env.baseUrl}/page`); // drive the UI, wait until rendered
} },
],
promoTiles: [{ name: 'promo', template: 'path/to/promo.html', preset: 'cws-promo-small',
replacements: { NAME: 'My Ext' } }],
demo: { name: 'demo', preset: 'cws-screenshot', async run({ page, env }) { /* walkthrough */ } },
};- A scene/tile takes a
presetname or an explicit{ width, height }(seePRESETS). - The harness reduces a captioned scene's capture height by the band height and stacks the band under it, so the final image is exactly the preset size and no UI is hidden.
Public API
require('@starter-series/shotkit') →
capture(config, opts) · serveDirectory · stageExtension · patchManifestForLocalhost ·
launchWithExtension · closeContext · compositeCaption · renderPromoTile ·
extractListing · renderDescriptionDoc · PRESETS · resolveSize.
Roadmap — one engine, many surfaces
| Surface | Status | For |
|---|---|---|
| CLI (shotkit, npx) with --json + path | ✅ now | humans / CI / shell-having agents |
| Programmatic capture() | ✅ now | embedding |
| Claude Code skill (skills/capture/) | ✅ now | Claude Code (portable to Codex/Cursor/Gemini via the Agent Skills format) |
| AGENTS.md run-block | ✅ now | every agent that reads AGENTS.md |
| npm package (@starter-series/shotkit) | ✅ now | npx zero-install |
| Capture-in-CI GitHub Action (xvfb + artifact) | planned | zero-local-browser first run + CI smoke test |
| starter-series marketplace entry | planned | discovery |
| Video editing (webm→mp4, trim, captions) | planned | SNS clips |
An MCP stdio tool was considered and dropped — see Non-goals: shotkit is a heavy, file-producing build tool, so a --json CLI + skill serves agents better than an MCP server's per-session context cost.
Generalization rule (for the next capability in the series): one npm package (engine + thin CLI), one *.config.js seam for irreducible per-repo intent, agent surfaces matched to the tool's nature (fast/structured: an MCP tool taking a path; heavy/build-time: a --json CLI + skill + AGENTS.md run-block), one marketplace entry. The engine never reads project specifics except through the config seam.
License
MIT © heznpc
