Skip to main content
skill GitHub Copilot official · GitHub

screen-recording — GitHub Copilot skill: GIF demos and setup

Record browser or desktop actions as GIFs and annotate selected frames. Use it to show a feature, bug reproduction, or fix in documentation and pull requests.

Install into GitHub Copilot · Skills CLI (Vercel) All methods and platforms ↓
npx skills add github/awesome-copilot --skill screen-recording
Open on GitHub

What screen-recording does

For browser demos, the skill uses Playwright to follow a sequence of actions and save frames. It assembles them into a GIF with imageio, which supports per-frame timing. Pillow examples show how to add annotations and fade them in.

Desktop capture uses mss. NumPy and scipy can identify changed areas between frames. The listed Python packages are playwright, Pillow, imageio, numpy, scipy, and mss; browser capture also needs Chromium installed through Playwright. For annotated GIFs with fade effects, use imageio because Pillow can merge similar frames. Install this skill when you need a walkthrough or bug demo as a GIF; it is unnecessary for a still screenshot.

What it helps with

  • record browser steps as a GIF
  • show how a feature behaves before and after a change
  • create an annotated walkthrough for documentation
  • capture a bug reproduction or fix as a GIF
  • locate changed regions between frames

Example prompts for the agent

  • Record this browser workflow as a GIF with pauses after the important actions.
  • Create a GIF showing the fix and annotate the key frames.
  • Capture the app window as a GIF and mark the regions that change.

How to install screen-recording

1Skills CLI (Vercel)

npx skills add github/awesome-copilot --skill screen-recording

2GitHub CLI

gh skill install github/awesome-copilot screen-recording

3Manually: put the files in place

.github/skills/screen-recording/SKILL.md

From the same set554

The whole set →
git-commit official github This skill reviews Git changes, stages related files, and creates Conventional Commits. Use it when you want an agent to make one commit or split work into separate commits. GitHub Copilot 47,165installs excalidraw-diagram-generator official github Turn a plain-language description into an Excalidraw diagram. Useful for mapping processes, system structure, and relationships between entities. GitHub Copilot 31,639installs multi-stage-dockerfile official github This skill guides GitHub Copilot in writing multi-stage Dockerfiles for different languages and frameworks. Use it when the final runtime image should contain fewer build dependencies. GitHub Copilot 29,688installs documentation-writer official github Skill that turns the agent into a technical writer following the Diátaxis framework: tutorials, how-to guides, reference, and explanation. Proposes structure before writing. GitHub Copilot 27,757installs prd official github Turns a feature idea into a structured PRD with user stories, technical requirements, and risks. Use it when planning a software feature or an AI-powered one. GitHub Copilot 24,035installs refactor official github This skill reshapes existing code without changing its external behavior. Use it for gradual cleanup of large functions, duplication, weak types, and code smells. GitHub Copilot 22,321installs java-springboot official github Gives GitHub Copilot Spring Boot development practices, from project layout to tests and security. Use it when writing or reviewing Java application code. GitHub Copilot 21,272installs create-readme official github This skill reviews a project and creates a structured README.md. Use it when the repository needs clear documentation based on its actual files and code. GitHub Copilot 19,081installs

Similar

tc-tracker Alireza Rezvani tc-tracker records technical changes in JSON, validates their states, and hands unfinished work to a later AI session. Claude Code 539installs handoff Alireza Rezvani Turns the current conversation into a handoff document for another agent. Use it when work moves to a fresh session and existing artifacts should stay referenced. Claude Code 427installs grill-with-docs Matt Pocock This skill interviews you about a plan or design and creates ADRs and a glossary along the way. Use it when decisions need sharper definition. Claude Code 1,219,756installs skill-creator official anthropics Creates and refines skills, then tests them with prompts, evaluations, and performance checks. Claude Code Claude.ai 414,180installs setup-matt-pocock-skills Matt Pocock This skill configures a repository for Matt Pocock's engineering skills by setting its issue tracker, triage labels, and domain docs layout. Run it before using the other skills. Claude Code 1,052,851installs handoff Matt Pocock Creates a handoff document from the current conversation so another agent can continue the work. Use it when a task moves to a new session or agent. Claude Code 1,038,491installs triage Matt Pocock This skill moves issues and external PRs through triage states, verification, and agent briefs. It fits maintainers managing an issue queue. Claude Code 990,453installs domain-modeling Matt Pocock This skill sharpens project terminology, maintains GLOSSARY.md, and records selected architecture decisions in ADRs. Use it while the domain model is changing. Claude Code 876,391installs

