paper-snapshot-cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +187 -0
- package/dist/bin.mjs +55374 -0
- package/package.json +72 -0
- package/skills/paper-snapshot/SKILL.md +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jeremy Osih
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# paper-snapshot
|
|
2
|
+
|
|
3
|
+
Paper Snapshot as a CLI. Copy and paste your real site directly into Paper as editable layers. No more screenshots.
|
|
4
|
+
|
|
5
|
+
Give paper-snapshot a URL, a local dev server, or a tab an agent already clicked its way to. It
|
|
6
|
+
loads the page, captures it (or a single element) with [Paper Snapshot](https://paper.design/snapshot-extension)'s
|
|
7
|
+
own serializer, and writes the result into the Paper file you have open as a new artboard: real
|
|
8
|
+
text, real layout, real colors and images, every layer editable. It is the Paper Snapshot
|
|
9
|
+
extension without the clicking, so an agent can bring a whole app into Paper in one command and
|
|
10
|
+
refresh any screen when the app changes.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
paper-snapshot needs Node 22 or later, the [Paper](https://paper.design/downloads) app running
|
|
15
|
+
(for pushing into a file), and a Chromium-based browser. An installed Chrome, Edge, Brave or
|
|
16
|
+
Chromium is found automatically; with none, a headless Chromium is downloaded once.
|
|
17
|
+
|
|
18
|
+
Run it without installing anything:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
npx paper-snapshot-cli https://linear.app
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Or install the `paper-snapshot` command:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
npm install -g paper-snapshot-cli
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The first run downloads the Paper Snapshot extension from the Chrome Web Store and caches it in
|
|
31
|
+
`~/.cache/paper-snapshot`. Nothing from Paper ships in this repository.
|
|
32
|
+
|
|
33
|
+
## Agents
|
|
34
|
+
|
|
35
|
+
Install the agent skill for Claude Code, OpenCode, Codex and other agents:
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
npx skills add jeremyosih/paper-snapshot --skill paper-snapshot -g
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
With the skill, an agent picks the source (a URL, or the browser it drove), sets up state such as
|
|
42
|
+
sign-in, theme and open menus with flags instead of scripts, places the artboards, and runs with
|
|
43
|
+
`--json`. Each capture prints one line with the artboard id, position, size and `warnings`, a count
|
|
44
|
+
of anything that won't import cleanly, so the agent can screenshot the artboards that need a look
|
|
45
|
+
and report the rest. The skill also tells the agent which steps wait on you, such as Chrome's
|
|
46
|
+
**Allow** dialog, so you hear about them before the command blocks.
|
|
47
|
+
|
|
48
|
+
## Usage
|
|
49
|
+
|
|
50
|
+
```sh
|
|
51
|
+
# A whole page, into the Paper file you have open
|
|
52
|
+
paper-snapshot https://linear.app
|
|
53
|
+
|
|
54
|
+
# One element of a local dev server, at phone size
|
|
55
|
+
paper-snapshot http://localhost:3000 -s "#pricing" --width 390 --height 844
|
|
56
|
+
|
|
57
|
+
# Several screens side by side (paths resolve against the first URL)
|
|
58
|
+
paper-snapshot http://localhost:3000/ /pricing /settings --layout row
|
|
59
|
+
|
|
60
|
+
# A batch from a manifest, one JSON line per artboard
|
|
61
|
+
paper-snapshot --manifest screens.json --json
|
|
62
|
+
|
|
63
|
+
# Refresh an existing artboard after the app changed (same id, position and name)
|
|
64
|
+
paper-snapshot http://localhost:3000/settings --replace 1A-0
|
|
65
|
+
|
|
66
|
+
# App state without scripting: dark theme kept in storage, a session cookie, an open menu
|
|
67
|
+
paper-snapshot http://localhost:3000 --local-storage theme=dark --color-scheme dark \
|
|
68
|
+
--cookie "session=…" --click "[data-testid=account-menu]"
|
|
69
|
+
|
|
70
|
+
# The tab agent-browser is on, after it logged in and opened a dialog
|
|
71
|
+
paper-snapshot
|
|
72
|
+
|
|
73
|
+
# A tab in your everyday Chrome (click Allow when Chrome asks)
|
|
74
|
+
paper-snapshot --source chrome --tab localhost:3000
|
|
75
|
+
|
|
76
|
+
# Just the HTML, or the extension's exact clipboard payload for a manual ⌘V
|
|
77
|
+
paper-snapshot https://example.com --out snap.html
|
|
78
|
+
paper-snapshot https://example.com --clipboard
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Every behaviour is a flag with a default: viewport, color scheme, page state, timeouts, scrolling,
|
|
82
|
+
fidelity passes, and the target file, page and position in Paper. `paper-snapshot --help` lists
|
|
83
|
+
them all.
|
|
84
|
+
|
|
85
|
+
## Browsers
|
|
86
|
+
|
|
87
|
+
Pages come from one of five places, chosen with `--source`:
|
|
88
|
+
|
|
89
|
+
| Source | Page comes from | What you do |
|
|
90
|
+
| --------------- | ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
|
|
91
|
+
| `launch` | A headless copy of your installed Chrome. The default when a URL is given | Nothing |
|
|
92
|
+
| `agent-browser` | The tab [agent-browser](https://github.com/vercel-labs/agent-browser) is driving. The default without a URL | Keep an agent-browser session open |
|
|
93
|
+
| `chrome` | Your everyday Chrome, with your logins. Tried after agent-browser when no URL is given | Turn on `chrome://inspect/#remote-debugging` once, then click **Allow** on each run |
|
|
94
|
+
| `playwriter` | Your Chrome through the [Playwriter](https://github.com/remorses/playwriter) extension | Connect the extension to its relay |
|
|
95
|
+
| `cdp` | Any Chrome DevTools Protocol endpoint (`--cdp`) | Start that browser with remote debugging |
|
|
96
|
+
|
|
97
|
+
Attaching lets an agent click, type and sign in first, then capture exactly that state. Attached
|
|
98
|
+
browsers are never closed. Passing a URL while attached opens a temporary tab and closes it after;
|
|
99
|
+
without a URL, `--tab <text>` picks the tab whose URL or title contains the text, and otherwise
|
|
100
|
+
the visible one.
|
|
101
|
+
|
|
102
|
+
With `--source chrome`, Chrome shows **Allow remote debugging?** each time paper-snapshot connects,
|
|
103
|
+
on the machine Chrome runs on, and keeps a "controlled by automated test software" banner up while
|
|
104
|
+
it's attached. The command waits for you, up to `--chrome-approval-timeout` (2 minutes); **Cancel**
|
|
105
|
+
fails it. A batch connects once, so it asks once. paper-snapshot reads Chrome's port from its
|
|
106
|
+
`DevToolsActivePort` file; when macOS hides that file from the calling app, it connects to
|
|
107
|
+
`127.0.0.1:9222` instead (`--chrome-port`).
|
|
108
|
+
|
|
109
|
+
## Batches and placement
|
|
110
|
+
|
|
111
|
+
Several URLs, or a `--manifest` JSON file, run as one batch over one browser and one Paper
|
|
112
|
+
connection. Each capture prints its own JSON line, and a failed capture prints
|
|
113
|
+
`{"index", "url", "error"}` without stopping the rest; the exit code is 1 if any failed.
|
|
114
|
+
|
|
115
|
+
A manifest item is a URL, or an object whose fields mirror the flags in camelCase.
|
|
116
|
+
`{ "defaults": {…}, "items": […] }` shares fields:
|
|
117
|
+
|
|
118
|
+
```json
|
|
119
|
+
{
|
|
120
|
+
"defaults": { "width": 1440, "storageState": "member.json" },
|
|
121
|
+
"items": [
|
|
122
|
+
{ "url": "/", "name": "Home · light" },
|
|
123
|
+
{
|
|
124
|
+
"url": "/",
|
|
125
|
+
"name": "Home · dark",
|
|
126
|
+
"colorScheme": "dark",
|
|
127
|
+
"localStorage": { "theme": "dark" }
|
|
128
|
+
},
|
|
129
|
+
{ "url": "/settings", "replace": "1A-0" }
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
New artboards follow `--layout row|column|grid` (with `--columns` and `--gap`) from the first
|
|
135
|
+
one, which `--x/--y`, `--below <artboardId>` or `--right-of <artboardId>` anchor. Without an
|
|
136
|
+
anchor, Paper picks an empty spot. `--replace <artboardId>` re-captures into an existing artboard
|
|
137
|
+
and keeps its id, position and name; `--file-id` and `--page-id` choose where new ones go.
|
|
138
|
+
|
|
139
|
+
## Fidelity
|
|
140
|
+
|
|
141
|
+
Before serializing, paper-snapshot adjusts the page so it imports the way it renders, and undoes
|
|
142
|
+
every change afterwards:
|
|
143
|
+
|
|
144
|
+
| Problem | What paper-snapshot does | Flag |
|
|
145
|
+
| ---------------------------------------------------------------------------- | ------------------------------------------------------------------ | --------------------- |
|
|
146
|
+
| App shells (`h-screen` with an `overflow: auto` main) cut off below the fold | Grows the viewport until no scroll container clips | `--full-page` |
|
|
147
|
+
| Icons from external SVG sprites import empty | Fetches the sprite and inlines the symbol with its computed colors | `--inline-sprites` |
|
|
148
|
+
| A `colspan` cell imports one column wide | Freezes the table into rows and cells at their rendered widths | `--fix-colspans` |
|
|
149
|
+
| `height: auto` images collapse | Pins rendered image heights | `--pin-image-heights` |
|
|
150
|
+
| Paper can't fetch images from localhost | Inlines them as data URIs | `--inline-images` |
|
|
151
|
+
|
|
152
|
+
Each pass is on by default; `--no-<flag>` turns one off. Whatever still won't import cleanly is
|
|
153
|
+
counted in the `warnings` of each JSON line: `emptySvgs`, `unresolvedSprites`,
|
|
154
|
+
`clippedScrollContainers`, `unresolvedImages` and `lostColspans`.
|
|
155
|
+
|
|
156
|
+
`--color-scheme` only flips the `prefers-color-scheme` media query. Apps that keep their theme in
|
|
157
|
+
storage also need `--local-storage <key>=dark`.
|
|
158
|
+
|
|
159
|
+
## How it works
|
|
160
|
+
|
|
161
|
+
The Paper Snapshot extension walks the element you pick, keeps only the computed styles that
|
|
162
|
+
differ from the browser's defaults, folds in pseudo-elements, canvas and video frames, form state
|
|
163
|
+
and same-document SVG references, and copies the resulting HTML to the clipboard wrapped in
|
|
164
|
+
`<x-paper-html>`. Paper turns that paste into layers.
|
|
165
|
+
|
|
166
|
+
paper-snapshot downloads the extension from the Chrome Web Store, evaluates its scripts in a
|
|
167
|
+
sandbox, and finds that serializer by what it does, not by its minified name, so new releases of
|
|
168
|
+
the extension keep working. It runs the serializer in the page through the Chrome DevTools
|
|
169
|
+
Protocol, then writes the HTML into a new artboard through the MCP relay that ships with the Paper
|
|
170
|
+
app (`~/.paper/bin/paper mcp`). `--clipboard` writes the extension's exact clipboard payload
|
|
171
|
+
instead.
|
|
172
|
+
|
|
173
|
+
## Development
|
|
174
|
+
|
|
175
|
+
```sh
|
|
176
|
+
bun install && bun run setup && bun run hooks:setup # dependencies, Effect diagnostics, git hooks
|
|
177
|
+
bun run check # oxfmt and oxlint with anti-slop (vite-plus), tsc with Effect diagnostics, knip
|
|
178
|
+
bun run build # dist/bin.mjs, committed so installs from GitHub need no build
|
|
179
|
+
bun run dev -- https://example.com --out -
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Built with [Effect](https://effect.website) 4 and its CLI module. Paper and Paper Snapshot are
|
|
183
|
+
products of Paper; this project is not affiliated with them.
|
|
184
|
+
|
|
185
|
+
## License
|
|
186
|
+
|
|
187
|
+
MIT
|