@pixerate/editor 0.223.4 → 0.223.6
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.
- package/dist/tools/skill-evals.d.cts +11 -1
- package/dist/tools/skill-evals.d.ts +11 -1
- package/package.json +1 -1
- package/skills/README.md +4 -1
- package/skills/pixerate-animation-editor/SKILL.md +8 -0
- package/skills/pixerate-animation-logo-reveal/SKILL.md +103 -0
- package/skills/pixerate-animation-logo-reveal/evals/draw-then-word.json +77 -0
- package/skills/pixerate-animation-logo-reveal/evals/hold-the-end.json +76 -0
- package/skills/pixerate-animation-logo-reveal/evals/on-the-beat.json +106 -0
- package/skills/pixerate-animation-motion-graphics/SKILL.md +100 -0
- package/skills/pixerate-animation-motion-graphics/evals/fit-length.json +109 -0
- package/skills/pixerate-animation-motion-graphics/evals/natural-easing.json +96 -0
- package/skills/pixerate-animation-motion-graphics/evals/staggered-entrance.json +69 -0
|
@@ -20,7 +20,7 @@ export interface SkillEvalCheck extends SkillEvalToolCall {
|
|
|
20
20
|
}
|
|
21
21
|
export interface SkillEval {
|
|
22
22
|
prompt: string;
|
|
23
|
-
fixture: SpreadsheetEvalFixture | ImageEvalFixture | VectorEvalFixture | PaintEvalFixture | VideoEvalFixture | ChartEvalFixture | DiagramEvalFixture;
|
|
23
|
+
fixture: SpreadsheetEvalFixture | ImageEvalFixture | VectorEvalFixture | PaintEvalFixture | VideoEvalFixture | ChartEvalFixture | DiagramEvalFixture | RichTextEvalFixture | AnimationEvalFixture;
|
|
24
24
|
checks: SkillEvalCheck[];
|
|
25
25
|
solution: SkillEvalToolCall[];
|
|
26
26
|
}
|
|
@@ -77,6 +77,16 @@ export interface DiagramEvalFixture {
|
|
|
77
77
|
/** Tool calls that build the starting diagram (`load_diagram_mermaid`), run in order. */
|
|
78
78
|
setup?: SkillEvalToolCall[];
|
|
79
79
|
}
|
|
80
|
+
export interface RichTextEvalFixture {
|
|
81
|
+
editor: 'rich-text';
|
|
82
|
+
/** The starting document as HTML. */
|
|
83
|
+
html: string;
|
|
84
|
+
}
|
|
85
|
+
export interface AnimationEvalFixture {
|
|
86
|
+
editor: 'animation';
|
|
87
|
+
/** Tool calls that build the starting scene (`set_animation_artwork_svg`, `insert_shots`), run in order. */
|
|
88
|
+
setup?: SkillEvalToolCall[];
|
|
89
|
+
}
|
|
80
90
|
/** One eval file of a skill. */
|
|
81
91
|
export interface SkillEvalFile {
|
|
82
92
|
skill: string;
|
|
@@ -20,7 +20,7 @@ export interface SkillEvalCheck extends SkillEvalToolCall {
|
|
|
20
20
|
}
|
|
21
21
|
export interface SkillEval {
|
|
22
22
|
prompt: string;
|
|
23
|
-
fixture: SpreadsheetEvalFixture | ImageEvalFixture | VectorEvalFixture | PaintEvalFixture | VideoEvalFixture | ChartEvalFixture | DiagramEvalFixture;
|
|
23
|
+
fixture: SpreadsheetEvalFixture | ImageEvalFixture | VectorEvalFixture | PaintEvalFixture | VideoEvalFixture | ChartEvalFixture | DiagramEvalFixture | RichTextEvalFixture | AnimationEvalFixture;
|
|
24
24
|
checks: SkillEvalCheck[];
|
|
25
25
|
solution: SkillEvalToolCall[];
|
|
26
26
|
}
|
|
@@ -77,6 +77,16 @@ export interface DiagramEvalFixture {
|
|
|
77
77
|
/** Tool calls that build the starting diagram (`load_diagram_mermaid`), run in order. */
|
|
78
78
|
setup?: SkillEvalToolCall[];
|
|
79
79
|
}
|
|
80
|
+
export interface RichTextEvalFixture {
|
|
81
|
+
editor: 'rich-text';
|
|
82
|
+
/** The starting document as HTML. */
|
|
83
|
+
html: string;
|
|
84
|
+
}
|
|
85
|
+
export interface AnimationEvalFixture {
|
|
86
|
+
editor: 'animation';
|
|
87
|
+
/** Tool calls that build the starting scene (`set_animation_artwork_svg`, `insert_shots`), run in order. */
|
|
88
|
+
setup?: SkillEvalToolCall[];
|
|
89
|
+
}
|
|
80
90
|
/** One eval file of a skill. */
|
|
81
91
|
export interface SkillEvalFile {
|
|
82
92
|
skill: string;
|
package/package.json
CHANGED
package/skills/README.md
CHANGED
|
@@ -61,6 +61,8 @@ request like "clean up this export" finds it.
|
|
|
61
61
|
| [`pixerate-diagram-architecture`](pixerate-diagram-architecture/SKILL.md) | Diagram (`pixerate-diagram`) | Systems at one level of detail, store shapes, tiers and trust boundaries, flows labelled with protocols. |
|
|
62
62
|
| [`pixerate-rich-text-report`](pixerate-rich-text-report/SKILL.md) | Rich text (`pixerate-rich-text`) | Reports with one title and a heading hierarchy, lists, tables and charts, and a consistency pass. |
|
|
63
63
|
| [`pixerate-rich-text-revise`](pixerate-rich-text-revise/SKILL.md) | Rich text (`pixerate-rich-text`) | Proofreading, renaming terms with exceptions and tightening, as minimal targeted edits. |
|
|
64
|
+
| [`pixerate-animation-motion-graphics`](pixerate-animation-motion-graphics/SKILL.md) | Animation (`pixerate-animation-editor`) | One idea per shot, staggered entrances, natural easing, holds to read, fitting a length, checks and export. |
|
|
65
|
+
| [`pixerate-animation-logo-reveal`](pixerate-animation-logo-reveal/SKILL.md) | Animation (`pixerate-animation-editor`) | A short reveal built from the logo's parts, landing on the beat and ending on the held, finished logo. |
|
|
64
66
|
| [`pixerate-talking-head-edit`](pixerate-talking-head-edit/SKILL.md) | Video (`pixerate-video-editor`) | Talking-head cleanup by transcript: fillers, long pauses and stutters found in one pass and cut as one plan reviewed before it applies. Owns the dialogue tools. |
|
|
65
67
|
| [`pixerate-bgm-alignment`](pixerate-bgm-alignment/SKILL.md) | Video (`pixerate-video-editor`) | Background music: beats and cuts on the beat, ducking under speech, loudness in LUFS. Owns the music tools. |
|
|
66
68
|
|
|
@@ -127,7 +129,8 @@ same change.
|
|
|
127
129
|
"vector", "width", "height", "setup" }` with commands that draw the starting art,
|
|
128
130
|
`{ "editor": "paint", "width", "height", "setup" }` `{ "editor": "video", "setup" }` or `{ "editor":
|
|
129
131
|
"chart", "setup" }` `{ "editor": "diagram", "setup" }` with tool calls,
|
|
130
|
-
|
|
132
|
+
`{ "editor": "rich-text", "html" }`, or
|
|
133
|
+
`{ "editor": "animation", "setup" }`), `checks` (a read-only
|
|
131
134
|
tool, or `run_command` with a read-only command such as `vector.list`, its `args`, what its result must match in `expect`, and `why`) and a `solution` (the
|
|
132
135
|
tool calls an expert would make). The test proves each eval: some check fails on the fixture,
|
|
133
136
|
and all pass after the solution. A model harness runs the same file with the model in place
|
|
@@ -21,6 +21,14 @@ For errors, namespaced tool names and the generic command tools, see `pixerate-a
|
|
|
21
21
|
The full command vocabulary (every type, option and default) is in
|
|
22
22
|
[references/commands.md](references/commands.md).
|
|
23
23
|
|
|
24
|
+
## Workflow skills
|
|
25
|
+
|
|
26
|
+
For these jobs, load the workflow skill too: it has the method, the checks between steps and
|
|
27
|
+
the pitfalls, and uses the tools below.
|
|
28
|
+
|
|
29
|
+
- `pixerate-animation-motion-graphics`: shots, staggered entrances, easing, holds, fitting a length.
|
|
30
|
+
- `pixerate-animation-logo-reveal`: a short reveal from the logo's parts, on the beat, ending held.
|
|
31
|
+
|
|
24
32
|
## Working method
|
|
25
33
|
|
|
26
34
|
1. **Read.** `get_animation` for elements, shots with timing, clips, drivers and issues. If
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pixerate-animation-logo-reveal
|
|
3
|
+
description: The logo reveal workflow in the Pixerate animation editor - a short branded intro or sting (two to four seconds) built from the logo's own parts - drawing or building the mark, bringing in the wordmark, landing beats on the music, ending on the complete logo held long enough to read, and exporting for video, web or Lottie. Use when asked to animate a logo, make a logo reveal, intro, outro, sting, bumper, brand animation or animated signature, sync a logo to music, or make a logo animation end cleanly, or when set_animation_artwork_svg, insert_shots, set_animation_settings or export_lottie are available. Load with pixerate-animation-editor, which lists every tool.
|
|
4
|
+
metadata:
|
|
5
|
+
kind: workflow
|
|
6
|
+
reference: pixerate-animation-editor
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Animating a logo reveal
|
|
10
|
+
|
|
11
|
+
A logo reveal is short and has one job: the viewer remembers the logo. It builds the logo
|
|
12
|
+
from its own parts (the mark, then the wordmark, or the reverse), moves in a way that suits the
|
|
13
|
+
brand, and ends on the complete, still logo long enough to read. Everything else is
|
|
14
|
+
decoration and should be cut if the reveal runs long.
|
|
15
|
+
|
|
16
|
+
This skill is the method. `pixerate-animation-editor` has the full tool reference and
|
|
17
|
+
`references/commands.md` every command.
|
|
18
|
+
|
|
19
|
+
## Goal and quality bar
|
|
20
|
+
|
|
21
|
+
- Two to four seconds in total (`get_animation` `duration`), unless the brief says otherwise.
|
|
22
|
+
- The logo is built from its parts in a clear order: the mark first (drawn on, popped or
|
|
23
|
+
assembled), then the wordmark.
|
|
24
|
+
- It ends on the finished logo, exactly as in the brand artwork, held at least 0.5 s
|
|
25
|
+
(about 1 s for video).
|
|
26
|
+
- The motion suits the brand: calm brands ease smoothly, playful ones can spring.
|
|
27
|
+
- With music, the key moments land on beats.
|
|
28
|
+
- `check_animation` shows no errors or warnings.
|
|
29
|
+
|
|
30
|
+
## Inputs to confirm
|
|
31
|
+
|
|
32
|
+
- **The logo artwork** (SVG with ids on the mark, the wordmark and any parts that move
|
|
33
|
+
separately).
|
|
34
|
+
- **Length, use and music:** a video intro, a web header loop, an outro; the tempo if there
|
|
35
|
+
is music.
|
|
36
|
+
- **Character:** calm, confident, playful, technical.
|
|
37
|
+
|
|
38
|
+
## Working method
|
|
39
|
+
|
|
40
|
+
1. **Read the artwork.** `get_animation` elements; if the logo is not loaded,
|
|
41
|
+
`set_animation_artwork_svg` with ids on its parts (outline text first; `get_text_layout`
|
|
42
|
+
shows letter units).
|
|
43
|
+
**Check:** every part you will animate has an id.
|
|
44
|
+
2. **Plan the build** in two or three beats: the mark arrives, the wordmark follows, the logo
|
|
45
|
+
settles.
|
|
46
|
+
3. **Write the reveal** as one or two shots with `insert_shots`: `enter` `style: "draw"` for an
|
|
47
|
+
outlined mark (or `pop`, `grow`, `iris`), then `enter` the wordmark (`slide`, `fade`, a
|
|
48
|
+
`wipe`, or `split: "letter"` for outlined text); `hold` at the end.
|
|
49
|
+
**Check:** `get_animation`: the mark's command starts before the wordmark's; the last shot
|
|
50
|
+
ends with a hold.
|
|
51
|
+
4. **Hit the music.** `set_animation_settings` `beat` with the `bpm`; `get_timing_grid` lists the
|
|
52
|
+
beats (counted from 0 at the start: at 120 BPM beat 4 is at 2000 ms, the downbeat of bar 2);
|
|
53
|
+
give the wordmark's shot `at: { beat }`.
|
|
54
|
+
**Check:** the shot's `start` in `get_animation` is the beat's time.
|
|
55
|
+
5. **Length and hold.** `fit_animation` with `seconds` and `keep` for the final hold, or
|
|
56
|
+
`update_shot` `hold` on the last shot.
|
|
57
|
+
**Check:** `duration` in range; the hold after the last command is long enough.
|
|
58
|
+
6. **Check and export.** `check_animation`; `render_animation_frame` at the end (`shot`, `at:
|
|
59
|
+
"end"`) to see the finished logo; `export_lottie` for the web.
|
|
60
|
+
|
|
61
|
+
## Decision table
|
|
62
|
+
|
|
63
|
+
| Mark | Entrance |
|
|
64
|
+
| --- | --- |
|
|
65
|
+
| An outline or line mark | `enter` `style: "draw"` (outline, then fill) |
|
|
66
|
+
| A solid, simple shape | `pop` or `grow`, `ease-out-back` |
|
|
67
|
+
| A mark made of parts | `enter` parts with `stagger`, or `match` into place |
|
|
68
|
+
| Outlined text wordmark | `enter` with `split: "letter"` |
|
|
69
|
+
| A wordmark beside the mark | `slide` away from the mark, or `wipe` |
|
|
70
|
+
| A calm brand | `fade`, `rise`, `ease-out`; no springs |
|
|
71
|
+
| A playful brand | `pop`, springs, a small `pulse` on landing |
|
|
72
|
+
|
|
73
|
+
## Recipes
|
|
74
|
+
|
|
75
|
+
**Draw then word.** `insert_shots` `[{ id: "reveal", run: [{ type: "enter", targets: ["mark"],
|
|
76
|
+
style: "draw" }, { type: "enter", targets: ["wordmark"], style: "slide", direction: "right" }],
|
|
77
|
+
hold: 700 }]`.
|
|
78
|
+
|
|
79
|
+
**Hold the end.** `update_shot` `{ shot: "reveal", set: { hold: 1000 } }`.
|
|
80
|
+
|
|
81
|
+
**On beat 4 at 120 BPM.** `set_animation_settings` `{ beat: { bpm: 120 } }` → `update_shot`
|
|
82
|
+
`{ shot: "word", set: { at: { beat: 4 } } }`.
|
|
83
|
+
|
|
84
|
+
## Pitfalls
|
|
85
|
+
|
|
86
|
+
- **Too long.** A reveal over four seconds loses the viewer; cut decoration first.
|
|
87
|
+
- **Ending in motion.** The logo must be still and complete at the end; hold it.
|
|
88
|
+
- **Distorting the logo** (stretching, recolouring) in the final frame; end on the brand
|
|
89
|
+
artwork.
|
|
90
|
+
- **Live text** in the artwork may render with a fallback font; outline it first.
|
|
91
|
+
- **Off-beat landings** with music feel wrong; cue shots to beats.
|
|
92
|
+
- **Too many effects** compete with the logo; one entrance per part.
|
|
93
|
+
|
|
94
|
+
## Tools used
|
|
95
|
+
|
|
96
|
+
- `get_animation`, `get_text_layout`, `find_animation_elements`: read the logo's parts
|
|
97
|
+
- `set_animation_artwork_svg`: load the logo with ids
|
|
98
|
+
- `insert_shots`, `update_shot`, `add_commands`, `update_command`: build the reveal
|
|
99
|
+
- `set_animation_settings`, `get_timing_grid`: music tempo and beats
|
|
100
|
+
- `fit_animation`: hit the length
|
|
101
|
+
- `check_animation`, `render_animation_frame`: check and look at the end frame
|
|
102
|
+
- `export_lottie`, `export_flair_motion`: deliver
|
|
103
|
+
- `undo_animation`: take back a step
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "Make a logo reveal under three seconds: draw the circle mark on, then bring in the wordmark, and end holding the full logo for at least half a second.",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "animation",
|
|
5
|
+
"setup": [
|
|
6
|
+
{
|
|
7
|
+
"tool": "set_animation_artwork_svg",
|
|
8
|
+
"args": {
|
|
9
|
+
"svg": "<svg viewBox=\"0 0 240 100\"><circle id=\"mark\" cx=\"50\" cy=\"50\" r=\"30\" fill=\"none\" stroke=\"#1d3557\" stroke-width=\"6\"/><rect id=\"wordmark\" x=\"100\" y=\"40\" width=\"120\" height=\"20\" fill=\"#1d3557\"/></svg>"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
"checks": [
|
|
15
|
+
{
|
|
16
|
+
"why": "the mark is drawn on before the wordmark arrives",
|
|
17
|
+
"tool": "get_animation",
|
|
18
|
+
"expect": {
|
|
19
|
+
"$expr": "(() => { const cs = v.shots.flatMap((s) => s.commands); const m = cs.find((c) => c.targets.includes('mark') && (c.type === 'draw' || (c.type === 'enter' && c.style === 'draw'))); const w = cs.find((c) => c.targets.includes('wordmark') && c.type === 'enter'); return !!m && !!w && m.start < w.start; })()"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"why": "under three seconds, ending on a hold of at least half a second",
|
|
24
|
+
"tool": "get_animation",
|
|
25
|
+
"expect": {
|
|
26
|
+
"duration": {
|
|
27
|
+
"$max": 3000
|
|
28
|
+
},
|
|
29
|
+
"shots": {
|
|
30
|
+
"$expr": "(() => { const s = v[v.length - 1]; return s.end - Math.max(...s.commands.map((c) => c.end)) >= 500; })()"
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"why": "no errors or warnings in the check",
|
|
36
|
+
"tool": "check_animation",
|
|
37
|
+
"expect": {
|
|
38
|
+
"errors": 0,
|
|
39
|
+
"warnings": 0
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
],
|
|
43
|
+
"solution": [
|
|
44
|
+
{
|
|
45
|
+
"tool": "insert_shots",
|
|
46
|
+
"args": {
|
|
47
|
+
"shots": [
|
|
48
|
+
{
|
|
49
|
+
"id": "reveal",
|
|
50
|
+
"label": "Logo reveal",
|
|
51
|
+
"run": [
|
|
52
|
+
{
|
|
53
|
+
"type": "enter",
|
|
54
|
+
"targets": [
|
|
55
|
+
"mark"
|
|
56
|
+
],
|
|
57
|
+
"style": "draw"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"type": "enter",
|
|
61
|
+
"targets": [
|
|
62
|
+
"wordmark"
|
|
63
|
+
],
|
|
64
|
+
"style": "slide",
|
|
65
|
+
"direction": "right"
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
"hold": 700
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"tool": "check_animation"
|
|
75
|
+
}
|
|
76
|
+
]
|
|
77
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "The reveal ends too abruptly. Hold the finished logo on screen for about a second at the end.",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "animation",
|
|
5
|
+
"setup": [
|
|
6
|
+
{
|
|
7
|
+
"tool": "set_animation_artwork_svg",
|
|
8
|
+
"args": {
|
|
9
|
+
"svg": "<svg viewBox=\"0 0 240 100\"><circle id=\"mark\" cx=\"50\" cy=\"50\" r=\"30\" fill=\"none\" stroke=\"#1d3557\" stroke-width=\"6\"/><rect id=\"wordmark\" x=\"100\" y=\"40\" width=\"120\" height=\"20\" fill=\"#1d3557\"/></svg>"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"tool": "insert_shots",
|
|
14
|
+
"args": {
|
|
15
|
+
"shots": [
|
|
16
|
+
{
|
|
17
|
+
"id": "reveal",
|
|
18
|
+
"run": [
|
|
19
|
+
{
|
|
20
|
+
"type": "enter",
|
|
21
|
+
"targets": [
|
|
22
|
+
"mark"
|
|
23
|
+
],
|
|
24
|
+
"style": "draw"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"type": "enter",
|
|
28
|
+
"targets": [
|
|
29
|
+
"wordmark"
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"hold": 0
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
},
|
|
40
|
+
"checks": [
|
|
41
|
+
{
|
|
42
|
+
"why": "the last shot holds about a second after its last command",
|
|
43
|
+
"tool": "get_animation",
|
|
44
|
+
"expect": {
|
|
45
|
+
"shots": {
|
|
46
|
+
"$expr": "(() => { const s = v[v.length - 1]; const h = s.end - Math.max(...s.commands.map((c) => c.end)); return h >= 800 && h <= 1500; })()"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"why": "the reveal itself is unchanged",
|
|
52
|
+
"tool": "get_animation",
|
|
53
|
+
"expect": {
|
|
54
|
+
"shots": {
|
|
55
|
+
"$some": {
|
|
56
|
+
"id": "reveal",
|
|
57
|
+
"commands": {
|
|
58
|
+
"$length": 2
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
],
|
|
65
|
+
"solution": [
|
|
66
|
+
{
|
|
67
|
+
"tool": "update_shot",
|
|
68
|
+
"args": {
|
|
69
|
+
"shot": "reveal",
|
|
70
|
+
"set": {
|
|
71
|
+
"hold": 1000
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
]
|
|
76
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "The sting music is 120 BPM. Make the wordmark land on beat 4: its shot should start on that beat.",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "animation",
|
|
5
|
+
"setup": [
|
|
6
|
+
{
|
|
7
|
+
"tool": "set_animation_artwork_svg",
|
|
8
|
+
"args": {
|
|
9
|
+
"svg": "<svg viewBox=\"0 0 240 100\"><circle id=\"mark\" cx=\"50\" cy=\"50\" r=\"30\" fill=\"none\" stroke=\"#1d3557\" stroke-width=\"6\"/><rect id=\"wordmark\" x=\"100\" y=\"40\" width=\"120\" height=\"20\" fill=\"#1d3557\"/></svg>"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"tool": "insert_shots",
|
|
14
|
+
"args": {
|
|
15
|
+
"shots": [
|
|
16
|
+
{
|
|
17
|
+
"id": "mark",
|
|
18
|
+
"run": [
|
|
19
|
+
{
|
|
20
|
+
"type": "enter",
|
|
21
|
+
"targets": [
|
|
22
|
+
"mark"
|
|
23
|
+
],
|
|
24
|
+
"style": "draw"
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"hold": 0
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"id": "word",
|
|
31
|
+
"run": [
|
|
32
|
+
{
|
|
33
|
+
"type": "enter",
|
|
34
|
+
"targets": [
|
|
35
|
+
"wordmark"
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
"hold": 800
|
|
40
|
+
}
|
|
41
|
+
]
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
},
|
|
46
|
+
"checks": [
|
|
47
|
+
{
|
|
48
|
+
"why": "a 120 BPM beat grid",
|
|
49
|
+
"tool": "get_timing_grid",
|
|
50
|
+
"expect": {
|
|
51
|
+
"grid": {
|
|
52
|
+
"bpm": 120
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
"why": "the wordmark's shot starts on beat 4",
|
|
58
|
+
"tool": "get_animation",
|
|
59
|
+
"expect": {
|
|
60
|
+
"shots": {
|
|
61
|
+
"$some": {
|
|
62
|
+
"id": "word",
|
|
63
|
+
"start": {
|
|
64
|
+
"$in": [
|
|
65
|
+
1500,
|
|
66
|
+
2000
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
"why": "no errors or warnings in the check",
|
|
75
|
+
"tool": "check_animation",
|
|
76
|
+
"expect": {
|
|
77
|
+
"errors": 0,
|
|
78
|
+
"warnings": 0
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
],
|
|
82
|
+
"solution": [
|
|
83
|
+
{
|
|
84
|
+
"tool": "set_animation_settings",
|
|
85
|
+
"args": {
|
|
86
|
+
"beat": {
|
|
87
|
+
"bpm": 120
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"tool": "update_shot",
|
|
93
|
+
"args": {
|
|
94
|
+
"shot": "word",
|
|
95
|
+
"set": {
|
|
96
|
+
"at": {
|
|
97
|
+
"beat": 4
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"tool": "check_animation"
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: pixerate-animation-motion-graphics
|
|
3
|
+
description: The motion graphics workflow in the Pixerate animation editor - planning one idea per shot, staggered entrances, easing and springs that feel natural, timing and holds that let the viewer read, fitting a target length, syncing to music, checking for issues and exporting to Lottie or Flair. Use when asked to animate, add motion to, make an explainer, a title sequence, an animated infographic, a UI or icon animation, staggered or sequenced entrances, smoother or snappier motion, or to fit an animation to a length, or when insert_shots, add_commands, fit_animation or check_animation are available. Load with pixerate-animation-editor, which lists every tool.
|
|
4
|
+
metadata:
|
|
5
|
+
kind: workflow
|
|
6
|
+
reference: pixerate-animation-editor
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Making motion graphics
|
|
10
|
+
|
|
11
|
+
Motion graphics direct attention: each shot shows one idea, things enter in the order they
|
|
12
|
+
should be read, motion eases the way real objects move, and the viewer gets time to read
|
|
13
|
+
before the next change. Write whole shots at once, let the default durations set the pace, and
|
|
14
|
+
change timing by shot (holds, speed, `fit_animation`) rather than nudging every command.
|
|
15
|
+
|
|
16
|
+
This skill is the method. `pixerate-animation-editor` has the full tool reference and
|
|
17
|
+
`references/commands.md` every command.
|
|
18
|
+
|
|
19
|
+
## Goal and quality bar
|
|
20
|
+
|
|
21
|
+
- One idea per shot, with a `label` saying what it shows.
|
|
22
|
+
- Related elements enter in reading order with a short stagger (60-200 ms between them), not
|
|
23
|
+
all at once and not one long queue.
|
|
24
|
+
- Every move and entrance eases (`ease-out` for things arriving, `ease-in` for leaving,
|
|
25
|
+
`ease-in-out` for moves, springs for playful motion); `linear` only for continuous motion
|
|
26
|
+
such as a rotation or a ticker.
|
|
27
|
+
- Holds give the viewer time to read: about 0.5 s plus 0.3 s per short line of text.
|
|
28
|
+
- The length fits the brief (`fit_animation`), and `check_animation` shows no errors or
|
|
29
|
+
warnings.
|
|
30
|
+
|
|
31
|
+
## Inputs to confirm
|
|
32
|
+
|
|
33
|
+
- **The message and order** the viewer should see things in.
|
|
34
|
+
- **Length** and **where it plays** (a loop on a site, an ad slot, a video).
|
|
35
|
+
- **Style:** calm and smooth, or snappy and playful; music and its tempo, if any.
|
|
36
|
+
|
|
37
|
+
## Working method
|
|
38
|
+
|
|
39
|
+
1. **Read.** `get_animation` for elements (ids, bounds), shots and issues. If there is no
|
|
40
|
+
artwork, `set_animation_artwork_svg` with an id on every element you will animate.
|
|
41
|
+
2. **Plan the shots** in words: what enters, moves or changes in each, and in what order.
|
|
42
|
+
3. **Write whole shots** with `insert_shots`: a `run` of commands with `targets`, `style`,
|
|
43
|
+
`stagger`, `ease`; leave `duration` out unless the pace must change; set `hold`.
|
|
44
|
+
**Check:** `get_animation`: each command's `start` and `end` are in the order you planned.
|
|
45
|
+
4. **Stagger and ease.** One `enter` with several `targets` and a `stagger` for a group; `ease`
|
|
46
|
+
presets or springs on moves (`update_command` `set: { ease }` to fix one).
|
|
47
|
+
**Check:** per-target starts differ by the stagger; no move left `linear` unless meant.
|
|
48
|
+
5. **Fit and cue.** `fit_animation` with `seconds` (and `keep` for shots whose pace matters,
|
|
49
|
+
such as a final hold); with music, `set_animation_settings` `beat` and shots `at: { beat }`
|
|
50
|
+
(see `pixerate-animation-logo-reveal`).
|
|
51
|
+
**Check:** `get_animation` `duration`.
|
|
52
|
+
6. **Check.** `check_animation`: fix `too-fast`, `overlap`, `out-of-frame`, `enter-visible` and
|
|
53
|
+
the rest. `get_motion_path` for spacing and arcs.
|
|
54
|
+
7. **Look and export.** `render_animation_frame` with `times` for a contact sheet; export with
|
|
55
|
+
`export_lottie` or `export_flair_motion` when asked.
|
|
56
|
+
|
|
57
|
+
## Decision table
|
|
58
|
+
|
|
59
|
+
| Want | Command and settings |
|
|
60
|
+
| --- | --- |
|
|
61
|
+
| A group appears in reading order | `enter` with several `targets`, `stagger` 60-200 |
|
|
62
|
+
| Something arrives | `enter` (`fade`, `rise`, `slide`, `pop`), `ease-out` |
|
|
63
|
+
| Something leaves | `exit`, `ease-in`, shorter than its entrance |
|
|
64
|
+
| A position change | `move` with `by` or `to`, `ease-in-out` |
|
|
65
|
+
| Playful, bouncy | `ease` `spring-bouncy` or `ease-out-back` |
|
|
66
|
+
| Draw a line or outline | `draw`, or `enter` `style: "draw"` |
|
|
67
|
+
| Attention on one element | `pulse`, `shake`, `wiggle` (sparingly) |
|
|
68
|
+
| A set length | `fit_animation` with `seconds`, `keep` for fixed shots |
|
|
69
|
+
|
|
70
|
+
## Recipes
|
|
71
|
+
|
|
72
|
+
**Staggered entrance.** `insert_shots` `[{ id: "bars", label: "Bars enter", run: [{ type:
|
|
73
|
+
"enter", targets: ["bar1", "bar2", "bar3"], style: "rise", stagger: 120 }], hold: 800 }]`.
|
|
74
|
+
|
|
75
|
+
**Natural move.** `update_command` `{ shot, command, set: { ease: "ease-in-out" } }`.
|
|
76
|
+
|
|
77
|
+
**Exactly four seconds.** `fit_animation` `{ seconds: 4 }`; then `check_animation` for
|
|
78
|
+
`too-fast` if shots were compressed a lot.
|
|
79
|
+
|
|
80
|
+
## Pitfalls
|
|
81
|
+
|
|
82
|
+
- **Everything at once.** Simultaneous entrances give the eye nowhere to start.
|
|
83
|
+
- **Linear moves** look mechanical; ease them.
|
|
84
|
+
- **Hand-set durations everywhere** make pacing inconsistent; keep the defaults and change pace
|
|
85
|
+
per shot.
|
|
86
|
+
- **No hold** at the end of a shot: the viewer cannot read it before it changes.
|
|
87
|
+
- **Overlapping commands** on one element fight each other (`overlap` in `check_animation`).
|
|
88
|
+
- **Elements without ids** in the artwork cannot be animated; add ids before importing.
|
|
89
|
+
|
|
90
|
+
## Tools used
|
|
91
|
+
|
|
92
|
+
- `get_animation`, `get_shot`, `find_animation_elements`, `describe_animation_command`: read scenes, elements and command fields
|
|
93
|
+
- `set_animation_artwork_svg`: the artwork with ids
|
|
94
|
+
- `insert_shots`, `update_shot`, `delete_shots`, `move_shot`: whole shots
|
|
95
|
+
- `add_commands`, `update_command`, `delete_commands`, `move_command`: refine commands
|
|
96
|
+
- `edit_animation`: several edits as one undo step
|
|
97
|
+
- `fit_animation`, `set_animation_settings`, `get_timing_grid`: length, settings and cues
|
|
98
|
+
- `check_animation`, `get_motion_path`, `render_animation_frame`: check and look
|
|
99
|
+
- `export_lottie`, `export_flair_motion`: deliver
|
|
100
|
+
- `undo_animation`: take back a step
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "This animation needs to be exactly 4 seconds long for the ad slot. Keep the pacing natural.",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "animation",
|
|
5
|
+
"setup": [
|
|
6
|
+
{
|
|
7
|
+
"tool": "set_animation_artwork_svg",
|
|
8
|
+
"args": {
|
|
9
|
+
"svg": "<svg viewBox=\"0 0 200 100\"><rect id=\"bar1\" x=\"20\" y=\"20\" width=\"20\" height=\"60\"/><rect id=\"bar2\" x=\"60\" y=\"20\" width=\"20\" height=\"60\"/><rect id=\"bar3\" x=\"100\" y=\"20\" width=\"20\" height=\"60\"/></svg>"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"tool": "insert_shots",
|
|
14
|
+
"args": {
|
|
15
|
+
"shots": [
|
|
16
|
+
{
|
|
17
|
+
"id": "intro",
|
|
18
|
+
"run": [
|
|
19
|
+
{
|
|
20
|
+
"type": "enter",
|
|
21
|
+
"targets": [
|
|
22
|
+
"bar1",
|
|
23
|
+
"bar2",
|
|
24
|
+
"bar3"
|
|
25
|
+
],
|
|
26
|
+
"stagger": 200
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"hold": 600
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"id": "middle",
|
|
33
|
+
"run": [
|
|
34
|
+
{
|
|
35
|
+
"type": "move",
|
|
36
|
+
"targets": [
|
|
37
|
+
"bar2"
|
|
38
|
+
],
|
|
39
|
+
"by": {
|
|
40
|
+
"x": 0,
|
|
41
|
+
"y": -20
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
],
|
|
45
|
+
"hold": 1500
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"id": "end",
|
|
49
|
+
"run": [
|
|
50
|
+
{
|
|
51
|
+
"type": "exit",
|
|
52
|
+
"targets": [
|
|
53
|
+
"bar1",
|
|
54
|
+
"bar2",
|
|
55
|
+
"bar3"
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
"hold": 1000
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
},
|
|
66
|
+
"checks": [
|
|
67
|
+
{
|
|
68
|
+
"why": "exactly 4 seconds",
|
|
69
|
+
"tool": "get_animation",
|
|
70
|
+
"expect": {
|
|
71
|
+
"duration": {
|
|
72
|
+
"$min": 3980,
|
|
73
|
+
"$max": 4020
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"why": "the same shots, in order",
|
|
79
|
+
"tool": "get_animation",
|
|
80
|
+
"expect": {
|
|
81
|
+
"shots": {
|
|
82
|
+
"$expr": "v.map((s) => s.id).join() === 'intro,middle,end'"
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"why": "no errors or warnings in the check",
|
|
88
|
+
"tool": "check_animation",
|
|
89
|
+
"expect": {
|
|
90
|
+
"errors": 0,
|
|
91
|
+
"warnings": 0
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
],
|
|
95
|
+
"solution": [
|
|
96
|
+
{
|
|
97
|
+
"tool": "get_animation"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"tool": "fit_animation",
|
|
101
|
+
"args": {
|
|
102
|
+
"seconds": 4
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"tool": "check_animation"
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "The bar's slide across looks mechanical. Make the movement feel natural.",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "animation",
|
|
5
|
+
"setup": [
|
|
6
|
+
{
|
|
7
|
+
"tool": "set_animation_artwork_svg",
|
|
8
|
+
"args": {
|
|
9
|
+
"svg": "<svg viewBox=\"0 0 200 100\"><rect id=\"bar1\" x=\"20\" y=\"20\" width=\"20\" height=\"60\"/><rect id=\"bar2\" x=\"60\" y=\"20\" width=\"20\" height=\"60\"/><rect id=\"bar3\" x=\"100\" y=\"20\" width=\"20\" height=\"60\"/></svg>"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"tool": "insert_shots",
|
|
14
|
+
"args": {
|
|
15
|
+
"shots": [
|
|
16
|
+
{
|
|
17
|
+
"id": "slide",
|
|
18
|
+
"run": [
|
|
19
|
+
{
|
|
20
|
+
"type": "move",
|
|
21
|
+
"targets": [
|
|
22
|
+
"bar1"
|
|
23
|
+
],
|
|
24
|
+
"by": {
|
|
25
|
+
"x": 60,
|
|
26
|
+
"y": 0
|
|
27
|
+
},
|
|
28
|
+
"ease": "linear"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
"checks": [
|
|
38
|
+
{
|
|
39
|
+
"why": "the move eases instead of running at constant speed",
|
|
40
|
+
"tool": "get_animation",
|
|
41
|
+
"expect": {
|
|
42
|
+
"shots": {
|
|
43
|
+
"$some": {
|
|
44
|
+
"id": "slide",
|
|
45
|
+
"commands": {
|
|
46
|
+
"$some": {
|
|
47
|
+
"type": "move",
|
|
48
|
+
"$expr": "v.ease !== 'linear'"
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"why": "it still slides the same distance",
|
|
57
|
+
"tool": "get_animation",
|
|
58
|
+
"expect": {
|
|
59
|
+
"shots": {
|
|
60
|
+
"$some": {
|
|
61
|
+
"id": "slide",
|
|
62
|
+
"commands": {
|
|
63
|
+
"$some": {
|
|
64
|
+
"type": "move",
|
|
65
|
+
"by": {
|
|
66
|
+
"x": 60,
|
|
67
|
+
"y": 0
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"why": "no errors or warnings in the check",
|
|
77
|
+
"tool": "check_animation",
|
|
78
|
+
"expect": {
|
|
79
|
+
"errors": 0,
|
|
80
|
+
"warnings": 0
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
],
|
|
84
|
+
"solution": [
|
|
85
|
+
{
|
|
86
|
+
"tool": "update_command",
|
|
87
|
+
"args": {
|
|
88
|
+
"shot": "slide",
|
|
89
|
+
"command": 0,
|
|
90
|
+
"set": {
|
|
91
|
+
"ease": "ease-in-out"
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"prompt": "Animate the three bars coming in one after another with a short, snappy stagger, then hold on all three.",
|
|
3
|
+
"fixture": {
|
|
4
|
+
"editor": "animation",
|
|
5
|
+
"setup": [
|
|
6
|
+
{
|
|
7
|
+
"tool": "set_animation_artwork_svg",
|
|
8
|
+
"args": {
|
|
9
|
+
"svg": "<svg viewBox=\"0 0 200 100\"><rect id=\"bar1\" x=\"20\" y=\"20\" width=\"20\" height=\"60\"/><rect id=\"bar2\" x=\"60\" y=\"20\" width=\"20\" height=\"60\"/><rect id=\"bar3\" x=\"100\" y=\"20\" width=\"20\" height=\"60\"/></svg>"
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
},
|
|
14
|
+
"checks": [
|
|
15
|
+
{
|
|
16
|
+
"why": "each bar enters, at a different time, within about half a second of each other",
|
|
17
|
+
"tool": "get_animation",
|
|
18
|
+
"expect": {
|
|
19
|
+
"$expr": "(() => { const starts = {}; for (const s of v.shots) for (const c of s.commands) if (c.type === 'enter') c.targets.forEach((t, i) => { starts[t] = c.start + (c.delay || 0) + i * (c.stagger || 0); }); const xs = ['bar1', 'bar2', 'bar3'].map((b) => starts[b]); return xs.every((x) => x !== undefined) && new Set(xs).size === 3 && Math.max(...xs) - Math.min(...xs) <= 600; })()"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"why": "it ends holding on the bars",
|
|
24
|
+
"tool": "get_animation",
|
|
25
|
+
"expect": {
|
|
26
|
+
"shots": {
|
|
27
|
+
"$expr": "(() => { const s = v[v.length - 1]; return s.end - Math.max(...s.commands.map((c) => c.end)) >= 300; })()"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"why": "no errors or warnings in the check",
|
|
33
|
+
"tool": "check_animation",
|
|
34
|
+
"expect": {
|
|
35
|
+
"errors": 0,
|
|
36
|
+
"warnings": 0
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
],
|
|
40
|
+
"solution": [
|
|
41
|
+
{
|
|
42
|
+
"tool": "insert_shots",
|
|
43
|
+
"args": {
|
|
44
|
+
"shots": [
|
|
45
|
+
{
|
|
46
|
+
"id": "bars",
|
|
47
|
+
"label": "Bars enter",
|
|
48
|
+
"run": [
|
|
49
|
+
{
|
|
50
|
+
"type": "enter",
|
|
51
|
+
"targets": [
|
|
52
|
+
"bar1",
|
|
53
|
+
"bar2",
|
|
54
|
+
"bar3"
|
|
55
|
+
],
|
|
56
|
+
"style": "rise",
|
|
57
|
+
"stagger": 120
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
"hold": 800
|
|
61
|
+
}
|
|
62
|
+
]
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"tool": "check_animation"
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
}
|