pixi-effects 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 +14 -0
- package/README.md +7 -6
- package/ai/reference/cheatsheet.md +5 -1
- package/ai/template.html +3 -3
- package/dist/Composition-CM62XJKT.cjs +14 -0
- package/dist/{Composition-3KHQPRBA.cjs.map → Composition-CM62XJKT.cjs.map} +1 -1
- package/dist/Composition-RJDSQYTV.js +5 -0
- package/dist/{Composition-DT657FO5.js.map → Composition-RJDSQYTV.js.map} +1 -1
- package/dist/Controller.cjs +55 -20
- package/dist/Controller.cjs.map +1 -1
- package/dist/Controller.d.cts +31 -2
- package/dist/Controller.d.ts +31 -2
- package/dist/Controller.js +55 -21
- package/dist/Controller.js.map +1 -1
- package/dist/{Movie-BK9daiTt.d.cts → Movie-CQOhUmko.d.cts} +24 -1
- package/dist/{Movie-B0OUKlZI.d.ts → Movie-HF3pSGjQ.d.ts} +24 -1
- package/dist/{chunk-6I55T4OH.cjs → chunk-AGMNSJJH.cjs} +13 -4
- package/dist/chunk-AGMNSJJH.cjs.map +1 -0
- package/dist/{chunk-4O2NYDJG.js → chunk-FNKSXBKB.js} +13 -4
- package/dist/chunk-FNKSXBKB.js.map +1 -0
- package/dist/{chunk-36Z4RIRK.js → chunk-O4AJYUPK.js} +3 -3
- package/dist/{chunk-36Z4RIRK.js.map → chunk-O4AJYUPK.js.map} +1 -1
- package/dist/{chunk-4VSIJLU3.cjs → chunk-PDBDDGG5.cjs} +21 -21
- package/dist/{chunk-4VSIJLU3.cjs.map → chunk-PDBDDGG5.cjs.map} +1 -1
- package/dist/index.cjs +82 -23
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +71 -12
- package/dist/index.js.map +1 -1
- package/dist/three.cjs +5 -5
- package/dist/three.js +1 -1
- package/docs/api.md +51 -0
- package/docs/dsl.md +14 -2
- package/llms-full.txt +70 -3
- package/package.json +1 -1
- package/dist/Composition-3KHQPRBA.cjs +0 -14
- package/dist/Composition-DT657FO5.js +0 -5
- package/dist/chunk-4O2NYDJG.js.map +0 -1
- package/dist/chunk-6I55T4OH.cjs.map +0 -1
package/dist/three.cjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkAGMNSJJH_cjs = require('./chunk-AGMNSJJH.cjs');
|
|
4
4
|
require('./chunk-UQBGW5DO.cjs');
|
|
5
5
|
var pixi_js = require('pixi.js');
|
|
6
6
|
var three$1 = require('three');
|
|
7
7
|
|
|
8
|
-
var ThreeSequence = class extends
|
|
8
|
+
var ThreeSequence = class extends chunkAGMNSJJH_cjs.Sequence {
|
|
9
9
|
_renderer = null;
|
|
10
10
|
_scene = null;
|
|
11
11
|
_camera = null;
|
|
@@ -24,7 +24,7 @@ var ThreeSequence = class extends chunk6I55T4OH_cjs.Sequence {
|
|
|
24
24
|
if (this.duration === void 0) {
|
|
25
25
|
this.duration = this.parent?.duration ?? this.root.duration;
|
|
26
26
|
}
|
|
27
|
-
const scope =
|
|
27
|
+
const scope = chunkAGMNSJJH_cjs.buildScope(this, this.parent, this.root);
|
|
28
28
|
const width = resolveDim(spec.width, scope) ?? this.parent?.width ?? this.root.width;
|
|
29
29
|
const height = resolveDim(spec.height, scope) ?? this.parent?.height ?? this.root.height;
|
|
30
30
|
const resolution = spec.resolution ?? 1;
|
|
@@ -144,12 +144,12 @@ var ThreeSequence = class extends chunk6I55T4OH_cjs.Sequence {
|
|
|
144
144
|
function resolveDim(v, scope) {
|
|
145
145
|
if (v === void 0) return void 0;
|
|
146
146
|
if (typeof v === "number") return v;
|
|
147
|
-
return
|
|
147
|
+
return chunkAGMNSJJH_cjs.evaluateExpr(v, scope);
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
// src/three/index.ts
|
|
151
151
|
function registerThree() {
|
|
152
|
-
|
|
152
|
+
chunkAGMNSJJH_cjs.registerSequenceType("three", ThreeSequence);
|
|
153
153
|
}
|
|
154
154
|
function three(spec) {
|
|
155
155
|
return spec;
|
package/dist/three.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Sequence, buildScope, evaluateExpr, registerSequenceType } from './chunk-
|
|
1
|
+
import { Sequence, buildScope, evaluateExpr, registerSequenceType } from './chunk-FNKSXBKB.js';
|
|
2
2
|
import './chunk-DKGG7WD4.js';
|
|
3
3
|
import { Texture, Sprite } from 'pixi.js';
|
|
4
4
|
import { WebGLRenderer, Scene, PerspectiveCamera } from 'three';
|
package/docs/api.md
CHANGED
|
@@ -163,6 +163,8 @@ interface RenderOptions {
|
|
|
163
163
|
}
|
|
164
164
|
```
|
|
165
165
|
|
|
166
|
+
**Audio codec fallback:** unless you name `audio.codec`, the first codec this browser can actually encode is used (mp4: `aac`, then `opus`, `mp3`, `flac`; webm: `opus`, `vorbis`). Chrome on Linux has no AAC encoder, so there an mp4 with sound carries Opus and a warning says so (before, the export failed with a message about encoder configurations). A codec you name is never swapped: if it cannot be encoded the error says which one would work.
|
|
167
|
+
|
|
166
168
|
Returns a `Blob` whose `type` is the container's MIME (e.g. `video/mp4`). Emits `'progress'` repeatedly during the render.
|
|
167
169
|
|
|
168
170
|
The renderer also forces a keyframe every ~2 seconds so the resulting file scrubs efficiently in standard players.
|
|
@@ -191,6 +193,12 @@ movie.off(event, fn): this
|
|
|
191
193
|
| `'play'` | none | when `play()` actually transitions from paused |
|
|
192
194
|
| `'pause'` | none | when `pause()` actually transitions from playing |
|
|
193
195
|
| `'progress'`| `{ progress: number; frame: number; totalFrames: number }` | during `render()`, once per encoded frame |
|
|
196
|
+
| `'seeking'` / `'seeked'` | `{ frame, totalFrames }` (the frame it lands on) | a `gotoFrame()` to another frame starts / has finished. NOT emitted for playback ticks, `render()`, `snapshot()` or `contactSheet()` |
|
|
197
|
+
| `'ended'` | none | playback ran off the end (after `'pause'`); pausing by hand does not emit it |
|
|
198
|
+
| `'volumechange'` | `{ volume: number; muted: boolean }` | `volume` or `muted` really changed (clamping counts) |
|
|
199
|
+
| `'error'` | `{ where: 'init' \| 'render' \| 'playback'; message: string; error: unknown }` | `init()` / `render()` failed (the call still rejects), or a frame failed during playback |
|
|
200
|
+
|
|
201
|
+
The names are the ones an HTML5 `<video>` uses, so a player written for `<video>` ports over.
|
|
194
202
|
|
|
195
203
|
`progress` is `0..100` (rounded integer percent).
|
|
196
204
|
|
|
@@ -216,6 +224,24 @@ Flips `muted` and returns the new value.
|
|
|
216
224
|
|
|
217
225
|
---
|
|
218
226
|
|
|
227
|
+
## Building your own player
|
|
228
|
+
|
|
229
|
+
`Controller` is one optional player; everything it does is public on the movie, so a player of your own is plain HTML + CSS + a few handlers (`examples/15-custom-player.html` is a complete one):
|
|
230
|
+
|
|
231
|
+
```js
|
|
232
|
+
const el = id => document.getElementById(id);
|
|
233
|
+
movie.on('ready', () => { el('seek').max = movie.totalFrames; });
|
|
234
|
+
movie.on('frame', ({ frame }) => { el('seek').value = frame; el('time').textContent = (frame / movie.frameRate).toFixed(1) + ' s'; });
|
|
235
|
+
movie.on('play', () => { el('play').textContent = '❚❚'; });
|
|
236
|
+
movie.on('pause', () => { el('play').textContent = '▶'; });
|
|
237
|
+
movie.on('ended', () => { el('play').textContent = '↻'; }); // play() at the end starts again from 0
|
|
238
|
+
movie.on('volumechange', ({ volume, muted }) => { el('vol').value = muted ? 0 : volume; });
|
|
239
|
+
el('play').onclick = () => (movie.isPlaying ? movie.pause() : movie.play());
|
|
240
|
+
el('seek').oninput = e => movie.gotoFrame(+e.target.value);
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
What you have: `play()`, `pause()`, `gotoFrame(frame)`, `volume`, `muted` / `toggleMute()`; the state `currentFrame`, `totalFrames`, `frameRate`, `duration`, `isPlaying`, `isReady`; the events above; `render()` for a download button; `snapshot()` for a thumbnail; `timelineData()` / `timelineSvg()` for a timeline like `pixi-effects-view`'s. Keep the movie's `canvas` wherever your layout wants it (the page's CSS sizes it). To only change how `Controller` looks, see **Theme** below.
|
|
244
|
+
|
|
219
245
|
## `Controller`
|
|
220
246
|
|
|
221
247
|
Imported from `pixi-effects/controller`.
|
|
@@ -247,6 +273,7 @@ interface ControllerOptions {
|
|
|
247
273
|
showExportButton?: boolean; // default true; hides ⬇ + popover
|
|
248
274
|
enableKeyboardShortcuts?: boolean; // default true
|
|
249
275
|
className?: string; // default 'movie-controller'
|
|
276
|
+
theme?: ControllerTheme; // colours / thickness / font of the bar, see Theme
|
|
250
277
|
}
|
|
251
278
|
```
|
|
252
279
|
|
|
@@ -255,6 +282,30 @@ Mounting strategy:
|
|
|
255
282
|
- If `canvas.parentElement` already has a non-static `position`, the controller is appended directly into it.
|
|
256
283
|
- Otherwise the canvas is wrapped in a `<div class="movie-controller-wrap">` (with `position: relative`). The wrapper is removed on `destroy()`.
|
|
257
284
|
|
|
285
|
+
### Theme: change the colours of the bar
|
|
286
|
+
|
|
287
|
+
The bar is blue by default. Every colour and the track thickness are CSS custom properties with the old values as defaults, so there are two ways to change them:
|
|
288
|
+
|
|
289
|
+
```js
|
|
290
|
+
new Controller(movie, { canvas, theme: { accent: '#ff4d6d', foreground: '#ffe9a8', trackHeight: 5 } }); // in code
|
|
291
|
+
controller.setTheme({ accent: '#7bd88f' }); // later, live; only the keys you give change
|
|
292
|
+
controller.setTheme({ accent: null }); // null = back to the default
|
|
293
|
+
```
|
|
294
|
+
```css
|
|
295
|
+
:root { --mc-accent: #ff4d6d; } /* or in your page CSS: the canvas's parent, or :root */
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
| `theme` key | CSS property | What | Default |
|
|
299
|
+
|---|---|---|---|
|
|
300
|
+
| `accent` | `--mc-accent` | progress bar, its thumb, focus rings, the export button | `#007AFF` |
|
|
301
|
+
| `foreground` | `--mc-fg` | icons, the time, the volume slider | `#fff` |
|
|
302
|
+
| `track` | `--mc-track` | the unfilled part of the progress / volume bars | `rgba(255,255,255,0.25)` |
|
|
303
|
+
| `barBackground` | `--mc-bar-bg` | the background behind the buttons (any CSS background, e.g. a gradient) | black fading to transparent upward |
|
|
304
|
+
| `trackHeight` | `--mc-track-height` | thickness of the progress bar (a number is px) | `3px` |
|
|
305
|
+
| `font` | `--mc-font` | `font-family` of the bar | system UI font |
|
|
306
|
+
|
|
307
|
+
A misspelt key warns with the valid ones. The default stylesheet is exported as `CONTROLLER_CSS` (from `pixi-effects/controller`) if you want to copy and restyle more.
|
|
308
|
+
|
|
258
309
|
### `controller.destroy(): void`
|
|
259
310
|
|
|
260
311
|
Idempotent. Removes:
|
package/docs/dsl.md
CHANGED
|
@@ -944,7 +944,7 @@ A filter by name, as plain data. `type` is the filter's class name without `Filt
|
|
|
944
944
|
keyframes: [{ at: 0, to: { 'filters.halo.outerStrength': 6 }, duration: 1 }] } // animate any scalar option by name
|
|
945
945
|
```
|
|
946
946
|
|
|
947
|
-
Name a filter (`name: 'halo'`) to animate it with `'filters.halo.<option>'`. `blur`, `noise`, `alpha` and `colorMatrix` come from pixi.js. All the others come from the **`pixi-filters`** package, which is loaded the first time a layer uses one (add `"pixi-filters": "https://esm.sh/pixi-filters@6.1.5?external=pixi.js"` to the import map, or `npm i pixi-filters`; `ai/template.html` already has it). A misspelt type says what you probably meant.
|
|
947
|
+
Name a filter (`name: 'halo'`) to animate it with `'filters.halo.<option>'`. `blur`, `noise`, `alpha` and `colorMatrix` come from pixi.js. All the others come from the **`pixi-filters`** package, which is loaded the first time a layer uses one (add `"pixi-filters": "https://esm.sh/pixi-filters@6.1.5?external=pixi.js"` to the import map, or `npm i pixi-filters`; `ai/template.html` already has it). A misspelt type says what you probably meant. Rendering and exporting were verified in a real browser for 40 of them (`examples/_checks/named-filters.html` and `named-filters-2.html`); `colorMap` and `simpleLightmap` need a texture, which JSON cannot hold, so use `custom` for those two:
|
|
948
948
|
|
|
949
949
|
| `type` | Options (the useful ones) | What it does |
|
|
950
950
|
|---|---|---|
|
|
@@ -972,13 +972,25 @@ Name a filter (`name: 'halo'`) to animate it with `'filters.halo.<option>'`. `bl
|
|
|
972
972
|
| `ascii` | `size color replaceColor` | Text-art |
|
|
973
973
|
| `colorOverlay` | `color alpha` | Tint over everything |
|
|
974
974
|
| `advancedBloom` / `bloom` | `threshold bloomScale brightness blur` | Bloom |
|
|
975
|
-
| `bevel
|
|
975
|
+
| `bevel` | `thickness rotation lightColor lightAlpha shadowColor shadowAlpha` | Raised edge |
|
|
976
|
+
| `dot` / `crossHatch` | `scale angle grayscale` / – | Halftone / hatching |
|
|
977
|
+
| `godray` | `angle gain lacunarity alpha parallel time` | Light shafts (animate `time`) |
|
|
978
|
+
| `reflection` | `mirror boundary amplitude waveLength alpha time` (ranges are `[start, end]`) | Water reflection |
|
|
979
|
+
| `simplexNoise` | `strength scale offset` | Cloudy noise over the layer |
|
|
980
|
+
| `colorGradient` | `gradientType: 'linear' 'radial' 'conic'` (the filter's own option is `type`, which the DSL uses), `stops: [{ offset, color, alpha }]`, `angle` | A gradient laid over the layer |
|
|
981
|
+
| `colorReplace` / `multiColorReplace` | `originalColor targetColor tolerance` / `replacements: [[from, to], …] tolerance` | Swap colours |
|
|
982
|
+
| `convolution` | `matrix` (9 numbers), `width height` | Sharpen, edge detect |
|
|
983
|
+
| `tiltShift` / `tiltShiftAxis` | `blur gradientBlur start end` (canvas pixels) | Miniature blur |
|
|
984
|
+
| `shockwave` | `center amplitude wavelength brightness speed radius time` (animate `time` 0 → 1) | A ripple from a point |
|
|
985
|
+
| `backdropBlur` | `strength` | Blurs what is BEHIND the layer, so alone it shows nothing |
|
|
986
|
+
| the rest of pixi-filters (`colorMap`, `simpleLightmap`) | need a texture: `{ type: 'custom' }` | see the [pixi-filters docs](https://pixijs.io/filters/docs/) |
|
|
976
987
|
|
|
977
988
|
Gotchas, all measured:
|
|
978
989
|
|
|
979
990
|
- **Centres and offsets are in canvas pixels, not the layer's:** `twist.offset`, `bulgePinch.center`, `zoomBlur.center`, `radialBlur.center`, `shockwave.center` default to the canvas's top-left corner, so a layer in the middle looks unaffected. Put the centre on the layer: `{ type: 'twist', offset: { x: 640, y: 360 } }` for a layer centred on a 1280×720 canvas.
|
|
980
991
|
- **A filter works inside the layer's bounds.** Glow, dropShadow, outline and blur draw outside it and are clipped unless you widen the area (`filterArea: { x: -24, y: -24, width: w + 48, height: h + 48 }`, in the layer's own coordinates). Do not widen it for `grayscale`, `oldFilm` or other filters that paint the whole area: they fill the extra margin with black.
|
|
981
992
|
- **Animate scalars by name** (`'filters.halo.outerStrength'`). Options that are points (`rgbSplit.red`, `dropShadow.offset`) do not tween as a whole; animate `'filters.<name>.red.x'` if the filter exposes it, or swap the filter. `pixelate` animates through `sizeX` / `sizeY`, not `size`.
|
|
993
|
+
- `shockwave` and `godray` are driven by `time` (a still frame at `time: 0` looks like nothing): animate it. `radialBlur`, `shockwave` and `tiltShift` positions are canvas pixels too.
|
|
982
994
|
- Some filters take their value as one argument; the DSL hides that (`{ type: 'pixelate', size: 8 }`, `{ type: 'emboss', strength: 6 }`).
|
|
983
995
|
|
|
984
996
|
### `custom`
|
package/llms-full.txt
CHANGED
|
@@ -139,9 +139,13 @@ Style (`initial` / keyframes): `fillColor fillAlpha strokeColor strokeAlpha stro
|
|
|
139
139
|
|
|
140
140
|
Add `threeD: true` to any visual layer, then use `z`, `rotationX`, `rotationY` (centre rotation with `anchorX/Y: 0.5` or `pivotX/Y`). Add a `{ type: 'camera' }` layer for a view. A `threeD` layer at `z: 0` with the default camera looks identical to a 2D one. Consecutive `threeD` layers are drawn farthest-first (equal `z` keeps array order); non-`threeD` layers ignore the camera and keep array order. Layers at/behind the camera plane are hidden. Not supported on `threeD` layers: masks, transitions, `filterArea`.
|
|
141
141
|
|
|
142
|
+
## Player
|
|
143
|
+
|
|
144
|
+
`new Controller(movie, { canvas, theme: { accent: '#ff4d6d' } })` (import from `pixi-effects/controller`; theme keys `accent foreground track barBackground trackHeight font`, or CSS `--mc-accent` …; `controller.setTheme(…)`). Your own player: `movie.play() pause() gotoFrame(f) volume muted toggleMute()`, state `currentFrame totalFrames frameRate duration isPlaying`, events `ready frame play pause ended seeking seeked volumechange error progress` (`<video>` names). `examples/15-custom-player.html` is a complete one.
|
|
145
|
+
|
|
142
146
|
## Filters by name (no import)
|
|
143
147
|
|
|
144
|
-
`filters: [{ type: 'glow', name: 'halo', outerStrength: 3, color: '#ffd166' }]` — `type` = the pixi / pixi-filters class name without `Filter`, camelCase (`glow dropShadow outline blur noise alpha adjustment hslAdjustment grayscale pixelate crt rgbSplit oldFilm glitch bulgePinch twist zoomBlur kawaseBlur radialBlur motionBlur emboss ascii colorOverlay advancedBloom bevel dot crossHatch tiltShift …`), the other keys are its options. `colorMatrix` takes `preset: 'sepia'|'grayscale'|'negative'|'polaroid'|'technicolor'|'vintage'|'kodachrome'|'browni'`. Name it to animate: `'filters.halo.outerStrength'` (scalars only; `pixelate` via `sizeX`/`sizeY`). Options: `glow` distance outerStrength innerStrength color alpha · `dropShadow` offset{x,y} blur alpha color · `outline` thickness color · `blur` strength · `adjustment` gamma contrast saturation brightness · `hslAdjustment` hue lightness saturation · `pixelate` size · `crt` curvature lineWidth noise vignetting · `rgbSplit` red/green/blue {x,y} · `oldFilm` sepia noise scratch vignetting · `glitch` slices offset · `twist` radius angle offset · `bulgePinch` center radius strength · `zoomBlur` strength center innerRadius · `colorOverlay` color alpha. **Centres/offsets are CANVAS pixels** (default top-left corner): put them on the layer. Glow / shadow / blur draw outside the layer: widen `filterArea` (not for `grayscale` / `oldFilm`, which fill the margin black). Full table: `docs/dsl.md` → Named filters.
|
|
148
|
+
`filters: [{ type: 'glow', name: 'halo', outerStrength: 3, color: '#ffd166' }]` — `type` = the pixi / pixi-filters class name without `Filter`, camelCase (`glow dropShadow outline blur noise alpha adjustment hslAdjustment grayscale pixelate crt rgbSplit oldFilm glitch bulgePinch twist zoomBlur kawaseBlur radialBlur motionBlur emboss ascii colorOverlay advancedBloom bevel dot crossHatch tiltShift …`), the other keys are its options. `colorMatrix` takes `preset: 'sepia'|'grayscale'|'negative'|'polaroid'|'technicolor'|'vintage'|'kodachrome'|'browni'`. Name it to animate: `'filters.halo.outerStrength'` (scalars only; `pixelate` via `sizeX`/`sizeY`). Options: `glow` distance outerStrength innerStrength color alpha · `dropShadow` offset{x,y} blur alpha color · `outline` thickness color · `blur` strength · `adjustment` gamma contrast saturation brightness · `hslAdjustment` hue lightness saturation · `pixelate` size · `crt` curvature lineWidth noise vignetting · `rgbSplit` red/green/blue {x,y} · `oldFilm` sepia noise scratch vignetting · `glitch` slices offset · `twist` radius angle offset · `bulgePinch` center radius strength · `zoomBlur` strength center innerRadius · `colorOverlay` color alpha · `colorGradient` gradientType('linear'|'radial'|'conic') stops[{offset,color,alpha}] angle · `colorReplace` originalColor targetColor tolerance · `convolution` matrix(9) · `shockwave` / `godray` are driven by `time` (animate it) · `colorMap` / `simpleLightmap` need a texture (use `custom`). **Centres/offsets are CANVAS pixels** (default top-left corner): put them on the layer. Glow / shadow / blur draw outside the layer: widen `filterArea` (not for `grayscale` / `oldFilm`, which fill the margin black). Full table: `docs/dsl.md` → Named filters.
|
|
145
149
|
|
|
146
150
|
## Transitions (on the parent composition)
|
|
147
151
|
|
|
@@ -1757,7 +1761,7 @@ A filter by name, as plain data. `type` is the filter's class name without `Filt
|
|
|
1757
1761
|
keyframes: [{ at: 0, to: { 'filters.halo.outerStrength': 6 }, duration: 1 }] } // animate any scalar option by name
|
|
1758
1762
|
```
|
|
1759
1763
|
|
|
1760
|
-
Name a filter (`name: 'halo'`) to animate it with `'filters.halo.<option>'`. `blur`, `noise`, `alpha` and `colorMatrix` come from pixi.js. All the others come from the **`pixi-filters`** package, which is loaded the first time a layer uses one (add `"pixi-filters": "https://esm.sh/pixi-filters@6.1.5?external=pixi.js"` to the import map, or `npm i pixi-filters`; `ai/template.html` already has it). A misspelt type says what you probably meant.
|
|
1764
|
+
Name a filter (`name: 'halo'`) to animate it with `'filters.halo.<option>'`. `blur`, `noise`, `alpha` and `colorMatrix` come from pixi.js. All the others come from the **`pixi-filters`** package, which is loaded the first time a layer uses one (add `"pixi-filters": "https://esm.sh/pixi-filters@6.1.5?external=pixi.js"` to the import map, or `npm i pixi-filters`; `ai/template.html` already has it). A misspelt type says what you probably meant. Rendering and exporting were verified in a real browser for 40 of them (`examples/_checks/named-filters.html` and `named-filters-2.html`); `colorMap` and `simpleLightmap` need a texture, which JSON cannot hold, so use `custom` for those two:
|
|
1761
1765
|
|
|
1762
1766
|
| `type` | Options (the useful ones) | What it does |
|
|
1763
1767
|
|---|---|---|
|
|
@@ -1785,13 +1789,25 @@ Name a filter (`name: 'halo'`) to animate it with `'filters.halo.<option>'`. `bl
|
|
|
1785
1789
|
| `ascii` | `size color replaceColor` | Text-art |
|
|
1786
1790
|
| `colorOverlay` | `color alpha` | Tint over everything |
|
|
1787
1791
|
| `advancedBloom` / `bloom` | `threshold bloomScale brightness blur` | Bloom |
|
|
1788
|
-
| `bevel
|
|
1792
|
+
| `bevel` | `thickness rotation lightColor lightAlpha shadowColor shadowAlpha` | Raised edge |
|
|
1793
|
+
| `dot` / `crossHatch` | `scale angle grayscale` / – | Halftone / hatching |
|
|
1794
|
+
| `godray` | `angle gain lacunarity alpha parallel time` | Light shafts (animate `time`) |
|
|
1795
|
+
| `reflection` | `mirror boundary amplitude waveLength alpha time` (ranges are `[start, end]`) | Water reflection |
|
|
1796
|
+
| `simplexNoise` | `strength scale offset` | Cloudy noise over the layer |
|
|
1797
|
+
| `colorGradient` | `gradientType: 'linear' 'radial' 'conic'` (the filter's own option is `type`, which the DSL uses), `stops: [{ offset, color, alpha }]`, `angle` | A gradient laid over the layer |
|
|
1798
|
+
| `colorReplace` / `multiColorReplace` | `originalColor targetColor tolerance` / `replacements: [[from, to], …] tolerance` | Swap colours |
|
|
1799
|
+
| `convolution` | `matrix` (9 numbers), `width height` | Sharpen, edge detect |
|
|
1800
|
+
| `tiltShift` / `tiltShiftAxis` | `blur gradientBlur start end` (canvas pixels) | Miniature blur |
|
|
1801
|
+
| `shockwave` | `center amplitude wavelength brightness speed radius time` (animate `time` 0 → 1) | A ripple from a point |
|
|
1802
|
+
| `backdropBlur` | `strength` | Blurs what is BEHIND the layer, so alone it shows nothing |
|
|
1803
|
+
| the rest of pixi-filters (`colorMap`, `simpleLightmap`) | need a texture: `{ type: 'custom' }` | see the [pixi-filters docs](https://pixijs.io/filters/docs/) |
|
|
1789
1804
|
|
|
1790
1805
|
Gotchas, all measured:
|
|
1791
1806
|
|
|
1792
1807
|
- **Centres and offsets are in canvas pixels, not the layer's:** `twist.offset`, `bulgePinch.center`, `zoomBlur.center`, `radialBlur.center`, `shockwave.center` default to the canvas's top-left corner, so a layer in the middle looks unaffected. Put the centre on the layer: `{ type: 'twist', offset: { x: 640, y: 360 } }` for a layer centred on a 1280×720 canvas.
|
|
1793
1808
|
- **A filter works inside the layer's bounds.** Glow, dropShadow, outline and blur draw outside it and are clipped unless you widen the area (`filterArea: { x: -24, y: -24, width: w + 48, height: h + 48 }`, in the layer's own coordinates). Do not widen it for `grayscale`, `oldFilm` or other filters that paint the whole area: they fill the extra margin with black.
|
|
1794
1809
|
- **Animate scalars by name** (`'filters.halo.outerStrength'`). Options that are points (`rgbSplit.red`, `dropShadow.offset`) do not tween as a whole; animate `'filters.<name>.red.x'` if the filter exposes it, or swap the filter. `pixelate` animates through `sizeX` / `sizeY`, not `size`.
|
|
1810
|
+
- `shockwave` and `godray` are driven by `time` (a still frame at `time: 0` looks like nothing): animate it. `radialBlur`, `shockwave` and `tiltShift` positions are canvas pixels too.
|
|
1795
1811
|
- Some filters take their value as one argument; the DSL hides that (`{ type: 'pixelate', size: 8 }`, `{ type: 'emboss', strength: 6 }`).
|
|
1796
1812
|
|
|
1797
1813
|
### `custom`
|
|
@@ -2115,6 +2131,8 @@ interface RenderOptions {
|
|
|
2115
2131
|
}
|
|
2116
2132
|
```
|
|
2117
2133
|
|
|
2134
|
+
**Audio codec fallback:** unless you name `audio.codec`, the first codec this browser can actually encode is used (mp4: `aac`, then `opus`, `mp3`, `flac`; webm: `opus`, `vorbis`). Chrome on Linux has no AAC encoder, so there an mp4 with sound carries Opus and a warning says so (before, the export failed with a message about encoder configurations). A codec you name is never swapped: if it cannot be encoded the error says which one would work.
|
|
2135
|
+
|
|
2118
2136
|
Returns a `Blob` whose `type` is the container's MIME (e.g. `video/mp4`). Emits `'progress'` repeatedly during the render.
|
|
2119
2137
|
|
|
2120
2138
|
The renderer also forces a keyframe every ~2 seconds so the resulting file scrubs efficiently in standard players.
|
|
@@ -2143,6 +2161,12 @@ movie.off(event, fn): this
|
|
|
2143
2161
|
| `'play'` | none | when `play()` actually transitions from paused |
|
|
2144
2162
|
| `'pause'` | none | when `pause()` actually transitions from playing |
|
|
2145
2163
|
| `'progress'`| `{ progress: number; frame: number; totalFrames: number }` | during `render()`, once per encoded frame |
|
|
2164
|
+
| `'seeking'` / `'seeked'` | `{ frame, totalFrames }` (the frame it lands on) | a `gotoFrame()` to another frame starts / has finished. NOT emitted for playback ticks, `render()`, `snapshot()` or `contactSheet()` |
|
|
2165
|
+
| `'ended'` | none | playback ran off the end (after `'pause'`); pausing by hand does not emit it |
|
|
2166
|
+
| `'volumechange'` | `{ volume: number; muted: boolean }` | `volume` or `muted` really changed (clamping counts) |
|
|
2167
|
+
| `'error'` | `{ where: 'init' \| 'render' \| 'playback'; message: string; error: unknown }` | `init()` / `render()` failed (the call still rejects), or a frame failed during playback |
|
|
2168
|
+
|
|
2169
|
+
The names are the ones an HTML5 `<video>` uses, so a player written for `<video>` ports over.
|
|
2146
2170
|
|
|
2147
2171
|
`progress` is `0..100` (rounded integer percent).
|
|
2148
2172
|
|
|
@@ -2168,6 +2192,24 @@ Flips `muted` and returns the new value.
|
|
|
2168
2192
|
|
|
2169
2193
|
---
|
|
2170
2194
|
|
|
2195
|
+
## Building your own player
|
|
2196
|
+
|
|
2197
|
+
`Controller` is one optional player; everything it does is public on the movie, so a player of your own is plain HTML + CSS + a few handlers (`examples/15-custom-player.html` is a complete one):
|
|
2198
|
+
|
|
2199
|
+
```js
|
|
2200
|
+
const el = id => document.getElementById(id);
|
|
2201
|
+
movie.on('ready', () => { el('seek').max = movie.totalFrames; });
|
|
2202
|
+
movie.on('frame', ({ frame }) => { el('seek').value = frame; el('time').textContent = (frame / movie.frameRate).toFixed(1) + ' s'; });
|
|
2203
|
+
movie.on('play', () => { el('play').textContent = '❚❚'; });
|
|
2204
|
+
movie.on('pause', () => { el('play').textContent = '▶'; });
|
|
2205
|
+
movie.on('ended', () => { el('play').textContent = '↻'; }); // play() at the end starts again from 0
|
|
2206
|
+
movie.on('volumechange', ({ volume, muted }) => { el('vol').value = muted ? 0 : volume; });
|
|
2207
|
+
el('play').onclick = () => (movie.isPlaying ? movie.pause() : movie.play());
|
|
2208
|
+
el('seek').oninput = e => movie.gotoFrame(+e.target.value);
|
|
2209
|
+
```
|
|
2210
|
+
|
|
2211
|
+
What you have: `play()`, `pause()`, `gotoFrame(frame)`, `volume`, `muted` / `toggleMute()`; the state `currentFrame`, `totalFrames`, `frameRate`, `duration`, `isPlaying`, `isReady`; the events above; `render()` for a download button; `snapshot()` for a thumbnail; `timelineData()` / `timelineSvg()` for a timeline like `pixi-effects-view`'s. Keep the movie's `canvas` wherever your layout wants it (the page's CSS sizes it). To only change how `Controller` looks, see **Theme** below.
|
|
2212
|
+
|
|
2171
2213
|
## `Controller`
|
|
2172
2214
|
|
|
2173
2215
|
Imported from `pixi-effects/controller`.
|
|
@@ -2199,6 +2241,7 @@ interface ControllerOptions {
|
|
|
2199
2241
|
showExportButton?: boolean; // default true; hides ⬇ + popover
|
|
2200
2242
|
enableKeyboardShortcuts?: boolean; // default true
|
|
2201
2243
|
className?: string; // default 'movie-controller'
|
|
2244
|
+
theme?: ControllerTheme; // colours / thickness / font of the bar, see Theme
|
|
2202
2245
|
}
|
|
2203
2246
|
```
|
|
2204
2247
|
|
|
@@ -2207,6 +2250,30 @@ Mounting strategy:
|
|
|
2207
2250
|
- If `canvas.parentElement` already has a non-static `position`, the controller is appended directly into it.
|
|
2208
2251
|
- Otherwise the canvas is wrapped in a `<div class="movie-controller-wrap">` (with `position: relative`). The wrapper is removed on `destroy()`.
|
|
2209
2252
|
|
|
2253
|
+
### Theme: change the colours of the bar
|
|
2254
|
+
|
|
2255
|
+
The bar is blue by default. Every colour and the track thickness are CSS custom properties with the old values as defaults, so there are two ways to change them:
|
|
2256
|
+
|
|
2257
|
+
```js
|
|
2258
|
+
new Controller(movie, { canvas, theme: { accent: '#ff4d6d', foreground: '#ffe9a8', trackHeight: 5 } }); // in code
|
|
2259
|
+
controller.setTheme({ accent: '#7bd88f' }); // later, live; only the keys you give change
|
|
2260
|
+
controller.setTheme({ accent: null }); // null = back to the default
|
|
2261
|
+
```
|
|
2262
|
+
```css
|
|
2263
|
+
:root { --mc-accent: #ff4d6d; } /* or in your page CSS: the canvas's parent, or :root */
|
|
2264
|
+
```
|
|
2265
|
+
|
|
2266
|
+
| `theme` key | CSS property | What | Default |
|
|
2267
|
+
|---|---|---|---|
|
|
2268
|
+
| `accent` | `--mc-accent` | progress bar, its thumb, focus rings, the export button | `#007AFF` |
|
|
2269
|
+
| `foreground` | `--mc-fg` | icons, the time, the volume slider | `#fff` |
|
|
2270
|
+
| `track` | `--mc-track` | the unfilled part of the progress / volume bars | `rgba(255,255,255,0.25)` |
|
|
2271
|
+
| `barBackground` | `--mc-bar-bg` | the background behind the buttons (any CSS background, e.g. a gradient) | black fading to transparent upward |
|
|
2272
|
+
| `trackHeight` | `--mc-track-height` | thickness of the progress bar (a number is px) | `3px` |
|
|
2273
|
+
| `font` | `--mc-font` | `font-family` of the bar | system UI font |
|
|
2274
|
+
|
|
2275
|
+
A misspelt key warns with the valid ones. The default stylesheet is exported as `CONTROLLER_CSS` (from `pixi-effects/controller`) if you want to copy and restyle more.
|
|
2276
|
+
|
|
2210
2277
|
### `controller.destroy(): void`
|
|
2211
2278
|
|
|
2212
2279
|
Idempotent. Removes:
|
package/package.json
CHANGED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var chunk4VSIJLU3_cjs = require('./chunk-4VSIJLU3.cjs');
|
|
4
|
-
require('./chunk-6I55T4OH.cjs');
|
|
5
|
-
require('./chunk-UQBGW5DO.cjs');
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Object.defineProperty(exports, "CompositionSequence", {
|
|
10
|
-
enumerable: true,
|
|
11
|
-
get: function () { return chunk4VSIJLU3_cjs.CompositionSequence; }
|
|
12
|
-
});
|
|
13
|
-
//# sourceMappingURL=Composition-3KHQPRBA.cjs.map
|
|
14
|
-
//# sourceMappingURL=Composition-3KHQPRBA.cjs.map
|