clipwise 0.7.1 → 0.9.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/README.ko.md CHANGED
@@ -5,26 +5,26 @@
5
5
  YAML 시나리오를 작성하면 시네마틱 데모 영상(MP4/GIF)을 자동으로 만들어주는 스크린 레코더. Playwright CDP 기반.
6
6
 
7
7
  <p align="center">
8
- <video src="https://github.com/user-attachments/assets/bfd3910d-3449-4d04-b95a-52bea1f16025" autoplay loop muted playsinline width="100%"></video>
8
+ <video src="https://github.com/user-attachments/assets/800d956f-ecf3-40c4-8750-c93b34285f11" autoplay loop muted playsinline width="100%"></video>
9
9
  </p>
10
10
 
11
- > *`npx clipwise demo` 한 줄로 생성된 영상입니다 — YAML 파일 1개, 239줄.*
11
+ > *`npx clipwise demo` 한 줄로 생성된 영상입니다 — YAML 파일 1개, 248줄.*
12
12
 
13
13
  ## 빠른 시작
14
14
 
15
15
  ```bash
16
- # 설치
17
- npm install -D clipwise
18
-
19
- # 내장 데모 즉시 실행
20
- npx clipwise demo
16
+ # 설치 불필요 — npx로 바로 실행 (package.json 무수정)
17
+ npx clipwise@latest demo # 내장 데모 즉시 실행
21
18
 
22
19
  # 또는 직접 시나리오 작성
23
- npx clipwise init # clipwise.yaml 템플릿 생성
24
- # clipwise.yaml 편집 — URL을 내 사이트로 변경
25
- npx clipwise record clipwise.yaml -f mp4 # 녹화!
20
+ npx clipwise@latest init # .clipwise/ 스캐폴딩 생성
21
+ # .clipwise/scenarios/demo.yaml 편집 — URL을 내 사이트로 변경
22
+ npx clipwise@latest record .clipwise/scenarios/demo.yaml
26
23
  ```
27
24
 
25
+ **Zero footprint**: Clipwise가 남기는 모든 것(시나리오, 픽스처, 인증 상태, 출력물)은
26
+ `.clipwise/` 디렉토리 하나에 담깁니다. `rm -rf .clipwise` 한 줄로 모든 흔적이 사라집니다.
27
+
28
28
  ## 요구사항
29
29
 
30
30
  - **Node.js** >= 18
@@ -54,11 +54,11 @@ npx clipwise demo --device android # Android 목업
54
54
  npx clipwise demo --device ipad # iPad 목업
55
55
  npx clipwise demo --url https://my-app.com # 내 사이트 데모
56
56
 
57
- # YAML 시나리오로 녹화
58
- npx clipwise record <scenario.yaml> -f mp4 -o ./output
59
- npx clipwise record <scenario.yaml> -f gif -o ./output
57
+ # YAML 시나리오로 녹화 (출력 기본 위치: .clipwise/output)
58
+ npx clipwise record <scenario.yaml> -f mp4
59
+ npx clipwise record <scenario.yaml> -f gif -o ./custom-dir
60
60
 
61
- # 템플릿 초기화
61
+ # .clipwise/ 스캐폴딩 (시나리오, 픽스처, prepare 에셋, 인증 — 단일 디렉토리)
62
62
  npx clipwise init
63
63
 
64
64
  # 녹화 없이 검증만
@@ -107,9 +107,11 @@ Claude가 자동으로:
107
107
  2. `npx clipwise validate`로 검증
108
108
  3. `npx clipwise record`로 MP4 녹화
109
109
 
110
- ### 업데이트
110
+ ### 업데이트 / 제거
111
111
 
112
112
  clipwise 업그레이드 후 `npx clipwise install-skill`을 다시 실행하면 최신 스킬로 업데이트됩니다.
113
+ `npx clipwise install-skill --remove`로 언제든 제거할 수 있습니다 — 스킬 파일은
114
+ Clipwise가 `.clipwise/` 밖에 남기는 유일한 파일입니다.
113
115
 
114
116
  ## YAML 시나리오 형식
