greenlight-motion 0.2.3 → 0.3.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/README.md +9 -9
- package/cli/index.mjs +9 -1
- package/dist/bundle-inputs.json +6 -0
- package/dist/greenlight-motion-script.mjs +25 -9
- package/dist/greenlight-motion.js +816 -651
- package/dist/greenlight-motion.mjs +38204 -37728
- package/package.json +1 -1
- package/schema/capabilities.json +1 -1
- package/skill/SKILL.md +17 -14
- package/skill/references/scene-script.md +6 -4
- package/skill/references/video-3d.md +1 -1
- package/skill/references/video-backgrounds.md +1 -1
- package/skill/references/video-camera.md +3 -1
- package/skill/references/video-effects.md +13 -12
- package/skill/references/video-particles.md +5 -5
- package/skill/references/video-projects.md +1 -0
- package/skill/references/video-text.md +1 -1
package/skill/SKILL.md
CHANGED
|
@@ -18,7 +18,7 @@ You never write UI or animation code. If something is not in the format, it is n
|
|
|
18
18
|
## Setup (once per machine)
|
|
19
19
|
|
|
20
20
|
```
|
|
21
|
-
npx greenlight-motion@0.
|
|
21
|
+
npx greenlight-motion@0.3.0 doctor
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
It checks Node 18+, Chrome or Edge, WebGPU and H.264 encoding, and prints a fix for anything missing. Do not install
|
|
@@ -39,7 +39,7 @@ animation presets (the same converter the GreenLight Motion connector uses in Cl
|
|
|
39
39
|
keyframes rarely look as good. The format, the design rules and the catalogues: `skill/references/scene-script.md`.
|
|
40
40
|
|
|
41
41
|
```
|
|
42
|
-
npx greenlight-motion@0.
|
|
42
|
+
npx greenlight-motion@0.3.0 script <folder> --from scenes.json # or write <folder>/script.json, then: script <folder>
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
Then `check` and `stills` (below), fix the SCRIPT and run `script` again — it rewrites `project.json`. A scene's
|
|
@@ -71,9 +71,12 @@ Keep the build repeatable: put your edits in a file you `apply` again after each
|
|
|
71
71
|
`apply`), so the script and the hand-made layers never drift apart.
|
|
72
72
|
|
|
73
73
|
What the engine does there, so you don't learn it from a broken frame:
|
|
74
|
-
- **A shader on a shape** draws
|
|
75
|
-
|
|
76
|
-
|
|
74
|
+
- **A shader on a shape** draws into its own buffer, at most 1280 px on its long side (the project background's: 2048),
|
|
75
|
+
and `iResolution` is that buffer's size, not the frame's or the shape's: a full-frame 1920×1080 shape renders at
|
|
76
|
+
1280×720, and a small shape's buffer can differ between preview and export. So compute in `fragCoord / iResolution.xy`
|
|
77
|
+
(0–1 across the shape), never in frame pixels. `iTime` counts from the layer's own start (the background's is the
|
|
78
|
+
timeline's), so layers whose shaders must stay in step need the same start. Its settings are not keyframe tracks:
|
|
79
|
+
change it over time inside the code, from `iTime`.
|
|
77
80
|
- **A track matte's source** is hidden only while a layer that uses it is on screen; outside that time it draws as an
|
|
78
81
|
ordinary layer. Give it the same start and end as the layer it cuts (`check` reports one that shows).
|
|
79
82
|
- **Fonts**: a text layer's family loads from Google Fonts while the page is online, unless a font file in `assets/`
|
|
@@ -82,14 +85,14 @@ What the engine does there, so you don't learn it from a broken frame:
|
|
|
82
85
|
|
|
83
86
|
## Workflow
|
|
84
87
|
|
|
85
|
-
1. `npx greenlight-motion@0.
|
|
88
|
+
1. `npx greenlight-motion@0.3.0 init <folder>` — starts from a working example (title, subtitle, accent line, four
|
|
86
89
|
options). `--from file.json` starts from a project you have (for example one exported from GreenLight Dash).
|
|
87
90
|
2. Edit `<folder>/project.json` — for changes to an EXISTING project prefer `apply` (below): it checks every edit and
|
|
88
91
|
applies all or nothing. Put pictures, video, sound and fonts in `<folder>/assets/` and refer to them as
|
|
89
92
|
`"asset:<file>"` (e.g. `"url": "asset:product.png"`).
|
|
90
|
-
3. `npx greenlight-motion@0.
|
|
91
|
-
frames, page errors). `--json` for machine output.
|
|
92
|
-
4. `npx greenlight-motion@0.
|
|
93
|
+
3. `npx greenlight-motion@0.3.0 check <folder>` — fix everything it lists (missing files, template mistakes, blank
|
|
94
|
+
frames, page errors), and read its notes: text the engine wraps where you did not break it. `--json` for machine output.
|
|
95
|
+
4. `npx greenlight-motion@0.3.0 stills <folder>` — renders frames and **a labelled contact sheet**. Open and look at
|
|
93
96
|
it before you go on: layout, readability, timing. Fix and repeat. `--at 0.5,1.2,3` for exact times.
|
|
94
97
|
5. Hand it over: tell the user to open `<folder>/index.html` (Chrome or Edge), or `pack` it into one file, or
|
|
95
98
|
`render` the MP4 yourself (`--fps 60 --motion-blur` for fast motion).
|
|
@@ -154,7 +157,7 @@ editor's own normalizer), so write only what you mean.
|
|
|
154
157
|
Full references (generated from the editor's own docs; ignore the `/api/` routes they mention):
|
|
155
158
|
`skill/references/` — video-design, scene-script, video-projects, video-text, video-text-kinetic, video-text-presets, video-shapes, video-keyframes,
|
|
156
159
|
video-camera, video-3d, video-effects, video-transitions, video-particles, video-paths, video-backgrounds, video-grid.
|
|
157
|
-
Machine-readable lists: `npx greenlight-motion@0.
|
|
160
|
+
Machine-readable lists: `npx greenlight-motion@0.3.0 schema effects | transitions | easings | paths | expressions`.
|
|
158
161
|
|
|
159
162
|
## Template
|
|
160
163
|
|
|
@@ -201,7 +204,7 @@ an absolute moment; `align` `sync` (default) / `start` / `end`; `offset` seconds
|
|
|
201
204
|
|
|
202
205
|
The library is 77 hand-picked sounds in categories (whooshes and swooshes, transitions, clicks, pop-ups and
|
|
203
206
|
notifications, data blips, typing and writing, foley, bubbles, impacts and bass drops, camera, gears, voice clips).
|
|
204
|
-
`npx greenlight-motion@0.
|
|
207
|
+
`npx greenlight-motion@0.3.0 schema sounds` lists every one with its `category`, `use` (what it is for), `duration`
|
|
205
208
|
and `sync`. Pick by `category` and `use`, then by name.
|
|
206
209
|
|
|
207
210
|
- **Where the files come from:** the GreenLight sound CDN. `build` downloads each sound a cue uses into
|
|
@@ -217,7 +220,7 @@ The page has **Notes**: the user marks what should change right on the frame (a
|
|
|
217
220
|
and writes a note for each mark. Every note carries the moment (seconds and frame), the mark in composition pixels
|
|
218
221
|
and the layers under it (item ids in project.json), so you change exactly that and nothing else.
|
|
219
222
|
|
|
220
|
-
- **They review on this computer:** run `npx greenlight-motion@0.
|
|
223
|
+
- **They review on this computer:** run `npx greenlight-motion@0.3.0 review <folder>` and give them the URL it prints
|
|
221
224
|
(it keeps running; `--open` opens their browser, only when they ask). Their notes land in `<folder>/review/`: read
|
|
222
225
|
`review/NOTES.md`, look at the `at-<t>s.png` pictures (the marks are numbered), make the changes (`apply`), `build`
|
|
223
226
|
again and tell them to reload the page.
|
|
@@ -246,11 +249,11 @@ that fails (`plugin`); look at `stills` for the look. A package that carries its
|
|
|
246
249
|
|
|
247
250
|
The same project opens in GreenLight Dash (the desktop editor this engine comes from) for full editing: the page's
|
|
248
251
|
edit note offers **Open in GreenLight Dash** (it imports the folder as a new project on the open board; a page with
|
|
249
|
-
changes saves a `.glvideo`). `npx greenlight-motion@0.
|
|
252
|
+
changes saves a `.glvideo`). `npx greenlight-motion@0.3.0 pack <folder> --glvideo` writes that file yourself: ONE
|
|
250
253
|
`.glvideo` (the project + its files) that opens in GreenLight Dash on a double-click, or dropped on its board. Hand it
|
|
251
254
|
over when the user wants to keep editing in the app. A
|
|
252
255
|
GreenLight Dash project comes the other way through the app's **Export for agents** — a ready folder like the one
|
|
253
|
-
`init` makes, with the options the author ticked. `npx greenlight-motion@0.
|
|
256
|
+
`init` makes, with the options the author ticked. `npx greenlight-motion@0.3.0 init <folder> --from <its project.json>`
|
|
254
257
|
starts from one too. Never tell the user they must install it: the page plays, changes options and renders on its own.
|
|
255
258
|
|
|
256
259
|
## Files
|
|
@@ -58,25 +58,27 @@ matte, masks, particles, 3D) goes on from `project.json`: SKILL.md, "Beyond the
|
|
|
58
58
|
a CSS gradient; `width` (px, wraps), `align`, `uppercase`, `letterSpacing`, `lineHeight`. A headline gets `glide-text` unless you set `textAnimation`.
|
|
59
59
|
The text box is CENTRED on `at`: without `width` it is as wide as its words but stays inside the frame (off-centre text wraps
|
|
60
60
|
sooner); for a left-aligned column give `width` and `"align": "left"` and put `at` at the column's centre.
|
|
61
|
-
- **rect · pill · circle**: `w`, `h`, `color` (or a CSS gradient), `radius`, `border` {width, color}, `shadow`: true. They enter with `pop-overshoot` unless you set `enter
|
|
61
|
+
- **rect · pill · circle**: `w`, `h`, `color` (or a CSS gradient), `radius`, `border` {width, color}, `shadow`: true. They enter with `pop-overshoot` unless you set `enter` (`"none"`: no entrance, it is simply there).
|
|
62
62
|
- **line**: from `at` to `to`, `width`, drawn on (`draw`: false to skip).
|
|
63
63
|
- **ring**: a circle drawn as a stroke from the top, clockwise (a timer, a status or focus ring): `w` (diameter), `width` (stroke),
|
|
64
64
|
`color`, `sweep` (degrees, 360 = full), drawn on (`draw`: false to skip), `drain`: true empties it again by the element's
|
|
65
|
-
end (a countdown), `ghost` (0–100: a faint full track under it).
|
|
65
|
+
end (a countdown) or `[start, end]` (s into the element) empties it then, `ghost` (0–100: a faint full track under it).
|
|
66
66
|
- **image · video**: `src` (a file in the folder's assets/ as `asset:<name>`, or an https link) or, for an image, `svg` (SVG markup you write); `w` or `h`
|
|
67
67
|
(px; the other follows the file's shape) or `fit` cover | contain
|
|
68
68
|
(default: a video covers the frame, a picture sits at 70 % of contain), `rotate` (deg). A video also takes
|
|
69
69
|
`startAt` (s into the file) and `volume` (0–100, default muted). No entrance unless you set `enter`.
|
|
70
70
|
- **Keyframes on any element** — your own motion: `"keyframes": { "x": [[0, -400], [0.8, 0, "Smooth Glide"]], "scale": [[0, 0.9], [2, 1.05]] }`
|
|
71
71
|
— tracks x, y (px offsets from `at`), scale, rotate (deg), opacity (0–1); each key [seconds into the element, value, easing of the
|
|
72
|
-
segment after it — Smooth Glide, AE Smooth, Expo Out, Back Out, Elastic, Linear …]. They replace an entrance's keys on the same track
|
|
72
|
+
segment after it — Smooth Glide, AE Smooth, Expo Out, Back Out, Elastic, Linear …]. They replace an entrance's keys on the same track;
|
|
73
|
+
one key holds that value for the whole element.
|
|
73
74
|
- **Every element**: `start` / `end` (s within its scene; default: staggered 0.12 s, to the scene's end), `enter` / `exit` (keyframe presets, `direction` up | down | left | right
|
|
74
75
|
for directional ones), `effects`: [{ "id", "params"? }], `sound` (played at its start), `id`, `label` (its name in the page's options), `opacity` (0–1),
|
|
75
76
|
`z` (px of depth, + toward the viewer, default 0: a real camera's dolly, orbit and depth of field separate layers by it), `locked`: true
|
|
76
77
|
(the scene's camera doesn't move it: a logo, a caption). Keyframes also take a `z` track.
|
|
77
78
|
- **Scene**: `duration` (s), `transition` into it (default Cross Fade, 0.6 s; `transitionDuration`), `transitionOptions` (the
|
|
78
79
|
transition's own settings, e.g. Circular Wipe's `point` { x, y } (% of the frame from its top-left: 50, 50 is the centre) and `feather`; every option: `npx greenlight-motion schema transitions`.
|
|
79
|
-
A transition's vivid colours, such as Circular Wipe's beam, take the accent unless you set them
|
|
80
|
+
A transition's vivid colours, such as Circular Wipe's beam, take the accent unless you set them; over a light backdrop Circular
|
|
81
|
+
Wipe's glowing beam is off, since it flares there, unless you set `beam`), `camera` (below; default push-in),
|
|
80
82
|
`background` (overrides style), `sounds`: [{ "sfx", "at" }]. Script-level `sound`: auto (default: a whoosh on each transition and
|
|
81
83
|
on the first headline, from the GreenLight sound library, which the CLI downloads into assets/sounds/ when it builds) | none (nothing from the library: when
|
|
82
84
|
nothing may be downloaded, use `music` with a file you made).
|
|
@@ -101,7 +101,7 @@ Some GLBs are authored facing away from the viewer — for those, set `baseRotat
|
|
|
101
101
|
| `env.exposure` | `0.05–8` | `1` | Tone-mapping exposure of the model pass. |
|
|
102
102
|
| `env.rotation` | `±360` deg | `0` | Spins the environment (moves reflections). |
|
|
103
103
|
| `lights.key/fill/rim` | `0–10` each | `1 / 0.45 / 0.35` | The three directional lights' intensities. **Accepted, normalised on read** — see "Scene Rig" below. Still the right shape to emit when a project has no rig layer; ignored on every model once one exists. |
|
|
104
|
-
| `animation.clip` | glTF animation name \| `"*"` \| `null` | `null` | Plays the named animation baked into the asset; `"*"` plays EVERY clip together, each on its own length (Blender's exporter writes one clip per animated object); `null` = static. Names must match the glTF exactly. `loop: "once"` holds the last frame. |
|
|
104
|
+
| `animation.clip` | glTF animation name \| `"*"` \| `null` | `null` | Plays the named animation baked into the asset; `"*"` plays EVERY clip together, each on its own length (Blender's exporter writes one clip per animated object); `null` = static. Names must match the glTF exactly. `loop: "once"` holds the last frame. A machine running or a device coming apart is made as such a GLB: video-mechanisms.md (GreenLight Dash only). |
|
|
105
105
|
| `animation.speed` | `-8–8` | `1` | Playback rate (negative = reversed). |
|
|
106
106
|
| `animation.loop` | `"once"` \| `"loop"` \| `"pingpong"` | `loop` | Loop mode. |
|
|
107
107
|
| `animation.offset` | `±600` s | `0` | Start offset into the animation. |
|
|
@@ -126,7 +126,7 @@ The vignette / footlight family (`blueplanet` through `spectrumdrift`) is the da
|
|
|
126
126
|
Custom shader backgrounds are **GLSL**, Shadertoy-shaped, and they are rasterised in their own WebGL context and handed to the compositor as a canvas — so they render identically on either engine the app is set to (`GET /api/video-editor/engine`), and they are the one place custom shading is not tied to it. `iTime` is driven by the **timeline** (not wall-clock), so output is deterministic and identical in preview and export.
|
|
127
127
|
|
|
128
128
|
- **Entry point:** `void mainImage(out vec4 fragColor, in vec2 fragCoord)`. Code that defines its own `main()` is used almost as-is instead.
|
|
129
|
-
- **In scope:** the Shadertoy uniforms — `iResolution` (vec3; `.xy` is the shader buffer size, which `shaderScale` sets), `iTime` (seconds), `iTimeDelta`, `iFrameRate`, `iFrame`, `iMouse` (zero), `iDate` — plus any uniform the shader declares itself, fed from `shaderParams` (see below).
|
|
129
|
+
- **In scope:** the Shadertoy uniforms — `iResolution` (vec3; `.xy` is the shader buffer size, which `shaderScale` sets and which is capped at **1280 px on its long side for a shape's background** and 2048 for the project background: a full-frame 1920×1080 shape renders at 1280×720, and a small shape's buffer follows the preview's raster density, so preview and export can differ — compute in `fragCoord / iResolution.xy`, never in composition pixels), `iTime` (seconds: on a shape, from that layer's start; on the project background, the timeline's), `iTimeDelta`, `iFrameRate`, `iFrame`, `iMouse` (zero), `iDate` — plus any uniform the shader declares itself, fed from `shaderParams` (see below).
|
|
130
130
|
- `fragCoord` arrives already scaled around the frame centre by `shaderZoom`, so a custom shader honours Scale without doing anything.
|
|
131
131
|
- **NOT available:** textures / image inputs (`iChannel0..3`), multi-buffer passes.
|
|
132
132
|
- Declaring a name the prelude also declares is safe — the duplicate is dropped from the prelude, which is what lets a pasted Shadertoy shader compile unchanged.
|
|
@@ -276,7 +276,7 @@ Parameter ranges (`CAMERA_RIG_PARAM_META` / `CAMERA_RIG_DEFAULTS`, `cameraRig.js
|
|
|
276
276
|
| Key | UI label | Range | Default |
|
|
277
277
|
| --- | --- | --- | --- |
|
|
278
278
|
| `radius` | Radius | `100`–`20000` px | `1800` |
|
|
279
|
-
| `height` | Height | `−8000`–`8000` px | `400` |
|
|
279
|
+
| `height` | Height | `−8000`–`8000` px | `400` (positive films from below the subject — a low hero angle; negative from above) |
|
|
280
280
|
| `startAngle` | **Start** | `−360`–`360`° | `−40` |
|
|
281
281
|
| `sweep` | Sweep | `−720`–`720`° | `90` |
|
|
282
282
|
| `rise` | Rise | `−8000`–`8000` px | `0` |
|
|
@@ -293,6 +293,8 @@ Parameter ranges (`CAMERA_RIG_PARAM_META` / `CAMERA_RIG_DEFAULTS`, `cameraRig.js
|
|
|
293
293
|
|
|
294
294
|
**Mode precedence — a rig or a live path BEATS the pose keyframes.** `getCameraPose` reads the tracks first, then `applyCameraRig` (mode `"rig"`) or `applyCameraPath` (mode `"path"` with a live path) overwrites `camX`, `camY`, `camDolly` — plus `camTiltX`/`camTiltY`/`camRoll` whenever an aim is computed. So on a rigged camera, `camX`/`camY`/`camDolly`/tilt/roll keyframes are stored, drawn in the timeline, and **render as nothing**. `camZoom`, the whole DOF family, `camPathT` and `camFollowTarget` are untouched by both and compose freely. Emitting a pose move therefore means emitting `"cameraMoveMode": "free"` (or omitting the field) with it — the editor enforces the same rule by flipping the mode to `"free"` when a motion preset that animates those props is applied, keeping `cameraRig` and `cameraPath` on the item so switching back restores the move.
|
|
295
295
|
|
|
296
|
+
**`radius` sets the framing.** The project camera films the frame at its own size from the perspective distance `(height / 2) / tan(14°)` (`perspectiveDistance`, `CAMERA_FOV` 28°): about **2166 px for a 1080-tall frame** and **3850 px for a 1920-tall one (9:16)**. A rig closer than that crops in, farther pulls back — so the default `1800` already crops a 16:9 frame a little and a vertical 9:16 one hard; set `radius` near the frame's distance unless the push is the point.
|
|
297
|
+
|
|
296
298
|
**Rig parameters are NOT keyframable** — keying `radius` would rebuild the whole move every frame. **`camPathT` (Path Progress) is the track that carries the move**, and a rig with no `camPathT` keys sits frozen at its start pose. Always emit `camPathT` 0 → 100 alongside a `cameraRig`:
|
|
297
299
|
|
|
298
300
|
```jsonc
|
|
@@ -91,12 +91,12 @@ An adjustment item processes every channel below it at its level. Inside the gro
|
|
|
91
91
|
{ "id": "plexus-glow-ch", "name": "Plexus glow", "visible": true, "unsnapped": true,
|
|
92
92
|
"items": [{ "id": "plexus-glow", "clipId": "plexus-glow-clip", "freeStart": 0, "trimStart": 0, "trimEnd": 1.05,
|
|
93
93
|
"effects": [{ "id": "glow", "eid": "plexus-glow-g", "enabled": true, "mix": 100,
|
|
94
|
-
"params": { "
|
|
94
|
+
"params": { "exposure": 0.85, "glowThreshold": 5, "glowRadius": 60, "tintAmount": 100, "tintInner": "#33EFAB", "tintOuter": "#33EFAB" } }] }] }]
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
```
|
|
98
98
|
|
|
99
|
-
One glow over the composite reads slightly differently from many. Per-layer glows add up wherever layers overlap; one glow over the composite does not. When converting an existing look, compare composited stills and raise `
|
|
99
|
+
One glow over the composite reads slightly differently from many. Per-layer glows add up wherever layers overlap; one glow over the composite does not. When converting an existing look, compare composited stills and raise `exposure` (or keyframe `fx:<eid>:exposure`) for the stretch where the layers lie on top of each other.
|
|
100
100
|
|
|
101
101
|
## Storage contract
|
|
102
102
|
|
|
@@ -136,10 +136,9 @@ The chain:
|
|
|
136
136
|
"enabled": true,
|
|
137
137
|
"mix": 100,
|
|
138
138
|
"params": {
|
|
139
|
-
"
|
|
140
|
-
"
|
|
141
|
-
"
|
|
142
|
-
"color": "#ffffff"
|
|
139
|
+
"glowRadius": 420,
|
|
140
|
+
"exposure": 1,
|
|
141
|
+
"glowThreshold": 72
|
|
143
142
|
},
|
|
144
143
|
"start": 0.5,
|
|
145
144
|
"end": 2.75,
|
|
@@ -210,7 +209,9 @@ Presets (the panel's chips, all params + colours in one click): Drifting Fog, Ro
|
|
|
210
209
|
|
|
211
210
|
#### Bloom
|
|
212
211
|
|
|
213
|
-
`
|
|
212
|
+
`glow` (**Deep Glow**, group Glow, both scopes) is light with a physically shaped falloff: a bright core and an inverse-square tail, computed in linear light. `glowRadius` (10–2000 px at 1080p) is how far the light reaches; `exposure` (0–4) is how much of the source's light scatters (0 = the effect does nothing and costs nothing); `falloff` (1.3–3.5, `2` = inverse square) steepens or flattens the tail. What glows: `glowThreshold` (0–100 %) with `thresholdSmooth`, measured by `thresholdBy` `0` Brightness (any bright colour, saturated neon included) / `1` Luminance / `2` Everything (the whole layer glows; the usual choice on a transparent text or shape layer). Shape: `aspect` (0.25–16 ×, above 1 = wider) and `angle` (−90…90°, clockwise) make it an ellipse — `aspect` ~11 with a short `glowRadius` (~130) is an anamorphic streak. Colour: the light takes the source's colour; `tintAmount` (0–100 %) recolours it from `tintInner` at the core to `tintOuter` at the edge (`tintMode` `0` Colorize / `1` Multiply), so a glow in one colour is `tintAmount` 100 with both set to it; `saturation` (0–200 %). The keys `intensity`, `threshold`, `radius` and `color` are not read. `radiusRed` / `radiusGreen` / `radiusBlue` (0.3–2.5 ×) let one channel reach further than another (red wide, blue tight = a warm fringe) and `aberration` (0–100 %) splits it radially. Output: `tonemap` `2` Hot Core (default — the picture under the glow stays exact; over-bright colour turns white instead of clipping) / `0` Clamp / `1` Soft Clip / `3` Reinhard / `4` ACES Filmic / `5` Hable Filmic (the last three regrade the whole layer), `linearLight` `1`/`0`, `blend` `0` Add / `1` Screen, `dither` `1`/`0`, `quality` `1` Standard / `0` Draft (half-resolution core). It writes outside the silhouette by design; leave `clip` unset. Example: `{"id": "glow", "mix": 100, "params": {"glowRadius": 260, "exposure": 1.7, "glowThreshold": 35, "saturation": 125}}` (Neon Tube).
|
|
213
|
+
|
|
214
|
+
`bloom` (**Bloom**, group Glow, both scopes) makes bright content leak light — a physically-shaped glow built on an octave pyramid rather than a blur kernel. `threshold` (0–1) with `knee` (soft shoulder) picks what counts as bright; `intensity` (0–600 %) scales the leak; `radius` (1–4) is **octaves of spread, not pixels** — 1 is a tight halo, 4 folds in a sixteenth-resolution octave whose halos span hundreds of px, and fractional values morph continuously. `saturation` desaturates or over-saturates the leaked light only, `tint` + `tintAmount` recolour it (the classic cold anamorphic look is a blue tint at ~60 %), and `blend` composites `0` Add / `1` Screen (protects already-bright frames from clipping) / `2` Lighten (max — halos never stack past the glow itself) / `3` Color Dodge (punchy filmic burn; falls back to Add over transparency so the outside halo survives) / `4` Bloom Only (just the leaked light, alpha from the bloom energy — for compositing the glow on its own). `anamorphic` (−100…100 %) smears the bloom into wide lens streaks — positive horizontal, negative vertical; magnitude sets streak length. `0` disables that pass entirely. It writes outside the silhouette by design; leave `clip` unset. On an adjustment item it blooms the whole below-stack — the usual "cinematic glow" move is an adjustment layer with `threshold` ~0.7 so only real highlights leak. Differs from `glow` (Deep Glow, below): Bloom's spread stops at 4 octaves and blends in display space; Deep Glow reaches up to 2000 px with an inverse-square tail in linear light.
|
|
214
215
|
|
|
215
216
|
#### Echo
|
|
216
217
|
|
|
@@ -282,7 +283,7 @@ It writes outside the silhouette by design; leave `clip` unset. Keyframable: `am
|
|
|
282
283
|
|
|
283
284
|
**Light cone through a line (the AE "Light Text Reveal" port).** The AE rig is a 2–4 px line whose own layer carries CC Radial Fast Blur ×2, Glow ×4 and Tint, with the text layers using it as a LUMA track matte. Rebuild it as:
|
|
284
285
|
|
|
285
|
-
1. A `sequence` clip holding: the glow line (`shapeType: "line"`, `lineWidth` 4, `lineStroke.paint` `{mode: "gradient", colors: ["#ffffff", "#000000", "#000000"], span: "path"}` — AE's white→black gradient stroke, which becomes the yellow→green split after the tint), animated with the AE `translateX/Y`/`rotate` keys; an adjustment item with `radialFastBlur` twice — Center 1 = Glow Position + (0, Spread), `zoom` 1, `falloff` 98, `intensity` 1500, `mix` 40; Center 2 = Glow Position − (0, Spread), `zoom` 1, `falloff` 96, `intensity` 1000 — `space` 1 on both, `amount` = AE amount (80 + Light Distance, 80 + 2 × Light Distance); and a second adjustment item with AE's outer glows
|
|
286
|
+
1. A `sequence` clip holding: the glow line (`shapeType: "line"`, `lineWidth` 4, `lineStroke.paint` `{mode: "gradient", colors: ["#ffffff", "#000000", "#000000"], span: "path"}` — AE's white→black gradient stroke, which becomes the yellow→green split after the tint), animated with the AE `translateX/Y`/`rotate` keys; an adjustment item with `radialFastBlur` twice — Center 1 = Glow Position + (0, Spread), `zoom` 1, `falloff` 98, `intensity` 1500, `mix` 40; Center 2 = Glow Position − (0, Spread), `zoom` 1, `falloff` 96, `intensity` 1000 — `space` 1 on both, `amount` = AE amount (80 + Light Distance, 80 + 2 × Light Distance); and a second adjustment item with AE's outer glows as two `glow` entries (`exposure` 0.5 / `glowThreshold` 71 / `glowRadius` 240 and `exposure` 0.1 / `glowThreshold` 0 / `glowRadius` 160), the Tint as `curves` with two points per channel (black → Light Color 3, white → Light Color 2: `r [[0, 43/255], [1, 198/255]]`, `g [[0, 217/255], [1, 1]]`, `b [[0, 143/255], [1, 74/255]]`) and AE's comp Curves as a second `curves` (kept inside the cone: on top of everything it also dims the white line). An effect chain holds 4 entries, hence two adjustment items.
|
|
286
287
|
2. Two items of that ONE sequence clip at the top level: one visible (the cone), one used only as the matte source (a matte source is hidden from output).
|
|
287
288
|
3. The white line (2 px) on its own channel, and the text with `trackMatte: {sourceId: <the matte item>, mode: "luma"}`.
|
|
288
289
|
Key the light on/off with the cone items' `opacity` plus `fx:<eid>:amount`, and raise `fx:<eid>:falloff` towards 99.8 as it goes off (CC's trail shortens with Amount; here the visible length is set by Falloff); key the light source with `fx:<eid>:centerX/centerY`. A ready rig: `tests/radial-fast-blur/build_light_rig.py`. CC's Standard mode keeps a thin line bright, which this effect's normalised Standard does not; Brightest + Falloff + Intensity is the measured match (see the report in `tests/radial-fast-blur/README.md`).
|
|
@@ -489,7 +490,7 @@ Geometry look controls: `objectNodes` — `shape` (0–7, `8` mixed), `size`, `w
|
|
|
489
490
|
"eid": "title-glow",
|
|
490
491
|
"enabled": true,
|
|
491
492
|
"mix": 85,
|
|
492
|
-
"params": { "
|
|
493
|
+
"params": { "glowRadius": 240, "exposure": 1.2, "glowThreshold": 50, "tintAmount": 100, "tintInner": "#69e7ff", "tintOuter": "#69e7ff" },
|
|
493
494
|
"clip": false
|
|
494
495
|
}
|
|
495
496
|
]
|
|
@@ -541,9 +542,9 @@ Overlay Effects use `fx:<eid>:<parameter>` tracks:
|
|
|
541
542
|
{ "position": 0, "value": "0", "easing": "AE Smooth" },
|
|
542
543
|
{ "position": 25, "value": "100", "easing": "AE Smooth" }
|
|
543
544
|
],
|
|
544
|
-
"fx:title-glow:
|
|
545
|
-
{ "position": 0, "value": "
|
|
546
|
-
{ "position": 100, "value": "
|
|
545
|
+
"fx:title-glow:glowRadius": [
|
|
546
|
+
{ "position": 0, "value": "80", "easing": "Smooth" },
|
|
547
|
+
{ "position": 100, "value": "440", "easing": "Linear" }
|
|
547
548
|
]
|
|
548
549
|
}
|
|
549
550
|
}
|
|
@@ -59,7 +59,7 @@ Rules:
|
|
|
59
59
|
"items": [
|
|
60
60
|
{ "id": "prtitem1", "clipId": "prt1", "trimStart": 0, "trimEnd": 6, "freeStart": 0,
|
|
61
61
|
"particleSystem": {
|
|
62
|
-
"schemaVersion":
|
|
62
|
+
"schemaVersion": 4,
|
|
63
63
|
"preset": "snow",
|
|
64
64
|
"seed": 55521,
|
|
65
65
|
"solver": { "cacheHz": 30, "maxParticles": 2000, "preRoll": 7, "space": "local",
|
|
@@ -110,7 +110,7 @@ Rules:
|
|
|
110
110
|
|
|
111
111
|
| Field | Range | Meaning |
|
|
112
112
|
| --- | --- | --- |
|
|
113
|
-
| `emit` | `continuous` \| `static` | `static` fills the system to the cap once and never emits again (rate and bursts ignored) — the right mode for a shatter/dissolve or anything Particle Activation releases. |
|
|
113
|
+
| `emit` | `continuous` \| `static` | `static` fills the system to the cap once and never emits again (rate and bursts ignored) — the right mode for a shatter/dissolve or anything Particle Activation releases. It fires at clip time `max(0, start)`, AFTER the pre-roll, so nothing it emits has a history at frame 0: for a trail that already exists at frame 0 (a comet), use `continuous` with `maxParticles` as the cap, which emits during the pre-roll. |
|
|
114
114
|
| `shape` | `point` \| `box` \| `sphere` \| `cone` \| `ring` \| `path` \| `block` \| `layer` \| `rows` | `layer` fires from a picture's opaque pixels — see below. With `render.colorMode: "source"` and a VIDEO source, `render.colorSourceTime` decides when each colour is read: `"live"` (default) re-reads the frame playing now, so the cloud is the moving picture; `"birth"` keeps the colour each particle was emitted with and lets the video move on without it. Either way the emission SITES stay from the one snapshot they were picked in, so nothing re-simulates and neither value is in the sim hash. v3: `ring` is an annulus in the comp plane (`ring: {radius, thickness}` px), `path` births evenly along a spline (`path.anchors` in the emitter's unit space, −0.5..0.5), `block` is a filled slab — the "layer of particles" source (pair it with `emit: "static"`). `rows` is a grid of **ready-made lines** — see [Lines](#lines-rendermode-lines--trails-and-ready-made-lines). |
|
|
115
115
|
| `dirMode` | `cone` \| `outward` \| `tangent` | v3, `ring`/`path` only: launch along `direction`+`spread`, away from the ring / normal to the path, or along it. |
|
|
116
116
|
| `distribution` | `{mode, jitter, order, sites, rings, clusters, tightness, bias, thickness, sequence, relaxIters}` | **How spawn sites are SPREAD inside the emitter's shape** — orthogonal to the geometry, so `box`, `sphere`, `cone`, `ring`, `path` and `block` all get every mode (`layer` and `point` do not use it; see below). Omit the block (or `mode: "random"`) for the emitter's original three independent draws; that is the default and is byte-identical to a system authored without it. See the table below. |
|
|
@@ -202,7 +202,7 @@ Physics that must hold when authoring by hand: with a `text` container, keep `fl
|
|
|
202
202
|
|
|
203
203
|
```json
|
|
204
204
|
"particleSystem": {
|
|
205
|
-
"schemaVersion":
|
|
205
|
+
"schemaVersion": 4, "preset": "smoke", "seed": 184729,
|
|
206
206
|
"solver": { "maxParticles": 4000, "preRoll": 0, "bounds": { "size": { "x": 1920, "y": 1080, "z": 480 }, "behavior": "kill" } },
|
|
207
207
|
"emitters": [{ "shape": "sphere", "position": { "x": 0, "y": -400, "z": 0 }, "size": { "x": 52, "y": 52, "z": 52 },
|
|
208
208
|
"rate": 900, "lifetime": { "value": 4, "random": 1.4 }, "speed": { "value": 180, "random": 45 },
|
|
@@ -221,7 +221,7 @@ To bend that plume with a fan, add `"forceEmitters": [{ "id": "b1", "kind": "jet
|
|
|
221
221
|
|
|
222
222
|
```json
|
|
223
223
|
"particleSystem": {
|
|
224
|
-
"schemaVersion":
|
|
224
|
+
"schemaVersion": 4, "preset": "shockwave", "seed": 51377,
|
|
225
225
|
"solver": { "maxParticles": 9000, "preRoll": 0, "bounds": { "size": { "x": 1920, "y": 1080, "z": 300 }, "behavior": "kill" } },
|
|
226
226
|
"emitters": [{ "emit": "continuous", "shape": "ring", "position": { "x": 0, "y": 0, "z": 0 }, "ring": { "radius": 38, "thickness": 12 }, "dirMode": "outward",
|
|
227
227
|
"size": { "x": 77, "y": 77, "z": 24 }, "rate": 0,
|
|
@@ -253,7 +253,7 @@ The other fluid presets differ from these only in numbers: *Cigarette* is Rising
|
|
|
253
253
|
|
|
254
254
|
#### Emitting from a layer (`shape: "layer"`) — dissolve a picture into its own pixels
|
|
255
255
|
|
|
256
|
-
Particles are born on the artwork's opaque pixels and can keep the colour of the pixel they came from. The artwork is a **bounded snapshot on the emitter**, never a live reference — the source layer can be trimmed, hidden or deleted without breaking the system. `fromItemId` is only a hint so the editor's **Update artwork from layer** can find it again.
|
|
256
|
+
Particles are born on the artwork's opaque pixels and can keep the colour of the pixel they came from. **How the sites are picked:** the picture is scaled down to at most 512 px on its long side (smoothed, so fine detail softens), every pixel with alpha above 8 is a site, and births pick evenly among the sites: alpha does not weight them, so density is the NUMBER of opaque pixels in an area — draw a dense region with more pixels, not brighter ones. Give the picture as a file or link (`asset:`, `/media/…`, https): a `url` is cut at 2,048 characters, so a data URL does not fit. The artwork is a **bounded snapshot on the emitter**, never a live reference — the source layer can be trimmed, hidden or deleted without breaking the system. `fromItemId` is only a hint so the editor's **Update artwork from layer** can find it again.
|
|
257
257
|
|
|
258
258
|
```json
|
|
259
259
|
{ "shape": "layer", "emit": "continuous", "rate": 0,
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
| HTML pages as timeline layers (html clips) and their bakes | video-html-clips.md (GreenLight Dash only) |
|
|
26
26
|
| Overlay Effects and Layer Effects, including Running Glow and Depth | [video-effects.md](video-effects.md) |
|
|
27
27
|
| 3D models, Scene Rig, lighting and shadow plates | [video-3d.md](video-3d.md) |
|
|
28
|
+
| Mechanisms and teardowns: a working machine or an exploded device as a 3D layer | video-mechanisms.md (GreenLight Dash only) |
|
|
28
29
|
| Camera layer, Camera Rig, camera paths and presets | [video-camera.md](video-camera.md) |
|
|
29
30
|
| Particles, packing, proximity, fluid and smoke | [video-particles.md](video-particles.md) |
|
|
30
31
|
| Writing motion tracks, roto masks or solved cameras | tracking-data.md (GreenLight Dash only) |
|
|
@@ -247,7 +247,7 @@ Rules the sanitizer enforces (anything else is dropped or clamped on load): `aid
|
|
|
247
247
|
| `gradient` | `colors` (2–6 hex), `angle` 0°, `span` `text`\|`unit`, `shift` 0 %, `repeat` false, `mix` 100 % | paints the unit with the gradient (across the whole text or each unit); `shift` slides the colours, `repeat` lets them loop |
|
|
248
248
|
| `hue` | `hue` 180°, `saturation` 0, `brightness` 0 % | rotates whatever colour the unit has at that point |
|
|
249
249
|
| `stroke` | `color` `#ffffff`, `width` 4 px, `outline` false | outline around the glyphs; `outline: true` fades the fill out |
|
|
250
|
-
| `glow` | `color` `#5ef2ff`, `size` 30 px, `strength` 120 % |
|
|
250
|
+
| `glow` | `color` `#5ef2ff`, `size` 30 px, `strength` 120 % | light around the glyphs (Deep Glow): a hot core and an inverse-square tail reaching about 5 × `size`; units with the same `size` share one glow, at most three sizes per layer |
|
|
251
251
|
| `shadow` | `color` `#000000`, `x` 0, `y` 18, `blur` 20 px, `opacity` 70 % | offset shadow; only when the user asks for a text shadow |
|
|
252
252
|
| `blur` | `amount` 18 px | defocus |
|
|
253
253
|
| `box` | `color` `#33efab`, `behind` `selected`\|`revealed`, `shape` `line`\|`unit`\|`block`, `padX` 12, `padY` 4, `radius` 10 px, `opacity` 100 %, `grow` true, `withText` false | `line`: one bar behind each run of selected units in a row; `unit`: a bar behind each selected unit of `basedOn` (a whole word even when drawn by letters), as bright as its amount; `block`: one shape around all of it. `behind: revealed` = behind what this animator lets through (a typing animator grows its box). `grow` makes a moving span sweep it like a marker. `withText` (`unit` only): each bar is as visible as its unit — every animator's opacity included — so a word that has not appeared yet has no bar |
|