@pixerate/editor 0.222.1 → 0.222.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. package/package.json +1 -1
  2. package/skills/README.md +8 -1
  3. package/skills/pixerate-paint-editor/SKILL.md +20 -59
  4. package/skills/pixerate-paint-editor/references/oils.md +19 -0
  5. package/skills/pixerate-paint-editor/references/wet-media.md +35 -0
  6. package/skills/pixerate-paint-oil-impasto/SKILL.md +103 -0
  7. package/skills/pixerate-paint-oil-impasto/evals/impasto-highlights.json +24 -0
  8. package/skills/pixerate-paint-oil-impasto/evals/lean-to-thick.json +17 -0
  9. package/skills/pixerate-paint-oil-impasto/evals/mix-green.json +15 -0
  10. package/skills/pixerate-paint-sketch-to-finish/SKILL.md +97 -0
  11. package/skills/pixerate-paint-sketch-to-finish/evals/clipped-shading.json +26 -0
  12. package/skills/pixerate-paint-sketch-to-finish/evals/flats-under-ink.json +27 -0
  13. package/skills/pixerate-paint-sketch-to-finish/evals/sketch-ink-hide.json +20 -0
  14. package/skills/pixerate-paint-watercolour/SKILL.md +106 -0
  15. package/skills/pixerate-paint-watercolour/evals/glaze-over-dry.json +24 -0
  16. package/skills/pixerate-paint-watercolour/evals/paper-and-brush-for-detail.json +16 -0
  17. package/skills/pixerate-paint-watercolour/evals/sky-wash.json +19 -0
  18. package/skills/pixerate-video-colour-grade/SKILL.md +105 -0
  19. package/skills/pixerate-video-colour-grade/evals/look-in-one-place.json +16 -0
  20. package/skills/pixerate-video-colour-grade/evals/lut-keep-skin.json +132 -0
  21. package/skills/pixerate-video-colour-grade/evals/match-exposure.json +14 -0
  22. package/skills/pixerate-video-editor/SKILL.md +3 -0
  23. package/skills/pixerate-video-montage/SKILL.md +99 -0
  24. package/skills/pixerate-video-montage/evals/assemble-on-beats.json +231 -0
  25. package/skills/pixerate-video-montage/evals/music-and-ending.json +210 -0
  26. package/skills/pixerate-video-montage/evals/short-crossfades.json +190 -0
  27. package/skills/pixerate-video-social-cut/SKILL.md +105 -0
  28. package/skills/pixerate-video-social-cut/evals/hook-first.json +19 -0
  29. package/skills/pixerate-video-social-cut/evals/opening-title.json +14 -0
  30. package/skills/pixerate-video-social-cut/evals/vertical-reframe.json +15 -0
@@ -0,0 +1,106 @@
1
+ ---
2
+ name: pixerate-paint-watercolour
3
+ description: The watercolour workflow in the Pixerate paint editor - choosing the paper, planning light to dark and keeping the paper's white for highlights, wet-in-wet and wet-on-dry washes, letting water flow and drying before glazing, steering water with the wet tools, granulation, blooms and edge darkening, and finishing detail with a small brush. Use when asked to paint in watercolour or gouache, lay a wash, paint a sky, glaze, paint wet-in-wet, make blooms or granulation, or paint a loose or botanical watercolour, or when wet_paper, advance_wet_paint, dry_paint or set_wet_settings are available. Load with pixerate-paint-editor, which lists every tool.
4
+ metadata:
5
+ kind: workflow
6
+ reference: pixerate-paint-editor
7
+ ---
8
+
9
+ # Painting in watercolour
10
+
11
+ Watercolour is transparent and it moves. Each wash lays water and pigment that keep flowing
12
+ until they dry: edges darken, pigment settles into the paper's valleys, wet colours bleed into
13
+ each other. Light comes from the paper, so you work light to dark and keep the white of the paper
14
+ where you want highlights. A dried wash is fixed; the next one glazes over it. For an agent,
15
+ time only passes when you call `advance_wet_paint` or `dry_paint`.
16
+
17
+ This skill is the method. `pixerate-paint-editor` has the full tool reference and
18
+ `references/wet-media.md` the engine's detail.
19
+
20
+ ## Goal and quality bar
21
+
22
+ - The paper suits the piece: cold pressed for most work, rough for texture and granulation, hot
23
+ pressed for fine detail (`get_canvas_info` `paper.preset`).
24
+ - Washes are even where they should be and soft where they should be; colours glow because
25
+ they are layered, not mixed to mud.
26
+ - Highlights are the paper itself, not white paint (unless the user asks for gouache).
27
+ - Every wash is dry before the next glaze over it (`get_wet_paint` `wet: false`), and the
28
+ painting is dry before export.
29
+
30
+ ## Inputs to confirm
31
+
32
+ - **Subject and look:** loose and atmospheric (wet-in-wet) or crisp and detailed (wet-on-dry).
33
+ - **Palette:** a few colours; `color_harmony` or `mix_colors` to plan.
34
+ - **Highlights to keep white**, and where they are.
35
+
36
+ ## Working method
37
+
38
+ 1. **Ground.** `set_paper` with a watercolour preset (`cold-pressed`, `rough-watercolor`,
39
+ `hot-pressed`). Keep each pass on its own layer when you may want to change it (`add_layer`).
40
+ **Check:** `get_canvas_info` shows the paper.
41
+ 2. **Plan values light to dark** and where the paper stays white. Mix colours first
42
+ (`mix_colors` predicts the pigment mix; `add_swatch` keeps them).
43
+ 3. **First wash, lightest colour.** For soft skies and backgrounds, `wet_paper` the area first
44
+ (wet-in-wet); for crisp edges paint on dry paper. `set_brush` `watercolor-wash`, `set_color`,
45
+ then a few long `paint_stroke`s across the area, overlapping, avoiding the highlights.
46
+ **Check:** `get_wet_paint` shows the layer wet; `pick_color` inside is the colour you meant.
47
+ 4. **Let it move, then dry.** `advance_wet_paint` (`seconds` 1-5) to let it spread, bloom and
48
+ granulate; drop a second colour in while it is wet for soft blends. Then `dry_paint`.
49
+ **Check:** `get_wet_paint` `wet: false`.
50
+ 5. **Glaze.** Each further wash goes over a dry one, a little darker or another hue (blue over
51
+ yellow makes green). Paint only where it should deepen.
52
+ **Check:** `pick_color` where you glazed is darker; where you did not, unchanged.
53
+ 6. **Shapes, then details.** `watercolor-round` for shapes, `watercolor-detail` for lines and
54
+ details on dry paper, last.
55
+ 7. **Steer and fix while wet**: `blot` lifts paint (clouds, a highlight you lost), the
56
+ `add-water` tool softens an edge, `hair-dryer` stops a spread, `set_canvas_tilt` makes a wash
57
+ run, `set_wet_settings` tunes `granulation`, `edgeDarkening` and `bloom` for the layer.
58
+ 8. **Finish.** `dry_paint` everything; `render_preview` to look; export.
59
+
60
+ ## Decision table
61
+
62
+ | Want | Approach |
63
+ | --- | --- |
64
+ | Soft sky, misty background | `wet_paper`, then `watercolor-wash`; drop colours in while wet |
65
+ | Crisp shapes, hard edges with a dark rim | Paint on dry paper |
66
+ | Deeper colour without mud | Dry, then glaze a second wash |
67
+ | A white highlight | Leave the paper; or `blot` while wet to lift |
68
+ | Light over dark | `gouache` (body 1) |
69
+ | Grainy, textured washes | `rough-watercolor` paper and `granulation` up in `set_wet_settings` |
70
+ | Fine lines and detail | `hot-pressed` paper, `watercolor-detail`, on dry paper |
71
+ | Cauliflower blooms | Add water into a drying wash; `bloom` up |
72
+
73
+ ## Recipes
74
+
75
+ **Flat wash.** `set_brush` `watercolor-wash` → `set_color` → one `paint_stroke` zigzagging
76
+ across the area (rows about half the brush size apart) → `advance_wet_paint` `seconds` 2-5 →
77
+ `dry_paint`.
78
+
79
+ **Glaze.** On the dried wash, the same or a darker colour, painted only where it should deepen
80
+ → `dry_paint`. Repeat for more depth; three glazes are usually plenty.
81
+
82
+ **Wet-in-wet sky.** `wet_paper` over the sky → blue wash along the top → while wet, a little
83
+ warm colour near the horizon → `advance_wet_paint` → `blot` a few clouds → `dry_paint`.
84
+
85
+ ## Pitfalls
86
+
87
+ - **Glazing on wet paint** mixes the two washes instead of layering them; dry first.
88
+ - **Painting light over dark** does not work in transparent watercolour; plan the whites.
89
+ - **Overworking**: many strokes over a wet wash lift and muddy it; lay it and leave it.
90
+ - **Drawing-paper presets** (cartridge, smooth) do not behave like watercolour paper.
91
+ - **Oil and watercolour on one layer**: a layer keeps the first medium's wet settings; use
92
+ separate layers.
93
+ - **Nothing moves by itself** for an agent: without `advance_wet_paint` there is no flow, and
94
+ without `dry_paint` the next stroke paints into wet paint.
95
+
96
+ ## Tools used
97
+
98
+ - `get_canvas_info`, `list_layers`, `render_preview`, `pick_color`: read the canvas and check colours
99
+ - `list_papers`, `set_paper`: the watercolour ground
100
+ - `add_layer`, `update_layer`: a layer per pass
101
+ - `set_brush`, `set_color`, `mix_colors`, `color_harmony`, `add_swatch`: brush and palette
102
+ - `paint_stroke`: washes, shapes and details, and the wet tools (water, dryer, blot)
103
+ - `wet_paper`, `advance_wet_paint`, `dry_paint`, `get_wet_paint`: wet-in-wet, flow, drying and checking
104
+ - `set_wet_settings`, `set_canvas_tilt`, `set_flow_map`: tune and steer the water
105
+ - `undo_paint`: take back a step
106
+ - `export_image`: deliver
@@ -0,0 +1,24 @@
1
+ {
2
+ "prompt": "The blue wash on this sheet is dry. Glaze a second wash of the same blue over the left half to deepen it, without lifting or muddying the first one.",
3
+ "fixture": {
4
+ "editor": "paint",
5
+ "width": 64,
6
+ "height": 64,
7
+ "setup": [
8
+ { "tool": "set_brush", "args": { "id": "watercolor-wash" } },
9
+ { "tool": "set_color", "args": { "color": "#6fa8dc" } },
10
+ { "tool": "paint_stroke", "args": { "points": [{ "x": 0, "y": 10 }, { "x": 64, "y": 10 }, { "x": 64, "y": 32 }, { "x": 0, "y": 32 }, { "x": 0, "y": 54 }, { "x": 64, "y": 54 }] } },
11
+ { "tool": "dry_paint" }
12
+ ]
13
+ },
14
+ "checks": [
15
+ { "why": "a second watercolour wash", "tool": "list_strokes", "expect": { "total": 2, "strokes": { "$every": { "brushId": { "$in": ["watercolor-round", "watercolor-wash", "gradient-wash", "watercolor-detail"] } } } } },
16
+ { "why": "the left half is deeper (darker) than the paper-side right", "tool": "pick_color", "args": { "x": 10, "y": 32 }, "expect": { "color": { "$expr": "(([r, g, b]) => 0.3 * r + 0.59 * g + 0.11 * b < 170 && b > r + 15)([1, 3, 5].map((i) => parseInt(v.slice(i, i + 2), 16)))" } } },
17
+ { "why": "the glaze is dry, so it stays put", "tool": "get_wet_paint", "expect": { "wet": false } }
18
+ ],
19
+ "solution": [
20
+ { "tool": "get_wet_paint" },
21
+ { "tool": "paint_stroke", "args": { "points": [{ "x": 2, "y": 12 }, { "x": 26, "y": 12 }, { "x": 26, "y": 32 }, { "x": 2, "y": 32 }, { "x": 2, "y": 52 }, { "x": 26, "y": 52 }] } },
22
+ { "tool": "dry_paint" }
23
+ ]
24
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "prompt": "I want a detailed botanical study in watercolour with crisp, fine lines. Set up the paper for that and paint the thin stem with a small detail brush, a green line from (32, 60) up to (32, 20).",
3
+ "fixture": { "editor": "paint", "width": 64, "height": 64 },
4
+ "checks": [
5
+ { "why": "smooth hot-pressed paper for fine detail", "tool": "get_canvas_info", "expect": { "paper": { "preset": "hot-pressed" } } },
6
+ { "why": "a fine watercolour detail brush", "tool": "list_strokes", "expect": { "strokes": { "$some": { "brushId": "watercolor-detail" } } } },
7
+ { "why": "a green stem", "tool": "pick_color", "args": { "x": 32, "y": 40 }, "expect": { "color": { "$expr": "(([r, g, b]) => g > r + 10 && g > b)([1, 3, 5].map((i) => parseInt(v.slice(i, i + 2), 16)))" } } }
8
+ ],
9
+ "solution": [
10
+ { "tool": "set_paper", "args": { "preset": "hot-pressed" } },
11
+ { "tool": "set_brush", "args": { "id": "watercolor-detail" } },
12
+ { "tool": "set_color", "args": { "color": "#3f7d3a" } },
13
+ { "tool": "paint_stroke", "args": { "points": [{ "x": 32, "y": 60 }, { "x": 32, "y": 40 }, { "x": 32, "y": 20 }] } },
14
+ { "tool": "dry_paint" }
15
+ ]
16
+ }
@@ -0,0 +1,19 @@
1
+ {
2
+ "prompt": "Paint a flat light-blue sky wash across the top third of the sheet in watercolour, and let it dry before anything else goes on.",
3
+ "fixture": { "editor": "paint", "width": 64, "height": 64, "setup": [{ "tool": "set_paper", "args": { "preset": "cartridge" } }] },
4
+ "checks": [
5
+ { "why": "on watercolour paper", "tool": "get_canvas_info", "expect": { "paper": { "preset": { "$in": ["cold-pressed", "hot-pressed", "rough-watercolor"] } } } },
6
+ { "why": "painted with a watercolour brush", "tool": "list_strokes", "expect": { "strokes": { "$length": { "$min": 1 }, "$every": { "brushId": { "$in": ["watercolor-round", "watercolor-wash", "gradient-wash", "watercolor-detail"] } } } } },
7
+ { "why": "the sky is blue", "tool": "pick_color", "args": { "x": 32, "y": 6 }, "expect": { "color": { "$expr": "(([r, g, b]) => b > r + 15)([1, 3, 5].map((i) => parseInt(v.slice(i, i + 2), 16)))" } } },
8
+ { "why": "the wash is dry", "tool": "get_wet_paint", "expect": { "wet": false } }
9
+ ],
10
+ "solution": [
11
+ { "tool": "set_paper", "args": { "preset": "cold-pressed" } },
12
+ { "tool": "set_brush", "args": { "id": "watercolor-wash" } },
13
+ { "tool": "set_color", "args": { "color": "#6fa8dc" } },
14
+ { "tool": "paint_stroke", "args": { "points": [{ "x": 0, "y": 6 }, { "x": 64, "y": 6 }, { "x": 64, "y": 14 }, { "x": 0, "y": 14 }] } },
15
+ { "tool": "advance_wet_paint", "args": { "seconds": 3 } },
16
+ { "tool": "dry_paint" },
17
+ { "tool": "get_wet_paint" }
18
+ ]
19
+ }
@@ -0,0 +1,105 @@
1
+ ---
2
+ name: pixerate-video-colour-grade
3
+ description: The colour grading workflow in the Pixerate video editor - correcting each shot first (exposure, contrast, white balance) so a scene matches, then one look over the whole piece on an adjustment clip, LUTs at a sensible strength with skin tones protected, masks for spot changes, and checking with scopes and frames. Use when asked to colour correct, colour grade, match shots, fix exposure or white balance in a video, add a look, a LUT, a film or cinematic look, warm or cool a video, or protect skin tones, or when update_video_clip grade, add_video_adjustment_clip, set_video_lut or get_video_scopes are available. Load with pixerate-video-editor, which lists every tool.
4
+ metadata:
5
+ kind: workflow
6
+ reference: pixerate-video-editor
7
+ ---
8
+
9
+ # Grading a video
10
+
11
+ A grade has two passes. **Correction** makes each shot right and makes shots in a scene match:
12
+ exposure, contrast and white balance on the clip's own `grade`. **The look** is one creative
13
+ decision over everything: an adjustment clip above the timeline with its own grade or a LUT,
14
+ so it is changed in one place. Faces are the reference: people notice skin that is wrong before
15
+ anything else.
16
+
17
+ This skill is the method. `pixerate-video-editor` has the full tool reference.
18
+
19
+ ## Goal and quality bar
20
+
21
+ - Shots in a scene match in brightness and colour; cuts between them do not jump.
22
+ - Corrections are moderate: exposure within about ±1 stop, contrast and saturation within
23
+ ±0.3, white balance within ±0.3, unless a shot is badly off.
24
+ - One look, in one place: an adjustment clip over the whole timeline (or one per scene), not
25
+ the same settings pasted on every clip.
26
+ - Skin stays natural under strong looks (skin protection 0.5-0.8 on LUTs).
27
+ - The original corrections are not overwritten by the look.
28
+
29
+ ## Inputs to confirm
30
+
31
+ - **The look:** natural, warm, cool, desaturated, high contrast, a named LUT; or a reference.
32
+ - **Which shot is the reference** for matching (the best-exposed, or the one the user likes).
33
+ - **Where the LUT file is** (a `.cube` path or URL the host can load).
34
+
35
+ ## Working method
36
+
37
+ 1. **Read.** `get_video_project` for clips and their `grade`; where the host has a preview,
38
+ `get_video_scopes` at a frame of each shot reads levels and colour in numbers.
39
+ **Check:** you know which shots are off and by how much.
40
+ 2. **Correct the reference shot** (`update_video_clip` `set.grade`): exposure first, then
41
+ contrast, then white balance (`temperature`, `tint`). The grade object replaces the clip's
42
+ whole grade, so pass every setting you want to keep.
43
+ 3. **Match the others to it.** A shot one stop under gets `exposure: 1`; a cooler shot more
44
+ `temperature`. `copy_video_grade` when shots from one camera setup need the same correction;
45
+ `apply_video_grade_preset` for a common starting point.
46
+ **Check:** the clip `grade` values; scopes or `get_video_frame` at both sides of each cut.
47
+ 4. **The look over everything.** `add_video_track` at the top (`at: 0`) and
48
+ `add_video_adjustment_clip` on it from 0 for the whole duration with the look's `grade`
49
+ (`scope: "underneath"`).
50
+ **Check:** one adjustment clip covering the timeline; media clips keep their corrections.
51
+ 5. **LUTs.** `set_video_lut` with `strength` 0.3-0.7 for a look (1 only for a technical
52
+ conversion LUT) and skin protection (`preserve_skin_tones: 0.7`, 0.5-0.8) when people are on screen;
53
+ `set_video_skin_protection` to change the protection later.
54
+ **Check:** each clip's `grade.lut` has the strength and protection you meant.
55
+ 6. **Spot changes.** `set_video_clip_mask` on a duplicate clip or an adjustment clip for a sky,
56
+ a face or a vignette.
57
+ 7. **Review.** `render_video_frame` with `times` across the piece for a contact sheet; fix any
58
+ shot that stands out.
59
+
60
+ ## Decision table
61
+
62
+ | Problem | Fix |
63
+ | --- | --- |
64
+ | Shot too dark or bright | `grade.exposure` in stops (+1 doubles the light) |
65
+ | Flat, low contrast | `grade.contrast` +0.1-0.3 |
66
+ | Blue or orange cast | `grade.temperature` against it |
67
+ | Green or magenta cast | `grade.tint` against it |
68
+ | Same correction on many shots from one setup | `copy_video_grade` |
69
+ | One look for the whole piece | Adjustment clip on a top track |
70
+ | A LUT look | `set_video_lut`, strength 0.3-0.7 |
71
+ | Faces off under the look | Skin protection 0.5-0.8 (`set_video_lut` or `set_video_skin_protection`), or lower the strength |
72
+ | Change only part of the frame | `set_video_clip_mask` |
73
+
74
+ ## Recipes
75
+
76
+ **Match an underexposed shot.** `update_video_clip` `{ clip, set: { grade: { exposure: 1 } } }`
77
+ for one stop under; check with scopes or frames on both sides of the cut.
78
+
79
+ **Warm, slightly desaturated look.** `add_video_track` `{ kind: "video", at: 0 }` →
80
+ `add_video_adjustment_clip` `{ track, start: 0, duration: <project duration>, grade:
81
+ { temperature: 0.2, saturation: -0.15 } }`.
82
+
83
+ **Tame a LUT.** `set_video_lut` `{ clips, src, strength: 0.6, preserve_skin_tones: 0.7 }`.
84
+
85
+ ## Pitfalls
86
+
87
+ - **Grading before correcting.** A look over unmatched shots makes the mismatch stronger.
88
+ - **Partial grade objects.** `set.grade` replaces the whole grade; read it first and include
89
+ the settings you keep.
90
+ - **The look on every clip.** Pasting it per clip means every change is many edits; use an
91
+ adjustment clip.
92
+ - **Full-strength creative LUTs** turn faces orange or green and crush detail.
93
+ - **ffmpeg and skin protection.** The export's `lut3d` cannot protect skin; the export notes
94
+ it, and the preview differs from the file. Lower the strength when that matters.
95
+ - **Judging on one frame.** Check several frames per shot; light changes within shots.
96
+
97
+ ## Tools used
98
+
99
+ - `get_video_project`, `get_video_scopes`, `get_video_frame`, `render_video_frame`: read grades, measure and look
100
+ - `update_video_clip`: each shot's correction (`set.grade`)
101
+ - `copy_video_grade`, `apply_video_grade_preset`: match and start from a preset
102
+ - `add_video_track`, `add_video_adjustment_clip`: one look over the timeline
103
+ - `set_video_lut`, `remove_video_lut`, `set_video_skin_protection`: LUT looks and skin
104
+ - `set_video_clip_mask`, `remove_video_clip_mask`: spot changes
105
+ - `undo_video`: take back a step
@@ -0,0 +1,16 @@
1
+ {
2
+ "prompt": "Give the whole piece a warm, slightly desaturated look that I can tweak in one place later, on top of the shot corrections.",
3
+ "fixture": { "editor": "video", "setup": [{ "tool": "add_video_asset", "args": { "id": "a", "kind": "video", "src": "shot-a.mp4", "duration": 8000 } },
4
+ { "tool": "add_video_asset", "args": { "id": "b", "kind": "video", "src": "shot-b.mp4", "duration": 8000 } },
5
+ { "tool": "add_video_clip", "args": { "track": "v1", "clip": { "type": "media", "asset": "a", "id": "c1", "start": 0, "duration": 6000 } } },
6
+ { "tool": "add_video_clip", "args": { "track": "v1", "clip": { "type": "media", "asset": "b", "id": "c2", "start": 6000, "duration": 6000 } } }] },
7
+ "checks": [
8
+ { "why": "one adjustment clip over the whole timeline", "tool": "get_video_project", "expect": { "tracks": { "$some": { "clips": { "$some": { "type": "adjustment", "start": 0, "duration": { "$min": 12000 } } } } } } },
9
+ { "why": "warm and a little desaturated", "tool": "get_video_project", "expect": { "tracks": { "$some": { "clips": { "$some": { "type": "adjustment", "grade": { "temperature": { "$min": 0.05, "$max": 0.5 }, "saturation": { "$min": -0.4, "$max": -0.02 } } } } } } } },
10
+ { "why": "the shots' own grades are left alone", "tool": "get_video_project", "expect": { "tracks": { "$some": { "clips": { "$expr": "v.filter((c) => c.type === 'media').every((c) => !c.grade)" } } } } }
11
+ ],
12
+ "solution": [
13
+ { "tool": "add_video_track", "args": { "kind": "video", "id": "v0", "at": 0 } },
14
+ { "tool": "add_video_adjustment_clip", "args": { "track": "v0", "start": 0, "duration": 12000, "grade": { "temperature": 0.2, "saturation": -0.15 } } }
15
+ ]
16
+ }
@@ -0,0 +1,132 @@
1
+ {
2
+ "prompt": "The teal-and-orange LUT on both shots is too strong and turns the faces orange. Tone the look down to a moderate strength and keep the skin tones natural.",
3
+ "fixture": {
4
+ "editor": "video",
5
+ "setup": [
6
+ {
7
+ "tool": "add_video_asset",
8
+ "args": {
9
+ "id": "a",
10
+ "kind": "video",
11
+ "src": "shot-a.mp4",
12
+ "duration": 8000
13
+ }
14
+ },
15
+ {
16
+ "tool": "add_video_asset",
17
+ "args": {
18
+ "id": "b",
19
+ "kind": "video",
20
+ "src": "shot-b.mp4",
21
+ "duration": 8000
22
+ }
23
+ },
24
+ {
25
+ "tool": "add_video_clip",
26
+ "args": {
27
+ "track": "v1",
28
+ "clip": {
29
+ "type": "media",
30
+ "asset": "a",
31
+ "id": "c1",
32
+ "start": 0,
33
+ "duration": 6000
34
+ }
35
+ }
36
+ },
37
+ {
38
+ "tool": "add_video_clip",
39
+ "args": {
40
+ "track": "v1",
41
+ "clip": {
42
+ "type": "media",
43
+ "asset": "b",
44
+ "id": "c2",
45
+ "start": 6000,
46
+ "duration": 6000
47
+ }
48
+ }
49
+ },
50
+ {
51
+ "tool": "set_video_lut",
52
+ "args": {
53
+ "clips": [
54
+ "c1",
55
+ "c2"
56
+ ],
57
+ "src": "data:text/plain,TITLE%20%22Teal%20orange%22%0ALUT_3D_SIZE%202%0A0%200.1%200.1%0A1%200.5%200.2%0A0%201%200.9%0A1%201%200.6%0A0%200.2%201%0A1%200.4%200.9%0A0%201%201%0A1%201%201%0A",
58
+ "strength": 1
59
+ }
60
+ }
61
+ ]
62
+ },
63
+ "checks": [
64
+ {
65
+ "why": "the LUT is still on both shots, at a moderate strength",
66
+ "tool": "get_video_project",
67
+ "expect": {
68
+ "tracks": {
69
+ "$some": {
70
+ "clips": {
71
+ "$length": 2,
72
+ "$every": {
73
+ "grade": {
74
+ "lut": {
75
+ "src": {
76
+ "$match": "^data:"
77
+ },
78
+ "strength": {
79
+ "$min": 0.3,
80
+ "$max": 0.85
81
+ }
82
+ }
83
+ }
84
+ }
85
+ }
86
+ }
87
+ }
88
+ }
89
+ },
90
+ {
91
+ "why": "skin tones protected",
92
+ "tool": "get_video_project",
93
+ "expect": {
94
+ "tracks": {
95
+ "$some": {
96
+ "clips": {
97
+ "$every": {
98
+ "grade": {
99
+ "lut": {
100
+ "preserveSkinTones": {
101
+ "$min": 0.4
102
+ }
103
+ }
104
+ }
105
+ }
106
+ }
107
+ }
108
+ }
109
+ }
110
+ }
111
+ ],
112
+ "solution": [
113
+ {
114
+ "tool": "get_video_project"
115
+ },
116
+ {
117
+ "tool": "set_video_lut",
118
+ "args": {
119
+ "clips": [
120
+ "c1",
121
+ "c2"
122
+ ],
123
+ "src": {
124
+ "$read": "get_video_project",
125
+ "path": "tracks.0.clips.0.grade.lut.src"
126
+ },
127
+ "strength": 0.6,
128
+ "preserve_skin_tones": 0.7
129
+ }
130
+ }
131
+ ]
132
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "prompt": "Shot two (c2) was filmed one stop underexposed compared with shot one. Match it to shot one without touching shot one.",
3
+ "fixture": { "editor": "video", "setup": [{ "tool": "add_video_asset", "args": { "id": "a", "kind": "video", "src": "shot-a.mp4", "duration": 8000 } },
4
+ { "tool": "add_video_asset", "args": { "id": "b", "kind": "video", "src": "shot-b.mp4", "duration": 8000 } },
5
+ { "tool": "add_video_clip", "args": { "track": "v1", "clip": { "type": "media", "asset": "a", "id": "c1", "start": 0, "duration": 6000 } } },
6
+ { "tool": "add_video_clip", "args": { "track": "v1", "clip": { "type": "media", "asset": "b", "id": "c2", "start": 6000, "duration": 6000 } } }] },
7
+ "checks": [
8
+ { "why": "c2 brought up by about one stop", "tool": "get_video_project", "expect": { "tracks": { "$some": { "clips": { "$some": { "id": "c2", "grade": { "exposure": { "$min": 0.8, "$max": 1.2 } } } } } } } },
9
+ { "why": "shot one is untouched", "tool": "get_video_project", "expect": { "tracks": { "$some": { "clips": { "$some": { "id": "c1", "$expr": "!v.grade || Object.values(v.grade).every((x) => x === 0)" } } } } } }
10
+ ],
11
+ "solution": [
12
+ { "tool": "update_video_clip", "args": { "clip": "c2", "set": { "grade": { "exposure": 1 } } } }
13
+ ]
14
+ }
@@ -33,6 +33,9 @@ the pitfalls, and uses the tools below.
33
33
 