Questions about screen-recording

How do I install screen-recording in GitHub Copilot?

Run npx skills add github/awesome-copilot --skill screen-recording or gh skill install github/awesome-copilot screen-recording.

What does screen-recording do?

It records browser or desktop activity as a GIF, supports variable frame timing, and provides examples for adding annotations.

What do I need for browser recording?

Install playwright, Pillow, imageio, numpy, scipy, and mss. Install Chromium for Playwright with playwright install chromium.

Source text

SKILL.md · MIT
---
name: screen-recording
description: 'Create annotated animated GIF demos and screen recordings for pull requests and documentation. Covers frame capture, timing, imageio-based GIF creation, and per-frame annotation workflows.'
---

# Screen Recording

Create animated GIF demos that show a feature or workflow in action — with annotations, variable timing, and proper pacing. Useful for PR descriptions, documentation, and release notes.

## When to Use This Skill

Use this skill when you need to:

- Record a multi-step UI interaction as an animated GIF
- Create a demo showing before/after behavior
- Build annotated walkthroughs for documentation or release notes
- Show a bug reproduction or fix in action

## Prerequisites

```bash
pip install playwright Pillow imageio numpy scipy mss -q
playwright install chromium
```

## Core Workflow

### 1. Capture frames

Use Playwright to step through the interaction and capture each frame:

```python
from playwright.async_api import async_playwright

async def record_frames(url, steps, width=1400, height=900):
    """
    steps: list of dicts with 'action' (async callable taking page)
           and 'name' (frame filename)
    """
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        page = await browser.new_page(viewport={"width": width, "height": height})
        await page.goto(url, wait_until="networkidle")

        for step in steps:
            if step.get("action"):
                await step["action"](page)
                await page.wait_for_timeout(step.get("wait", 500))
            await page.screenshot(path=step["name"])

        await browser.close()
```

### 2. Assemble GIF with imageio

**Use imageio, not PIL, for GIF writing** — PIL's GIF encoder merges visually similar frames, which kills animations.

```python
import imageio.v3 as iio
from PIL import Image
import numpy as np

frames = []
durations = []

for frame_path, duration_ms in frame_list:
    img = Image.open(frame_path)
    frames.append(np.array(img))
    durations.append(duration_ms)

iio.imwrite("demo.gif", frames, duration=durations, loop=0)
```

### 3. Variable frame timing

Uniform timing makes everything feel either too fast or too slow. Use variable durations:

| Phase | Duration | Why |
|-------|----------|-----|
| Fast action (typing, clicking) | 100ms | Feels natural, keeps energy |
| Pause after action | 600-800ms | Let the viewer process what happened |
| Hero/final message | 500ms+ | Main takeaway needs time to land |

### 4. Annotate frames

Apply annotations to specific frames using the `image-annotations` skill:

```python
from PIL import Image, ImageDraw, ImageFont

def annotate_frame(frame_path, annotations, out_path):
    img = Image.open(frame_path)
    draw = ImageDraw.Draw(img)

    for ann in annotations:
        # Apply annotation (rect, arrow, label, etc.)
        pass

    img.save(out_path)
```

### 5. Fade-in annotations

For smooth annotation appearance:

```python
def apply_fade(base_frame, annotation_layer, alpha):
    """Blend annotation onto frame at given alpha (0.0 to 1.0)"""
    blended = Image.blend(
        base_frame.convert("RGBA"),
        annotation_layer.convert("RGBA"),
        alpha
    )
    return blended.convert("RGB")

# 2-frame pop-in at 10fps: 50% then 100%
faded_frames = [
    apply_fade(base, annotations, 0.5),  # frame 1: half opacity
    apply_fade(base, annotations, 1.0),  # frame 2: full opacity
]
```

At 10fps, use 2 fade frames (0.2s total). At 30fps, use 3-4 frames. Easing curves look bad at low FPS — simple pop-in is snappier and more readable.

## Build as a Script

The annotation logic gets complex for anything beyond trivial demos. Write a dedicated script (e.g., `annotate_gif.py`) with functions instead of inline code. You'll iterate on timing and placement.

## Testing Animations

