clipwise 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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 kwakseongjae
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,359 @@
1
+ # Clipwise
2
+
3
+ Scriptable cinematic screen recorder for product demos — YAML in, polished MP4 out. Powered by Playwright CDP.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ # Install
9
+ npm install -D clipwise
10
+
11
+ # Try the built-in demo instantly
12
+ npx clipwise demo
13
+
14
+ # Or create your own scenario
15
+ npx clipwise init # Creates clipwise.yaml template
16
+ # Edit clipwise.yaml — change URL to your site
17
+ npx clipwise record clipwise.yaml -f mp4 # Record!
18
+ ```
19
+
20
+ ## Requirements
21
+
22
+ - **Node.js** >= 18
23
+ - **ffmpeg** (for MP4 output)
24
+ - **Chromium** (auto-installed on first run via Playwright)
25
+
26
+ ```bash
27
+ # macOS
28
+ brew install ffmpeg
29
+
30
+ # Ubuntu
31
+ sudo apt install ffmpeg
32
+
33
+ # Windows
34
+ choco install ffmpeg
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ ### CLI Commands
40
+
41
+ ```bash
42
+ # Instant demo — records the built-in dashboard showcase
43
+ npx clipwise demo # Browser frame, MP4
44
+ npx clipwise demo --device iphone # iPhone mockup
45
+ npx clipwise demo --device android # Android mockup
46
+ npx clipwise demo --device ipad # iPad mockup
47
+ npx clipwise demo --url https://my-app.com # Your deployed site
48
+
49
+ # Record from YAML scenario
50
+ npx clipwise record <scenario.yaml> -f mp4 -o ./output
51
+ npx clipwise record <scenario.yaml> -f gif -o ./output
52
+
53
+ # Initialize a template
54
+ npx clipwise init
55
+
56
+ # Validate without recording
57
+ npx clipwise validate <scenario.yaml>
58
+ ```
59
+
60
+ ### Programmatic API
61
+
62
+ ```typescript
63
+ import { ClipwiseRecorder, CanvasRenderer, encodeMp4, loadScenario } from "clipwise";
64
+
65
+ const scenario = await loadScenario("my-scenario.yaml");
66
+ const recorder = new ClipwiseRecorder();
67
+ const session = await recorder.record(scenario);
68
+
69
+ const renderer = new CanvasRenderer(scenario.effects, scenario.output, scenario.steps);
70
+ const frames = await renderer.composeAll(session.frames);
71
+
72
+ const mp4 = await encodeMp4(frames, scenario.output);
73
+ ```
74
+
75
+ ## YAML Scenario Format
76
+
77
+ A scenario has 4 sections: metadata, effects, output, and steps.
78
+
79
+ ```yaml
80
+ name: "My Demo"
81
+ description: "Optional description"
82
+
83
+ viewport:
84
+ width: 1280 # Browser width (default: 1280)
85
+ height: 800 # Browser height (default: 800)
86
+
87
+ effects:
88
+ # See "Effects" section below
89
+
90
+ output:
91
+ format: mp4 # gif | mp4 | png-sequence
92
+ width: 1280
93
+ height: 800
94
+ fps: 30 # 1-60
95
+ quality: 80 # 1-100 (MP4: maps to CRF)
96
+
97
+ steps:
98
+ - name: "Step name"
99
+ actions:
100
+ - action: navigate
101
+ url: "https://example.com"
102
+ captureDelay: 200 # ms to wait after actions
103
+ holdDuration: 800 # ms to hold on result
104
+ transition: none # none | fade
105
+ ```
106
+
107
+ ### Actions
108
+
109
+ | Action | Parameters | Description |
110
+ |--------|-----------|-------------|
111
+ | `navigate` | `url`, `waitUntil?` | Navigate to URL |
112
+ | `click` | `selector`, `delay?` | Click an element |
113
+ | `type` | `selector`, `text`, `delay?` | Type text (char-by-char) |
114
+ | `hover` | `selector` | Hover over element |
115
+ | `scroll` | `y?`, `x?`, `selector?`, `smooth?` | Scroll by offset |
116
+ | `wait` | `duration` | Wait (ms) |
117
+ | `screenshot` | `name?`, `fullPage?` | Capture marker |
118
+
119
+ **`waitUntil`** options: `"load"`, `"domcontentloaded"`, `"networkidle"` (default)
120
+
121
+ ### Timing Tips
122
+
123
+ For snappy demos (~30 seconds):
124
+ - `captureDelay: 50-100` ms
125
+ - `holdDuration: 500-800` ms
126
+ - `type.delay: 15-25` ms per character
127
+
128
+ For slower, cinematic demos:
129
+ - `captureDelay: 200-400` ms
130
+ - `holdDuration: 1500-2500` ms
131
+ - `type.delay: 40-60` ms per character
132
+
133
+ ## Effects
134
+
135
+ All effects are optional and have sensible defaults.
136
+
137
+ ### Zoom
138
+
139
+ Adaptive zoom follows cursor and zooms in on click targets.
140
+
141
+ ```yaml
142
+ zoom:
143
+ enabled: true
144
+ scale: 1.8 # Peak zoom level (1-5)
145
+ duration: 500 # Zoom animation ms
146
+ autoZoom:
147
+ followCursor: true
148
+ maxScale: 2.0
149
+ transitionDuration: 300
150
+ padding: 200
151
+ ```
152
+
153
+ ### Cursor
154
+
155
+ Custom cursor with click ripple, trail, glow highlight, and speed control.
156
+
157
+ ```yaml
158
+ cursor:
159
+ enabled: true
160
+ size: 20
161
+ speed: "fast" # fast (~72ms) | normal (~144ms) | slow (~288ms)
162
+ clickEffect: true
163
+ clickColor: "rgba(59, 130, 246, 0.3)"
164
+ trail: true
165
+ trailLength: 6
166
+ highlight: true
167
+ highlightRadius: 35
168
+ ```
169
+
170
+ ### Background
171
+
172
+ Gradient/solid padding with rounded corners and shadow.
173
+
174
+ ```yaml
175
+ background:
176
+ type: gradient # gradient | solid | image
177
+ value: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
178
+ padding: 48
179
+ borderRadius: 14
180
+ shadow: true
181
+ ```
182
+
183
+ ### Device Frame
184
+
185
+ Wraps the recording in a device mockup.
186
+
187
+ ```yaml
188
+ deviceFrame:
189
+ enabled: true
190
+ type: browser # browser | iphone | ipad | android | none
191
+ darkMode: true
192
+ ```
193
+
194
+ | Type | Description |
195
+ |------|-------------|
196
+ | `browser` | macOS browser chrome with traffic lights |
197
+ | `iphone` | iPhone 15 Pro with Dynamic Island + home bar |
198
+ | `ipad` | iPad Pro with front camera dot |
199
+ | `android` | Android generic with punch-hole camera |
200
+
201
+ ### Keystroke HUD
202
+
203
+ Displays typed keys at the bottom of the screen.
204
+
205
+ ```yaml
206
+ keystroke:
207
+ enabled: true
208
+ position: bottom-center
209
+ fontSize: 16
210
+ fadeAfter: 1500
211
+ ```
212
+
213
+ ### Watermark
214
+
215
+ Text overlay at a corner.
216
+
217
+ ```yaml
218
+ watermark:
219
+ enabled: true
220
+ text: "Clipwise"
221
+ position: bottom-right
222
+ opacity: 0.5
223
+ ```
224
+
225
+ ### Speed Ramp
226
+
227
+ Automatically slows down near clicks and speeds up idle sections.
228
+
229
+ ```yaml
230
+ speedRamp:
231
+ enabled: true
232
+ idleSpeed: 3.0 # Skip factor for idle frames
233
+ actionSpeed: 0.8 # Slow factor near clicks
234
+ ```
235
+
236
+ ## Output Compression
237
+
238
+ MP4 output uses `libx264` with `slow` preset and `animation` tuning for best quality-per-byte. The `quality` field maps to CRF:
239
+
240
+ | quality | CRF | Use case |
241
+ |---------|-----|----------|
242
+ | 90-100 | 0-5 | Lossless / archival |
243
+ | 70-85 | 8-15 | High quality demos |
244
+ | 50-70 | 15-26 | Web sharing |
245
+ | 30-50 | 26-36 | Small file size |
246
+
247
+ **Recommended**: `quality: 80` for most demos (CRF ~10, good visual quality, ~3-7 MB for 30s).
248
+
249
+ For further compression after export:
250
+
251
+ ```bash
252
+ # Re-encode with tighter CRF
253
+ ffmpeg -i input.mp4 -c:v libx264 -crf 26 -preset slow -movflags +faststart output.mp4
254
+
255
+ # Convert to WebM (smaller, web-native)
256
+ ffmpeg -i input.mp4 -c:v libvpx-vp9 -crf 30 -b:v 0 output.webm
257
+ ```
258
+
259
+ ## Writing Your Own Scenario
260
+
261
+ 1. **Create your target page** — any URL (localhost, file://, or remote)
262
+
263
+ 2. **Create a YAML file** with your steps:
264
+
265
+ ```yaml
266
+ name: "My App Demo"
267
+ viewport:
268
+ width: 1280
269
+ height: 800
270
+
271
+ effects:
272
+ deviceFrame:
273
+ enabled: true
274
+ type: browser
275
+ background:
276
+ padding: 48
277
+ borderRadius: 14
278
+
279
+ output:
280
+ format: mp4
281
+ fps: 30
282
+ quality: 80
283
+
284
+ steps:
285
+ - name: "Open app"
286
+ captureDelay: 100
287
+ holdDuration: 1000
288
+ actions:
289
+ - action: navigate
290
+ url: "http://localhost:3000"
291
+ waitUntil: networkidle
292
+
293
+ - name: "Click login"
294
+ captureDelay: 50
295
+ holdDuration: 800
296
+ actions:
297
+ - action: click
298
+ selector: "#login-btn"
299
+
300
+ - name: "Type email"
301
+ captureDelay: 50
302
+ holdDuration: 600
303
+ actions:
304
+ - action: click
305
+ selector: "input[name=email]"
306
+ - action: type
307
+ selector: "input[name=email]"
308
+ text: "demo@example.com"
309
+ delay: 20
310
+ ```
311
+
312
+ 3. **Record**:
313
+
314
+ ```bash
315
+ npx clipwise record my-scenario.yaml -f mp4 -o ./output
316
+ ```
317
+
318
+ ### Tips
319
+
320
+ - Use CSS selectors (`#id`, `.class`, `[data-testid=...]`) for reliable targeting
321
+ - Start each interaction with enough scroll to make the target element visible
322
+ - Use `waitUntil: "networkidle"` for pages with API calls
323
+ - Keep `type.delay` at 15-25ms for a fast but readable typing effect
324
+ - Use `transition: fade` between major sections for cinematic cuts
325
+
326
+ ## Hosting the Demo Site (GitHub Pages)
327
+
328
+ Clipwise includes a demo dashboard in `docs/index.html`. To host it:
329
+
330
+ 1. Push to GitHub: `git push origin main`
331
+ 2. Go to **Settings > Pages**
332
+ 3. Set source to **Deploy from a branch**, select `main`, folder `/docs`
333
+ 4. Demo goes live at `https://kwakseongjae.github.io/clipwise/`
334
+
335
+ Then anyone can record the demo site:
336
+
337
+ ```bash
338
+ npx clipwise demo --url https://kwakseongjae.github.io/clipwise/
339
+ ```
340
+
341
+ ## Security
342
+
343
+ - **Selector validation**: All CSS selectors in YAML are validated against a safe character allowlist
344
+ - **URL handling**: Only `http://`, `https://`, and `file://` schemes are accepted
345
+ - **Chromium sandbox**: Playwright runs Chromium with default sandboxing
346
+ - **Local processing**: Recordings are processed locally — frames never leave your machine
347
+
348
+ ## Development
349
+
350
+ ```bash
351
+ npm install # Install dependencies
352
+ npm run build # Build with tsup
353
+ npm run typecheck # Type check
354
+ npm test # Run tests (vitest)
355
+ ```
356
+
357
+ ## License
358
+
359
+ MIT
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node