clipwise 0.5.0 → 0.5.2
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/README.ko.md +32 -1
- package/README.md +32 -1
- package/dist/cli/index.js +52 -4
- package/package.json +2 -1
- package/skills/clipwise.md +373 -0
package/README.ko.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
YAML 시나리오를 작성하면 시네마틱 데모 영상(MP4/GIF)을 자동으로 만들어주는 스크린 레코더. Playwright CDP 기반.
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
<img src="
|
|
8
|
+
<img src="./docs/demo.gif" alt="Clipwise 데모" width="100%" />
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
> *`npx clipwise demo` 한 줄로 생성된 영상입니다 — YAML 파일 1개, 239줄.*
|
|
@@ -337,6 +337,37 @@ VideoToolbox는 런타임에 자동 감지되며, 사용 불가 시 `libx264`로
|
|
|
337
337
|
|
|
338
338
|
[PROMPTS.md](./PROMPTS.md)에 바로 사용할 수 있는 AI 프롬프트 템플릿이 있습니다. ChatGPT나 Claude에 복붙하고 내 사이트 URL만 넣으면 YAML 시나리오를 생성해줍니다.
|
|
339
339
|
|
|
340
|
+
## Claude Code 스킬
|
|
341
|
+
|
|
342
|
+
Clipwise에는 [Claude Code](https://claude.com/claude-code) 스킬이 내장되어 있습니다. 설치 후 Claude Code에서 `/clipwise`를 입력하면 자연어로 YAML 시나리오 생성, 검증, 녹화까지 한 번에 할 수 있습니다.
|
|
343
|
+
|
|
344
|
+
### 스킬 설치
|
|
345
|
+
|
|
346
|
+
```bash
|
|
347
|
+
npx clipwise install-skill
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
`.claude/skills/clipwise.md`에 스킬 파일이 복사됩니다 (`.claude/` 디렉토리가 있으면 프로젝트 레벨, 없으면 `~/.claude/skills/`에 설치).
|
|
351
|
+
|
|
352
|
+
### 사용법
|
|
353
|
+
|
|
354
|
+
Claude Code 세션에서:
|
|
355
|
+
|
|
356
|
+
```
|
|
357
|
+
/clipwise
|
|
358
|
+
> http://localhost:3000 대시보드 데모 녹화해줘
|
|
359
|
+
— 로그인 버튼 클릭, 이메일/비밀번호 입력, 분석 페이지 이동
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
Claude가 자동으로:
|
|
363
|
+
1. `clipwise.yaml` 시나리오 생성
|
|
364
|
+
2. `npx clipwise validate`로 검증
|
|
365
|
+
3. `npx clipwise record`로 MP4 녹화
|
|
366
|
+
|
|
367
|
+
### 업데이트
|
|
368
|
+
|
|
369
|
+
clipwise 업그레이드 후 `npx clipwise install-skill`을 다시 실행하면 최신 스킬로 업데이트됩니다.
|
|
370
|
+
|
|
340
371
|
## GitHub Pages
|
|
341
372
|
|
|
342
373
|
`docs/` 폴더에 문서 사이트와 라이브 데모 대시보드가 포함되어 있습니다:
|
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
Scriptable cinematic screen recorder for product demos — YAML in, polished MP4 out. Powered by Playwright CDP.
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
<img src="
|
|
8
|
+
<img src="./docs/demo.gif" alt="Clipwise demo" width="100%" />
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
> *Generated with `npx clipwise demo` — 1 YAML file, 239 lines, one command.*
|
|
@@ -421,6 +421,37 @@ npx clipwise record my-scenario.yaml -f mp4 -o ./output
|
|
|
421
421
|
|
|
422
422
|
See [PROMPTS.md](./PROMPTS.md) for a ready-to-use prompt template. Copy-paste it to ChatGPT or Claude with your site URL, and get a working YAML scenario back.
|
|
423
423
|
|
|
424
|
+
## Claude Code Skill
|
|
425
|
+
|
|
426
|
+
Clipwise ships a built-in [Claude Code](https://claude.com/claude-code) skill. Once installed, type `/clipwise` in Claude Code to generate YAML scenarios, validate, and record — all through natural language.
|
|
427
|
+
|
|
428
|
+
### Install the skill
|
|
429
|
+
|
|
430
|
+
```bash
|
|
431
|
+
npx clipwise install-skill
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
This copies the skill file to `.claude/skills/clipwise.md` (project-level if `.claude/` exists, otherwise `~/.claude/skills/`).
|
|
435
|
+
|
|
436
|
+
### Usage
|
|
437
|
+
|
|
438
|
+
In any Claude Code session:
|
|
439
|
+
|
|
440
|
+
```
|
|
441
|
+
/clipwise
|
|
442
|
+
> Record a demo of my dashboard at http://localhost:3000
|
|
443
|
+
— click the login button, type credentials, navigate to analytics
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
Claude will:
|
|
447
|
+
1. Generate a complete `clipwise.yaml` scenario
|
|
448
|
+
2. Run `npx clipwise validate` to check for errors
|
|
449
|
+
3. Run `npx clipwise record` to produce the MP4
|
|
450
|
+
|
|
451
|
+
### Update
|
|
452
|
+
|
|
453
|
+
Re-run `npx clipwise install-skill` after upgrading clipwise to get the latest skill.
|
|
454
|
+
|
|
424
455
|
## GitHub Pages
|
|
425
456
|
|
|
426
457
|
Clipwise includes a documentation site and a live demo dashboard in the `docs/` folder. To host it:
|
package/dist/cli/index.js
CHANGED
|
@@ -2881,17 +2881,17 @@ var StreamingSession = class extends EventEmitter {
|
|
|
2881
2881
|
};
|
|
2882
2882
|
|
|
2883
2883
|
// src/cli/index.ts
|
|
2884
|
-
import { writeFile as writeFile2, mkdir as mkdir2, access } from "fs/promises";
|
|
2884
|
+
import { writeFile as writeFile2, mkdir as mkdir2, access, copyFile, readFile as readFile3 } from "fs/promises";
|
|
2885
2885
|
import { join as join2, resolve, dirname } from "path";
|
|
2886
|
-
import { pathToFileURL } from "url";
|
|
2886
|
+
import { pathToFileURL, fileURLToPath as fileURLToPath2 } from "url";
|
|
2887
|
+
import { homedir } from "os";
|
|
2887
2888
|
var program = new Command();
|
|
2888
2889
|
program.name("clipwise").description(
|
|
2889
2890
|
"Playwright-based cinematic screen recorder for product demos"
|
|
2890
2891
|
).version("0.1.0");
|
|
2891
2892
|
program.command("record").description("Record a demo from a YAML scenario file").argument("<scenario>", "Path to YAML scenario file").option("-o, --output <dir>", "Output directory", "./output").option(
|
|
2892
2893
|
"-f, --format <format>",
|
|
2893
|
-
"Output format (gif|mp4|png-sequence)"
|
|
2894
|
-
"gif"
|
|
2894
|
+
"Output format (gif|mp4|png-sequence)"
|
|
2895
2895
|
).option("--no-effects", "Disable all effects").action(async (scenarioPath, options) => {
|
|
2896
2896
|
const spinner = ora();
|
|
2897
2897
|
try {
|
|
@@ -3359,4 +3359,52 @@ Error: ${message}`));
|
|
|
3359
3359
|
process.exit(1);
|
|
3360
3360
|
}
|
|
3361
3361
|
});
|
|
3362
|
+
program.command("install-skill").description("Install the Clipwise skill for Claude Code").action(async () => {
|
|
3363
|
+
try {
|
|
3364
|
+
const __dirname = dirname(fileURLToPath2(import.meta.url));
|
|
3365
|
+
const skillSource = resolve(__dirname, "..", "..", "skills", "clipwise.md");
|
|
3366
|
+
try {
|
|
3367
|
+
await access(skillSource);
|
|
3368
|
+
} catch {
|
|
3369
|
+
console.error(chalk.red("Error: Skill file not found in clipwise package."));
|
|
3370
|
+
console.error(chalk.yellow("This may happen if you're running from source. Try: npm rebuild clipwise"));
|
|
3371
|
+
process.exit(1);
|
|
3372
|
+
}
|
|
3373
|
+
const projectSkillDir = resolve(".claude", "skills");
|
|
3374
|
+
const globalSkillDir = join2(homedir(), ".claude", "skills");
|
|
3375
|
+
let targetDir;
|
|
3376
|
+
try {
|
|
3377
|
+
await access(resolve(".claude"));
|
|
3378
|
+
targetDir = projectSkillDir;
|
|
3379
|
+
} catch {
|
|
3380
|
+
targetDir = globalSkillDir;
|
|
3381
|
+
}
|
|
3382
|
+
await mkdir2(targetDir, { recursive: true });
|
|
3383
|
+
const targetPath = join2(targetDir, "clipwise.md");
|
|
3384
|
+
try {
|
|
3385
|
+
const existing = await readFile3(targetPath, "utf-8");
|
|
3386
|
+
const incoming = await readFile3(skillSource, "utf-8");
|
|
3387
|
+
if (existing === incoming) {
|
|
3388
|
+
console.log(chalk.green("Clipwise skill is already up to date."));
|
|
3389
|
+
console.log(` Location: ${chalk.bold(targetPath)}`);
|
|
3390
|
+
console.log(`
|
|
3391
|
+
Use ${chalk.bold("/clipwise")} in Claude Code to get started.`);
|
|
3392
|
+
return;
|
|
3393
|
+
}
|
|
3394
|
+
} catch {
|
|
3395
|
+
}
|
|
3396
|
+
await copyFile(skillSource, targetPath);
|
|
3397
|
+
console.log(chalk.green("Clipwise skill installed successfully!"));
|
|
3398
|
+
console.log(` Location: ${chalk.bold(targetPath)}`);
|
|
3399
|
+
console.log(`
|
|
3400
|
+
Usage in Claude Code:`);
|
|
3401
|
+
console.log(` ${chalk.bold("/clipwise")} \u2014 Generate YAML scenarios, validate, and record demos`);
|
|
3402
|
+
console.log(`
|
|
3403
|
+
To update the skill later, run this command again.`);
|
|
3404
|
+
} catch (error) {
|
|
3405
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3406
|
+
console.error(chalk.red(`Failed to install skill: ${message}`));
|
|
3407
|
+
process.exit(1);
|
|
3408
|
+
}
|
|
3409
|
+
});
|
|
3362
3410
|
program.parse();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clipwise",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "Scriptable cinematic screen recorder for product demos — YAML in, polished MP4 out",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"files": [
|
|
12
12
|
"dist",
|
|
13
|
+
"skills",
|
|
13
14
|
"README.md",
|
|
14
15
|
"LICENSE"
|
|
15
16
|
],
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
# Clipwise — Cinematic Screen Recorder
|
|
2
|
+
|
|
3
|
+
You are an expert at creating Clipwise YAML scenarios. Clipwise is a Playwright + CDP-based scriptable screen recorder that turns YAML scenarios into polished MP4/GIF demo videos with cinematic effects (zoom, cursor trail, device frame, keystroke HUD, etc.).
|
|
4
|
+
|
|
5
|
+
TRIGGER: when the user wants to record a demo video, create a screen recording scenario, generate a product demo, or mentions "clipwise".
|
|
6
|
+
|
|
7
|
+
## Setup Check
|
|
8
|
+
|
|
9
|
+
Before creating a scenario, verify clipwise is installed:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npx clipwise --version
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
If not installed:
|
|
16
|
+
```bash
|
|
17
|
+
npm install -D clipwise
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
ffmpeg is required for MP4 output:
|
|
21
|
+
```bash
|
|
22
|
+
# macOS
|
|
23
|
+
brew install ffmpeg
|
|
24
|
+
# Ubuntu
|
|
25
|
+
sudo apt install ffmpeg
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## YAML Schema Reference
|
|
29
|
+
|
|
30
|
+
### Top-Level Structure
|
|
31
|
+
|
|
32
|
+
```yaml
|
|
33
|
+
name: string # Scenario name (required)
|
|
34
|
+
description: string # Optional description
|
|
35
|
+
|
|
36
|
+
viewport:
|
|
37
|
+
width: 1280 # Browser width (100-3840, default: 1280)
|
|
38
|
+
height: 800 # Browser height (100-3840, default: 800)
|
|
39
|
+
|
|
40
|
+
effects: # All optional, sensible defaults
|
|
41
|
+
zoom: ...
|
|
42
|
+
cursor: ...
|
|
43
|
+
background: ...
|
|
44
|
+
deviceFrame: ...
|
|
45
|
+
keystroke: ...
|
|
46
|
+
watermark: ...
|
|
47
|
+
speedRamp: ...
|
|
48
|
+
|
|
49
|
+
output:
|
|
50
|
+
format: mp4 # mp4 | gif | png-sequence
|
|
51
|
+
width: 1280 # Output width
|
|
52
|
+
height: 800 # Output height
|
|
53
|
+
fps: 30 # 1-60
|
|
54
|
+
preset: balanced # social | balanced | archive
|
|
55
|
+
outputDir: "./output"
|
|
56
|
+
filename: "my-recording"
|
|
57
|
+
|
|
58
|
+
steps: [] # Array of steps (min 1, first must have navigate)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Step Structure
|
|
62
|
+
|
|
63
|
+
```yaml
|
|
64
|
+
- name: "Step name" # Optional label
|
|
65
|
+
captureDelay: 50 # ms to wait after actions before capturing (50-100 for snappy)
|
|
66
|
+
holdDuration: 700 # ms to hold on result (500-800 for snappy)
|
|
67
|
+
transition: none # none | fade
|
|
68
|
+
actions: [] # Array of actions
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Actions (12 types)
|
|
72
|
+
|
|
73
|
+
#### Basic Actions
|
|
74
|
+
|
|
75
|
+
1. **navigate** — Open a URL (MUST be the first action in step 1)
|
|
76
|
+
```yaml
|
|
77
|
+
- action: navigate
|
|
78
|
+
url: "https://example.com"
|
|
79
|
+
waitUntil: load # load | domcontentloaded | networkidle (default)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
2. **click** — Click an element
|
|
83
|
+
```yaml
|
|
84
|
+
- action: click
|
|
85
|
+
selector: "#my-button"
|
|
86
|
+
delay: 0 # Optional click delay (ms)
|
|
87
|
+
timeout: 15000 # Optional element wait timeout
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
3. **type** — Type text character-by-character (auto-focuses the element)
|
|
91
|
+
```yaml
|
|
92
|
+
- action: type
|
|
93
|
+
selector: "#email-input"
|
|
94
|
+
text: "user@example.com"
|
|
95
|
+
delay: 18 # ms per character (15-25 recommended, default: 50)
|
|
96
|
+
timeout: 15000 # Optional
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
4. **hover** — Hover over an element
|
|
100
|
+
```yaml
|
|
101
|
+
- action: hover
|
|
102
|
+
selector: ".card"
|
|
103
|
+
timeout: 15000 # Optional
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
5. **scroll** — Scroll the page
|
|
107
|
+
```yaml
|
|
108
|
+
- action: scroll
|
|
109
|
+
y: 400 # Vertical px (positive=down, negative=up)
|
|
110
|
+
x: 0 # Horizontal px
|
|
111
|
+
selector: ".container" # Optional: scroll within element
|
|
112
|
+
smooth: true # Default: true
|
|
113
|
+
timeout: 15000 # Optional
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
6. **wait** — Pause for a fixed duration
|
|
117
|
+
```yaml
|
|
118
|
+
- action: wait
|
|
119
|
+
duration: 1000 # ms
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
7. **screenshot** — Capture marker (for png-sequence)
|
|
123
|
+
```yaml
|
|
124
|
+
- action: screenshot
|
|
125
|
+
name: "result" # Optional label
|
|
126
|
+
fullPage: false # Default: false
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
#### Async Wait Actions (for dynamic/API content)
|
|
130
|
+
|
|
131
|
+
8. **waitForSelector** — Wait for element state
|
|
132
|
+
```yaml
|
|
133
|
+
- action: waitForSelector
|
|
134
|
+
selector: ".result-panel"
|
|
135
|
+
state: visible # visible (default) | attached | hidden
|
|
136
|
+
timeout: 15000
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
9. **waitForNavigation** — Wait for page load
|
|
140
|
+
```yaml
|
|
141
|
+
- action: waitForNavigation
|
|
142
|
+
waitUntil: networkidle # load | domcontentloaded | networkidle
|
|
143
|
+
timeout: 15000
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
10. **waitForURL** — Wait for URL match
|
|
147
|
+
```yaml
|
|
148
|
+
- action: waitForURL
|
|
149
|
+
url: "https://example.com/dashboard"
|
|
150
|
+
timeout: 15000
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
11. **waitForFunction** — Wait for JS expression to be truthy
|
|
154
|
+
```yaml
|
|
155
|
+
- action: waitForFunction
|
|
156
|
+
expression: "document.querySelector('.done') !== null"
|
|
157
|
+
polling: raf # raf (default) | number in ms (e.g. 500)
|
|
158
|
+
timeout: 30000
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
12. **waitForResponse** — Wait for network response (URL substring match)
|
|
162
|
+
```yaml
|
|
163
|
+
- action: waitForResponse
|
|
164
|
+
url: "/api/chat/completions"
|
|
165
|
+
status: 200 # Optional HTTP status filter
|
|
166
|
+
timeout: 30000
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Effects Configuration
|
|
170
|
+
|
|
171
|
+
#### Zoom — Adaptive zoom follows cursor on clicks
|
|
172
|
+
```yaml
|
|
173
|
+
zoom:
|
|
174
|
+
enabled: true
|
|
175
|
+
intensity: moderate # subtle(1.15x) | light(1.25x) | moderate(1.35x) | strong(1.5x) | dramatic(1.8x)
|
|
176
|
+
# scale: 1.35 # Or use numeric value (overridden by intensity)
|
|
177
|
+
duration: 500 # Zoom animation ms
|
|
178
|
+
easing: ease-in-out # ease-in-out | ease-in | ease-out | linear
|
|
179
|
+
autoZoom:
|
|
180
|
+
followCursor: true
|
|
181
|
+
transitionDuration: 300
|
|
182
|
+
padding: 200
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
#### Cursor — Custom cursor with click effect, trail, highlight
|
|
186
|
+
```yaml
|
|
187
|
+
cursor:
|
|
188
|
+
enabled: true
|
|
189
|
+
size: 20
|
|
190
|
+
color: "#000000"
|
|
191
|
+
speed: fast # fast (~72ms) | normal (~144ms) | slow (~288ms)
|
|
192
|
+
smoothing: true
|
|
193
|
+
clickEffect: true
|
|
194
|
+
clickColor: "rgba(59, 130, 246, 0.3)"
|
|
195
|
+
clickRadius: 30
|
|
196
|
+
trail: true
|
|
197
|
+
trailLength: 8
|
|
198
|
+
trailColor: "rgba(59, 130, 246, 0.2)"
|
|
199
|
+
highlight: true
|
|
200
|
+
highlightRadius: 40
|
|
201
|
+
highlightColor: "rgba(255, 215, 0, 0.18)"
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
#### Background — Gradient/solid padding with corners and shadow
|
|
205
|
+
```yaml
|
|
206
|
+
background:
|
|
207
|
+
type: gradient # gradient | solid | image
|
|
208
|
+
value: "linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
|
|
209
|
+
padding: 48
|
|
210
|
+
borderRadius: 14
|
|
211
|
+
shadow: true
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
#### Device Frame — Wraps recording in a device mockup
|
|
215
|
+
```yaml
|
|
216
|
+
deviceFrame:
|
|
217
|
+
enabled: true
|
|
218
|
+
type: browser # browser | macbook | iphone | ipad | android | none
|
|
219
|
+
darkMode: true
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
| Type | Description |
|
|
223
|
+
|------|-------------|
|
|
224
|
+
| browser | macOS browser chrome with traffic lights |
|
|
225
|
+
| macbook | MacBook Pro frame |
|
|
226
|
+
| iphone | iPhone 15 Pro with Dynamic Island |
|
|
227
|
+
| ipad | iPad Pro with camera dot |
|
|
228
|
+
| android | Android with punch-hole camera |
|
|
229
|
+
|
|
230
|
+
#### Keystroke HUD — Shows typed keys on screen
|
|
231
|
+
```yaml
|
|
232
|
+
keystroke:
|
|
233
|
+
enabled: true
|
|
234
|
+
showTyping: false # true = show regular typing; false = shortcuts only (industry default)
|
|
235
|
+
position: bottom-center # bottom-center | bottom-left | bottom-right
|
|
236
|
+
fontSize: 16
|
|
237
|
+
backgroundColor: "rgba(0, 0, 0, 0.75)"
|
|
238
|
+
textColor: "#ffffff"
|
|
239
|
+
padding: 8
|
|
240
|
+
fadeAfter: 1500
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
#### Watermark — Text overlay at corner
|
|
244
|
+
```yaml
|
|
245
|
+
watermark:
|
|
246
|
+
enabled: true
|
|
247
|
+
text: "My App"
|
|
248
|
+
position: bottom-right # top-left | top-right | bottom-left | bottom-right
|
|
249
|
+
opacity: 0.5
|
|
250
|
+
fontSize: 14
|
|
251
|
+
color: "#ffffff"
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
#### Speed Ramp — Auto-adjusts speed near actions
|
|
255
|
+
```yaml
|
|
256
|
+
speedRamp:
|
|
257
|
+
enabled: true
|
|
258
|
+
idleSpeed: 3.0 # Skip factor for idle frames (0.5-8)
|
|
259
|
+
actionSpeed: 0.8 # Slow factor near clicks (0.25-2)
|
|
260
|
+
transitionFrames: 15
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Output Presets
|
|
264
|
+
|
|
265
|
+
| Preset | Use case | Approx size (30s) |
|
|
266
|
+
|--------|----------|--------------------|
|
|
267
|
+
| social | Twitter, LinkedIn, Loom | ~2-4 MB |
|
|
268
|
+
| balanced | General purpose, portfolio | ~4-6 MB |
|
|
269
|
+
| archive | High-fidelity storage | larger |
|
|
270
|
+
|
|
271
|
+
## Critical Rules
|
|
272
|
+
|
|
273
|
+
1. **First step MUST contain a `navigate` action** — the browser needs a page to start
|
|
274
|
+
2. **Selectors**: use CSS selectors (`#id`, `.class`, `[data-testid="..."]`). No control chars, semicolons, backticks, or backslashes
|
|
275
|
+
3. **Type needs focus**: the `type` action auto-focuses, but the element must exist and be visible
|
|
276
|
+
4. **Scroll before interact**: if an element is below the fold, `scroll` to it first
|
|
277
|
+
5. **Prefer async waits over fixed `wait`**: use `waitForSelector`, `waitForFunction`, `waitForResponse` instead of guessing durations
|
|
278
|
+
6. **Viewport = output**: if viewport and output dimensions differ, output will be scaled (a warning is shown)
|
|
279
|
+
7. **Mobile scenarios**: use `viewport: {width: 390, height: 844}` with `deviceFrame.type: iphone` and `output: {width: 540, height: 1080}`
|
|
280
|
+
|
|
281
|
+
## Timing Presets
|
|
282
|
+
|
|
283
|
+
### Snappy demo (~30s)
|
|
284
|
+
- `captureDelay: 50-100`
|
|
285
|
+
- `holdDuration: 500-800`
|
|
286
|
+
- `type.delay: 15-25`
|
|
287
|
+
|
|
288
|
+
### Cinematic demo (~60s)
|
|
289
|
+
- `captureDelay: 200-400`
|
|
290
|
+
- `holdDuration: 1500-2500`
|
|
291
|
+
- `type.delay: 40-60`
|
|
292
|
+
|
|
293
|
+
## CLI Commands
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
# Record from YAML scenario
|
|
297
|
+
npx clipwise record <scenario.yaml> -f mp4 -o ./output
|
|
298
|
+
|
|
299
|
+
# Instant demo with built-in dashboard
|
|
300
|
+
npx clipwise demo
|
|
301
|
+
npx clipwise demo --device iphone
|
|
302
|
+
npx clipwise demo --url https://my-app.com
|
|
303
|
+
|
|
304
|
+
# Create template YAML
|
|
305
|
+
npx clipwise init
|
|
306
|
+
|
|
307
|
+
# Validate scenario without recording
|
|
308
|
+
npx clipwise validate <scenario.yaml>
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
## Workflow
|
|
312
|
+
|
|
313
|
+
1. Ask the user for: target URL, what actions to demo, and preferred style (snappy/cinematic)
|
|
314
|
+
2. Generate a complete `clipwise.yaml` scenario
|
|
315
|
+
3. Run `npx clipwise validate clipwise.yaml` to check for errors
|
|
316
|
+
4. If valid, run `npx clipwise record clipwise.yaml -f mp4 -o ./output`
|
|
317
|
+
5. If the user has specific selectors, use them. Otherwise suggest inspecting the page first
|
|
318
|
+
|
|
319
|
+
## Selector Discovery
|
|
320
|
+
|
|
321
|
+
If the user doesn't know selectors, help them find them:
|
|
322
|
+
```bash
|
|
323
|
+
# Open the target URL in a browser and inspect elements
|
|
324
|
+
npx playwright open <url>
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Or read the page HTML to find appropriate selectors:
|
|
328
|
+
```bash
|
|
329
|
+
curl -s <url> | head -200
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
## Example: Minimal Scenario
|
|
333
|
+
|
|
334
|
+
```yaml
|
|
335
|
+
name: "My App Demo"
|
|
336
|
+
viewport:
|
|
337
|
+
width: 1280
|
|
338
|
+
height: 800
|
|
339
|
+
|
|
340
|
+
effects:
|
|
341
|
+
deviceFrame:
|
|
342
|
+
enabled: true
|
|
343
|
+
type: browser
|
|
344
|
+
cursor:
|
|
345
|
+
enabled: true
|
|
346
|
+
clickEffect: true
|
|
347
|
+
highlight: true
|
|
348
|
+
background:
|
|
349
|
+
padding: 48
|
|
350
|
+
borderRadius: 14
|
|
351
|
+
shadow: true
|
|
352
|
+
|
|
353
|
+
output:
|
|
354
|
+
format: mp4
|
|
355
|
+
fps: 30
|
|
356
|
+
preset: balanced
|
|
357
|
+
|
|
358
|
+
steps:
|
|
359
|
+
- name: "Open app"
|
|
360
|
+
captureDelay: 100
|
|
361
|
+
holdDuration: 1000
|
|
362
|
+
actions:
|
|
363
|
+
- action: navigate
|
|
364
|
+
url: "http://localhost:3000"
|
|
365
|
+
waitUntil: load
|
|
366
|
+
|
|
367
|
+
- name: "Click CTA"
|
|
368
|
+
captureDelay: 50
|
|
369
|
+
holdDuration: 800
|
|
370
|
+
actions:
|
|
371
|
+
- action: click
|
|
372
|
+
selector: "#cta-button"
|
|
373
|
+
```
|