115
117
 
@@ -212,6 +214,118 @@ steps:
212
214
  - `holdDuration: 1500-2500` ms
213
215
  - `type.delay: 40-60` ms/글자
214
216
 
217
+ ### 인증
218
+
219
+ 브라우저 세션을 복원해 로그인 뒤 페이지를 녹화합니다. Playwright `storageState`
220
+ 파일(권장) 또는 인라인 쿠키를 지원합니다.
221
+
222
+ ```yaml
223
+ # 방법 1: Playwright storageState 파일 (쿠키 + localStorage)
224
+ auth:
225
+ storageState: ../auth/auth-state.json
226
+
227
+ # 방법 2: 인라인 쿠키
228
+ auth:
229
+ cookies:
230
+ - name: session_id
231
+ value: abc123
232
+ domain: .example.com
233
+ ```
234
+
235
+ 대화형 로그인으로 `storageState` 파일 생성:
236
+
237
+ ```bash
238
+ npx playwright codegen --save-storage=.clipwise/auth/auth-state.json https://my-app.com
239
+ ```
240
+
241
+ ### Prepare — 녹화 시 런타임 주입
242
+
243
+ **앱 코드를 건드리지 않고** 데모용으로 페이지를 조정합니다. `prepare`의 모든
244
+ 항목은 녹화 브라우저에만 주입됩니다 — 소스, 빌드, DB는 무접촉이며 참조 파일은
245
+ 전부 `.clipwise/` 안에 둡니다.
246
+
247
+ ```yaml
248
+ prepare:
249
+ # 데모에 어울리지 않는 요소 숨김 (쿠키 배너, dev 오버레이)
250
+ hide:
251
+ - "#cookie-banner"
252
+ - "[data-nextjs-toast]"
253
+
254
+ # 시계 동결 — 매 녹화마다 동일한 날짜 표시
255
+ freezeTime: "2026-06-10T09:00:00Z"
256
+
257
+ # Math.random 결정론화 — 매번 같은 차트/데이터
258
+ seedRandom: 42
259
+
260
+ # 앱 부팅 전 웹 스토리지 시드 (온보딩 건너뛰기, 플래그 설정)
261
+ storage:
262
+ localStorage:
263
+ onboarding_done: "true"
264
+
265
+ # API 응답 목(mock) — DB 시드 없이 데모 데이터 제공
266
+ mock:
267
+ - url: "/api/dashboard/stats" # URL 부분 문자열 매칭
268
+ fixture: ../fixtures/stats.json # 이 YAML 기준 상대 경로
269
+ - url: "/api/user"
270
+ body: { name: "Demo User" } # 또는 인라인
271
+
272
+ # 그 외 모든 것 — 임의 CSS/JS 주입
273
+ inject:
274
+ css: ../prepare/demo.css
275
+ ```
276
+
277
+ | 앱 코드를 수정하게 되는 압력 | Prepare 대체 |
278
+ |------------------------------|--------------|
279
+ | dev 오버레이/쿠키 배너 조건부 숨김 코드 | `hide:` |
280
+ | 시드 데이터를 가진 "데모 모드" 구현 | `mock:` |
281
+ | 일관된 데모를 위한 날짜/랜덤 스텁 | `freezeTime:` + `seedRandom:` |
282
+ | 녹화용 온보딩 사전 완료 분기 | `storage:` |
283
+
284
+ `freezeTime` + `seedRandom`을 함께 쓰면 녹화가 **결정론적**이 됩니다 —
285
+ 같은 시나리오는 몇 번을 돌려도 바이트 단위로 동일한 프레임을 만듭니다.
286
+
287
+ ### Scenes — 키노트 스타일 런치 영상 <sup>v0.9</sup>
288
+
289
+ `scenes:` 타임라인을 선언하면 `clipwise record` 한 번으로 완성된 런치 영상이
290
+ 렌더됩니다: 키네틱 타이포 → 푸티지 비네트(크롭/푸시인/분할, 셀렉터 기반 선
291
+ 드로잉 주석) → 아웃트로 — 컷을 넘어 이어지는 잉크 스레드로 연결됩니다.
292
+
293
+ ```yaml
294
+ viewport: { width: 1280, height: 800, deviceScaleFactor: 2 } # 2 = 레티나 출력
295
+
296
+ scenes:
297
+ - type: screen # 푸티지 테이크 — 1회 녹화, 비네트들이 인용
298
+ id: demo
299
+ steps: [...] # 기존 steps 문법 그대로
300
+
301
+ - type: motion # 키네틱 타이포 (내장 템플릿)
302
+ template: kinetic-type
303
+ duration: 2200
304
+ props: { lines: "Ship *demos*,||not edits.", size: 86 }
305
+
306
+ - type: vignette # 푸티지를 레이어로 — 카메라를 선언으로
307
+ footage: demo
308
+ duration: 4200
309
+ layout: crop # hero | crop | split
310
+ label: "Smart Speed"
311
+ caption: "로딩은 빠르게, *결과는 또렷하게*"
312
+ crop: { selector: ".panel", pad: 14 } # 픽셀이 아니라 셀렉터
313
+ push: { from: 1.05, to: 1 }
314
+ start: { step: 3 } # step 경계에서 인용 시작
315
+ rate: 1.15
316
+ fx: [{ kind: circle, selector: "#revenue", delay: 2500 }]
317
+ ```
318
+
319
+ **고퀄리티 레시피** (쇼케이스 영상이 이렇게 나오는 이유):
320
+ 1. `viewport.deviceScaleFactor: 2` — 레티나 해상도 캡처 (푸티지·타이포 전부)
321
+ 2. `prepare:` — 배너 숨김, 시간 동결, 랜덤 시드, API 목킹
322
+ 3. `.clipwise/brand.yaml` — 톤 프리셋, accent, 폰트 프리셋(`editorial` = Inter + Fraunces),
323
+ 캐치프레이즈. 선 드로잉 주석 + 연결 스레드는 자동 적용
324
+ 4. 구성: 키네틱 훅 → 히어로 푸시인 → 클로즈업 비네트 → 인터스티셜 → 분할(YAML × 푸티지) → 아웃트로
325
+
326
+ 가장 빠른 길: Claude Code 스킬 설치(`npx clipwise install-skill`) 후
327
+ `/clipwise`에 자연어로 요청하면 — 이 YAML을 대신 만들어줍니다.
328
+
215
329
  ## 이펙트
