frameyard 0.7.0 → 0.8.0
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/CHANGELOG.md +61 -0
- package/GLOSSARY.md +40 -16
- package/README.md +54 -48
- package/dist/cli.js +23 -16
- package/dist/cli.js.map +1 -1
- package/dist/composition/descriptor.d.ts +17 -3
- package/dist/composition/descriptor.d.ts.map +1 -1
- package/dist/composition/descriptor.js +51 -28
- package/dist/composition/descriptor.js.map +1 -1
- package/dist/composition/format.d.ts +12 -0
- package/dist/composition/format.d.ts.map +1 -0
- package/dist/composition/format.js +28 -0
- package/dist/composition/format.js.map +1 -0
- package/dist/composition/index.d.ts +2 -1
- package/dist/composition/index.d.ts.map +1 -1
- package/dist/composition/index.js +1 -0
- package/dist/composition/index.js.map +1 -1
- package/dist/contracts.d.ts +55 -6
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +3 -0
- package/dist/contracts.js.map +1 -1
- package/dist/errors.d.ts +1 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js.map +1 -1
- package/dist/html/document-adapter.d.ts +3 -3
- package/dist/html/document-adapter.d.ts.map +1 -1
- package/dist/html/document-adapter.js +1 -1
- package/dist/html/document-adapter.js.map +1 -1
- package/dist/html/index.d.ts +1 -1
- package/dist/html/index.d.ts.map +1 -1
- package/dist/html/parse.d.ts +10 -2
- package/dist/html/parse.d.ts.map +1 -1
- package/dist/html/parse.js +14 -5
- package/dist/html/parse.js.map +1 -1
- package/dist/html/validate.d.ts +12 -1
- package/dist/html/validate.d.ts.map +1 -1
- package/dist/html/validate.js +233 -61
- package/dist/html/validate.js.map +1 -1
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/preview/main.d.ts +2 -2
- package/dist/preview/main.d.ts.map +1 -1
- package/dist/preview/main.js +35 -14
- package/dist/preview/main.js.map +1 -1
- package/dist/preview/timeline-data.d.ts +5 -1
- package/dist/preview/timeline-data.d.ts.map +1 -1
- package/dist/preview/timeline-host.d.ts.map +1 -1
- package/dist/preview/timeline-host.js +10 -0
- package/dist/preview/timeline-host.js.map +1 -1
- package/dist/preview/timeline-main.js +3 -2
- package/dist/preview/timeline-main.js.map +1 -1
- package/dist/project.d.ts +3 -5
- package/dist/project.d.ts.map +1 -1
- package/dist/project.js.map +1 -1
- package/dist/renderer/browser.d.ts +2 -2
- package/dist/renderer/browser.d.ts.map +1 -1
- package/dist/renderer/browser.js +10 -4
- package/dist/renderer/browser.js.map +1 -1
- package/dist/renderer/ffmpeg.d.ts +3 -0
- package/dist/renderer/ffmpeg.d.ts.map +1 -1
- package/dist/renderer/ffmpeg.js +122 -56
- package/dist/renderer/ffmpeg.js.map +1 -1
- package/dist/renderer/index.d.ts +40 -4
- package/dist/renderer/index.d.ts.map +1 -1
- package/dist/renderer/index.js +99 -24
- package/dist/renderer/index.js.map +1 -1
- package/dist/renderer/timeline.d.ts.map +1 -1
- package/dist/renderer/timeline.js +89 -0
- package/dist/renderer/timeline.js.map +1 -1
- package/dist/runtime/host.d.ts.map +1 -1
- package/dist/runtime/host.js +155 -31
- package/dist/runtime/host.js.map +1 -1
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +104 -101
- package/dist/scaffold.js.map +1 -1
- package/dist/server/composition-html.d.ts +13 -7
- package/dist/server/composition-html.d.ts.map +1 -1
- package/dist/server/composition-html.js +65 -16
- package/dist/server/composition-html.js.map +1 -1
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +26 -6
- package/dist/server/server.js.map +1 -1
- package/dist/server/timeline-preview-data.d.ts.map +1 -1
- package/dist/server/timeline-preview-data.js +11 -0
- package/dist/server/timeline-preview-data.js.map +1 -1
- package/dist/server/timeline-preview-html.d.ts.map +1 -1
- package/dist/server/timeline-preview-html.js +2 -1
- package/dist/server/timeline-preview-html.js.map +1 -1
- package/dist/timeline/resolve.d.ts +4 -3
- package/dist/timeline/resolve.d.ts.map +1 -1
- package/dist/timeline/resolve.js +14 -4
- package/dist/timeline/resolve.js.map +1 -1
- package/dist/timeline/schema.d.ts +7 -0
- package/dist/timeline/schema.d.ts.map +1 -1
- package/dist/timeline/schema.js +50 -0
- package/dist/timeline/schema.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/adr/0007-make-html-documents-the-composition-unit.md +1 -1
- package/docs/adr/0008-share-the-composition-document-grammar.md +1 -1
- package/docs/adr/0011-compose-timeline-frames-in-a-live-browser-host.md +1 -1
- package/docs/adr/0012-render-timelines-with-segmented-lossless-clip-intermediates.md +1 -1
- package/docs/adr/0014-compose-timeline-clips-with-css-blend-modes.md +37 -0
- package/docs/adr/0015-inherit-composition-format-from-the-project.md +28 -0
- package/docs/adr/0016-author-compositions-as-html-fragments.md +32 -0
- package/docs/adr/0017-render-timeless-compositions-as-stills.md +99 -0
- package/docs/migration-0.4.md +3 -1
- package/docs/migration-0.8.md +163 -0
- package/docs/preview-testing.md +7 -0
- package/docs/v0.1-design.md +42 -34
- package/examples/blend/README.md +106 -0
- package/examples/blend/assets/ink.mp4 +0 -0
- package/examples/blend/compositions/aurora.html +55 -0
- package/examples/blend/compositions/backdrop.html +74 -0
- package/examples/blend/compositions/labels.html +149 -0
- package/examples/blend/scripts/make-ink.sh +26 -0
- package/examples/blend/timelines/blend.timeline.json +155 -0
- package/examples/blend/video.config.js +11 -0
- package/examples/demo/compositions/demo.html +243 -251
- package/examples/static/README.md +17 -0
- package/examples/static/compositions/still.html +37 -0
- package/examples/static/timelines/still.timeline.json +13 -0
- package/examples/static/video.config.js +9 -0
- package/examples/video/compositions/video-mp4.html +349 -357
- package/examples/video/compositions/video-overlay.html +337 -345
- package/examples/video/compositions/video.html +349 -357
- package/examples/webgl/compositions/webgl.html +205 -213
- package/package.json +2 -1
- package/skills/frameyard/SKILL.md +15 -13
- package/skills/frameyard/references/common-mistakes.md +29 -6
- package/skills/frameyard/references/controllers.md +5 -4
- package/skills/frameyard/references/deterministic-authoring.md +41 -36
- package/skills/frameyard/references/diagnostics.md +11 -3
- package/skills/frameyard/references/failure-recovery.md +25 -5
- package/skills/frameyard/references/json-results.md +46 -4
- package/skills/frameyard/references/timelines.md +16 -12
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Frameyard blend example
|
|
2
|
+
|
|
3
|
+
A 12-second, 1920×1080, 30 fps timeline that demonstrates every supported CSS
|
|
4
|
+
blend mode on composition and video clips. Four video tracks build one frame:
|
|
5
|
+
|
|
6
|
+
- `v1` **backdrop** — a static opaque HTML composition with a grid, concentric
|
|
7
|
+
rings, and a dark vignette. It omits the time metadata and all dimensions, so
|
|
8
|
+
it inherits the project format and is captured once at the timeline's size.
|
|
9
|
+
- `v2` **aurora** — a static transparent HTML composition with three blurred
|
|
10
|
+
color blobs. It declares its dimensions but no time metadata, so it is also
|
|
11
|
+
captured once. Its clip uses `blend: "screen"` for the full 12 seconds.
|
|
12
|
+
- `v3` **ink** — a local 1280×720 H.264 clip scaled to fill the project frame.
|
|
13
|
+
Twelve touching clips play one second each, cycling through all 12 supported
|
|
14
|
+
modes in timeline order.
|
|
15
|
+
- `v4` **labels** — an animated transparent HTML composition in normal mode. It
|
|
16
|
+
lists the modes and their time ranges, and draws a progress bar from the
|
|
17
|
+
`--fy-progress` frame-state variable, so it is evaluated per frame.
|
|
18
|
+
|
|
19
|
+
The mode sequence on `v3` is:
|
|
20
|
+
|
|
21
|
+
| Time | Mode |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| 0–1 s | `normal` |
|
|
24
|
+
| 1–2 s | `multiply` |
|
|
25
|
+
| 2–3 s | `screen` |
|
|
26
|
+
| 3–4 s | `overlay` |
|
|
27
|
+
| 4–5 s | `darken` |
|
|
28
|
+
| 5–6 s | `lighten` |
|
|
29
|
+
| 6–7 s | `color-dodge` |
|
|
30
|
+
| 7–8 s | `color-burn` |
|
|
31
|
+
| 8–9 s | `hard-light` |
|
|
32
|
+
| 9–10 s | `soft-light` |
|
|
33
|
+
| 10–11 s | `difference` |
|
|
34
|
+
| 11–12 s | `exclusion` |
|
|
35
|
+
|
|
36
|
+
The aurora is transparent, so its `screen` blends only where its blobs have
|
|
37
|
+
alpha. The video is opaque, so its whole scaled frame participates in the blend.
|
|
38
|
+
The labels layer stays in `normal` mode so the copy remains readable.
|
|
39
|
+
|
|
40
|
+
Blend modes are static per clip. The example uses consecutive clips on `v3` to
|
|
41
|
+
show every mode in one timeline; it does not animate `blend` itself. `hue`,
|
|
42
|
+
`saturation`, `color`, and `luminosity` are rejected because they need
|
|
43
|
+
cross-channel math and are not part of the supported set.
|
|
44
|
+
|
|
45
|
+
`backdrop` and `aurora` are static compositions: they declare no
|
|
46
|
+
`duration-in-frames` or `fps`, are captured once, and the same image is reused
|
|
47
|
+
for every timeline frame. `labels` remains animated because its progress bar
|
|
48
|
+
reads `--fy-progress`; making it static would freeze the bar.
|
|
49
|
+
|
|
50
|
+
Preview composites with Chromium `mix-blend-mode`; production uses FFmpeg's
|
|
51
|
+
`blend` filter plus an alpha mask. The preview stage stacks by track order and
|
|
52
|
+
is isolated from the preview chrome. Small scaling, alpha, and color differences
|
|
53
|
+
between preview and the final encode are expected.
|
|
54
|
+
|
|
55
|
+
## Files
|
|
56
|
+
|
|
57
|
+
```text
|
|
58
|
+
examples/blend/
|
|
59
|
+
compositions/backdrop.html opaque base composition
|
|
60
|
+
compositions/aurora.html transparent screen layer
|
|
61
|
+
compositions/labels.html transparent mode list and progress layer
|
|
62
|
+
timelines/blend.timeline.json
|
|
63
|
+
assets/ink.mp4 procedural 12-second source clip
|
|
64
|
+
scripts/make-ink.sh regenerate assets/ink.mp4
|
|
65
|
+
video.config.js
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
The timeline lives in `timelines/blend.timeline.json`; the project format and
|
|
69
|
+
entries are fixed in `video.config.js`. `backdrop.html` is a static composition
|
|
70
|
+
that omits all dimensions and time metadata, so it inherits the project's
|
|
71
|
+
1920×1080 size. `aurora.html` is a static composition that declares its
|
|
72
|
+
dimensions but no time metadata. `labels.html` is an animated composition and
|
|
73
|
+
keeps its `fps` and `duration-in-frames`.
|
|
74
|
+
|
|
75
|
+
## Commands
|
|
76
|
+
|
|
77
|
+
From the repository root:
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
pnpm build
|
|
81
|
+
node dist/cli.js check blend-timeline --project examples/blend
|
|
82
|
+
node dist/cli.js still blend-timeline --frame 15,45,75,105,135,165,195,225,255,285,315,345 --project examples/blend --out blend-stills
|
|
83
|
+
node dist/cli.js still blend-timeline --frame 285 --project examples/blend --out blend-soft-light.png
|
|
84
|
+
node dist/cli.js render blend-timeline --project examples/blend
|
|
85
|
+
node dist/cli.js dev --project examples/blend
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The batch still captures one representative frame per mode into `blend-stills/`
|
|
89
|
+
using the same clip capture and composite path as the render. `render` writes
|
|
90
|
+
`out/blend-timeline.mp4` inside the project by default; use `--out <file.mp4>`
|
|
91
|
+
to choose another path. `dev` lists the compositions and the timeline in the
|
|
92
|
+
preview.
|
|
93
|
+
|
|
94
|
+
## Source clip
|
|
95
|
+
|
|
96
|
+
`assets/ink.mp4` is a 12-second, 1280×720, 30 fps rotating gradient with a
|
|
97
|
+
silent AAC track, generated by FFmpeg. Regenerate it with:
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
bash examples/blend/scripts/make-ink.sh
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Pass an output path as the first argument to write elsewhere. Replace
|
|
104
|
+
`assets/ink.mp4` with any local, seekable MP4 or WebM that is at least 12 seconds
|
|
105
|
+
long; remote URLs and live streams are not supported. If you use a different
|
|
106
|
+
length, update the clip durations and source in-points in the timeline.
|
|
Binary file
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<style>
|
|
2
|
+
html,
|
|
3
|
+
body,
|
|
4
|
+
fy-composition {
|
|
5
|
+
margin: 0;
|
|
6
|
+
width: 100%;
|
|
7
|
+
height: 100%;
|
|
8
|
+
background: transparent;
|
|
9
|
+
}
|
|
10
|
+
fy-composition {
|
|
11
|
+
display: block;
|
|
12
|
+
overflow: hidden;
|
|
13
|
+
}
|
|
14
|
+
.scene {
|
|
15
|
+
position: relative;
|
|
16
|
+
width: 100%;
|
|
17
|
+
height: 100%;
|
|
18
|
+
overflow: hidden;
|
|
19
|
+
isolation: isolate;
|
|
20
|
+
}
|
|
21
|
+
.blob {
|
|
22
|
+
position: absolute;
|
|
23
|
+
border-radius: 50%;
|
|
24
|
+
filter: blur(78px);
|
|
25
|
+
opacity: 0.9;
|
|
26
|
+
}
|
|
27
|
+
.pink {
|
|
28
|
+
left: 6%;
|
|
29
|
+
top: -18%;
|
|
30
|
+
width: 980px;
|
|
31
|
+
height: 980px;
|
|
32
|
+
background: radial-gradient(circle, rgba(255, 64, 164, 0.92), rgba(255, 64, 164, 0) 68%);
|
|
33
|
+
}
|
|
34
|
+
.blue {
|
|
35
|
+
right: -12%;
|
|
36
|
+
top: 4%;
|
|
37
|
+
width: 1180px;
|
|
38
|
+
height: 1180px;
|
|
39
|
+
background: radial-gradient(circle, rgba(46, 146, 255, 0.88), rgba(46, 146, 255, 0) 68%);
|
|
40
|
+
}
|
|
41
|
+
.amber {
|
|
42
|
+
left: 30%;
|
|
43
|
+
bottom: -30%;
|
|
44
|
+
width: 900px;
|
|
45
|
+
height: 900px;
|
|
46
|
+
background: radial-gradient(circle, rgba(255, 186, 72, 0.7), rgba(255, 186, 72, 0) 70%);
|
|
47
|
+
}
|
|
48
|
+
</style>
|
|
49
|
+
<fy-composition width="1920" height="1080">
|
|
50
|
+
<div class="scene">
|
|
51
|
+
<div class="blob pink"></div>
|
|
52
|
+
<div class="blob blue"></div>
|
|
53
|
+
<div class="blob amber"></div>
|
|
54
|
+
</div>
|
|
55
|
+
</fy-composition>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
<style>
|
|
2
|
+
html,
|
|
3
|
+
body {
|
|
4
|
+
margin: 0;
|
|
5
|
+
width: 100%;
|
|
6
|
+
height: 100%;
|
|
7
|
+
background: #05070d;
|
|
8
|
+
}
|
|
9
|
+
fy-composition {
|
|
10
|
+
display: block;
|
|
11
|
+
width: 100%;
|
|
12
|
+
height: 100%;
|
|
13
|
+
overflow: hidden;
|
|
14
|
+
}
|
|
15
|
+
.scene {
|
|
16
|
+
position: relative;
|
|
17
|
+
width: 100%;
|
|
18
|
+
height: 100%;
|
|
19
|
+
overflow: hidden;
|
|
20
|
+
background:
|
|
21
|
+
radial-gradient(1200px 760px at 72% 34%, rgba(42, 104, 220, 0.5), transparent 62%),
|
|
22
|
+
radial-gradient(860px 620px at 18% 82%, rgba(255, 76, 140, 0.14), transparent 64%),
|
|
23
|
+
linear-gradient(145deg, #060a12 0%, #0b1424 52%, #05070d 100%);
|
|
24
|
+
}
|
|
25
|
+
.grid {
|
|
26
|
+
position: absolute;
|
|
27
|
+
inset: -1px;
|
|
28
|
+
background-image:
|
|
29
|
+
linear-gradient(rgba(150, 190, 255, 0.075) 1px, transparent 1px),
|
|
30
|
+
linear-gradient(90deg, rgba(150, 190, 255, 0.075) 1px, transparent 1px);
|
|
31
|
+
background-size: 72px 72px;
|
|
32
|
+
}
|
|
33
|
+
.fade {
|
|
34
|
+
position: absolute;
|
|
35
|
+
inset: 0;
|
|
36
|
+
background:
|
|
37
|
+
radial-gradient(ellipse at 58% 38%, transparent 18%, rgba(5, 7, 13, 0.55) 62%, rgba(5, 7, 13, 0.92) 100%),
|
|
38
|
+
linear-gradient(90deg, rgba(5, 7, 13, 0.5), transparent 38%, transparent 74%, rgba(5, 7, 13, 0.55));
|
|
39
|
+
}
|
|
40
|
+
.ring {
|
|
41
|
+
position: absolute;
|
|
42
|
+
left: 58%;
|
|
43
|
+
top: 44%;
|
|
44
|
+
width: 1060px;
|
|
45
|
+
height: 1060px;
|
|
46
|
+
border: 1px solid rgba(160, 205, 255, 0.18);
|
|
47
|
+
border-radius: 50%;
|
|
48
|
+
box-shadow:
|
|
49
|
+
0 0 140px rgba(54, 118, 255, 0.16) inset,
|
|
50
|
+
0 0 90px rgba(54, 118, 255, 0.08);
|
|
51
|
+
transform: translate(-50%, -50%);
|
|
52
|
+
}
|
|
53
|
+
.ring::before,
|
|
54
|
+
.ring::after {
|
|
55
|
+
content: "";
|
|
56
|
+
position: absolute;
|
|
57
|
+
border: 1px solid rgba(255, 118, 190, 0.13);
|
|
58
|
+
border-radius: 50%;
|
|
59
|
+
}
|
|
60
|
+
.ring::before {
|
|
61
|
+
inset: 138px;
|
|
62
|
+
}
|
|
63
|
+
.ring::after {
|
|
64
|
+
inset: 286px;
|
|
65
|
+
border-color: rgba(255, 179, 71, 0.12);
|
|
66
|
+
}
|
|
67
|
+
</style>
|
|
68
|
+
<fy-composition>
|
|
69
|
+
<div class="scene">
|
|
70
|
+
<div class="grid"></div>
|
|
71
|
+
<div class="ring"></div>
|
|
72
|
+
<div class="fade"></div>
|
|
73
|
+
</div>
|
|
74
|
+
</fy-composition>
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
<style>
|
|
2
|
+
html,
|
|
3
|
+
body,
|
|
4
|
+
fy-composition {
|
|
5
|
+
margin: 0;
|
|
6
|
+
width: 100%;
|
|
7
|
+
height: 100%;
|
|
8
|
+
background: transparent;
|
|
9
|
+
}
|
|
10
|
+
fy-composition {
|
|
11
|
+
display: block;
|
|
12
|
+
overflow: hidden;
|
|
13
|
+
}
|
|
14
|
+
.scene {
|
|
15
|
+
position: relative;
|
|
16
|
+
width: 100%;
|
|
17
|
+
height: 100%;
|
|
18
|
+
overflow: hidden;
|
|
19
|
+
color: #eef4ff;
|
|
20
|
+
font-family: Inter, "Helvetica Neue", ui-sans-serif, system-ui, sans-serif;
|
|
21
|
+
}
|
|
22
|
+
.panel {
|
|
23
|
+
position: absolute;
|
|
24
|
+
left: 92px;
|
|
25
|
+
top: 96px;
|
|
26
|
+
width: 920px;
|
|
27
|
+
padding: 44px 46px 40px;
|
|
28
|
+
border: 1px solid rgba(160, 205, 255, 0.24);
|
|
29
|
+
border-radius: 22px;
|
|
30
|
+
background: linear-gradient(135deg, rgba(6, 12, 24, 0.91), rgba(6, 12, 24, 0.64));
|
|
31
|
+
box-shadow: 0 38px 110px rgba(0, 0, 0, 0.38);
|
|
32
|
+
}
|
|
33
|
+
.kicker {
|
|
34
|
+
color: #7fd6ff;
|
|
35
|
+
font-family: ui-monospace, "SFMono-Regular", "Cascadia Code", monospace;
|
|
36
|
+
font-size: 13px;
|
|
37
|
+
font-weight: 650;
|
|
38
|
+
letter-spacing: 0.22em;
|
|
39
|
+
text-transform: uppercase;
|
|
40
|
+
}
|
|
41
|
+
h1 {
|
|
42
|
+
margin: 18px 0 14px;
|
|
43
|
+
font-size: 78px;
|
|
44
|
+
font-weight: 680;
|
|
45
|
+
letter-spacing: -0.045em;
|
|
46
|
+
line-height: 0.95;
|
|
47
|
+
}
|
|
48
|
+
h1 span {
|
|
49
|
+
color: #ffb347;
|
|
50
|
+
}
|
|
51
|
+
.subtitle {
|
|
52
|
+
margin: 0;
|
|
53
|
+
max-width: 780px;
|
|
54
|
+
color: #a9b8d0;
|
|
55
|
+
font-size: 20px;
|
|
56
|
+
line-height: 1.4;
|
|
57
|
+
}
|
|
58
|
+
.modes {
|
|
59
|
+
display: grid;
|
|
60
|
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
61
|
+
gap: 14px 18px;
|
|
62
|
+
margin-top: 28px;
|
|
63
|
+
}
|
|
64
|
+
.modes div {
|
|
65
|
+
padding-top: 9px;
|
|
66
|
+
border-top: 2px solid rgba(127, 214, 255, 0.5);
|
|
67
|
+
}
|
|
68
|
+
.modes div:nth-child(4n + 2) {
|
|
69
|
+
border-top-color: rgba(255, 179, 71, 0.5);
|
|
70
|
+
}
|
|
71
|
+
.modes div:nth-child(4n + 3) {
|
|
72
|
+
border-top-color: rgba(255, 100, 180, 0.5);
|
|
73
|
+
}
|
|
74
|
+
.modes div:nth-child(4n + 4) {
|
|
75
|
+
border-top-color: rgba(160, 190, 255, 0.5);
|
|
76
|
+
}
|
|
77
|
+
.modes b {
|
|
78
|
+
display: block;
|
|
79
|
+
margin-bottom: 5px;
|
|
80
|
+
color: #eef4ff;
|
|
81
|
+
font-family: ui-monospace, "SFMono-Regular", "Cascadia Code", monospace;
|
|
82
|
+
font-size: 15px;
|
|
83
|
+
font-weight: 600;
|
|
84
|
+
letter-spacing: -0.01em;
|
|
85
|
+
}
|
|
86
|
+
.modes span {
|
|
87
|
+
display: block;
|
|
88
|
+
color: #7f90a8;
|
|
89
|
+
font-family: ui-monospace, "SFMono-Regular", "Cascadia Code", monospace;
|
|
90
|
+
font-size: 11px;
|
|
91
|
+
}
|
|
92
|
+
.foot {
|
|
93
|
+
margin-top: 26px;
|
|
94
|
+
color: #73839a;
|
|
95
|
+
font-family: ui-monospace, "SFMono-Regular", "Cascadia Code", monospace;
|
|
96
|
+
font-size: 12px;
|
|
97
|
+
line-height: 1.55;
|
|
98
|
+
letter-spacing: 0.03em;
|
|
99
|
+
}
|
|
100
|
+
.progress {
|
|
101
|
+
position: absolute;
|
|
102
|
+
left: 142px;
|
|
103
|
+
bottom: 92px;
|
|
104
|
+
width: 820px;
|
|
105
|
+
height: 3px;
|
|
106
|
+
overflow: hidden;
|
|
107
|
+
border-radius: 99px;
|
|
108
|
+
background: rgba(220, 235, 255, 0.16);
|
|
109
|
+
}
|
|
110
|
+
.progress::after {
|
|
111
|
+
content: "";
|
|
112
|
+
display: block;
|
|
113
|
+
width: calc(var(--fy-progress) * 100%);
|
|
114
|
+
height: 100%;
|
|
115
|
+
border-radius: inherit;
|
|
116
|
+
background: linear-gradient(90deg, #7fd6ff, #ffb347);
|
|
117
|
+
}
|
|
118
|
+
</style>
|
|
119
|
+
<fy-composition width="1920" height="1080" fps="30" duration-in-frames="360">
|
|
120
|
+
<div class="scene">
|
|
121
|
+
<div class="panel">
|
|
122
|
+
<div class="kicker">Frameyard / Blend lab</div>
|
|
123
|
+
<h1>12 modes.<br /><span>One timeline.</span></h1>
|
|
124
|
+
<p class="subtitle">
|
|
125
|
+
A composition stays on screen while the video clip cycles through every supported CSS blend mode, one second
|
|
126
|
+
each.
|
|
127
|
+
</p>
|
|
128
|
+
<div class="modes">
|
|
129
|
+
<div><b>normal</b><span>0–1s</span></div>
|
|
130
|
+
<div><b>multiply</b><span>1–2s</span></div>
|
|
131
|
+
<div><b>screen</b><span>2–3s</span></div>
|
|
132
|
+
<div><b>overlay</b><span>3–4s</span></div>
|
|
133
|
+
<div><b>darken</b><span>4–5s</span></div>
|
|
134
|
+
<div><b>lighten</b><span>5–6s</span></div>
|
|
135
|
+
<div><b>color-dodge</b><span>6–7s</span></div>
|
|
136
|
+
<div><b>color-burn</b><span>7–8s</span></div>
|
|
137
|
+
<div><b>hard-light</b><span>8–9s</span></div>
|
|
138
|
+
<div><b>soft-light</b><span>9–10s</span></div>
|
|
139
|
+
<div><b>difference</b><span>10–11s</span></div>
|
|
140
|
+
<div><b>exclusion</b><span>11–12s</span></div>
|
|
141
|
+
</div>
|
|
142
|
+
<div class="foot">
|
|
143
|
+
v2 · composition · screen · 0–12s<br />
|
|
144
|
+
v3 · video · 12 modes · 1s each · Preview uses CSS; render uses FFmpeg + alpha mask
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
<div class="progress"></div>
|
|
148
|
+
</div>
|
|
149
|
+
</fy-composition>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
5
|
+
out="${1:-$root/assets/ink.mp4}"
|
|
6
|
+
mkdir -p "$(dirname "$out")"
|
|
7
|
+
|
|
8
|
+
ffmpeg -y -v error \
|
|
9
|
+
-f lavfi \
|
|
10
|
+
-i "gradients=size=1280x720:rate=30:c0=0x0b1020:c1=0x1b4dff:c2=0xff2d7a:c3=0xffb347:n=4:type=spiral:speed=0.08:duration=12" \
|
|
11
|
+
-f lavfi \
|
|
12
|
+
-i "anullsrc=channel_layout=stereo:sample_rate=48000" \
|
|
13
|
+
-t 12 \
|
|
14
|
+
-map 0:v:0 \
|
|
15
|
+
-map 1:a:0 \
|
|
16
|
+
-c:v libx264 \
|
|
17
|
+
-preset medium \
|
|
18
|
+
-crf 20 \
|
|
19
|
+
-pix_fmt yuv420p \
|
|
20
|
+
-g 30 \
|
|
21
|
+
-c:a aac \
|
|
22
|
+
-b:a 96k \
|
|
23
|
+
-shortest \
|
|
24
|
+
"$out"
|
|
25
|
+
|
|
26
|
+
printf 'Wrote %s\n' "$out"
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"name": "Blend lab: every supported mode on a video clip",
|
|
4
|
+
"background": "#05070d",
|
|
5
|
+
"tracks": [
|
|
6
|
+
{ "id": "v1", "kind": "video", "name": "Backdrop" },
|
|
7
|
+
{ "id": "v2", "kind": "video", "name": "Aurora · screen" },
|
|
8
|
+
{ "id": "v3", "kind": "video", "name": "Video · 12 modes, one per second" },
|
|
9
|
+
{ "id": "v4", "kind": "video", "name": "Labels" }
|
|
10
|
+
],
|
|
11
|
+
"clips": [
|
|
12
|
+
{
|
|
13
|
+
"id": "backdrop",
|
|
14
|
+
"track": "v1",
|
|
15
|
+
"source": { "kind": "composition", "id": "backdrop" },
|
|
16
|
+
"start": 0,
|
|
17
|
+
"duration": 360
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"id": "aurora",
|
|
21
|
+
"track": "v2",
|
|
22
|
+
"source": { "kind": "composition", "id": "aurora" },
|
|
23
|
+
"start": 0,
|
|
24
|
+
"duration": 360,
|
|
25
|
+
"blend": "screen"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"id": "ink-normal",
|
|
29
|
+
"track": "v3",
|
|
30
|
+
"source": { "kind": "video", "src": "assets/ink.mp4" },
|
|
31
|
+
"start": 0,
|
|
32
|
+
"duration": 30,
|
|
33
|
+
"sourceIn": 0,
|
|
34
|
+
"blend": "normal",
|
|
35
|
+
"audio": { "muted": true }
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"id": "ink-multiply",
|
|
39
|
+
"track": "v3",
|
|
40
|
+
"source": { "kind": "video", "src": "assets/ink.mp4" },
|
|
41
|
+
"start": 30,
|
|
42
|
+
"duration": 30,
|
|
43
|
+
"sourceIn": 30,
|
|
44
|
+
"blend": "multiply",
|
|
45
|
+
"audio": { "muted": true }
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"id": "ink-screen",
|
|
49
|
+
"track": "v3",
|
|
50
|
+
"source": { "kind": "video", "src": "assets/ink.mp4" },
|
|
51
|
+
"start": 60,
|
|
52
|
+
"duration": 30,
|
|
53
|
+
"sourceIn": 60,
|
|
54
|
+
"blend": "screen",
|
|
55
|
+
"audio": { "muted": true }
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"id": "ink-overlay",
|
|
59
|
+
"track": "v3",
|
|
60
|
+
"source": { "kind": "video", "src": "assets/ink.mp4" },
|
|
61
|
+
"start": 90,
|
|
62
|
+
"duration": 30,
|
|
63
|
+
"sourceIn": 90,
|
|
64
|
+
"blend": "overlay",
|
|
65
|
+
"audio": { "muted": true }
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"id": "ink-darken",
|
|
69
|
+
"track": "v3",
|
|
70
|
+
"source": { "kind": "video", "src": "assets/ink.mp4" },
|
|
71
|
+
"start": 120,
|
|
72
|
+
"duration": 30,
|
|
73
|
+
"sourceIn": 120,
|
|
74
|
+
"blend": "darken",
|
|
75
|
+
"audio": { "muted": true }
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"id": "ink-lighten",
|
|
79
|
+
"track": "v3",
|
|
80
|
+
"source": { "kind": "video", "src": "assets/ink.mp4" },
|
|
81
|
+
"start": 150,
|
|
82
|
+
"duration": 30,
|
|
83
|
+
"sourceIn": 150,
|
|
84
|
+
"blend": "lighten",
|
|
85
|
+
"audio": { "muted": true }
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"id": "ink-color-dodge",
|
|
89
|
+
"track": "v3",
|
|
90
|
+
"source": { "kind": "video", "src": "assets/ink.mp4" },
|
|
91
|
+
"start": 180,
|
|
92
|
+
"duration": 30,
|
|
93
|
+
"sourceIn": 180,
|
|
94
|
+
"blend": "color-dodge",
|
|
95
|
+
"audio": { "muted": true }
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"id": "ink-color-burn",
|
|
99
|
+
"track": "v3",
|
|
100
|
+
"source": { "kind": "video", "src": "assets/ink.mp4" },
|
|
101
|
+
"start": 210,
|
|
102
|
+
"duration": 30,
|
|
103
|
+
"sourceIn": 210,
|
|
104
|
+
"blend": "color-burn",
|
|
105
|
+
"audio": { "muted": true }
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"id": "ink-hard-light",
|
|
109
|
+
"track": "v3",
|
|
110
|
+
"source": { "kind": "video", "src": "assets/ink.mp4" },
|
|
111
|
+
"start": 240,
|
|
112
|
+
"duration": 30,
|
|
113
|
+
"sourceIn": 240,
|
|
114
|
+
"blend": "hard-light",
|
|
115
|
+
"audio": { "muted": true }
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
"id": "ink-soft-light",
|
|
119
|
+
"track": "v3",
|
|
120
|
+
"source": { "kind": "video", "src": "assets/ink.mp4" },
|
|
121
|
+
"start": 270,
|
|
122
|
+
"duration": 30,
|
|
123
|
+
"sourceIn": 270,
|
|
124
|
+
"blend": "soft-light",
|
|
125
|
+
"audio": { "muted": true }
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"id": "ink-difference",
|
|
129
|
+
"track": "v3",
|
|
130
|
+
"source": { "kind": "video", "src": "assets/ink.mp4" },
|
|
131
|
+
"start": 300,
|
|
132
|
+
"duration": 30,
|
|
133
|
+
"sourceIn": 300,
|
|
134
|
+
"blend": "difference",
|
|
135
|
+
"audio": { "muted": true }
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"id": "ink-exclusion",
|
|
139
|
+
"track": "v3",
|
|
140
|
+
"source": { "kind": "video", "src": "assets/ink.mp4" },
|
|
141
|
+
"start": 330,
|
|
142
|
+
"duration": 30,
|
|
143
|
+
"sourceIn": 330,
|
|
144
|
+
"blend": "exclusion",
|
|
145
|
+
"audio": { "muted": true }
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
"id": "labels",
|
|
149
|
+
"track": "v4",
|
|
150
|
+
"source": { "kind": "composition", "id": "labels" },
|
|
151
|
+
"start": 0,
|
|
152
|
+
"duration": 360
|
|
153
|
+
}
|
|
154
|
+
]
|
|
155
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
format: { width: 1920, height: 1080, fps: 30 },
|
|
3
|
+
compositions: {
|
|
4
|
+
backdrop: "./compositions/backdrop.html",
|
|
5
|
+
aurora: "./compositions/aurora.html",
|
|
6
|
+
labels: "./compositions/labels.html",
|
|
7
|
+
},
|
|
8
|
+
timelines: {
|
|
9
|
+
"blend-timeline": "./timelines/blend.timeline.json",
|
|
10
|
+
},
|
|
11
|
+
};
|