Demo Video Recording¶
Automated Playwright scripts that record product demo videos for the landing page and marketing.
Prerequisites¶
- Backend running at
localhost:8000 - Frontend running at
localhost:3000 - A pre-analyzed project with edits and at least one asset overlay
- Chromium installed:
cd e2e && npm install && npx playwright install chromium
Quick Start¶
cd e2e
# Record all three demos
npx playwright test demo/desktop.spec.ts --headed
npx playwright test demo/mobile-portrait.spec.ts --headed
npx playwright test demo/mobile-landscape.spec.ts --headed
# Convert WebM to MP4
./record-demos.sh
Output goes to e2e/demo-videos/.
Seeding a Demo Project¶
If you need to set up a fresh demo project from scratch:
- Place
longer_video.MOVin the project root (not in git — 1.2GB) - Optionally place an overlay image (PNG) for asset testing
- Run the seed script:
cd e2e
# With asset overlay
DEMO_ASSET=../path/to/overlay.png ./seed-demo-project.sh
# Without asset (skips overlay insertion)
./seed-demo-project.sh
The seed script:
- Logs in as admin (admin@example.com / password from env)
- Creates a project named "longer_video"
- Uploads the video via presigned URL
- Runs analysis (pacing 50, false start sensitivity 50, pt-BR)
- Optionally uploads an asset image and inserts it as an overlay at ~2:31
After seeding, open localhost:3000, log in, and resume the project so localStorage is populated.
Demo Scripts¶
Desktop (demo/desktop.spec.ts)¶
Viewport: 1920x1080, 2x DPR, visible cursor
What it records (~80s):
- Login → Projects list → Resume project
- Play video with captions visible
- Click edit card → popover (ACCEPT/DISMISS)
- FALSE START filter toggle
- Expanded timeline (E key)
- Click + drag-resize edit in expanded mode
- Undo
- Zoom in/out on expanded timeline
- Asset overlay: click blue asset on waveform → overlay appears with handles → resize → drag to reposition → undo
- Loop viewport toggle
- A/B Original/Edited toggle
- Add manual cut + undo
- Format switching (Vertical → Square → Original)
- Caption position change (top → bottom)
- Caption font change
- Captions panel open/close
- Export button
- Final playback
Mobile Portrait (demo/mobile-portrait.spec.ts)¶
Viewport: 390x844 (iPhone 12 Pro), touch events
What it records (~40s):
- Login → Projects → open project
- Play video with captions
- Accept/dismiss edits via buttons
- CutFocusMode: play, loop toggle, close
- FocusMode via Layers button: zoom in, CUT/KEEP toggle, +CUT/undo
- CAPTIONS tab
- STYLE tab: caption position change
- FORMAT tab: 9:16, 1:1
Mobile Landscape (demo/mobile-landscape.spec.ts)¶
Viewport: 844x390 (iPhone 12 Pro landscape), touch events
What it records (~50s):
- SwipeReview landscape layout (video left, content right)
- Play video
- Accept/dismiss edits
- FORMAT tab: 9:16, 16:9
- FocusMode landscape: zoom in (8x), click edit, CUT/KEEP, +CUT/undo
- Navigate to asset card → expand → AssetFocusMode
- Overlay: drag to reposition, resize via corner drag
- Visual mode switching (OVERLAY → FULL → OVERLAY)
Note: Uses a two-context strategy — logs in via portrait context first to set cookies/localStorage, then opens landscape context for recording.
Architecture¶
Helpers (demo/helpers.ts)¶
| Function | Purpose |
|---|---|
login(page, email, password) |
Fill credentials + submit + wait for dashboard |
injectCursor(page) |
Add visible orange cursor circle (desktop only) |
smoothClick(page, selector) |
Move cursor smoothly then click |
smoothClickAt(page, x, y) |
Move to coordinates then click |
smoothDrag(page, from, to) |
Smooth drag between two points |
smoothTap(page, selector) |
Tap for touch devices |
swipe(page, ...) |
Simulate swipe gesture |
pause(page, ms) |
Wait for viewer to absorb |
Play Button Overlay Issue¶
The mobile video player has a full-screen Play button overlay (z-10, absolute inset-0) that intercepts pointer events. This blocks Playwright's elementHandle.tap() for buttons behind it (Layers, zoom, nav arrows).
Solution: Use page.evaluate() to call .click() directly on the DOM element, bypassing Playwright's pointer event interception check. All mobile FocusMode interactions use this pattern:
await page.evaluate(() => {
const btn = document.querySelector('[aria-label="Timeline overview"]') as HTMLElement;
if (btn) btn.click();
});
Credentials¶
Scripts read DEMO_EMAIL and DEMO_PASSWORD env vars, defaulting to admin@example.com / TestPassword123!.
Post-Processing¶
The record-demos.sh script converts WebM to MP4:
ffmpeg -y -i input.webm \
-c:v libx264 -crf 18 -preset slow \
-pix_fmt yuv420p \
-movflags +faststart \
output.mp4
For trimming or speed adjustment: