pixi-effects 0.30.0 → 0.31.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.
Files changed (63) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +6 -5
  3. package/ai/chat-template.html +3 -3
  4. package/ai/tools/check.mjs +42 -2
  5. package/ai/tools/lookup.mjs +12 -6
  6. package/ai/tools/render.mjs +15 -2
  7. package/ai/tools/varArgs.mjs +75 -0
  8. package/dist/{Base-CB1_FPZD.d.cts → Base-BKagtWc0.d.cts} +1 -1
  9. package/dist/{Base-Ne74ztNl.d.ts → Base-jRiMHcWT.d.ts} +1 -1
  10. package/dist/Composition-DQCPJPFE.js +7 -0
  11. package/dist/{Composition-RJGA7KDU.js.map → Composition-DQCPJPFE.js.map} +1 -1
  12. package/dist/Composition-V2XYSW6P.cjs +16 -0
  13. package/dist/{Composition-MUKR3FYD.cjs.map → Composition-V2XYSW6P.cjs.map} +1 -1
  14. package/dist/Controller.cjs +42 -1
  15. package/dist/Controller.cjs.map +1 -1
  16. package/dist/Controller.d.cts +10 -2
  17. package/dist/Controller.d.ts +10 -2
  18. package/dist/Controller.js +42 -1
  19. package/dist/Controller.js.map +1 -1
  20. package/dist/{Movie-DdnpLpw1.d.cts → Movie-BH81stkb.d.cts} +90 -3
  21. package/dist/{Movie-C2rZFkrO.d.ts → Movie-CfFPItoL.d.ts} +90 -3
  22. package/dist/{chunk-A3Q3SDSH.js → chunk-BGMCZA36.js} +3 -3
  23. package/dist/{chunk-A3Q3SDSH.js.map → chunk-BGMCZA36.js.map} +1 -1
  24. package/dist/{chunk-ZVUO325O.cjs → chunk-DJ5B7IKT.cjs} +9 -3
  25. package/dist/chunk-DJ5B7IKT.cjs.map +1 -0
  26. package/dist/{chunk-WHNADXXG.cjs → chunk-L73KRFXI.cjs} +61 -61
  27. package/dist/{chunk-WHNADXXG.cjs.map → chunk-L73KRFXI.cjs.map} +1 -1
  28. package/dist/{chunk-ZAXYPXKW.js → chunk-MMTESMJ5.js} +9 -4
  29. package/dist/chunk-MMTESMJ5.js.map +1 -0
  30. package/dist/{chunk-CRQFDY7E.js → chunk-UTIBYMIO.js} +461 -56
  31. package/dist/chunk-UTIBYMIO.js.map +1 -0
  32. package/dist/{chunk-HREBQAY4.cjs → chunk-X3WHETQ3.cjs} +485 -80
  33. package/dist/chunk-X3WHETQ3.cjs.map +1 -0
  34. package/dist/index.cjs +31 -31
  35. package/dist/index.d.cts +5 -5
  36. package/dist/index.d.ts +5 -5
  37. package/dist/index.js +3 -3
  38. package/dist/loader.css +1 -1
  39. package/dist/present.cjs +3 -3
  40. package/dist/present.d.cts +2 -2
  41. package/dist/present.d.ts +2 -2
  42. package/dist/present.js +3 -3
  43. package/dist/three.cjs +5 -5
  44. package/dist/three.d.cts +2 -2
  45. package/dist/three.d.ts +2 -2
  46. package/dist/three.js +1 -1
  47. package/dist/{types-BzIB65Vk.d.cts → types-CK_crNAI.d.cts} +2 -0
  48. package/dist/{types-BzIB65Vk.d.ts → types-CK_crNAI.d.ts} +2 -0
  49. package/docs/api.md +28 -1
  50. package/docs/dsl.md +32 -1
  51. package/llms-full.txt +145 -11
  52. package/package.json +83 -20
  53. package/skills/pixi-effects/SKILL.md +1 -1
  54. package/skills/pixi-effects/reference/cheatsheet.md +3 -0
  55. package/skills/pixi-effects/reference/pitfalls.md +4 -0
  56. package/skills/pixi-effects/reference/recipes.md +79 -8
  57. package/skills/pixi-effects/template.html +6 -6
  58. package/dist/Composition-MUKR3FYD.cjs +0 -16
  59. package/dist/Composition-RJGA7KDU.js +0 -7
  60. package/dist/chunk-CRQFDY7E.js.map +0 -1
  61. package/dist/chunk-HREBQAY4.cjs.map +0 -1
  62. package/dist/chunk-ZAXYPXKW.js.map +0 -1
  63. package/dist/chunk-ZVUO325O.cjs.map +0 -1
package/dist/index.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var chunkHREBQAY4_cjs = require('./chunk-HREBQAY4.cjs');
4
- require('./chunk-WHNADXXG.cjs');
5
- var chunkZVUO325O_cjs = require('./chunk-ZVUO325O.cjs');
3
+ var chunkX3WHETQ3_cjs = require('./chunk-X3WHETQ3.cjs');
4
+ require('./chunk-L73KRFXI.cjs');
5
+ var chunkDJ5B7IKT_cjs = require('./chunk-DJ5B7IKT.cjs');
6
6
  require('./chunk-2DXPTKQZ.cjs');
7
7
  require('./chunk-LYOKH7KE.cjs');
8
8
  var chunkTWZNOUM7_cjs = require('./chunk-TWZNOUM7.cjs');
@@ -11,115 +11,115 @@ var chunkTWZNOUM7_cjs = require('./chunk-TWZNOUM7.cjs');
11
11
 
12
12
  Object.defineProperty(exports, "Movie", {
13
13
  enumerable: true,
14
- get: function () { return chunkHREBQAY4_cjs.Movie; }
14
+ get: function () { return chunkX3WHETQ3_cjs.Movie; }
15
15
  });
16
16
  Object.defineProperty(exports, "animateText", {
17
17
  enumerable: true,
18
- get: function () { return chunkHREBQAY4_cjs.animateText; }
18
+ get: function () { return chunkX3WHETQ3_cjs.animateText; }
19
19
  });
20
20
  Object.defineProperty(exports, "audioEnvelope", {
21
21
  enumerable: true,
22
- get: function () { return chunkHREBQAY4_cjs.audioEnvelope; }
22
+ get: function () { return chunkX3WHETQ3_cjs.audioEnvelope; }
23
23
  });
24
24
  Object.defineProperty(exports, "bpmEnvelope", {
25
25
  enumerable: true,
26
- get: function () { return chunkHREBQAY4_cjs.bpmEnvelope; }
26
+ get: function () { return chunkX3WHETQ3_cjs.bpmEnvelope; }
27
27
  });
28
28
  Object.defineProperty(exports, "cameraPath", {
29
29
  enumerable: true,
30
- get: function () { return chunkHREBQAY4_cjs.cameraPath; }
30
+ get: function () { return chunkX3WHETQ3_cjs.cameraPath; }
31
31
  });
32
32
  Object.defineProperty(exports, "computeEnvelope", {
33
33
  enumerable: true,
34
- get: function () { return chunkHREBQAY4_cjs.computeEnvelope; }
34
+ get: function () { return chunkX3WHETQ3_cjs.computeEnvelope; }
35
35
  });
36
36
  Object.defineProperty(exports, "dismissLoader", {
37
37
  enumerable: true,
38
- get: function () { return chunkHREBQAY4_cjs.dismissLoader; }
38
+ get: function () { return chunkX3WHETQ3_cjs.dismissLoader; }
39
39
  });
40
40
  Object.defineProperty(exports, "ease", {
41
41
  enumerable: true,
42
- get: function () { return chunkHREBQAY4_cjs.parseEase; }
42
+ get: function () { return chunkX3WHETQ3_cjs.parseEase; }
43
43
  });
44
44
  Object.defineProperty(exports, "failLoader", {
45
45
  enumerable: true,
46
- get: function () { return chunkHREBQAY4_cjs.failLoader; }
46
+ get: function () { return chunkX3WHETQ3_cjs.failLoader; }
47
47
  });
48
48
  Object.defineProperty(exports, "followPath", {
49
49
  enumerable: true,
50
- get: function () { return chunkHREBQAY4_cjs.followPath; }
50
+ get: function () { return chunkX3WHETQ3_cjs.followPath; }
51
51
  });
52
52
  Object.defineProperty(exports, "kenBurns", {
53
53
  enumerable: true,
54
- get: function () { return chunkHREBQAY4_cjs.kenBurns; }
54
+ get: function () { return chunkX3WHETQ3_cjs.kenBurns; }
55
55
  });
56
56
  Object.defineProperty(exports, "measureText", {
57
57
  enumerable: true,
58
- get: function () { return chunkHREBQAY4_cjs.measureText; }
58
+ get: function () { return chunkX3WHETQ3_cjs.measureText; }
59
59
  });
60
60
  Object.defineProperty(exports, "musicBuffer", {
61
61
  enumerable: true,
62
- get: function () { return chunkHREBQAY4_cjs.musicBuffer; }
62
+ get: function () { return chunkX3WHETQ3_cjs.musicBuffer; }
63
63
  });
64
64
  Object.defineProperty(exports, "musicEnvelope", {
65
65
  enumerable: true,
66
- get: function () { return chunkHREBQAY4_cjs.musicEnvelope; }
66
+ get: function () { return chunkX3WHETQ3_cjs.musicEnvelope; }
67
67
  });
68
68
  Object.defineProperty(exports, "musicEvents", {
69
69
  enumerable: true,
70
- get: function () { return chunkHREBQAY4_cjs.musicEvents; }
70
+ get: function () { return chunkX3WHETQ3_cjs.musicEvents; }
71
71
  });
72
72
  Object.defineProperty(exports, "orbit", {
73
73
  enumerable: true,
74
- get: function () { return chunkHREBQAY4_cjs.orbit; }
74
+ get: function () { return chunkX3WHETQ3_cjs.orbit; }
75
75
  });
76
76
  Object.defineProperty(exports, "particles", {
77
77
  enumerable: true,
78
- get: function () { return chunkHREBQAY4_cjs.particles; }
78
+ get: function () { return chunkX3WHETQ3_cjs.particles; }
79
79
  });
80
80
  Object.defineProperty(exports, "react", {
81
81
  enumerable: true,
82
- get: function () { return chunkHREBQAY4_cjs.react; }
82
+ get: function () { return chunkX3WHETQ3_cjs.react; }
83
83
  });
84
84
  Object.defineProperty(exports, "resolveLoader", {
85
85
  enumerable: true,
86
- get: function () { return chunkHREBQAY4_cjs.resolveLoader; }
86
+ get: function () { return chunkX3WHETQ3_cjs.resolveLoader; }
87
87
  });
88
88
  Object.defineProperty(exports, "splitText", {
89
89
  enumerable: true,
90
- get: function () { return chunkHREBQAY4_cjs.splitText; }
90
+ get: function () { return chunkX3WHETQ3_cjs.splitText; }
91
91
  });
92
92
  Object.defineProperty(exports, "stagger", {
93
93
  enumerable: true,
94
- get: function () { return chunkHREBQAY4_cjs.stagger; }
94
+ get: function () { return chunkX3WHETQ3_cjs.stagger; }
95
95
  });
96
96
  Object.defineProperty(exports, "wiggle", {
97
97
  enumerable: true,
98
- get: function () { return chunkHREBQAY4_cjs.wiggle; }
98
+ get: function () { return chunkX3WHETQ3_cjs.wiggle; }
99
99
  });
100
100
  Object.defineProperty(exports, "withFade", {
101
101
  enumerable: true,
102
- get: function () { return chunkHREBQAY4_cjs.withFade; }
102
+ get: function () { return chunkX3WHETQ3_cjs.withFade; }
103
103
  });
104
104
  Object.defineProperty(exports, "Sequence", {
105
105
  enumerable: true,
106
- get: function () { return chunkZVUO325O_cjs.Sequence; }
106
+ get: function () { return chunkDJ5B7IKT_cjs.Sequence; }
107
107
  });
108
108
  Object.defineProperty(exports, "noise", {
109
109
  enumerable: true,
110
- get: function () { return chunkZVUO325O_cjs.noise; }
110
+ get: function () { return chunkDJ5B7IKT_cjs.noise; }
111
111
  });
112
112
  Object.defineProperty(exports, "rand", {
113
113
  enumerable: true,
114
- get: function () { return chunkZVUO325O_cjs.rand; }
114
+ get: function () { return chunkDJ5B7IKT_cjs.rand; }
115
115
  });
116
116
  Object.defineProperty(exports, "random", {
117
117
  enumerable: true,
118
- get: function () { return chunkZVUO325O_cjs.random; }
118
+ get: function () { return chunkDJ5B7IKT_cjs.random; }
119
119
  });
120
120
  Object.defineProperty(exports, "registerSequenceType", {
121
121
  enumerable: true,
122
- get: function () { return chunkZVUO325O_cjs.registerSequenceType; }
122
+ get: function () { return chunkDJ5B7IKT_cjs.registerSequenceType; }
123
123
  });