**Always test in isolation first** — don't rebuild the full demo to test a fade tweak:

```python
# Small test GIF: 10 bare frames → fade frames → 15 hold frames
# Add a frame counter overlay for debugging:
draw.text((10, height - 30), f"F{i}/{total} a={alpha:.0%} FADE",
          fill="white", font=small_font)
```

## Desktop Screen Recording (mss)

For recording desktop apps, terminals, or anything outside a browser. Uses `mss` for fast screen capture.

```python
import mss
from PIL import Image
import time

def record_gif(output_path, region=None, duration=5, fps=8):
    """Record screen region to GIF. region = {left, top, width, height} or None for full screen."""
    with mss.mss() as sct:
        if region is None:
            region = sct.monitors[1]  # primary monitor

        frames = []
        t_end = time.time() + duration
        while time.time() < t_end:
            t0 = time.time()
            shot = sct.grab(region)
            frames.append(Image.frombytes('RGB', shot.size, shot.rgb))
            time.sleep(max(0, 1 / fps - (time.time() - t0)))

    frames[0].save(output_path, save_all=True, append_images=frames[1:],
                   duration=int(1000 / fps), loop=0, optimize=True)
    return len(frames)

record_gif('demo.gif', region={'left': 0, 'top': 0, 'width': 800, 'height': 500}, duration=3)
```

Tested: 3s at 8fps → 24 frames, ~31KB. Keep fps ≤ 10 for reasonable file sizes.

**Note:** `PIL.save(save_all=True)` works for simple recordings but merges visually similar frames. For annotated GIFs with fade effects, use `imageio.v3.imwrite` instead.

### Combining with window capture

```python
# Find window rect, then record it as a GIF
# Reuse find_window() from the ui-screenshots skill
import ctypes
from ctypes import c_int, Structure, byref, windll

class RECT(Structure):
    _fields_ = [('left', c_int), ('top', c_int), ('right', c_int), ('bottom', c_int)]

hwnd = find_window('My App')[0][0]
rect = RECT()
windll.user32.GetWindowRect(hwnd, byref(rect))
region = {'left': rect.left, 'top': rect.top,
          'width': rect.right - rect.left, 'height': rect.bottom - rect.top}
record_gif('app-demo.gif', region=region, duration=5, fps=8)
```

## Diff-Based Cluster Detection

Programmatically find changed regions between frames to decide what to annotate:

```python
import numpy as np
from scipy import ndimage

def find_changed_clusters(frame_a, frame_b, threshold=30, min_pixels=300, dilate=5):
    """Find bounding boxes of changed regions between two frames."""
    diff = np.abs(frame_b.astype(float) - frame_a.astype(float)).max(axis=2)
    mask = diff > threshold
    dilated = ndimage.binary_dilation(mask, iterations=dilate)
    labeled, n = ndimage.label(dilated)
    clusters = []
    for i in range(1, n + 1):
        ys, xs = np.where(labeled == i)
        if len(ys) < min_pixels:
            continue
        clusters.append((xs.min(), ys.min(), xs.max(), ys.max(), len(ys)))
    return sorted(clusters, key=lambda c: -c[4])  # largest first
```

## Format Compatibility

| Format | VS Code Preview | GitHub | Browser |
|--------|----------------|--------|---------|
| GIF | ✅ Animates | ✅ | ✅ |
| WebP | ⚠️ Static only | ✅ | ✅ |
| MP4 | ❌ Broken | ⚠️ | ✅ |

**GIF is the only universally supported animated format** across VS Code preview, GitHub markdown, and browsers.

## Guidelines

1. **Type → pause → annotate** — during fast action, show NO annotation. Pause first, then annotate
2. **Hero message gets the biggest font** — 64pt+ for the main takeaway, 38pt for details
3. **GIF palette does NOT kill gradients** — 20 distinct alpha steps survive 256-color palette
4. **10fps minimum** for typing/interaction — lower looks stuttery
5. **Build iteratively** — get the frame sequence right first, add annotations second, tune timing last

## Limitations

- GIF is limited to 256 colors per frame — fine for UI screenshots, may show banding on photographic content
- Large GIFs (50+ frames at high resolution) can be several MB — consider cropping to the relevant area
- No audio support in GIF — use MP4 for narrated demos (but lose VS Code preview support)

© github · MIT · github/awesome-copilot

See also

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor