Screen recording to pdf
Claude Code skill: convert screen recordings & chat-history scrolls into PDFs. --capture-all captures every message (一条不差); --auto for key frames. ffmpeg + Pillow + img2pdf.
npx -y skills add Denlie-code/screen-recording-to-pdfAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Convert a screen recording / screencast / demo video (.mp4, .mov, .mkv, .webm, .gif, etc.) into a single multi-page PDF by extracting key frames and assembling them. Use when the user has a recording and wants it as a PDF document. TWO modes: (1) `--capture-all` -- scroll-aware capture for CONTINUOUS content like a scrolling CHAT-RECORDING, captures EVERY message (一条不差, no skips) by measuring scroll and keeping a frame each half-screen; (2) `--auto` / manual scene-detection / max-frames -- key-frame extraction for demos/tutorials. Triggers (CN/EN): 录屏转pdf, 录屏做成PDF, 把这段录屏转成PDF, 录屏导出PDF, 聊天记录转pdf, 聊天记录导出, chat history to pdf, screen recording to pdf, video to pdf, 视频转PDF. Requires Python 3 + ffmpeg (system PATH, or `pip install imageio-ffmpeg`) + numpy (for --capture-all) + Pillow; `pip install img2pdf` for lossless JPEG-to-PDF assembly.
SKILL.md
9.7 KB, ~2.5k tokens by cl100k_base, as published. Nobody here has run it
Screen Recording to PDF
Turn a screen recording (or any video) into a multi-page PDF. Pick the mode by what the recording IS:
- Scrolling / continuous content (a chat-history recording, a long page you
scrolled through, a feed) where every item must be captured -> use
--capture-all. It measures the scroll and keeps a frame each half-screen so nothing scrolls past uncaught. - Demonstrations / tutorials / click-throughs where you only want the
moments that change -> use
--auto(or manual--scene-threshold/--max-frames).
Two scripts, pipelined:
video.mp4 --extract_frames.py--> frame_*.jpg --frames_to_pdf.py--> output.pdf
extract_frames.py is adapted from mugnimaestra/video-frames-skill
(see references/video-frames-source.md). Local additions: an ffmpeg/ffprobe
resolution layer (no system ffmpeg needed), a fix to the scene-detection filter
for ffmpeg >= 7, --auto (smart key-frame + pause de-dup), and --capture-all
(scroll-aware complete capture).
Prerequisites
python -c "import imageio_ffmpeg, PIL, numpy; print('core OK')"
python -c "import img2pdf; print('img2pdf OK (lossless)')" || echo "optional"
Install anything missing (one line, no admin / no system ffmpeg):
pip install imageio-ffmpeg Pillow numpy img2pdf
numpy is required only for --capture-all (scroll matching). The other
modes work without it.
Quick Start
Chat-history / scrolling recording (capture every message):
python scripts/extract_frames.py chat.mp4 --capture-all \
| python scripts/frames_to_pdf.py --json - -o chat.pdf
Demo / tutorial (key frames only):
python scripts/extract_frames.py demo.mp4 --auto \
| python scripts/frames_to_pdf.py --json - -o demo.pdf
Workflow
- Get the video path and confirm it exists.
- Pick the mode by content (see Decision Guide). If unsure whether it's
"scrolling chat" vs "demo", ask the user, or default to
--capture-allwhen completeness matters. - Extract frames with
extract_frames.py-> JSON to stdout (frames,output_dir,resolution,summary, plusstrategy/capture/dedup). - Assemble the PDF with
frames_to_pdf.py(frames dir or piped JSON). - Report output path, page count, size. For
--capture-all, mention thecapture.keptcount and that adjacent pages overlap (~50%+) so every message is on multiple pages. - Clean up the temp frames dir if throwaway.
Decision Guide
| Mode | When to use | Example |
|---|---|---|
--capture-all ⭐ | Scrolling / continuous content -- chat-history recording, long-page scroll, feed. Captures EVERY message (no skips). Measures scroll, keeps a frame each half-screen. | --capture-all |
--auto ⭐ | Demos / tutorials / click-throughs -- wants only the moments that change; de-duplicates pauses. | --auto |
--scene-threshold T | Manual scene detection (distinct screen changes). | --scene-threshold 0.4 |
--max-frames N | Predictable page count, smooth/gradual content. | --max-frames 30 |
--fps N | Fixed-rate sampling. Rarely best. | --fps 1 |
All modes are mutually exclusive at the CLI (--capture-all overrides the
others).
--capture-all tuning
| Option | Default | Meaning |
|---|---|---|
--sample-fps FPS | 10.0 | Dense sampling rate. Must be high enough that no message scrolls all the way past between samples. Raise for fast scrolls. |
--overlap FRAC | 0.5 | Keep a frame each time content scrolls by this fraction of the frame height. Lower = more pages / safer; higher = fewer pages. 0.5 = adjacent pages overlap ~50%. |
How it guarantees completeness: it densely samples (default 10fps), measures the
vertical scroll between consecutive frames, and only advances to a new page once
the content has scrolled by overlap of the screen. Adjacent pages therefore
always overlap, so any message that was ever on screen appears on at least one
(usually several) pages. For a 133s phone chat scroll this yields ~50 pages with
~79% adjacent overlap. If you see gaps, lower --overlap (e.g. 0.35) or raise
--sample-fps.
--auto tuning
| Option | Default | Meaning |
|---|---|---|
--target-density SECS | 2.0 | Target seconds between kept frames (auto-raised for long videos). |
--dedup-threshold DIFF | 6.0 | Grayscale mean-abs-diff below which two frames are duplicates (higher = keep more). |
Quality presets
| Preset | Max dim | JPEG q | Best for |
|---|---|---|---|
balanced | 1024px | 3 | General (default) |
detailed | 1568px | 2 | UI detail, small text, color fidelity |
ocr | 1568px | 1 (gray+sharpen) | Text-heavy -- loses color |
PDF Options (frames_to_pdf.py)
| Option | Default | Meaning |
|---|---|---|
<frames_dir> | -- | Directory of frame images |
--json FILE | -- | Read frame list from extract JSON (- = stdin) |
-o / --output | required | Output PDF path |
--page | none | a4/a4l/letter/letterl/none (none = native pixel size) |
--margin | 0 | Page margin in points (needs --page) |
--backend | auto | img2pdf (lossless JPEG embed) / pillow / auto |
Troubleshooting
- Chat recording is missing messages. You used a key-frame mode (
--auto/--max-frames) -- those skip frames and miss messages that scroll past. Use--capture-allinstead. If still gappy, lower--overlap 0.35and/or raise--sample-fps 15. --capture-allpage count too high. Raise--overlap(e.g.0.65= fewer pages, less overlap) -- but stay below ~0.8 or you risk gaps on fast scrolls.--capture-allsays it needs numpy.pip install numpy.- Scene detection returns 0 frames. Normal for smooth scrolls -- use
--capture-all(chat) or--auto(it falls back to fixed-rate). ffmpeg not found.pip install imageio-ffmpeg(bundled, no admin) orwinget install Gyan.FFmpeg.- Text blurry.
--preset ocr(grayscale, sharpened) or--preset detailed --max-dimension 1920. - No
img2pdf. Falls back to Pillow (re-encodes).pip install img2pdf.
Files
scripts/extract_frames.py-- video -> JPEG frames. Modes:--capture-all(scroll-aware complete capture),--auto(smart key-frames + pause dedup),--scene-threshold/--max-frames/--fps(manual). Prints JSON.scripts/frames_to_pdf.py-- frames -> one PDF (img2pdf lossless embed, or Pillow).references/video-frames-source.md,references/llm-image-specs.md-- upstream refs.references/THIRD-PARTY-LICENSES.md-- full third-party license texts.LICENSE-- Mixed license (WDenlie Commercial-Authorization for original work + MIT for upstream-derived).
License & Third-Party Notices
This skill uses a mixed license (see LICENSE for the full text):
- Original work —
frames_to_pdf.py, the--capture-all/--auto/ pause-de-dup / ffmpeg-resolution additions inextract_frames.py, andSKILL.md— is © 2026 WDenlie under the PolyForm Noncommercial License 1.0.0: free for personal / academic / non-commercial use with attribution; commercial use requires a separate license. To license commercially, contact WDenlie via WeChat (ID: WDenlie). - Upstream-derived code — the core frame-extraction logic in
extract_frames.py, plusreferences/video-frames-source.mdandreferences/llm-image-specs.md— is adapted/copied from mugnimaestra/video-frames-skill and remains under its MIT License (MIT permits commercial use of those portions; this cannot be revoked).
No binaries, no vendored libraries are shipped; deps are pip-installed by the user and ffmpeg is invoked only as an external process.
- Runtime deps (not bundled):
img2pdf(LGPL-3.0-or-later),imageio-ffmpeg(BSD-2-Clause),Pillow(PIL Software License),numpy(BSD-3-Clause, only for--capture-all). - ffmpeg is the GPL (
--enable-gpl) build when fetched byimageio-ffmpeg, invoked only as a separate subprocess -- the skill does not link, bundle, or redistribute it, so GPL copyleft does not reach this skill's code. For commercial distribution prefer an LGPL-only ffmpeg build (configure without--enable-gpl/x264/x265) -- this skill only decodes video and encodes JPEG.
Full third-party license texts: references/THIRD-PARTY-LICENSES.md.
Not legal advice. Engineering-level license guidance; have counsel review before commercial distribution.
Claude, OpenAI, and Gemini are trademarks of their respective owners; this skill is independent and not affiliated with or endorsed by them.
Gives 0 of the 12 instructions most pdf office docs skills give in ~2.5k tokens
Counted across 636 of the 690 authors here whose files we hold, read 2026-08-07
- extract text using pdfplumberin 89 of 636, across 23 files
- create PDFs using reportlabin 83 of 636, across 16 files
- read forms.md to fill out pdf formsin 80 of 636, across 13 files
- OCR scanned PDFs using pytesseractin 77 of 636, across 10 files
- merge or split PDFs using qpdfin 70 of 636, across 3 files
- use excel formulas instead of hardcoded calculated valuesin 68 of 636, across 13 files
- unpack edit xml and repack existing documentsin 63 of 636, across 8 files
- document sources for hardcoded valuesin 61 of 636, across 9 files
- write minimal python code without unnecessary commentsin 59 of 636, across 7 files
- run the recalculation script after adding or modifying formulasin 59 of 636, across 7 files
- fix all identified formula errors and recalculatein 58 of 636, across 6 files
- format years as text stringsin 57 of 636, across 5 files
Said here and by no other author read
- Use capture-all for scrolling content
- Use auto for demonstration videos
- Ask the user if content type is unclear
- Extract frames to JSON output
- Assemble frames into a PDF
- Lower overlap if messages are missing
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.