124
124
  Object.defineProperty(exports, "warnUnknownOptions", {
125
125
  enumerable: true,
package/dist/index.d.cts CHANGED
@@ -1,8 +1,8 @@
1
- import { M as MusicEvents } from './Movie-DdnpLpw1.cjs';
2
- export { A as AudioInspectOptions, a as AudioReport, b as AudioSourceReport, C as ContactSheetOptions, F as FontReport, c as FrameEvent, I as InspectOptions, d as InspectReport, e as IssueGroup, L as LayerInfo, f as LoadProgressState, g as LoadStage, h as LoaderOption, i as MotionBlurOptions, j as MotionBlurSpec, k as Movie, l as MovieErrorEvent, m as MovieOptions, n as MusicDrumEvents, o as MusicDrumHit, p as MusicNote, q as MusicSummary, r as MusicTrackEvents, O as OnionSkinOptions, P as ProgressEvent, R as RenderOptions, s as ReviewOptions, t as ReviewReport, S as SnapshotOptions, u as SoundMeasure, T as TimelineData, v as TimelineHtmlOptions, w as TimelineRow, x as TimelineSvgOptions, y as TimelineTransition, V as VolumeEvent, z as dismissLoader, B as failLoader, D as resolveLoader } from './Movie-DdnpLpw1.cjs';
3
- import { S as SequenceSpec, C as CompositionShape, I as ImageSequenceSpec, a as CameraSequenceSpec, K as Keyframe, T as TextSequenceSpec, M as MusicOptions, b as SequenceCommon } from './types-BzIB65Vk.cjs';
4
- export { A as ArcShapeSpec, c as AssetSpec, d as AudioAssetSpec, e as AudioMusicSpec, f as AudioSequenceSpec, g as AudioSfxSpec, B as BlendModeName, h as ChromaKeyFilterSpec, i as CircleShapeSpec, j as CompositionSequenceSpec, k as CompositionSpec, l as CrossfadeTransition, m as CustomFilterSpec, D as DipTransition, n as DissolveTransition, E as EllipseShapeSpec, o as Expr, F as FilterSpec, G as GradientSpec, p as IrisTransition, L as LightSequenceSpec, q as LineShapeSpec, r as LumaTransition, s as MaskRefSpec, t as MatteRefSpec, u as MusicDrum, v as MusicDrums, w as MusicInstrument, x as MusicLevel, y as MusicTrack, N as NullSequenceSpec, P as PathShapeSpec, z as PolygonShapeSpec, H as PropValue, J as Props, R as RectShapeSpec, O as SfxKnobs, Q as SfxOptions, U as SfxPreset, V as SfxVoice, W as ShaderSequenceSpec, X as ShapeSequenceSpec, Y as SlideTransition, Z as Stop, _ as StopSpec, $ as TransitionCommon, a0 as TransitionSpec, a1 as VideoSequenceSpec, a2 as WipeTransition, a3 as ZoomTransition } from './types-BzIB65Vk.cjs';
5
- import { S as Sequence } from './Base-CB1_FPZD.cjs';
1
+ import { M as MusicEvents } from './Movie-BH81stkb.cjs';
2
+ export { A as AudioInspectOptions, a as AudioReport, b as AudioSourceReport, C as ContactSheetOptions, F as FontReport, c as FrameEvent, I as InspectOptions, d as InspectReport, e as IssueGroup, L as LayerInfo, f as LoadProgressState, g as LoadStage, h as LoaderOption, i as LoopEvent, j as MotionBlurOptions, k as MotionBlurSpec, l as Movie, m as MovieErrorEvent, n as MovieOptions, o as MusicDrumEvents, p as MusicDrumHit, q as MusicNote, r as MusicSummary, s as MusicTrackEvents, O as OnionSkinOptions, P as ProgressEvent, R as RebuildOptions, t as RebuildReason, u as RebuildReport, v as RenderOptions, w as ReviewOptions, x as ReviewReport, S as SnapshotOptions, y as SoundMeasure, T as TimelineData, z as TimelineHtmlOptions, B as TimelineRow, D as TimelineSvgOptions, E as TimelineTransition, V as VolumeEvent, G as dismissLoader, H as failLoader, J as resolveLoader } from './Movie-BH81stkb.cjs';
3
+ import { S as SequenceSpec, C as CompositionShape, I as ImageSequenceSpec, a as CameraSequenceSpec, K as Keyframe, T as TextSequenceSpec, M as MusicOptions, b as SequenceCommon } from './types-CK_crNAI.cjs';
4
+ export { A as ArcShapeSpec, c as AssetSpec, d as AudioAssetSpec, e as AudioMusicSpec, f as AudioSequenceSpec, g as AudioSfxSpec, B as BlendModeName, h as ChromaKeyFilterSpec, i as CircleShapeSpec, j as CompositionSequenceSpec, k as CompositionSpec, l as CrossfadeTransition, m as CustomFilterSpec, D as DipTransition, n as DissolveTransition, E as EllipseShapeSpec, o as Expr, F as FilterSpec, G as GradientSpec, p as IrisTransition, L as LightSequenceSpec, q as LineShapeSpec, r as LumaTransition, s as MaskRefSpec, t as MatteRefSpec, u as MusicDrum, v as MusicDrums, w as MusicInstrument, x as MusicLevel, y as MusicTrack, N as NullSequenceSpec, P as PathShapeSpec, z as PolygonShapeSpec, H as PropValue, J as Props, R as RectShapeSpec, O as SfxKnobs, Q as SfxOptions, U as SfxPreset, V as SfxVoice, W as ShaderSequenceSpec, X as ShapeSequenceSpec, Y as SlideTransition, Z as Stop, _ as StopSpec, $ as TransitionCommon, a0 as TransitionSpec, a1 as VideoSequenceSpec, a2 as WipeTransition, a3 as ZoomTransition } from './types-CK_crNAI.cjs';
5
+ import { S as Sequence } from './Base-BKagtWc0.cjs';
6
6
  import 'pixi.js';
7
7
 
8
8
  /** A text style as written in a `text` layer's `style` (numbers, not expressions, for the fields that size the text). */
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { M as MusicEvents } from './Movie-C2rZFkrO.js';
2
- export { A as AudioInspectOptions, a as AudioReport, b as AudioSourceReport, C as ContactSheetOptions, F as FontReport, c as FrameEvent, I as InspectOptions, d as InspectReport, e as IssueGroup, L as LayerInfo, f as LoadProgressState, g as LoadStage, h as LoaderOption, i as MotionBlurOptions, j as MotionBlurSpec, k as Movie, l as MovieErrorEvent, m as MovieOptions, n as MusicDrumEvents, o as MusicDrumHit, p as MusicNote, q as MusicSummary, r as MusicTrackEvents, O as OnionSkinOptions, P as ProgressEvent, R as RenderOptions, s as ReviewOptions, t as ReviewReport, S as SnapshotOptions, u as SoundMeasure, T as TimelineData, v as TimelineHtmlOptions, w as TimelineRow, x as TimelineSvgOptions, y as TimelineTransition, V as VolumeEvent, z as dismissLoader, B as failLoader, D as resolveLoader } from './Movie-C2rZFkrO.js';
3
- import { S as SequenceSpec, C as CompositionShape, I as ImageSequenceSpec, a as CameraSequenceSpec, K as Keyframe, T as TextSequenceSpec, M as MusicOptions, b as SequenceCommon } from './types-BzIB65Vk.js';
4
- export { A as ArcShapeSpec, c as AssetSpec, d as AudioAssetSpec, e as AudioMusicSpec, f as AudioSequenceSpec, g as AudioSfxSpec, B as BlendModeName, h as ChromaKeyFilterSpec, i as CircleShapeSpec, j as CompositionSequenceSpec, k as CompositionSpec, l as CrossfadeTransition, m as CustomFilterSpec, D as DipTransition, n as DissolveTransition, E as EllipseShapeSpec, o as Expr, F as FilterSpec, G as GradientSpec, p as IrisTransition, L as LightSequenceSpec, q as LineShapeSpec, r as LumaTransition, s as MaskRefSpec, t as MatteRefSpec, u as MusicDrum, v as MusicDrums, w as MusicInstrument, x as MusicLevel, y as MusicTrack, N as NullSequenceSpec, P as PathShapeSpec, z as PolygonShapeSpec, H as PropValue, J as Props, R as RectShapeSpec, O as SfxKnobs, Q as SfxOptions, U as SfxPreset, V as SfxVoice, W as ShaderSequenceSpec, X as ShapeSequenceSpec, Y as SlideTransition, Z as Stop, _ as StopSpec, $ as TransitionCommon, a0 as TransitionSpec, a1 as VideoSequenceSpec, a2 as WipeTransition, a3 as ZoomTransition } from './types-BzIB65Vk.js';
5
- import { S as Sequence } from './Base-Ne74ztNl.js';
1
+ import { M as MusicEvents } from './Movie-CfFPItoL.js';
2
+ export { A as AudioInspectOptions, a as AudioReport, b as AudioSourceReport, C as ContactSheetOptions, F as FontReport, c as FrameEvent, I as InspectOptions, d as InspectReport, e as IssueGroup, L as LayerInfo, f as LoadProgressState, g as LoadStage, h as LoaderOption, i as LoopEvent, j as MotionBlurOptions, k as MotionBlurSpec, l as Movie, m as MovieErrorEvent, n as MovieOptions, o as MusicDrumEvents, p as MusicDrumHit, q as MusicNote, r as MusicSummary, s as MusicTrackEvents, O as OnionSkinOptions, P as ProgressEvent, R as RebuildOptions, t as RebuildReason, u as RebuildReport, v as RenderOptions, w as ReviewOptions, x as ReviewReport, S as SnapshotOptions, y as SoundMeasure, T as TimelineData, z as TimelineHtmlOptions, B as TimelineRow, D as TimelineSvgOptions, E as TimelineTransition, V as VolumeEvent, G as dismissLoader, H as failLoader, J as resolveLoader } from './Movie-CfFPItoL.js';
3
+ import { S as SequenceSpec, C as CompositionShape, I as ImageSequenceSpec, a as CameraSequenceSpec, K as Keyframe, T as TextSequenceSpec, M as MusicOptions, b as SequenceCommon } from './types-CK_crNAI.js';
4
+ export { A as ArcShapeSpec, c as AssetSpec, d as AudioAssetSpec, e as AudioMusicSpec, f as AudioSequenceSpec, g as AudioSfxSpec, B as BlendModeName, h as ChromaKeyFilterSpec, i as CircleShapeSpec, j as CompositionSequenceSpec, k as CompositionSpec, l as CrossfadeTransition, m as CustomFilterSpec, D as DipTransition, n as DissolveTransition, E as EllipseShapeSpec, o as Expr, F as FilterSpec, G as GradientSpec, p as IrisTransition, L as LightSequenceSpec, q as LineShapeSpec, r as LumaTransition, s as MaskRefSpec, t as MatteRefSpec, u as MusicDrum, v as MusicDrums, w as MusicInstrument, x as MusicLevel, y as MusicTrack, N as NullSequenceSpec, P as PathShapeSpec, z as PolygonShapeSpec, H as PropValue, J as Props, R as RectShapeSpec, O as SfxKnobs, Q as SfxOptions, U as SfxPreset, V as SfxVoice, W as ShaderSequenceSpec, X as ShapeSequenceSpec, Y as SlideTransition, Z as Stop, _ as StopSpec, $ as TransitionCommon, a0 as TransitionSpec, a1 as VideoSequenceSpec, a2 as WipeTransition, a3 as ZoomTransition } from './types-CK_crNAI.js';
5
+ import { S as Sequence } from './Base-jRiMHcWT.js';
6
6
  import 'pixi.js';
7
7
 
8
8
  /** A text style as written in a `text` layer's `style` (numbers, not expressions, for the fields that size the text). */
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
- export { Movie, animateText, audioEnvelope, bpmEnvelope, cameraPath, computeEnvelope, dismissLoader, parseEase as ease, failLoader, followPath, kenBurns, measureText, musicBuffer, musicEnvelope, musicEvents, orbit, particles, react, resolveLoader, splitText, stagger, wiggle, withFade } from './chunk-CRQFDY7E.js';
2
- import './chunk-A3Q3SDSH.js';
3
- export { Sequence, noise, rand, random, registerSequenceType } from './chunk-ZAXYPXKW.js';
1
+ export { Movie, animateText, audioEnvelope, bpmEnvelope, cameraPath, computeEnvelope, dismissLoader, parseEase as ease, failLoader, followPath, kenBurns, measureText, musicBuffer, musicEnvelope, musicEvents, orbit, particles, react, resolveLoader, splitText, stagger, wiggle, withFade } from './chunk-UTIBYMIO.js';
2
+ import './chunk-BGMCZA36.js';
3
+ export { Sequence, noise, rand, random, registerSequenceType } from './chunk-MMTESMJ5.js';
4
4
  import './chunk-4KB3GUEK.js';
5
5
  import './chunk-RCVZX2JP.js';
6
6
  export { warnUnknownOptions } from './chunk-BXOCEZ4U.js';
package/dist/loader.css CHANGED
@@ -1,7 +1,7 @@
1
1
  /*
2
2
  * pixi-effects loader: one line of HTML on the page, a few lines of CSS, no JavaScript of your own.
3
3
  *
4
- * <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/pixi-effects@0.30.0/dist/loader.css">
4
+ * <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/pixi-effects@0.31.0/dist/loader.css">
5
5
  * <div class="stage" style="position: relative"> <!-- any box the canvas sits in, with position: relative -->
6
6
  * <canvas id="stage" width="1280" height="720"></canvas>
7
7
  * <div class="pe-loader" data-label="LOADING"></div> <!-- or class="pe-loader pe-loader--bar" -->
package/dist/present.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
- require('./chunk-HREBQAY4.cjs');
4
- require('./chunk-WHNADXXG.cjs');
5
- require('./chunk-ZVUO325O.cjs');
3
+ require('./chunk-X3WHETQ3.cjs');
4
+ require('./chunk-L73KRFXI.cjs');
5
+ require('./chunk-DJ5B7IKT.cjs');
6
6
  require('./chunk-2DXPTKQZ.cjs');
7
7
  require('./chunk-LYOKH7KE.cjs');
8
8
  var chunkTWZNOUM7_cjs = require('./chunk-TWZNOUM7.cjs');
@@ -1,5 +1,5 @@
1
- import { k as Movie, j as MotionBlurSpec } from './Movie-DdnpLpw1.cjs';
2
- import { S as SequenceSpec, J as Props, K as Keyframe, a0 as TransitionSpec, k as CompositionSpec, Z as Stop } from './types-BzIB65Vk.cjs';
1
+ import { l as Movie, k as MotionBlurSpec } from './Movie-BH81stkb.cjs';
2
+ import { S as SequenceSpec, J as Props, K as Keyframe, a0 as TransitionSpec, k as CompositionSpec, Z as Stop } from './types-CK_crNAI.cjs';
3
3
  import 'pixi.js';
4
4
 
5
5
  interface PresenterOptions {
package/dist/present.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { k as Movie, j as MotionBlurSpec } from './Movie-C2rZFkrO.js';
2
- import { S as SequenceSpec, J as Props, K as Keyframe, a0 as TransitionSpec, k as CompositionSpec, Z as Stop } from './types-BzIB65Vk.js';
1
+ import { l as Movie, k as MotionBlurSpec } from './Movie-CfFPItoL.js';
2
+ import { S as SequenceSpec, J as Props, K as Keyframe, a0 as TransitionSpec, k as CompositionSpec, Z as Stop } from './types-CK_crNAI.js';
3
3
  import 'pixi.js';
4
4
 
5
5
  interface PresenterOptions {
package/dist/present.js CHANGED
@@ -1,6 +1,6 @@
1
- import './chunk-CRQFDY7E.js';
2
- import './chunk-A3Q3SDSH.js';
3
- import './chunk-ZAXYPXKW.js';
1
+ import './chunk-UTIBYMIO.js';
2
+ import './chunk-BGMCZA36.js';
3
+ import './chunk-MMTESMJ5.js';
4
4
  import './chunk-4KB3GUEK.js';
5
5
  import './chunk-RCVZX2JP.js';
6
6
  import { warnUnknownOptions } from './chunk-BXOCEZ4U.js';
package/dist/three.cjs CHANGED
@@ -1,12 +1,12 @@
1
1
  'use strict';
2
2
 
3
- var chunkZVUO325O_cjs = require('./chunk-ZVUO325O.cjs');
3
+ var chunkDJ5B7IKT_cjs = require('./chunk-DJ5B7IKT.cjs');
4
4
  require('./chunk-LYOKH7KE.cjs');
5
5
  require('./chunk-TWZNOUM7.cjs');
6
6
  var pixi_js = require('pixi.js');
7
7
  var three$1 = require('three');
8
8
 
9
- var ThreeSequence = class extends chunkZVUO325O_cjs.Sequence {
9
+ var ThreeSequence = class extends chunkDJ5B7IKT_cjs.Sequence {
10
10
  _renderer = null;
11
11
  _scene = null;
12
12
  _camera = null;
@@ -25,7 +25,7 @@ var ThreeSequence = class extends chunkZVUO325O_cjs.Sequence {
25
25
  if (this.duration === void 0) {
26
26
  this.duration = this.parent?.duration ?? this.root.duration;
27
27
  }
28
- const scope = chunkZVUO325O_cjs.buildScope(this, this.parent, this.root);
28
+ const scope = chunkDJ5B7IKT_cjs.buildScope(this, this.parent, this.root);
29
29
  const width = resolveDim(spec.width, scope) ?? this.parent?.width ?? this.root.width;
30
30
  const height = resolveDim(spec.height, scope) ?? this.parent?.height ?? this.root.height;
31
31
  const resolution = spec.resolution ?? 1;
@@ -145,12 +145,12 @@ var ThreeSequence = class extends chunkZVUO325O_cjs.Sequence {
145
145
  function resolveDim(v, scope) {
146
146
  if (v === void 0) return void 0;
147
147
  if (typeof v === "number") return v;
148
- return chunkZVUO325O_cjs.evaluateExpr(v, scope);
148
+ return chunkDJ5B7IKT_cjs.evaluateExpr(v, scope);
149
149
  }
150
150
 
151
151
  // src/three/index.ts
152
152
  function registerThree() {
153
- chunkZVUO325O_cjs.registerSequenceType("three", ThreeSequence);
153
+ chunkDJ5B7IKT_cjs.registerSequenceType("three", ThreeSequence);
154
154
  }
155
155
  function three(spec) {
156
156
  return spec;
package/dist/three.d.cts CHANGED
@@ -1,6 +1,6 @@
1
- import { b as SequenceCommon, H as PropValue, S as SequenceSpec } from './types-BzIB65Vk.cjs';
1
+ import { b as SequenceCommon, H as PropValue, S as SequenceSpec } from './types-CK_crNAI.cjs';
2
2
  import { Scene, Camera, WebGLRenderer } from 'three';
3
- import { S as Sequence, P as PathRouters } from './Base-CB1_FPZD.cjs';
3
+ import { S as Sequence, P as PathRouters } from './Base-BKagtWc0.cjs';
4
4
  import 'pixi.js';
5
5
 
6
6
  /** Handed to setup / update / dispose. One per three sequence. */
package/dist/three.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { b as SequenceCommon, H as PropValue, S as SequenceSpec } from './types-BzIB65Vk.js';
1
+ import { b as SequenceCommon, H as PropValue, S as SequenceSpec } from './types-CK_crNAI.js';
2
2
  import { Scene, Camera, WebGLRenderer } from 'three';
3
- import { S as Sequence, P as PathRouters } from './Base-Ne74ztNl.js';
3
+ import { S as Sequence, P as PathRouters } from './Base-jRiMHcWT.js';
4
4
  import 'pixi.js';
5
5
 
6
6
  /** Handed to setup / update / dispose. One per three sequence. */
package/dist/three.js CHANGED
@@ -1,4 +1,4 @@
1
- import { Sequence, buildScope, evaluateExpr, registerSequenceType } from './chunk-ZAXYPXKW.js';
1
+ import { Sequence, buildScope, evaluateExpr, registerSequenceType } from './chunk-MMTESMJ5.js';
2
2
  import './chunk-RCVZX2JP.js';
3
3
  import './chunk-BXOCEZ4U.js';
4
4
  import { Texture, Sprite } from 'pixi.js';
@@ -692,6 +692,8 @@ interface CompositionShape {
692
692
  frameRate?: number;
693
693
  /** Called after each layer is built (the root shape only): feeds `loadprogress` and lets the page paint now and then. */
694
694
  onLayerBuilt?: () => void | Promise<void>;
695
+ /** The numbers declared as variables (`movie.init({ vars })`), on the root shape only: an expression reads them as identifiers. */
696
+ vars?: Record<string, number>;
695
697
  }
696
698
 
697
699
  export type { TransitionCommon as $, ArcShapeSpec as A, BlendModeName as B, CompositionShape as C, DipTransition as D, EllipseShapeSpec as E, FilterSpec as F, GradientSpec as G, PropValue as H, ImageSequenceSpec as I, Props as J, Keyframe as K, LightSequenceSpec as L, MusicOptions as M, NullSequenceSpec as N, SfxKnobs as O, PathShapeSpec as P, SfxOptions as Q, RectShapeSpec as R, SequenceSpec as S, TextSequenceSpec as T, SfxPreset as U, SfxVoice as V, ShaderSequenceSpec as W, ShapeSequenceSpec as X, SlideTransition as Y, Stop as Z, StopSpec as _, CameraSequenceSpec as a, TransitionSpec as a0, VideoSequenceSpec as a1, WipeTransition as a2, ZoomTransition as a3, SequenceCommon as b, AssetSpec as c, AudioAssetSpec as d, AudioMusicSpec as e, AudioSequenceSpec as f, AudioSfxSpec as g, ChromaKeyFilterSpec as h, CircleShapeSpec as i, CompositionSequenceSpec as j, CompositionSpec as k, CrossfadeTransition as l, CustomFilterSpec as m, DissolveTransition as n, Expr as o, IrisTransition as p, LineShapeSpec as q, LumaTransition as r, MaskRefSpec as s, MatteRefSpec as t, MusicDrum as u, MusicDrums as v, MusicInstrument as w, MusicLevel as x, MusicTrack as y, PolygonShapeSpec as z };
@@ -692,6 +692,8 @@ interface CompositionShape {
692
692
  frameRate?: number;
693
693
  /** Called after each layer is built (the root shape only): feeds `loadprogress` and lets the page paint now and then. */
694
694
  onLayerBuilt?: () => void | Promise<void>;
695
+ /** The numbers declared as variables (`movie.init({ vars })`), on the root shape only: an expression reads them as identifiers. */
696
+ vars?: Record<string, number>;
695
697
  }
696
698
 
697
699
  export type { TransitionCommon as $, ArcShapeSpec as A, BlendModeName as B, CompositionShape as C, DipTransition as D, EllipseShapeSpec as E, FilterSpec as F, GradientSpec as G, PropValue as H, ImageSequenceSpec as I, Props as J, Keyframe as K, LightSequenceSpec as L, MusicOptions as M, NullSequenceSpec as N, SfxKnobs as O, PathShapeSpec as P, SfxOptions as Q, RectShapeSpec as R, SequenceSpec as S, TextSequenceSpec as T, SfxPreset as U, SfxVoice as V, ShaderSequenceSpec as W, ShapeSequenceSpec as X, SlideTransition as Y, Stop as Z, StopSpec as _, CameraSequenceSpec as a, TransitionSpec as a0, VideoSequenceSpec as a1, WipeTransition as a2, ZoomTransition as a3, SequenceCommon as b, AssetSpec as c, AudioAssetSpec as d, AudioMusicSpec as e, AudioSequenceSpec as f, AudioSfxSpec as g, ChromaKeyFilterSpec as h, CircleShapeSpec as i, CompositionSequenceSpec as j, CompositionSpec as k, CrossfadeTransition as l, CustomFilterSpec as m, DissolveTransition as n, Expr as o, IrisTransition as p, LineShapeSpec as q, LumaTransition as r, MaskRefSpec as s, MatteRefSpec as t, MusicDrum as u, MusicDrums as v, MusicInstrument as w, MusicLevel as x, MusicTrack as y, PolygonShapeSpec as z };
package/docs/api.md CHANGED
@@ -42,6 +42,8 @@ interface MovieOptions {
42
42
  canvas?: HTMLCanvasElement; // existing canvas to render into; otherwise PixiJS creates one
43
43
  assets?: AssetSpec[]; // [{ name, src }]
44
44
  composition?: CompositionSpec; // root composition (see DSL reference)
45
+ vars?: Record<string, number | string>; // named values the composition reads: a number as a name in an expression, any as {name} in a string (see Variables)
46
+ loop?: boolean; // start with movie.loop on: playing goes back to the start at the end (default false, like a <video>)
45
47
  poster?: number; // seconds: the frame shown before play (negative: from the end), see movie.poster
46
48
  motionBlur?: boolean | number | { samples?: number; shutter?: number }; // blur for render() / snapshot() / contactSheet(), not live playback; see Motion blur
47
49
  loader?: HTMLElement | string | false; // the page's loader (see pixi-effects/loader.css): shows how far init is (a bar, "BUILDING LAYERS 62%"), faded out when ready, stopped if init fails; default: a .pe-loader next to the canvas
@@ -78,6 +80,25 @@ Play, and pause exactly at `seconds` (the frame `round(seconds × frameRate)`).
78
80
 
79
81
  Look around and put the movie back: pauses, runs `fn` (seek, take pictures with `snapshot()`; the seeks made inside are not reported as `seeking` / `seeked`), then puts the playhead (or the poster) back where it was, whatever `fn` did, and returns what `fn` returned. `stopImages()` and `inspectStops()` (`pixi-effects/present`) are made with it.
80
82
 
83
+ ### Movie variables and rebuilding: `vars`, `setVars()`, `resize()`, `rebuild()`
84
+
85
+ Variables are declared in `init({ vars: { title: 'NORD', shift: 0 } })` and read by the composition (see [Variables](dsl.md#variables)). Changing one builds the composition again: the new one is built off the stage first and swapped in when it is whole, at the same frame; a failure leaves the old one in place.
86
+
87
+ ```ts
88
+ movie.vars // the current values (a copy)
89
+ await movie.setVars({ shift: 40 }); // the declared names only (others: ignored with a did-you-mean); the same values: nothing happens
90
+ await movie.resize(1080, 1920); // the movie's size; W / H / GW / GH follow. Beats a width / height the composition names
91
+ await movie.rebuild({ composition, vars, width, height }); // the general form: any of the four; `composition` replaces the whole spec (your layout function, called again)
92
+ // all three resolve to a report, and fire 'rebuilt' with it:
93
+ interface RebuildReport { reason: 'vars' | 'resize' | 'rebuild'; ms: number; audio: 'reused' | 'mixed' | 'none'; frame: number; playing: boolean; unchanged?: true }
94
+ ```
95
+
96
+ - The new composition is built while the old one goes on; at the swap the movie keeps doing what it is doing at that moment: the same frame, playing or paused (a `pause()`, a seek or a `play()` you made during the build is kept), the poster if it was shown. A playing movie whose sound is unchanged (`audio: 'reused'`) is not stopped at all: the frame clock and the sound go on and only the picture is swapped, so rebuilds in a row (a pointer) do not hold the playhead back. When the sound changed, the movie stops and plays on from the same frame with the new sound. A `playUntil()` in flight ends. The canvas changes size at the swap, not before. A `render()` or `peek()` in flight is not interrupted: the swap waits for it.
97
+ - The sound is mixed only when it changed: `audio: 'reused'` means the same mix as before (the mix is the slow part, 0.6 to 0.8 s for a film; the rest takes about 20 ms). A time remap (`warp` / `sourceMap`) turns the cache off.
98
+ - Calls that arrive during a rebuild are joined: at most one rebuild runs and one waits, with the latest values. Safe to call from `pointermove` or `scroll`: a rebuild that leaves the sound alone takes tens of milliseconds (11 to 42 ms on four gallery pieces), one that mixes the sound again 0.6 to 0.8 s, so a slider that changes the sound will lag behind the hand.
99
+ - A rebuild that fails (a bad expression, a missing asset, a size that is not pixels) rejects, emits `error` with `where: 'rebuild'`, and the movie goes on with what it had. A `destroy()` during a rebuild ends it the same way.
100
+ - To follow a window: observe a CSS-sized box around the canvas, not the canvas itself (the movie sets the canvas's pixel size): `new ResizeObserver(() => movie.resize(Math.round(box.clientWidth * devicePixelRatio), Math.round(box.clientHeight * devicePixelRatio))).observe(box)` (the `liquid-layout` recipe).
101
+
81
102
  ### `movie.snapshot(frame?, options?): Promise<Blob | string>`
82
103
 
83
104
  ```ts
@@ -261,7 +282,9 @@ movie.off(event, fn): this
261
282
  | `'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()` |
262
283
  | `'ended'` | none | playback ran off the end (after `'pause'`); pausing by hand does not emit it |
263
284
  | `'volumechange'` | `{ volume: number; muted: boolean }` | `volume` or `muted` really changed (clamping counts) |
264
- | `'error'` | `{ where: 'init' \| 'render' \| 'playback'; message: string; error: unknown }` | `init()` / `render()` failed (the call still rejects), or a frame failed during playback |
285
+ | `'loopchange'` | `{ loop: boolean }` | `movie.loop` really changed (the first value from `init({ loop })` is not a change) |
286
+ | `'error'` | `{ where: 'init' \| 'render' \| 'playback' \| 'rebuild'; message: string; error: unknown }` | `init()` / `render()` / a rebuild failed (the call still rejects), or a frame failed during playback |
287
+ | `'rebuilt'` | `RebuildReport` (see above) | a `setVars()` / `resize()` / `rebuild()` built the composition again (not for a call that changed nothing) |
265
288
 
266
289
  The names are the ones an HTML5 `<video>` uses, so a player written for `<video>` ports over.
267
290
 
@@ -280,8 +303,10 @@ The names are the ones an HTML5 `<video>` uses, so a player written for `<video>
280
303
  | `background` | string | CSS color |
281
304
  | `volume` | number | 0..1 getter/setter; immediate. Setter clamps and applies to active audio |
282
305
  | `muted` | boolean | getter/setter; immediate |
306
+ | `loop` | boolean | getter/setter, default `false`. When true, an ordinary `play()` that reaches the end goes back to the start and plays on: no `ended`, no `pause` / `play` events at the wrap, the sound starts again (a short gap). `playUntil()` and `render()` ignore it. Say `loopchange` when it changes |
283
307
  | `app` | `pixi.js Application \| null` | PIXI Application instance (advanced/escape hatch) |
284
308
  | `timeline` | `Timeline \| null` | the movie's timeline (advanced): `time(t)`, `duration()`, `segments()` |
309
+ | `vars` | `Record<string, number \| string>` | the current variable values (a copy) |
285
310
  | `stops` | `Stop[]` | the composition's stops: named times (see Presentations); empty for an ordinary movie |
286
311
 
287
312
  ### Presentations: `stops` and `pixi-effects/present`
@@ -455,6 +480,7 @@ interface ControllerOptions {
455
480
  exportButton?: boolean; // default true; false hides ⬇ + popover
456
481
  keyboard?: boolean; // default true
457
482
  presentButton?: boolean; // default true: a movie with stops gets a Present button (marks on the seek bar are always shown)
483
+ loopButton?: boolean; // default true: a loop button next to the volume (and the L key) that flips movie.loop
458
484
  pauseAtStops?: boolean; // default true: with stops, play / Space / click on the picture play to the next stop and pause; false plays straight through
459
485
  clickToPlay?: boolean; // default true: a click / tap on the picture plays / pauses (like <video>); false leaves the canvas alone
460
486
  className?: string; // default 'movie-controller'
@@ -523,6 +549,7 @@ Active when `keyboard: true` and the key target is not `<input>`/`<textarea>`/`<
523
549
  | `←` / `→` | step ±1 frame |
524
550
  | `↑` / `↓` | volume ±5% (clears mute when increasing past zero) |
525
551
  | `M` | toggle mute |
552
+ | `L` | toggle loop (`movie.loop`) |
526
553
  | `Shift+E` | export with current settings (skips the popover) |
527
554
  | `F` | toggle fullscreen |
528
555
  | `Esc` | close the export popover or exit fullscreen (browser) |
package/docs/dsl.md CHANGED
@@ -71,7 +71,7 @@ A layer is **not removed** when its lifespan `[at, at + duration)` ends: it is o
71
71
 
72
72
  ### `text`
73
73
 
74
- Renders a [PIXI.Text](https://pixijs.com/8.x/guides/components/scene-objects/text/text). Animatable position, rotation, scale, opacity and `fill`. `style` accepts any PixiJS `TextStyle` field and is applied once at build time — notably `fontSize fontFamily fontWeight fill letterSpacing lineHeight align wordWrap wordWrapWidth stroke dropShadow padding` (numbers may be expressions). A `dropShadow` glow is clipped unless `padding` is at least twice its `blur`. Text content can change over time (see *Changing text* below): a `{value}` placeholder prints an animatable number (counters), a keyframe `set: { text: '…' }` swaps the string, and `visibleChars` types it out. Multi-line text is centre-aligned unless `style.align` says otherwise. In expressions `w` / `h` are the size of the styled text, so `x: '-w'` places it just off the left edge.
74
+ Renders a [PIXI.Text](https://pixijs.com/8.x/guides/components/scene-objects/text/text). Animatable position, rotation, scale, opacity and `fill`. `style` accepts any PixiJS `TextStyle` field and is applied once at build time (an outline `stroke: { color, width }` is **round-joined** unless you give `join`: PixiJS's own default, `miter`, grows spikes on the sharp corners of W, V, A, k; the stroke is centred on the glyph edge, so half its width covers the fill: keep `width` to about a tenth of `fontSize`, or put a second, stroked copy of the text under the plain one for a thick outline) — notably `fontSize fontFamily fontWeight fill letterSpacing lineHeight align wordWrap wordWrapWidth stroke dropShadow padding` (numbers may be expressions). A `dropShadow` glow is clipped unless `padding` is at least twice its `blur`. Text content can change over time (see *Changing text* below): a `{value}` placeholder prints an animatable number (counters), a keyframe `set: { text: '…' }` swaps the string, and `visibleChars` types it out. Multi-line text is centre-aligned unless `style.align` says otherwise. In expressions `w` / `h` are the size of the styled text, so `x: '-w'` places it just off the left edge.
75
75
 
76
76
  ```ts
77
77
  {
@@ -1084,6 +1084,8 @@ No comparison, conditional, bitwise, or string operators — keep it numeric (`s
1084
1084
 
1085
1085
  ### Scope variables
1086
1086
 
1087
+ (Your own names, set from outside, are [Variables](#variables) below.)
1088
+
1087
1089
  Each sequence has its own scope, computed at build time:
1088
1090
 
1089
1091
  | Name | Meaning |
@@ -1119,6 +1121,35 @@ style: { fontSize: 'min(GW, GH) * 0.06' }
1119
1121
  initial: { x: 'GW/2', y: 'GH * 0.96', anchorX: 0.5, anchorY: 1 }
1120
1122
  ```
1121
1123
 
1124
+ ### Variables
1125
+
1126
+ A **variable** is a name with a value you can change after the movie is built: the language of a title, a brand colour, an offset, the screen size. Declare them once in `movie.init`; the composition reads them by name.
1127
+
1128
+ ```ts
1129
+ await movie.init({
1130
+ vars: { title: 'NORD', accent: '#e5399a', shift: 0 }, // a number or a string; no booleans (write 0 / 1)
1131
+ composition: { sequences: [
1132
+ { type: 'shape', shape: 'rect', width: 'GW', height: 'GH', initial: { x: 'GW/2', y: 'GH/2', fillColor: '{accent}' } },
1133
+ { type: 'text', text: '{title}', initial: { x: 'W/2 + shift', y: 'H/2' } },
1134
+ ] },
1135
+ });
1136
+ await movie.setVars({ title: 'SÜD', shift: 40 }); // builds the composition again, at the same frame
1137
+ ```
1138
+
1139
+ | Where | How it reads a variable |
1140
+ | --- | --- |
1141
+ | a numeric expression (`x`, `scale`, `width`, `fontSize` … any value that takes an [expression](#expressions)) | the **name**, like `W` or `GW`: `'W/2 + shift'`. Only number variables. |
1142
+ | any string anywhere in the composition (`text`, a colour, `asset`, a layer `name`, nested layers) | **`{name}`**: `'{title}'`, `'#{hex}'`, `'{lang}-logo'`. The text is replaced before the layer is built. A `{name}` that was not declared stays as written (`{value}` is the [counter](#counters-value) of a text layer, so it is also a name no variable can take). `$` is not used: it is a price (`'$5'`). |
1143
+
1144
+ Rules, all checked when the movie is built (each warning says what to change):
1145
+ - A name is letters, digits and `_`, not starting with a digit. These are **reserved** and are refused: `w h W H GW GH t d T contain cover value`, every expression function (`min max abs … step rand noise lerp clamp smoothstep mod`) and `PI`.
1146
+ - A variable that nothing reads (no `{name}` in a string, no use in an expression) is said: it is usually a typo on one side. A `{name}` that was not declared says the declared name it looks like.
1147
+ - Values are read **when the composition is built**, once (not every frame). `at` and `duration` are plain numbers, so a variable moves values, not timing; to change the structure in time, call `movie.rebuild({ composition })` with a composition made by your own function.
1148
+ - `setVars` of a name that was not declared is ignored with a did-you-mean; `setVars` of the values it already has does nothing.
1149
+ - Everything is built again, the playhead stays at the same frame, a playing movie keeps playing, and the sound is mixed again **only if** the sound changed. See [`movie.rebuild`](api.md#movie-variables-and-rebuilding-vars-setvars-resize-rebuild).
1150
+ - A video file is a function of the script **and** the variables: `pixi-effects render page.html --var title=SÜD --var shift=40`, `check --size 1920x1080,1080x1920` (a contact sheet per size).
1151
+ - Layout that should follow the screen size uses `W` / `H` / `GW` / `GH`, not pixels: after `movie.resize(w, h)` they are the new size.
1152
+
1122
1153
  ---
1123
1154
 
1124
1155
  ## Stops (presentations)