Skip to content

Commit b494ff1

Browse files
committed
feat: enhance background generation
1 parent 364428d commit b494ff1

File tree

7 files changed

+114
-3331
lines changed

7 files changed

+114
-3331
lines changed

.claude/skills/rustmotion/SKILL.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ Read individual rule files for detailed explanations, GOOD/BAD examples, and con
5858
- [rules/text-background.md](rules/text-background.md) - text-background renders a colored rectangle behind text
5959
- [rules/3d-perspective.md](rules/3d-perspective.md) - 3D perspective transforms with rotate_x, rotate_y, perspective keyframes
6060
- [rules/timeline-sequencing.md](rules/timeline-sequencing.md) - Timeline steps for multi-phase animations within a single scene
61+
- [rules/gradient-quality.md](rules/gradient-quality.md) - Gradient quality: linear color space, 10-bit encoding, ProRes for dark gradients
6162

6263
---
6364

@@ -306,8 +307,10 @@ Read individual rule files for detailed explanations, GOOD/BAD examples, and con
306307
| `height` | u32 | required | Video height in pixels. **Must be even for H.264.** |
307308
| `fps` | u32 | `30` | Frames per second |
308309
| `background` | string | `"#000000"` | Default background color (hex `#RRGGBB` or `#RRGGBBAA`) |
309-
| `codec` | string | `null` | `"h264"`, `"h265"`, `"vp9"`, `"prores"` |
310-
| `crf` | u8 | `null` | Constant Rate Factor (0-51, lower = better quality) |
310+
| `codec` | string | `null` | `"h264"` (10-bit), `"h265"`, `"vp9"`, `"prores"` |
311+
| `crf` | u8 | `23` | Constant Rate Factor (0-51, lower = better quality) |
312+
313+
> **Encoding note:** H.264 outputs 10-bit (`yuv420p10le`) by default when ffmpeg is available, which reduces color banding on dark gradients. For best quality on gradient-heavy videos, use `--codec prores` (lossless).
311314
312315
#### `audio` (optional array)
313316

@@ -1294,7 +1297,7 @@ Scenes support a virtual camera with animatable pan, zoom, and rotation.
12941297

12951298
#### Animated Background
12961299

1297-
Scenes can have animated gradient backgrounds. Use `concentric_circles` for a subtle, professional look (dark arc rings radiating from center). Use `gradient_shift` for color-shifting gradients.
1300+
Scenes can have animated gradient backgrounds. Gradients are interpolated in **linear color space** with subdivided color stops for smooth dark transitions. Use `concentric_circles` for a subtle, professional look (dark arc rings radiating from center). Use `gradient_shift` for color-shifting gradients.
12981301

12991302
```json
13001303
{
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Rule: Gradient Quality and Encoding
2+
3+
Dark gradients are prone to color banding (visible steps instead of smooth transitions). Rustmotion mitigates this with:
4+
5+
1. **Linear color space interpolation** for animated background gradients (smoother dark tones)
6+
2. **Subdivided color stops** (16 intermediate stops between each color pair)
7+
3. **10-bit H.264** encoding (`yuv420p10le`, `high10` profile) when ffmpeg is available
8+
4. **Dithering** enabled on all gradient paints
9+
10+
## Encoding recommendations
11+
12+
| Scenario | Recommendation |
13+
|---|---|
14+
| Dark gradient backgrounds | Use `--codec prores` for best quality |
15+
| General use | Default H.264 10-bit (requires ffmpeg) |
16+
| No ffmpeg available | Built-in openh264 (8-bit, may show banding on dark gradients) |
17+
18+
**GOOD:** Use `gradient_type: "radial"` with at least 3 colors for smooth transitions:
19+
```json
20+
{
21+
"animated-background": {
22+
"colors": ["#0f172a", "#1e1b4b", "#0f172a"],
23+
"speed": 20,
24+
"gradient_type": "radial"
25+
}
26+
}
27+
```
28+
29+
**BAD:** Only 2 very similar dark colors (minimal contrast = worst banding):
30+
```json
31+
{
32+
"animated-background": {
33+
"colors": ["#0a0a0a", "#0b0b0b"],
34+
"gradient_type": "radial"
35+
}
36+
}
37+
```
38+
39+
## ffmpeg auto-detection
40+
41+
When ffmpeg is installed, rustmotion uses it automatically for all MP4 output (10-bit H.264). Without ffmpeg, it falls back to the built-in openh264 encoder (8-bit). No flag needed.

CLAUDE.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,9 @@ See .claude/skills/ for detailed instructions on generating rustmotion scenarios
66
## Règle obligatoire
77

88
Tout JSON de scénario généré doit être validé avec `rustmotion validate` avant d'être présenté à l'utilisateur.
9+
10+
## Encodage
11+
12+
- ffmpeg est auto-détecté et utilisé par défaut (10-bit H.264, meilleure qualité sur les gradients sombres)
13+
- Sans ffmpeg, le fallback openh264 intégré encode en 8-bit
14+
- Pour les vidéos avec des gradients sombres, recommander `--codec prores` pour une qualité maximale

README.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ A CLI tool that renders motion design videos from JSON scenarios. No browser, no
1212
cargo install rustmotion
1313
```
1414

15-
**Requirements:** Rust toolchain + C++ compiler (for openh264). Optional: `ffmpeg` CLI for H.265/VP9/ProRes/WebM/GIF output.
15+
**Requirements:** Rust toolchain + C++ compiler (for openh264). **Recommended:** `ffmpeg` CLI for 10-bit H.264 and H.265/VP9/ProRes/WebM/GIF output.
1616

1717
## Quick Start
1818

@@ -1220,7 +1220,7 @@ Scenes support a virtual camera with animatable pan, zoom, and rotation.
12201220

12211221
### Animated Background
12221222

1223-
Scenes can have animated gradient backgrounds.
1223+
Scenes can have animated gradient backgrounds. Gradients are interpolated in linear color space with subdivided color stops for smooth dark transitions.
12241224

12251225
```json
12261226
{
@@ -1572,7 +1572,8 @@ Renders multiple sub-frames and composites them for physically-correct motion bl
15721572

15731573
| Format | Command | Requires |
15741574
|---|---|---|
1575-
| **MP4 (H.264)** | `rustmotion render in.json -o out.mp4` | Built-in |
1575+
| **MP4 (H.264 10-bit)** | `rustmotion render in.json -o out.mp4` | ffmpeg (auto-detected) |
1576+
| **MP4 (H.264 8-bit)** | `rustmotion render in.json -o out.mp4` | Built-in (fallback without ffmpeg) |
15761577
| **MP4 (H.265)** | `rustmotion render in.json -o out.mp4 --codec h265` | ffmpeg |
15771578
| **WebM (VP9)** | `rustmotion render in.json -o out.webm --codec vp9` | ffmpeg |
15781579
| **MOV (ProRes)** | `rustmotion render in.json -o out.mov --codec prores` | ffmpeg |
@@ -1582,6 +1583,8 @@ Renders multiple sub-frames and composites them for physically-correct motion bl
15821583

15831584
Transparency is supported with `--transparent` for PNG sequences, WebM (VP9), and ProRes 4444.
15841585

1586+
> **Gradient quality:** When ffmpeg is available, H.264 uses 10-bit color depth (`yuv420p10le`, `high10` profile) which greatly reduces banding on dark gradients. For maximum quality, use `--codec prores`. The built-in openh264 encoder (fallback without ffmpeg) outputs 8-bit only.
1587+
15851588
---
15861589

15871590
## Full Example

0 commit comments

Comments
 (0)