This skill should be used when recording video walkthroughs of features for PR descriptions. It captures browser interactions using agent-browser CLI, optionally creates GIF/MP4 demos (requires ffmpeg), and optionally uploads via rclone. Gracefully degrades when optional tools are missing.
From soleurnpx claudepluginhub jikig-ai/soleur --plugin soleurThis skill uses the workspace's default tool permissions.
scripts/check_deps.sh<command_purpose>Record a video walkthrough demonstrating a feature, upload it, and add it to the PR description.</command_purpose>
<role>Developer Relations Engineer creating feature demo videos</role>
This skill creates professional video walkthroughs of features for PR documentation:
Run check_deps.sh before proceeding. When invoked from a pipeline (e.g., one-shot), pass --auto to skip interactive prompts and install missing tools automatically:
bash ./plugins/soleur/skills/feature-video/scripts/check_deps.sh
For pipeline/automated use:
bash ./plugins/soleur/skills/feature-video/scripts/check_deps.sh --auto
If the script exits non-zero, agent-browser is missing and recording cannot proceed. Stop and inform the user.
If ffmpeg or rclone show [skip], note which tools are unavailable. The skill continues with degraded capability:
Store the availability as variables for use in later steps:
HAS_FFMPEG=$(command -v ffmpeg >/dev/null 2>&1 && echo "true" || echo "false")
HAS_RCLONE=$(command -v rclone >/dev/null 2>&1 && echo "true" || echo "false")
RCLONE_CONFIGURED="false"
if [ "$HAS_RCLONE" = "true" ]; then
REMOTES=$(rclone listremotes 2>/dev/null || true)
[ -n "$REMOTES" ] && RCLONE_CONFIGURED="true"
fi
<parse_args>
Arguments: $ARGUMENTS
Parse the input:
http://localhost:3000)# Get PR number for current branch if needed
gh pr view --json number -q '.number'
</parse_args>
<gather_context>
Get PR details:
gh pr view [number] --json title,body,files,headRefName -q '.'
Get changed files:
gh pr view [number] --json files -q '.files[].path'
Map files to testable routes (same as playwright-test):
| File Pattern | Route(s) |
|---|---|
app/views/users/* | /users, /users/:id, /users/new |
app/controllers/settings_controller.rb | /settings |
app/javascript/controllers/*_controller.js | Pages using that Stimulus controller |
app/components/*_component.rb | Pages rendering that component |
</gather_context>
<plan_flow>
Before recording, create a shot list:
Ask user to confirm or adjust the flow:
**Proposed Video Flow**
Based on PR #[number]: [title]
1. Start at: /[starting-route]
2. Navigate to: /[feature-route]
3. Demonstrate:
- [Action 1]
- [Action 2]
- [Action 3]
4. Show result: [success state]
Estimated duration: ~[X] seconds
Does this look right?
1. Yes, start recording
2. Modify the flow (describe changes)
3. Add specific interactions to demonstrate
</plan_flow>
<setup_recording>
Create directories:
mkdir -p tmp/screenshots tmp/videos
Recording approach: Use browser screenshots as frames
agent-browser captures screenshots at key moments. If ffmpeg is available, screenshots are combined into video/GIF in step 5.
If ffmpeg is unavailable: Screenshots are the final output. Skip video/GIF creation commands in step 5.
</setup_recording>
<record_walkthrough>
Execute the planned flow, capturing each step:
Step 1: Navigate to starting point
agent-browser open "[base-url]/[start-route]"
agent-browser wait 2000
agent-browser screenshot tmp/screenshots/01-start.png
Step 2: Perform navigation/interactions
agent-browser snapshot -i # Get refs
agent-browser click @e1 # Click navigation element
agent-browser wait 1000
agent-browser screenshot tmp/screenshots/02-navigate.png
Step 3: Demonstrate feature
agent-browser snapshot -i # Get refs for feature elements
agent-browser click @e2 # Click feature element
agent-browser wait 1000
agent-browser screenshot tmp/screenshots/03-feature.png
Step 4: Capture result
agent-browser wait 2000
agent-browser screenshot tmp/screenshots/04-result.png
Create video/GIF from screenshots (skip if ffmpeg unavailable):
If HAS_FFMPEG=false, skip the ffmpeg commands below. The screenshots in tmp/screenshots/ are the final output. Inform the user: "ffmpeg not installed -- screenshots captured but video/GIF creation skipped."
# Only run if HAS_FFMPEG=true
# Create MP4 video (RECOMMENDED - better quality, smaller size)
# -framerate 0.5 = 2 seconds per frame (slower playback)
# -framerate 1 = 1 second per frame
ffmpeg -y -framerate 0.5 -pattern_type glob -i 'tmp/screenshots/*.png' \
-c:v libx264 -pix_fmt yuv420p -vf "scale=1280:-2" \
tmp/videos/feature-demo.mp4
# Create low-quality GIF for preview (small file, for GitHub embed)
ffmpeg -y -framerate 0.5 -pattern_type glob -i 'tmp/screenshots/*.png' \
-vf "scale=640:-1:flags=lanczos,split[s0][s1];[s0]palettegen=max_colors=128[p];[s1][p]paletteuse" \
-loop 0 tmp/videos/feature-demo-preview.gif
Note:
-2 in MP4 scale ensures height is divisible by 2 (required for H.264)</record_walkthrough>
<upload_video>
Skip this step if RCLONE_CONFIGURED=false. Inform the user: "rclone not available or not configured -- video retained locally at tmp/videos/."
Upload with rclone (only if RCLONE_CONFIGURED=true):
# Upload video, preview GIF, and screenshots to cloud storage
# Use --s3-no-check-bucket to avoid permission errors
rclone copy tmp/videos/ r2:kieran-claude/pr-videos/pr-[number]/ --s3-no-check-bucket --progress
rclone copy tmp/screenshots/ r2:kieran-claude/pr-videos/pr-[number]/screenshots/ --s3-no-check-bucket --progress
# List uploaded files
rclone ls r2:kieran-claude/pr-videos/pr-[number]/
Public URLs (R2 with public access):
Video: https://pub-4047722ebb1b4b09853f24d3b61467f1.r2.dev/pr-videos/pr-[number]/feature-demo.mp4
Preview: https://pub-4047722ebb1b4b09853f24d3b61467f1.r2.dev/pr-videos/pr-[number]/feature-demo-preview.gif
</upload_video>
<update_pr>
Get current PR body:
gh pr view [number] --json body -q '.body'
Add a demo section to the PR description based on what was produced:
If the PR already has a demo section, replace it. Otherwise, append.
Case A: Video uploaded (HAS_FFMPEG=true, RCLONE_CONFIGURED=true)
Use a clickable GIF that links to the video (GitHub cannot embed external MP4s directly):
## Demo
[]([video-mp4-url])
*Click to view full video*
Case B: Video created locally (HAS_FFMPEG=true, RCLONE_CONFIGURED=false)
Upload the video to the PR as a GitHub comment attachment before cleanup deletes local files:
# Upload video as a PR comment (GitHub accepts drag-and-drop or API upload)
echo "Upload tmp/videos/feature-demo.mp4 to PR #[number] as a comment attachment"
Then add to PR body:
## Demo
See video in PR comments below.
Case C: Screenshots only (HAS_FFMPEG=false)
Upload screenshots to the PR as comment attachments before cleanup deletes local files, then embed in the PR body:
## Demo
Screenshots captured (video conversion requires ffmpeg). See PR comments for images.
Update the PR:
gh pr edit [number] --body "[updated body with demo section]"
</update_pr>
# Always clean up tmp artifacts after PR description is updated
rm -rf tmp/screenshots tmp/videos
echo "Cleaned up tmp/screenshots/ and tmp/videos/"
</cleanup>
Present completion summary:
## Feature Video Complete
**PR:** #[number] - [title]
**Video:** [url or local path]
**Duration:** ~[X] seconds
**Format:** [GIF/MP4]
### Shots Captured
1. [Starting point] - [description]
2. [Navigation] - [description]
3. [Feature demo] - [description]
4. [Result] - [description]
### PR Updated
- [x] Video section added to PR description
- [ ] Ready for review
**Next steps:**
- Review the video to ensure it accurately demonstrates the feature
- Share with reviewers for context
</summary>
# Record video for current branch's PR
/feature-video
# Record video for specific PR
/feature-video 847
# Record with custom base URL
/feature-video 847 http://localhost:5000
# Record for staging environment
/feature-video current https://staging.example.com