Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ npx @starter-series/shotkit <path> --json # run against another checkout
```

Prereqs: `npx playwright install chromium` (one-time); the config's `build`
command must succeed. Loading an MV3 extension needs a **headed** Chromium —
works as-is locally, `xvfb-run` in CI. Exit codes: `0` ok · `1` runtime
command must succeed. Headless works (`HEADED=0`; verified on macOS + Linux CI,
video included); the local default is headed. Exit codes: `0` ok · `1` runtime
failure · `2` usage / no config. In `--json` mode progress logs go to stderr;
stdout is exactly one JSON object. Useful flags: `--scene <name>`,
`--no-video`, `--no-build`.
Expand Down Expand Up @@ -45,9 +45,13 @@ test/ → unit tests for the pure/safe modules (no browser)
- **`serve.js` path-safety**: never feed the request URL straight into `path.join`.
Keep the `path.normalize(...).replace(/^(\.\.(\/|\\|$))+/, '')` sanitizer
(CodeQL `js/path-injection`). There's a test for it.
- **Headed Chromium**: MV3 extensions only load headed (`channel:'chromium'`,
`headless:false`). Runs headed locally, `xvfb-run` in CI. Don't "optimize" to
headless.
- **Full-Chromium channel**: always `channel:'chromium'` — the headless-shell
strips the extension subsystem; never switch to it. Under the full channel,
headless **works** (`HEADED=0`; verified 2026-06-10 on macOS + Linux CI,
recordVideo included); the local default stays headed for debuggability.
Headed-under-xvfb needs a 24-bit screen
(`xvfb-run -a --server-args="-screen 0 1920x1080x24"` — the 8-bit default
breaks `Page.captureScreenshot`).
- **Caption band stacks UNDER the shot** (scene captured at `height - bandHeight`,
band appended) so the final image is the exact preset size and no UI is hidden.
- **`promo.js` innerHTML** is trusted, build-time content only (the repo's own
Expand Down
4 changes: 2 additions & 2 deletions README.ko.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
## 상태와 범위 (Status & Scope)

- **현재 구현된 것** — Playwright 캡처 **엔진**(빌드 → `--load-extension`으로 *빌드된* 익스텐션 로드 → scene 구동 → 스크린샷 → 캡션/면책 밴드 → HTML 프로모 타일 → 데모 `webm` → `STORE_LISTING.md`에서 문안 추출), **에이전트 계약**을 갖춘 **CLI**(`shotkit` — `--json` 머신 출력, 선택적 `path` 인자, `0/1/2` 종료 코드), 양쪽 용도 **사이즈 프리셋**(CWS `1280×800`/`440×280`, SNS `1200×675`/`1200×630`/`1080×1080`), **path-traversal 안전** 로컬 픽스처 서버, 프로그램 API(`capture()`), **Claude Code skill**([`skills/capture/`](skills/capture/SKILL.md)), 셸을 가진 어떤 코딩 에이전트든 호출법을 읽을 수 있는 **AGENTS.md 실행 블록**, 그리고 **npm 패키지** [`@starter-series/shotkit`](https://www.npmjs.com/package/@starter-series/shotkit). `browser-extension-starter`·`skillBridge`가 소비.
- **계획된 것** — **capture-in-CI GitHub Action**(공식 Playwright 이미지 + `xvfb`로 캡처를 CI에서 돌리고 `store-assets/`를 artifact로 업로드 — 로컬 브라우저 0); `starter-series` 플러그인 **마켓플레이스** 등재; **동영상 편집**(`webm → mp4`, 트림, 캡션).
- **계획된 것** — `starter-series` 플러그인 **마켓플레이스** 등재; **동영상 편집**(`webm → mp4`, 트림, 캡션). (capture-in-CI GitHub Action은 ✅ — `browser-extension-starter`의 `capture.yml`로 출하, headless 기본.)
- **설계 의도** — *엔진 1개, 표면 여러 개 — 단, 도구 성격에 맞는 표면.* shotkit은 무겁고 파일을 산출하는 빌드 도구라 표면이 CLI(+`--json`)·skill·CI입니다 — MCP가 아니라(하지 않기로 한 것 참고). 캡처는 **결정적**(로그인 불필요 픽스처, freeze된 데이터)이고, 실행이 **실제 빌드본 smoke test를 겸함** — 스크린샷이 나온다 = 그 기능이 출하 코드에서 렌더됨. 모든 샷에 면책 밴드를 합성해 **상표 안전**.
- **하지 않기로 한 것** — **MCP 서버**(의도적으로 폐기: 셸이 있는 에이전트에는 `--json` + skill이 세션당 컨텍스트 비용 없이 더 나은 계약이며, 여기엔 빠른 구조화 질의가 없음). repo별 **scene 설정** 제거(어떤 화면이 *당신의* money shot인지는 환원 불가한 의도 — `shotkit.config.js`에 둠). 범용 동영상 편집기(v1은 깔끔한 녹화만; 편집은 계획). 호스티드 서비스(파일을 만지는 캡처는 본질적으로 로컬).
- **공개하지 않음** — 없음.
Expand All @@ -38,7 +38,7 @@ npx playwright install chromium # 최초 1회: shotkit이 구동할 브라우
npx @starter-series/shotkit
```

> MV3 익스텐션 로드는 **headed** Chromium이 필요합니다 — 로컬 headed, CI는 `xvfb-run`.
> shotkit은 **풀 Chromium**(`channel: 'chromium'`)을 구동합니다 — 확장 서브시스템이 없는 headless-shell이 아닙니다. **headless 동작 검증 완료**(`HEADED=0`; macOS·Linux CI, 영상 포함)이며 starter capture 워크플로의 기본값입니다. 로컬 기본은 디버깅 편의상 headed. CI에서 headed가 필요하면 xvfb에 24비트 화면을 주십시오(`--server-args="-screen 0 1920x1080x24"` — 8비트 기본값은 스크린샷 캡처가 깨집니다).

## 사용

Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Screenshots · promo images · demo screencast · listing copy. One command.
## 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 → demo `webm` → listing copy from `STORE_LISTING.md`), a **CLI** (`shotkit`) with an **agent contract** (`--json` machine output, optional `path` argument, `0/1/2` exit codes), **size presets** for both audiences (CWS `1280×800`/`440×280`, SNS `1200×675`/`1200×630`/`1080×1080`), a **path-traversal-safe** localhost fixture server, a programmatic API (`capture()`), a **Claude Code skill** ([`skills/capture/`](skills/capture/SKILL.md)), an **AGENTS.md run-block** so any shell-having coding agent can invoke it, and the **npm package** [`@starter-series/shotkit`](https://www.npmjs.com/package/@starter-series/shotkit). Consumed by `browser-extension-starter` and `skillBridge`.
- **Planned** — a **capture-in-CI GitHub Action** (run the capture under `xvfb` on the official Playwright image and upload `store-assets/` as an artifact — zero local browser); a listing in the `starter-series` plugin **marketplace**; **video editing** (`webm → mp4`, trim, captions) for SNS.
- **Planned** — a listing in the `starter-series` plugin **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 your `shotkit.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.
Expand All @@ -41,7 +41,7 @@ Zero-install in any repo that has a config:
npx @starter-series/shotkit
```

> Loading an MV3 extension requires a **headed** Chromium — runs headed locally, under `xvfb-run` in CI. Set `HEADED=0` to force headless (not recommended for extensions).
> shotkit launches the **full Chromium** (`channel: 'chromium'`) — never the default headless-shell, which strips the extension subsystem. **Headless works** (`HEADED=0`; verified on macOS and Linux CI, video included) and is the CI default in the starter's capture workflow; the local default stays headed for easy debugging. If you need headed-under-xvfb in CI, give xvfb a 24-bit screen (`xvfb-run -a --server-args="-screen 0 1920x1080x24"`) — the 8-bit default breaks Chromium's screenshot capture.

## Usage

Expand Down Expand Up @@ -121,7 +121,7 @@ module.exports = {
| Claude Code skill ([`skills/capture/`](skills/capture/SKILL.md)) | ✅ 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 |
| Capture-in-CI GitHub Action | ✅ now — ships in [`browser-extension-starter`](https://github.com/starter-series/browser-extension-starter)'s `capture.yml` (headless default, 24-bit-xvfb fallback) | zero-local-browser runs + CI smoke test |
| `starter-series` marketplace entry | planned | discovery |
| Video editing (`webm→mp4`, trim, captions) | planned | SNS clips |

Expand Down
6 changes: 4 additions & 2 deletions skills/capture/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ rendered from the shipped code.

## Notes

- Loading an MV3 extension needs a **headed** Chromium: works as-is locally;
use `xvfb-run` in CI.
- Runs the full-Chromium channel; headless works (`HEADED=0 npx …` — verified,
video included) and is the right mode for CI. If headed-in-CI is required,
use `xvfb-run -a --server-args="-screen 0 1920x1080x24"` (the 8-bit xvfb
default breaks Chromium screenshots).
- Scenes are the repo's own config — to change *what* is captured, edit
`shotkit.config.js`, not shotkit.
11 changes: 6 additions & 5 deletions src/launch.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@
* back the dynamically-assigned extension ID. The launch flags mirror the
* ones a Playwright extension E2E suite needs — they're not optional:
*
* channel: 'chromium' + headless:false
* channel: 'chromium'
* The default headless-shell strips the extension subsystem entirely
* (no service worker, MV3 onInstalled never fires). The full Chromium
* channel run headed (or under xvfb in CI) is the only reliable way to
* load MV3 extensions and have content scripts inject. Set HEADED=0 at
* your own risk.
* (no service worker, MV3 onInstalled never fires) — the full Chromium
* channel is required. Under it, headless ALSO works (HEADED=0; verified
* 2026-06-10 on macOS + Linux CI, recordVideo included). The local
* default stays headed for easy debugging. Headed-under-xvfb needs a
* 24-bit screen (--server-args="-screen 0 1920x1080x24").
*
* --disable-features=DisableLoadExtensionCommandLineSwitch
* Chromium 121+ guards --load-extension behind this flag by default.
Expand Down