# How Frame Resolution Scaling Enforces the 1998px Max Height Constraint for Claude Compatibility

> Learn how frame resolution scaling enforces the 1998px max height for Claude compatibility using FFmpeg. Discover how this process maintains aspect ratio and ensures even dimensions.

- Repository: [bradautomates/claude-video](https://github.com/bradautomates/claude-video)
- Tags: internals
- Published: 2026-08-03

---

**The `claude-video` project caps frame height at 1998 pixels using an FFmpeg scale filter in [`skills/watch/scripts/frames.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/frames.py) that applies `MAX_READ_DIMENSION = 1998` while preserving aspect ratio and ensuring even dimensions.**

Frame resolution scaling in the `bradautomates/claude-video` repository ensures every extracted video frame meets Claude's display requirements. The implementation centers on a single FFmpeg filter configuration that hard-limits height regardless of source video dimensions or user-requested width.

## The Core Scaling Mechanism in [`frames.py`](https://github.com/bradautomates/claude-video/blob/main/frames.py)

The video frame extraction pipeline resides in **[`skills/watch/scripts/frames.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/frames.py)**. At the heart of the system is the private helper `_scale_filter`, which constructs the FFmpeg scale filter string:

```python
def _scale_filter(resolution: int) -> str:
    return (
        f"scale=w='min({resolution},iw)':h='min({MAX_READ_DIMENSION},ih)':"
        "force_original_aspect_ratio=decrease:force_divisible_by=2"
    )

```

**`MAX_READ_DIMENSION = 1998`** is defined near line 30 of the file. This constant represents the absolute ceiling for frame height.

The filter operates with three key behaviors:

1. **Width control** — The output width becomes the smaller of the user-requested `resolution` (default 512) and the source width (`iw`)
2. **Height ceiling** — The output height is capped at `MAX_READ_DIMENSION` (1998 px) or the source height (`ih`), whichever is lower
3. **Aspect ratio preservation** — `force_original_aspect_ratio=decrease` prevents stretching by scaling down until both constraints are satisfied

## Why 1998 Pixels?

Claude's UI cannot display video preview frames taller than 1998 pixels. By enforcing this limit at extraction time, the skill guarantees every generated JPEG renders without additional post-processing. No frames exceed the threshold regardless of original video resolution.

The filter also includes `force_divisible_by=2` to prevent codec errors, as many video encoders require even-numbered dimensions.

## How the Filter Integrates Into Extraction

During frame extraction, `_scale_filter` feeds directly into the FFmpeg command. In the `extract` function (lines 94-95), the constructed filter string becomes part of the video filter chain:

```bash
ffmpeg … -vf fps=...,scale=w='min(512,iw)':h='min(1998,ih)':force_original_aspect_ratio=decrease:force_divisible_by=2 …

```

This ensures the height constraint applies uniformly across all processing paths.

## Practical Usage Examples

### Extract frames with default settings (512px width, 1998px height cap)

```bash
python -m skills.watch.scripts.frames \
    /path/to/video.mp4 ./out_frames

```

The generated command uses the default resolution of 512, with height automatically capped at 1998 pixels.

### Request larger width while maintaining height ceiling

```bash
python -m skills.watch.scripts.frames \
    /path/to/video.mp4 ./out_frames \
    --resolution 1024

```

The resulting filter becomes:

```

scale=w='min(1024,iw)':h='min(1998,ih)':force_original_aspect_ratio=decrease:force_divisible_by=2

```

For a 3840 × 2160 source video, output frames scale to **1024 × 176** (width limited to 1024, height calculated from aspect ratio, both well under 1998px). For a vertical video like 2160 × 3840, the height hits the 1998px ceiling and width adjusts proportionally.

### Debug the exact filter string

```python
from skills.watch.scripts.frames import _scale_filter, MAX_READ_DIMENSION

resolution = 1280
print(_scale_filter(resolution))

# → scale=w='min(1280,iw)':h='min(1998,ih)':force_original_aspect_ratio=decrease:force_divisible_by=2

```

## Source File References

| File | Purpose |
|------|---------|
| [`skills/watch/scripts/frames.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/frames.py) | Contains `MAX_READ_DIMENSION`, `_scale_filter`, and `extract` function |
| [`skills/watch/scripts/watch.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/watch.py) | Orchestrates the full pipeline and passes resolution to [`frames.py`](https://github.com/bradautomates/claude-video/blob/main/frames.py) |
| [`AGENTS.md`](https://github.com/bradautomates/claude-video/blob/main/AGENTS.md) | Documents Claude compatibility constraints |

According to the `bradautomates/claude-video` source code, these components work together to guarantee frame resolution scaling never produces output incompatible with Claude's display limits.

## Summary

- **`MAX_READ_DIMENSION = 1998`** in [`skills/watch/scripts/frames.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/frames.py) hard-codes the height ceiling
- The `_scale_filter` helper builds an FFmpeg scale filter that applies this limit while preserving aspect ratio
- **Both dimensions use `min()` constraints** — width respects user input or source, height respects 1998px or source
- **Even dimensions are enforced** via `force_divisible_by=2` to prevent codec errors
- The filter integrates into FFmpeg commands in the `extract` function (lines 94-95)

## Frequently Asked Questions

### What happens if I request a resolution taller than 1998 pixels?

The `_scale_filter` function does not accept height as a parameter. You control width via the `--resolution` argument, and height derives from aspect ratio with the 1998px ceiling applied automatically. Even with extremely wide requests, height cannot exceed `MAX_READ_DIMENSION`.

### Does the 1998px limit affect video download quality?

No. The limit applies only to **frame extraction** for preview images in Claude. The [`watch.py`](https://github.com/bradautomates/claude-video/blob/main/watch.py) skill downloads full-resolution video separately. Frame scaling occurs afterward to generate Claude-compatible thumbnails.

### Why is the constant named `MAX_READ_DIMENSION` rather than `MAX_HEIGHT`?

The naming suggests potential future flexibility, though the current implementation in [`frames.py`](https://github.com/bradautomates/claude-video/blob/main/frames.py) applies this value exclusively to height in the FFmpeg filter. The constant's position and usage make its purpose unambiguous despite the generic name.

### Can I override the 1998px limit by modifying the source code?

Yes. Changing `MAX_READ_DIMENSION` in [`skills/watch/scripts/frames.py`](https://github.com/bradautomates/claude-video/blob/main/skills/watch/scripts/frames.py) (line ~30) would affect all subsequent extractions. However, frames exceeding 1998px height will not display properly in Claude's interface, making this modification incompatible with the tool's design intent.