216
330
 
217
331
  모든 이펙트는 선택사항이며 합리적인 기본값이 있습니다.
@@ -279,6 +393,7 @@ deviceFrame:
279
393
  enabled: true
280
394
  type: browser # browser | iphone | ipad | android | none
281
395
  darkMode: true
396
+ url: "app.example.com" # 주소창 표시 URL (기본: localhost)
282
397
  ```
283
398
 
284
399
  | 타입 | 설명 |
package/README.md CHANGED
@@ -5,26 +5,26 @@
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
- <video src="https://github.com/user-attachments/assets/bfd3910d-3449-4d04-b95a-52bea1f16025" autoplay loop muted playsinline width="100%"></video>
8
+ <video src="https://github.com/user-attachments/assets/800d956f-ecf3-40c4-8750-c93b34285f11" autoplay loop muted playsinline width="100%"></video>
9
9
  </p>
10
10
 
11
- > *Generated with `npx clipwise demo` — 1 YAML file, 239 lines, one command.*
11
+ > *Generated with `npx clipwise demo` — 1 YAML file, 248 lines, one command.*
12
12
 
13
13
  ## Quick Start
14
14
 
15
15
  ```bash
16
- # Install
17
- npm install -D clipwise
18
-
19
- # Try the built-in demo instantly
20
- npx clipwise demo
16
+ # No install needed — run straight from npx (your package.json stays untouched)
17
+ npx clipwise@latest demo # Try the built-in demo instantly
21
18
 
22
19
  # Or create your own scenario