34
34
  - `pixerate-talking-head-edit`: dialogue cleanup by transcript: fillers, pauses, stutters.
35
35
  - `pixerate-bgm-alignment`: cutting to the beat, ducking music under speech, loudness.
36
+ - `pixerate-video-social-cut`: vertical reframes, the hook first, platform lengths, titles in the safe area.
37
+ - `pixerate-video-colour-grade`: correct and match shots, one look on an adjustment clip, LUTs and skin.
38
+ - `pixerate-video-montage`: selects on the beat, pacing, transitions, music and the ending.
36
39
 
37
40
  ## Working method
38
41
 
@@ -0,0 +1,99 @@
1
+ ---
2
+ name: pixerate-video-montage
3
+ description: The montage workflow in the Pixerate video editor - choosing selects and their best moments, assembling them on beats or a rhythm, varying shot length for pacing, cutting on action, short transitions where they help, music under the whole sequence, and a clean start and end. Use when asked to make a montage, a highlight reel, a sizzle reel, a recap, a music video edit, a slideshow of clips or photos, or to cut a set of clips to music or a rhythm, or when edit_video, add_video_marker, set_video_transition or find_video_gaps are available. Load with pixerate-video-editor, which lists every tool.
4
+ metadata:
5
+ kind: workflow
6
+ reference: pixerate-video-editor
7
+ ---
8
+
9
+ # Cutting a montage
10
+
11
+ A montage tells its story through rhythm: the best moment of each shot, in an order that
12
+ builds, cut to a beat. The work is choosing (selects and their best seconds), then placing
13
+ (on the beat, with shot lengths that breathe and quicken), then finishing (transitions only
14
+ where they help, music under everything, a clear ending).
15
+
16
+ This skill is the method. `pixerate-video-editor` has the full tool reference; for beats in a
17
+ music track and cutting to them, see `pixerate-bgm-alignment`.
18
+
19
+ ## Goal and quality bar
20
+
21
+ - Each shot is its best moment: taken from the middle of the action, not its first frames
22
+ (`in` past the camera's settle).
23
+ - Cuts land on beats or on action, on frame boundaries, with no gaps (`find_video_gaps` empty).
24
+ - Pacing varies: longer shots to establish, shorter to build, a held shot to land.
25
+ - Straight cuts by default; short crossfades (300-600 ms) or dips only for a reason (time
26
+ passing, a change of section), each with enough media on both sides (no handle errors).
27
+ - Music runs under the whole sequence and ends with it (a fade out or a musical ending), and
28
+ the picture ends cleanly (a fade to black or a held final frame).
29
+
30
+ ## Inputs to confirm
31
+
32
+ - **Selects and order:** which clips, in what order (story, chronology, energy).
33
+ - **Rhythm:** music with beats, markers, or a shot length (e.g. 1 s per shot).
34
+ - **Length** of the finished piece.
35
+
36
+ ## Working method
37
+
38
+ 1. **Read.** `get_video_project`: assets (with durations), markers (beats), music.
39
+ With music, `find_video_beats` (`pixerate-bgm-alignment`) marks the beats.
40
+ **Check:** you have a beat grid or a shot length, and each select's usable range.
41
+ 2. **Pick the moments.** For each select, the `in` point of its best stretch (skip the first
42
+ second or two, where the camera settles).
43
+ 3. **Assemble in one batch.** `edit_video` with one add-clip op per shot (`asset`, `id`, `in`,
44
+ `start` on a beat, `duration` to the next beat), `dry_run: true` first.
45
+ **Check:** the clips are in order, each `start` on a beat; `find_video_gaps` is empty.
46
+ 4. **Refine the rhythm.** `roll_video_edit` to move a cut to a beat or onto action without
47
+ shifting anything else; `slip_video_clip` to change what a shot shows without moving it.
48
+ Vary lengths: build up with shorter shots before the peak.
49
+ 5. **Transitions, sparingly.** `set_video_transition` `crossfade` 300-600 ms (or `dip` for a
50
+ section change); every type but dip needs half its length in media past the cut on both sides.
51
+ **Check:** `check_video_project` has no errors.
52
+ 6. **Music and ending.** The music clip on an audio track from 0 for the whole duration, with a
53
+ `fadeOut` of 1-3 s (or cut on its last beat); the last picture clip `fadeOut` 300-1000 ms to
54
+ black.
55
+ **Check:** `get_video_project` shows both, ending together.
56
+ 7. **Review.** `render_video_frame` with `times` at each cut for a contact sheet; watch the
57
+ rhythm in the preview where available.
58
+
59
+ ## Decision table
60
+
61
+ | Want | Approach |
62
+ | --- | --- |
63
+ | Energy, a build | Shorter shots toward the peak, cuts on every beat |
64
+ | Calm, reflective | Longer shots, cuts every 2-4 beats, crossfades |
65
+ | Time passing | Crossfade or dip between shots |
66
+ | A section change | Dip to black or a held shot, then a new rhythm |
67
+ | Continuity of motion | Cut on action (`roll_video_edit` onto the movement) |
68
+ | Photos in a slideshow | Image assets, a slow push-in (`set_video_keyframes` scale 1 to 1.08) |
69
+
70
+ ## Recipes
71
+
72
+ **On the beat.** Beats every `b` ms from 0: `edit_video` with `{ op: "add_clip", track: "v1", clip:
73
+ { type: "media", asset, id, in, start: k * b, duration: b } }` for each shot `k`; then `find_video_gaps`.
74
+
75
+ **Crossfades.** `edit_video` with `{ op: "set_transition", clip, transition: { type: "crossfade",
76
+ duration: 400 } }` for every clip after the first; then `check_video_project`.
77
+
78
+ **Music and fade-out.** `add_video_clip` on the audio track `{ type: "media", asset: music,
79
+ start: 0, duration: <sequence>, fadeOut: 2000 }`; `update_video_clip` on the last shot
80
+ `{ set: { fadeOut: 500 } }`.
81
+
82
+ ## Pitfalls
83
+
84
+ - **First frames of a clip** are often the camera settling; take `in` later.
85
+ - **Transitions everywhere** soften the rhythm and look dated; cut straight by default.
86
+ - **Missing handles.** A transition needs media past the cut on both sides; trimmed-to-the-edge
87
+ clips fail `check_video_project`.
88
+ - **Music that stops dead** at the end of the picture; fade it or end on a musical phrase.
89
+ - **Uniform shot lengths** for a long montage feel mechanical; vary them.
90
+
91
+ ## Tools used
92
+
93
+ - `get_video_project`, `find_video_gaps`, `check_video_project`, `render_video_frame`: read and check
94
+ - `add_video_marker`: beats and sections
95
+ - `edit_video`, `add_video_clip`: assemble in one batch
96
+ - `roll_video_edit`, `slip_video_clip`, `trim_video_clip`, `close_video_gaps`: refine the rhythm
97
+ - `set_video_transition`: crossfades and dips
98
+ - `update_video_clip`, `set_video_keyframes`: fades, volume and push-ins
99
+ - `undo_video`: take back a step