23
- npx clipwise init # Creates clipwise.yaml template
24
- # Edit clipwise.yaml — change URL to your site
25
- npx clipwise record clipwise.yaml -f mp4 # Record!
20
+ npx clipwise@latest init # Scaffolds .clipwise/ (single footprint dir)
21
+ # Edit .clipwise/scenarios/demo.yaml — change the URL to your site
22
+ npx clipwise@latest record .clipwise/scenarios/demo.yaml
26
23
  ```
27
24
 
25
+ **Zero footprint**: everything Clipwise touches lives in one `.clipwise/` directory —
26
+ scenarios, fixtures, auth state, output. Remove every trace with `rm -rf .clipwise`.
27
+
28
28
  ## Requirements
29
29
 
30
30
  - **Node.js** >= 18
@@ -54,11 +54,11 @@ npx clipwise demo --device android # Android mockup
54
54
  npx clipwise demo --device ipad # iPad mockup
55
55
  npx clipwise demo --url https://my-app.com # Your deployed site
56
56
 
57
- # Record from YAML scenario
58
- npx clipwise record <scenario.yaml> -f mp4 -o ./output
59
- npx clipwise record <scenario.yaml> -f gif -o ./output
57
+ # Record from YAML scenario (output defaults to .clipwise/output)
58
+ npx clipwise record <scenario.yaml> -f mp4
59
+ npx clipwise record <scenario.yaml> -f gif -o ./custom-dir
60
60
 
61
- # Initialize a template
61
+ # Scaffold .clipwise/ (scenarios, fixtures, prepare assets, auth — one dir, zero footprint)
62
62
  npx clipwise init
63
63
 
64
64
  # Validate without recording
@@ -107,9 +107,11 @@ Claude will:
107
107
  2. Run `npx clipwise validate` to check for errors
108
108
  3. Run `npx clipwise record` to produce the MP4
109
109
 
110
- ### Update
110
+ ### Update / Remove
111
111
 
112
112
  Re-run `npx clipwise install-skill` after upgrading clipwise to get the latest skill.
113
+ Remove it anytime with `npx clipwise install-skill --remove` — the skill file is the
114
+ only thing Clipwise leaves outside `.clipwise/`.
113
115
 
114
116
  ## YAML Scenario Format
115
117
 
@@ -154,7 +156,7 @@ steps:
154
156
  |--------|-----------|---------|-------------|
155
157
  | `navigate` | `url`, `waitUntil?` | `waitUntil: "networkidle"` | Navigate to URL |
156
158
  | `click` | `selector`, `delay?`, `timeout?` | | Click an element |
157
- | `type` | `selector`, `text`, `delay?`, `timeout?` | `delay: 50` | Type text (char-by-char) |
159
+ | `type` | `selector`, `text`, `delay?`, `timeout?` | `delay: 50` | Type text (char-by-char, React/Vue compatible) |
158
160
  | `hover` | `selector`, `timeout?` | | Hover over element |
159
161
  | `scroll` | `y?`, `x?`, `selector?`, `smooth?`, `timeout?` | `y: 0`, `x: 0`, `smooth: true` | Scroll by offset |
160
162
  | `wait` | `duration` | | Wait (ms) |
@@ -164,13 +166,15 @@ steps:
164
166
 
165
167
  | Action | Parameters | Default | Description |
166
168
  |--------|-----------|---------|-------------|
167
- | `waitForSelector` | `selector`, `state?`, `timeout?` | `state: "visible"`, `timeout: 15000` | Wait for element state |
168
- | `waitForNavigation` | `waitUntil?`, `timeout?` | `waitUntil: "networkidle"`, `timeout: 15000` | Wait for page load |
169
- | `waitForURL` | `url`, `timeout?` | `timeout: 15000` | Wait for URL match |
170
- | `waitForFunction` | `expression`, `polling?`, `timeout?` | `polling: "raf"`, `timeout: 30000` | Wait for JS expression to be truthy |
171
- | `waitForResponse` | `url`, `status?`, `timeout?` | `timeout: 30000` | Wait for network response (URL substring match) |
169
+ | `waitForSelector` | `selector`, `state?`, `timeout?`, `captureWhileWaiting?`, `displaySpeed?` | `state: "visible"`, `timeout: 15000` | Wait for element state |
170
+ | `waitForNavigation` | `waitUntil?`, `timeout?`, `captureWhileWaiting?`, `displaySpeed?` | `waitUntil: "networkidle"`, `timeout: 15000` | Wait for page load |
171
+ | `waitForURL` | `url`, `timeout?`, `captureWhileWaiting?`, `displaySpeed?` | `timeout: 15000` | Wait for URL match |
172
+ | `waitForFunction` | `expression`, `polling?`, `timeout?`, `captureWhileWaiting?`, `displaySpeed?` | `polling: "raf"`, `timeout: 30000` | Wait for JS expression to be truthy |
173
+ | `waitForResponse` | `url`, `status?`, `timeout?`, `captureWhileWaiting?`, `displaySpeed?` | `timeout: 30000` | Wait for network response (URL substring match) |
172
174
  | `smartWait` | `until`, `selector?`, `timeout?`, `displaySpeed?` | `until: "networkIdle"`, `timeout: 30000`, `displaySpeed: 8` | Smart wait — records real wait, auto-speeds in output |
173
175
 
176
+ **`captureWhileWaiting`**: When `true`, continuously captures frames during the wait (like `smartWait`). Useful for recording loading animations, progress bars, streaming responses. Pairs with `displaySpeed` (1-32, default: 8) to auto-compress wait frames in the output.
177
+
174
178
  **`waitUntil`** options: `"load"`, `"domcontentloaded"`, `"networkidle"` (default)
175
179
  **`state`** options: `"visible"` (default), `"attached"`, `"hidden"`
176
180
  **`polling`** options: `"raf"` (requestAnimationFrame, default) or milliseconds (e.g. `500`)
@@ -213,6 +217,117 @@ For slower, cinematic demos:
213
217
  - `holdDuration: 1500-2500` ms
214
218
  - `type.delay: 40-60` ms per character
215
219
 
220
+ ### Authentication
221
+
222
+ Record pages behind login by restoring a browser session. Supports Playwright's `storageState` file (recommended) or inline cookies.
223
+
224
+ ```yaml
225
+ # Option 1: Playwright storageState file (cookies + localStorage)
226
+ auth:
227
+ storageState: ./auth-state.json
228
+
229
+ # Option 2: Inline cookies
230
+ auth:
231
+ cookies:
232
+ - name: session_id
233
+ value: abc123
234
+ domain: .example.com
235
+ ```
236
+
237
+ Generate a `storageState` file by logging in interactively:
238
+
239
+ ```bash
240
+ npx playwright codegen --save-storage=.clipwise/auth/auth-state.json https://my-app.com
241
+ ```
242
+
243
+ ### Prepare — Recording-Time Injection
244
+
245
+ Tweak the page for the demo **without touching your app code**. Everything in
246
+ `prepare` is injected only into the recording browser — your source, build, and
247
+ database stay untouched, and all referenced files live in `.clipwise/`.
248
+
249
+ ```yaml
250
+ prepare:
251
+ # Hide elements that don't belong in a demo (cookie banners, dev overlays)
252
+ hide:
253
+ - "#cookie-banner"
254
+ - "[data-nextjs-toast]"
255
+
256
+ # Freeze the clock — dates render identically on every recording
257
+ freezeTime: "2026-06-10T09:00:00Z"
258
+
259
+ # Make Math.random deterministic — same charts/data every run
260
+ seedRandom: 42
261
+
262
+ # Seed web storage before the app boots (skip onboarding, set flags)
263
+ storage:
264
+ localStorage:
265
+ onboarding_done: "true"
266
+
267
+ # Mock API responses — demo data without seeding your database
268
+ mock:
269
+ - url: "/api/dashboard/stats" # URL substring match
270
+ fixture: ../fixtures/stats.json # relative to this YAML
271
+ - url: "/api/user"
272
+ body: { name: "Demo User" } # or inline
273
+
274
+ # Inject arbitrary CSS/JS for anything else
275
+ inject:
276
+ css: ../prepare/demo.css
277
+ ```
278
+
279
+ | Pressure to modify app code | Prepare replacement |
280
+ |------------------------------|---------------------|
281
+ | Hide dev overlays / cookie banners conditionally | `hide:` |
282
+ | Build a "demo mode" with seeded data | `mock:` |
283
+ | Stub dates and randomness for consistent demos | `freezeTime:` + `seedRandom:` |
284
+ | Pre-complete onboarding for recordings | `storage:` |
285
+
286
+ Combined with `freezeTime` + `seedRandom`, recordings become **deterministic** —
287
+ the same scenario produces byte-identical frames run after run.
288
+
289
+ ### Scenes — Keynote-style launch videos <sup>v0.9</sup>
290
+
291
+ Declare a `scenes:` timeline and one `clipwise record` renders a complete
292
+ launch video: kinetic typography → footage vignettes (crop / push-in / split,
293
+ selector-anchored line annotations) → outro — connected by an ink thread that
294
+ travels across cuts.
295
+
296
+ ```yaml
297
+ viewport: { width: 1280, height: 800, deviceScaleFactor: 2 } # 2 = retina output
298
+
299
+ scenes:
300
+ - type: screen # footage take — recorded once, quoted by vignettes
301
+ id: demo
302
+ steps: [...] # the same steps you already know
303
+
304
+ - type: motion # kinetic typography (built-in templates)
305
+ template: kinetic-type
306
+ duration: 2200
307
+ props: { lines: "Ship *demos*,||not edits.", size: 86 }
308
+
309
+ - type: vignette # footage as a layer — camera is declarative
310
+ footage: demo
311
+ duration: 4200
312
+ layout: crop # hero | crop | split
313
+ label: "Smart Speed"
314
+ caption: "Loading compressed, *results crisp*"
315
+ crop: { selector: ".panel", pad: 14 } # selectors, not pixels
316
+ push: { from: 1.05, to: 1 }
317
+ start: { step: 3 } # quote from a step boundary
318
+ rate: 1.15
319
+ fx: [{ kind: circle, selector: "#revenue", delay: 2500 }]
320
+ ```
321
+
322
+ **Quality recipe** (what makes the showcase videos look the way they do):
323
+ 1. `viewport.deviceScaleFactor: 2` — retina-resolution capture (footage, type, everything)
324
+ 2. `prepare:` — hide banners, freeze time, seed randomness, mock APIs
325
+ 3. `.clipwise/brand.yaml` — tone preset, accent, font preset (`editorial` = Inter + Fraunces), catchphrases; line annotations + the connecting thread switch on automatically
326
+ 4. Structure: kinetic hook → hero push-in → close-up vignettes → interstitial → split (YAML × footage) → outro
327
+
328
+ The fastest path: install the Claude Code skill (`npx clipwise install-skill`)
329
+ and ask `/clipwise` in natural language — it generates this YAML for you.
330
+
216
331
  ## Effects
217
332
 
218
333
  All effects are optional and have sensible defaults.
@@ -284,6 +399,7 @@ deviceFrame:
284
399
  enabled: true
285
400
  type: browser # browser | iphone | ipad | android | none
286
401
  darkMode: true
402
+ url: "app.example.com" # address-bar display URL (default: localhost)
287
403
  ```
288
404
 
289
405
  | Type | Description |
@@ -297,7 +413,7 @@ deviceFrame:
297
413
 
298
414
  Displays a HUD at the bottom of the screen showing what was typed. By default, only modifier+key shortcuts are shown (industry standard — same as Screen Studio, KeyCastr, ScreenFlow). Set `showTyping: true` to also show regular typed text.
299
415
 
300
- When typing across multiple input fields, each field gets its own line in the HUD (up to 3 recent sessions, oldest dimmed at top, newest bright at bottom).
416
+ When typing across multiple input fields, each field gets its own line in the HUD (up to 3 recent sessions, oldest dimmed at top, newest bright at bottom). CJK text (Korean, Chinese, Japanese) is automatically wrapped to fit the screen width.
301
417
 
302
418
  ```yaml
303
419
  keystroke: