pixi-effects 0.22.0 → 0.25.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 (85) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +9 -7
  3. package/ai/SKILL.md +5 -3
  4. package/ai/chat-template.html +3 -3
  5. package/ai/reference/cheatsheet.md +8 -5
  6. package/ai/reference/pitfalls.md +13 -1
  7. package/ai/reference/recipes.md +131 -0
  8. package/ai/template.html +5 -5
  9. package/ai/tools/check.mjs +7 -0
  10. package/dist/{Base-gu-5X0Cv.d.ts → Base-BgnRXbtJ.d.ts} +1 -1
  11. package/dist/{Base-BzlPgd-D.d.cts → Base-DHVKqA46.d.cts} +1 -1
  12. package/dist/Composition-2GJSCHPP.cjs +16 -0
  13. package/dist/{Composition-BK5SH6J7.cjs.map → Composition-2GJSCHPP.cjs.map} +1 -1
  14. package/dist/Composition-C4FSWJZF.js +7 -0
  15. package/dist/{Composition-Q5TVG3HM.js.map → Composition-C4FSWJZF.js.map} +1 -1
  16. package/dist/Controller.cjs +2 -2
  17. package/dist/Controller.d.cts +2 -2
  18. package/dist/Controller.d.ts +2 -2
  19. package/dist/Controller.js +1 -1
  20. package/dist/{Movie-DMxOoTdW.d.cts → Movie-CTpN1wYL.d.cts} +3 -1
  21. package/dist/{Movie--_TJvdJa.d.ts → Movie-FM5m67V0.d.ts} +3 -1
  22. package/dist/Presenter.cjs +2 -2
  23. package/dist/Presenter.d.cts +2 -2
  24. package/dist/Presenter.d.ts +2 -2
  25. package/dist/Presenter.js +1 -1
  26. package/dist/{blendModes-HCP5XTNP.js → blendModes-G3NOAU3T.js} +5 -5
  27. package/dist/{blendModes-HCP5XTNP.js.map → blendModes-G3NOAU3T.js.map} +1 -1
  28. package/dist/{blendModes-5E4G2ZZQ.cjs → blendModes-YV43K6E7.cjs} +6 -6
  29. package/dist/{blendModes-5E4G2ZZQ.cjs.map → blendModes-YV43K6E7.cjs.map} +1 -1
  30. package/dist/{chunk-K4JVI5HK.cjs → chunk-3DLYAPK7.cjs} +7 -9
  31. package/dist/{chunk-K4JVI5HK.cjs.map → chunk-3DLYAPK7.cjs.map} +1 -1
  32. package/dist/{chunk-YEPDQ7I3.js → chunk-AXZUKNXF.js} +6 -6
  33. package/dist/{chunk-YEPDQ7I3.js.map → chunk-AXZUKNXF.js.map} +1 -1
  34. package/dist/{chunk-NHICCDTC.js → chunk-BXOCEZ4U.js} +12 -3
  35. package/dist/chunk-BXOCEZ4U.js.map +1 -0
  36. package/dist/{chunk-IFZOI3JQ.cjs → chunk-DP37TTMO.cjs} +842 -40
  37. package/dist/chunk-DP37TTMO.cjs.map +1 -0
  38. package/dist/{chunk-BPTW7L25.cjs → chunk-ECA2WNRX.cjs} +23 -9
  39. package/dist/chunk-ECA2WNRX.cjs.map +1 -0
  40. package/dist/{chunk-DC4JPY6A.js → chunk-PRZ4U6JN.js} +814 -22
  41. package/dist/chunk-PRZ4U6JN.js.map +1 -0
  42. package/dist/chunk-SY27HZC5.cjs +1727 -0
  43. package/dist/chunk-SY27HZC5.cjs.map +1 -0
  44. package/dist/{chunk-E7RONUZ7.js → chunk-TLYTYBWX.js} +20 -6
  45. package/dist/chunk-TLYTYBWX.js.map +1 -0
  46. package/dist/{chunk-UZTKEYFP.cjs → chunk-TWZNOUM7.cjs} +12 -3
  47. package/dist/chunk-TWZNOUM7.cjs.map +1 -0
  48. package/dist/chunk-XS6GSJCN.js +1724 -0
  49. package/dist/chunk-XS6GSJCN.js.map +1 -0
  50. package/dist/index.cjs +227 -77
  51. package/dist/index.cjs.map +1 -1
  52. package/dist/index.d.cts +5 -5
  53. package/dist/index.d.ts +5 -5
  54. package/dist/index.js +166 -16
  55. package/dist/index.js.map +1 -1
  56. package/dist/loader.css +1 -1
  57. package/dist/{music-FUN7N225.js → music-AF4VTFAF.js} +3 -3
  58. package/dist/{music-FUN7N225.js.map → music-AF4VTFAF.js.map} +1 -1
  59. package/dist/{music-GEAH2XCT.cjs → music-KB7YZLHP.cjs} +7 -7
  60. package/dist/{music-GEAH2XCT.cjs.map → music-KB7YZLHP.cjs.map} +1 -1
  61. package/dist/{sfx-2DYTYNYW.cjs → sfx-2O6UQEUP.cjs} +8 -8
  62. package/dist/{sfx-2DYTYNYW.cjs.map → sfx-2O6UQEUP.cjs.map} +1 -1
  63. package/dist/{sfx-3IDAJ3UZ.js → sfx-VUKARHDX.js} +3 -3
  64. package/dist/{sfx-3IDAJ3UZ.js.map → sfx-VUKARHDX.js.map} +1 -1
  65. package/dist/three.cjs +7 -7
  66. package/dist/three.d.cts +2 -2
  67. package/dist/three.d.ts +2 -2
  68. package/dist/three.js +3 -3
  69. package/dist/{types-DBbZVKGS.d.cts → types-CoT0ypcx.d.cts} +60 -4
  70. package/dist/{types-DBbZVKGS.d.ts → types-CoT0ypcx.d.ts} +60 -4
  71. package/docs/dsl.md +138 -5
  72. package/llms-full.txt +295 -14
  73. package/package.json +1 -1
  74. package/dist/Composition-BK5SH6J7.cjs +0 -16
  75. package/dist/Composition-Q5TVG3HM.js +0 -7
  76. package/dist/chunk-BPTW7L25.cjs.map +0 -1
  77. package/dist/chunk-DC4JPY6A.js.map +0 -1
  78. package/dist/chunk-E7RONUZ7.js.map +0 -1
  79. package/dist/chunk-IFZOI3JQ.cjs.map +0 -1
  80. package/dist/chunk-MHOO2CVU.cjs +0 -840
  81. package/dist/chunk-MHOO2CVU.cjs.map +0 -1
  82. package/dist/chunk-NHICCDTC.js.map +0 -1
  83. package/dist/chunk-UQDEDYVM.js +0 -838
  84. package/dist/chunk-UQDEDYVM.js.map +0 -1
  85. package/dist/chunk-UZTKEYFP.cjs.map +0 -1
@@ -1,7 +1,7 @@
1
- import { collectPropKeys, describeLayer } from './chunk-E7RONUZ7.js';
2
- import { suggestName, warnUnknownOptions } from './chunk-NHICCDTC.js';
1
+ import { collectPropKeys, describeLayer } from './chunk-TLYTYBWX.js';
2
+ import { suggestName, warnUnknownOptions } from './chunk-BXOCEZ4U.js';
3
3
  import * as PIXI from 'pixi.js';
4
- import { Rectangle, Container, GraphicsPath, Graphics, Assets, Texture, Sprite, FillGradient, Text, Filter, GlProgram, defaultFilterVert, GpuProgram, UniformGroup, Color } from 'pixi.js';
4
+ import { Rectangle, Container, Color, GraphicsPath, Sprite, Texture, Graphics, Assets, FillGradient, Text, Filter, GlProgram, defaultFilterVert, GpuProgram, UniformGroup } from 'pixi.js';
5
5
  import { gsap } from 'gsap';
6
6
 
7
7
  // src/expr/random.ts
@@ -528,8 +528,8 @@ function partitionProps(props) {
528
528
  for (const k of Object.keys(props)) {
529
529
  const m = k.match(/^filters\.([^.]+)\.(.+)$/);
530
530
  if (m) {
531
- const [, name, sub] = m;
532
- (filterProps[name] ??= {})[sub] = props[k];
531
+ const [, name, sub2] = m;
532
+ (filterProps[name] ??= {})[sub2] = props[k];
533
533
  } else {
534
534
  ownProps[k] = props[k];
535
535
  }
@@ -541,10 +541,10 @@ function splitRouted(props, routers) {
541
541
  const rest = {};
542
542
  const routed = [];
543
543
  for (const k of Object.keys(props)) {
544
- const dot = k.indexOf(".");
545
- const router = dot > 0 ? routers[k.slice(0, dot)] : void 0;
544
+ const dot2 = k.indexOf(".");
545
+ const router = dot2 > 0 ? routers[k.slice(0, dot2)] : void 0;
546
546
  if (router) {
547
- const hit = router(k.slice(dot + 1));
547
+ const hit = router(k.slice(dot2 + 1));
548
548
  if (hit) routed.push({ target: hit.target, prop: hit.prop, key: k, value: props[k] });
549
549
  } else {
550
550
  rest[k] = props[k];
@@ -1145,10 +1145,238 @@ var GrainFilter = class extends Filter {
1145
1145
  this.u.uFrame = this._fps > 0 ? Math.floor(t * this._fps + 1e-3) : 0;
1146
1146
  }
1147
1147
  };
1148
+ var WARP_KINDS = ["wave", "haze"];
1149
+ var OPTION_KEYS = ["kind", "strength", "scale", "speed", "angle", "seed"];
1150
+ var DEG = Math.PI / 180;
1151
+ var HASH_GL2 = `
1152
+ uint hash(uint x) { x ^= x >> 16; x *= 0x7feb352du; x ^= x >> 15; x *= 0x846ca68bu; x ^= x >> 16; return x; }
1153
+ float lattice(ivec2 p, uint k) {
1154
+ uint h = hash(uint(p.x) + hash(uint(p.y) + hash(k)));
1155
+ return float(h >> 8) / 16777215.0;
1156
+ }
1157
+ float valueNoise(vec2 q, uint k) {
1158
+ vec2 i = floor(q);
1159
+ vec2 f = fract(q);
1160
+ vec2 u = f * f * (3.0 - 2.0 * f);
1161
+ ivec2 p = ivec2(i);
1162
+ float a = lattice(p, k), b = lattice(p + ivec2(1, 0), k), c = lattice(p + ivec2(0, 1), k), d = lattice(p + ivec2(1, 1), k);
1163
+ return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
1164
+ }`;
1165
+ var GL_VERTEX2 = `#version 300 es
1166
+ precision highp float;
1167
+ in vec2 aPosition;
1168
+ out vec2 vTextureCoord;
1169
+ uniform highp vec4 uInputSize;
1170
+ uniform highp vec4 uOutputFrame;
1171
+ uniform highp vec4 uOutputTexture;
1172
+ void main(void) {
1173
+ vec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy;
1174
+ position.x = position.x * (2.0 / uOutputTexture.x) - 1.0;
1175
+ position.y = position.y * (2.0 * uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z;
1176
+ gl_Position = vec4(position, 0.0, 1.0);
1177
+ vTextureCoord = aPosition * (uOutputFrame.zw * uInputSize.zw);
1178
+ }`;
1179
+ var GL_FRAGMENT3 = `#version 300 es
1180
+ precision highp float;
1181
+ precision highp int;
1182
+ in vec2 vTextureCoord;
1183
+ uniform sampler2D uTexture;
1184
+ uniform highp vec4 uInputSize;
1185
+ uniform highp vec4 uInputClamp;
1186
+ uniform float uStrength;
1187
+ uniform float uScale;
1188
+ uniform float uSpeed;
1189
+ uniform float uAngle;
1190
+ uniform float uSeed;
1191
+ uniform float uMode;
1192
+ uniform float uTime;
1193
+ out vec4 finalColor;
1194
+ ${HASH_GL2}
1195
+ void main(void) {
1196
+ vec2 pos = vTextureCoord * uInputSize.xy;
1197
+ vec2 off;
1198
+ if (uMode < 0.5) {
1199
+ float phase = dot(pos, vec2(cos(uAngle), sin(uAngle))) / uScale - uSpeed * uTime;
1200
+ float s = uStrength * sin(6.28318530718 * phase);
1201
+ off = vec2(-sin(uAngle), cos(uAngle)) * s;
1202
+ } else {
1203
+ uint k = hash(uint(uSeed));
1204
+ vec2 p = vec2(pos.x / uScale, pos.y / uScale - uSpeed * uTime);
1205
+ off = uStrength * 2.0 * vec2(valueNoise(p, k) - 0.5, valueNoise(p + vec2(37.2, 17.8), k) - 0.5);
1206
+ }
1207
+ vec2 suv = clamp(vTextureCoord + off * uInputSize.zw, uInputClamp.xy, uInputClamp.zw);
1208
+ finalColor = texture(uTexture, suv);
1209
+ }`;
1210
+ var WGSL_SOURCE3 = `
1211
+ struct GlobalFilterUniforms {
1212
+ uInputSize: vec4<f32>,
1213
+ uInputPixel: vec4<f32>,
1214
+ uInputClamp: vec4<f32>,
1215
+ uOutputFrame: vec4<f32>,
1216
+ uGlobalFrame: vec4<f32>,
1217
+ uOutputTexture: vec4<f32>,
1218
+ };
1219
+ struct WarpUniforms {
1220
+ uStrength: f32,
1221
+ uScale: f32,
1222
+ uSpeed: f32,
1223
+ uAngle: f32,
1224
+ uSeed: f32,
1225
+ uMode: f32,
1226
+ uTime: f32,
1227
+ };
1228
+ @group(0) @binding(0) var<uniform> gfu: GlobalFilterUniforms;
1229
+ @group(0) @binding(1) var uTexture: texture_2d<f32>;
1230
+ @group(0) @binding(2) var uSampler : sampler;
1231
+ @group(1) @binding(0) var<uniform> warpUniforms : WarpUniforms;
1232
+
1233
+ struct VSOutput {
1234
+ @builtin(position) position: vec4<f32>,
1235
+ @location(0) uv : vec2<f32>,
1236
+ };
1237
+ fn filterVertexPosition(aPosition : vec2<f32>) -> vec4<f32> {
1238
+ var position = aPosition * gfu.uOutputFrame.zw + gfu.uOutputFrame.xy;
1239
+ position.x = position.x * (2.0 / gfu.uOutputTexture.x) - 1.0;
1240
+ position.y = position.y * (2.0 * gfu.uOutputTexture.z / gfu.uOutputTexture.y) - gfu.uOutputTexture.z;
1241
+ return vec4<f32>(position, 0.0, 1.0);
1242
+ }
1243
+ fn filterTextureCoord(aPosition : vec2<f32>) -> vec2<f32> {
1244
+ return aPosition * (gfu.uOutputFrame.zw * gfu.uInputSize.zw);
1245
+ }
1246
+ @vertex
1247
+ fn mainVertex(
1248
+ @location(0) aPosition : vec2<f32>,
1249
+ ) -> VSOutput {
1250
+ return VSOutput(
1251
+ filterVertexPosition(aPosition),
1252
+ filterTextureCoord(aPosition),
1253
+ );
1254
+ }
1255
+
1256
+ fn hash(xIn: u32) -> u32 {
1257
+ var x = xIn;
1258
+ x = x ^ (x >> 16u); x = x * 0x7feb352du; x = x ^ (x >> 15u); x = x * 0x846ca68bu; x = x ^ (x >> 16u);
1259
+ return x;
1260
+ }
1261
+ fn lattice(p: vec2<i32>, k: u32) -> f32 {
1262
+ let h = hash(u32(p.x) + hash(u32(p.y) + hash(k)));
1263
+ return f32(h >> 8u) / 16777215.0;
1264
+ }
1265
+ fn valueNoise(q: vec2<f32>, k: u32) -> f32 {
1266
+ let i = floor(q);
1267
+ let f = fract(q);
1268
+ let u = f * f * (3.0 - 2.0 * f);
1269
+ let p = vec2<i32>(i);
1270
+ let a = lattice(p, k);
1271
+ let b = lattice(p + vec2<i32>(1, 0), k);
1272
+ let c = lattice(p + vec2<i32>(0, 1), k);
1273
+ let d = lattice(p + vec2<i32>(1, 1), k);
1274
+ return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
1275
+ }
1276
+
1277
+ @fragment
1278
+ fn mainFragment(@location(0) uv : vec2<f32>) -> @location(0) vec4<f32> {
1279
+ let pos = uv * gfu.uInputSize.xy;
1280
+ var off = vec2<f32>(0.0);
1281
+ if (warpUniforms.uMode < 0.5) {
1282
+ let phase = dot(pos, vec2<f32>(cos(warpUniforms.uAngle), sin(warpUniforms.uAngle))) / warpUniforms.uScale - warpUniforms.uSpeed * warpUniforms.uTime;
1283
+ let s = warpUniforms.uStrength * sin(6.28318530718 * phase);
1284
+ off = vec2<f32>(-sin(warpUniforms.uAngle), cos(warpUniforms.uAngle)) * s;
1285
+ } else {
1286
+ let k = hash(u32(warpUniforms.uSeed));
1287
+ let p = vec2<f32>(pos.x / warpUniforms.uScale, pos.y / warpUniforms.uScale - warpUniforms.uSpeed * warpUniforms.uTime);
1288
+ off = warpUniforms.uStrength * 2.0 * vec2<f32>(valueNoise(p, k) - 0.5, valueNoise(p + vec2<f32>(37.2, 17.8), k) - 0.5);
1289
+ }
1290
+ let suv = clamp(uv + off * gfu.uInputSize.zw, gfu.uInputClamp.xy, gfu.uInputClamp.zw);
1291
+ return textureSampleLevel(uTexture, uSampler, suv, 0.0);
1292
+ }`;
1293
+ var WarpFilter = class extends Filter {
1294
+ constructor(options = {}) {
1295
+ warnUnknownOptions("warp filter", options, OPTION_KEYS);
1296
+ let { kind = "wave", strength = 6, scale = 80, speed = 0.5, angle = 0, seed = 0 } = options;
1297
+ if (!WARP_KINDS.includes(kind)) {
1298
+ const guess = suggestName(String(kind), WARP_KINDS);
1299
+ console.warn(`pixi-effects: warp: kind ${JSON.stringify(kind)} is not supported${guess ? `; did you mean "${guess}"?` : ""} (use ${WARP_KINDS.join(" or ")}); wave is used`);
1300
+ kind = "wave";
1301
+ }
1302
+ if (!(strength >= 0 && strength <= 200)) {
1303
+ console.warn(`pixi-effects: warp: strength ${strength} is not a number from 0 to 200: it is the largest shift in pixels (8 is a clear ripple); ${strength > 200 ? "200" : "0"} is used`);
1304
+ strength = strength > 200 ? 200 : 0;
1305
+ }
1306
+ if (!(seed >= 0)) {
1307
+ console.warn(`pixi-effects: warp: seed ${seed} must be 0 or more (an integer that picks the haze pattern); 0 is used`);
1308
+ seed = 0;
1309
+ }
1310
+ if (!(scale > 0)) {
1311
+ console.warn(`pixi-effects: warp: scale ${scale} must be above 0: it is the wavelength in pixels (80 is the default); 1 is used`);
1312
+ scale = 1;
1313
+ }
1314
+ super({
1315
+ glProgram: GlProgram.from({ vertex: GL_VERTEX2, fragment: GL_FRAGMENT3, name: "warp-filter" }),
1316
+ gpuProgram: GpuProgram.from({ vertex: { source: WGSL_SOURCE3, entryPoint: "mainVertex" }, fragment: { source: WGSL_SOURCE3, entryPoint: "mainFragment" } }),
1317
+ resources: {
1318
+ warpUniforms: new UniformGroup({
1319
+ uStrength: { value: strength, type: "f32" },
1320
+ uScale: { value: scale, type: "f32" },
1321
+ uSpeed: { value: speed, type: "f32" },
1322
+ uAngle: { value: angle * DEG, type: "f32" },
1323
+ uSeed: { value: Math.floor(seed), type: "f32" },
1324
+ uMode: { value: kind === "haze" ? 1 : 0, type: "f32" },
1325
+ uTime: { value: 0, type: "f32" }
1326
+ })
1327
+ }
1328
+ });
1329
+ this.padding = Math.ceil(strength);
1330
+ }
1331
+ get u() {
1332
+ return this.resources.warpUniforms.uniforms;
1333
+ }
1334
+ get kind() {
1335
+ return this.u.uMode === 1 ? "haze" : "wave";
1336
+ }
1337
+ set kind(v) {
1338
+ this.u.uMode = v === "haze" ? 1 : 0;
1339
+ }
1340
+ get strength() {
1341
+ return this.u.uStrength;
1342
+ }
1343
+ set strength(v) {
1344
+ this.u.uStrength = v;
1345
+ this.padding = Math.ceil(Math.max(0, v));
1346
+ }
1347
+ get scale() {
1348
+ return this.u.uScale;
1349
+ }
1350
+ set scale(v) {
1351
+ this.u.uScale = Math.max(v, 1e-3);
1352
+ }
1353
+ get speed() {
1354
+ return this.u.uSpeed;
1355
+ }
1356
+ set speed(v) {
1357
+ this.u.uSpeed = v;
1358
+ }
1359
+ get angle() {
1360
+ return this.u.uAngle / DEG;
1361
+ }
1362
+ set angle(v) {
1363
+ this.u.uAngle = v * DEG;
1364
+ }
1365
+ get seed() {
1366
+ return this.u.uSeed;
1367
+ }
1368
+ set seed(v) {
1369
+ this.u.uSeed = v >= 0 ? Math.floor(v) : 0;
1370
+ }
1371
+ /** The movie calls this with the time (s) of the frame it is about to draw. */
1372
+ setTime(t) {
1373
+ this.u.uTime = t;
1374
+ }
1375
+ };
1148
1376
 
1149
1377
  // src/filters/named.ts
1150
1378
  var CORE = { blur: "BlurFilter", noise: "NoiseFilter", alpha: "AlphaFilter" };
1151
- var CORE_TYPES = [...Object.keys(CORE), "colorMatrix", "grain"];
1379
+ var CORE_TYPES = [...Object.keys(CORE), "colorMatrix", "grain", "warp"];
1152
1380
  var LIBRARY_TYPES = [
1153
1381
  "adjustment",
1154
1382
  "advancedBloom",
@@ -1266,6 +1494,7 @@ function colorGradientParams(params) {
1266
1494
  function createNamedFilter(type, params) {
1267
1495
  if (lower(type) === "colormatrix") return colorMatrix(params);
1268
1496
  if (lower(type) === "grain") return new GrainFilter(params);
1497
+ if (lower(type) === "warp") return new WarpFilter(params);
1269
1498
  const core = Object.entries(CORE).find(([k]) => lower(k) === lower(type));
1270
1499
  if (core) return new PIXI[core[1]](params);
1271
1500
  if (!isLibraryType(type)) throw unknownType(type);
@@ -1521,7 +1750,7 @@ function clockTable(remap, prop, duration, at, scope, to) {
1521
1750
  }
1522
1751
 
1523
1752
  // src/space/math.ts
1524
- var DEG = Math.PI / 180;
1753
+ var DEG2 = Math.PI / 180;
1525
1754
  var DEFAULT_FOV = 40;
1526
1755
  var MIN_FOV = 1;
1527
1756
  var MAX_FOV = 179;
@@ -1531,7 +1760,7 @@ function clampFov(fov) {
1531
1760
  return Math.min(MAX_FOV, Math.max(MIN_FOV, fov));
1532
1761
  }
1533
1762
  function homeDistance(compHeight, fovDeg) {
1534
- return compHeight / 2 / Math.tan(clampFov(fovDeg) * DEG / 2);
1763
+ return compHeight / 2 / Math.tan(clampFov(fovDeg) * DEG2 / 2);
1535
1764
  }
1536
1765
  function homeCamera(compW, compH, fov = DEFAULT_FOV) {
1537
1766
  return {
@@ -1585,7 +1814,7 @@ function cameraBasis(cam, compW, compH) {
1585
1814
  fx,
1586
1815
  fy,
1587
1816
  fz,
1588
- focal: compH / 2 / Math.tan(clampFov(cam.fov) * DEG / 2),
1817
+ focal: compH / 2 / Math.tan(clampFov(cam.fov) * DEG2 / 2),
1589
1818
  halfW: compW / 2,
1590
1819
  halfH: compH / 2
1591
1820
  };
@@ -1705,6 +1934,9 @@ var CameraSequence = class extends Sequence {
1705
1934
  warnedAperture = false;
1706
1935
  /** True when the camera writes `focus` or `aperture` anywhere: depth of field is on. */
1707
1936
  dof = false;
1937
+ /** True when the camera writes any fog key anywhere: depth fog is on (nothing is made for a camera without fog). */
1938
+ fog = false;
1939
+ fogC = null;
1708
1940
  zOfName = null;
1709
1941
  layerNames = /* @__PURE__ */ new Set();
1710
1942
  async build() {
@@ -1726,10 +1958,15 @@ var CameraSequence = class extends Sequence {
1726
1958
  carrier.aperture = DEFAULT_APERTURE;
1727
1959
  carrier.offsetX = carrier.offsetY = carrier.offsetZ = 0;
1728
1960
  carrier.lookOffsetX = carrier.lookOffsetY = carrier.lookOffsetZ = 0;
1961
+ carrier.fogNear = home.z;
1962
+ carrier.fogFar = home.z * 3;
1963
+ carrier.fogColor = "#000000";
1964
+ carrier.fogAmount = 1;
1729
1965
  this.target = carrier;
1730
1966
  const keys = collectPropKeys(this.spec);
1731
1967
  this.autoZ = !keys.has("z");
1732
1968
  this.dof = keys.has("focus") || keys.has("aperture");
1969
+ this.fog = keys.has("fogNear") || keys.has("fogFar") || keys.has("fogColor") || keys.has("fogAmount");
1733
1970
  }
1734
1971
  /** The aperture to use now: off unless depth of field is on and the value is a number of 0 or more (said once if it is not). */
1735
1972
  apertureNow(a) {
@@ -1777,6 +2014,20 @@ var CameraSequence = class extends Sequence {
1777
2014
  aperture: this.apertureNow(c.aperture)
1778
2015
  };
1779
2016
  }
2017
+ /** The fog now (colour as 0..1 channels, distances, 0..1 amount), or null when the camera writes no fog key. */
2018
+ fogState() {
2019
+ if (!this.fog) return null;
2020
+ const c = this.target;
2021
+ const fc = this.fogC ??= new Color();
2022
+ try {
2023
+ fc.setValue(c.fogColor);
2024
+ } catch {
2025
+ fc.setValue(0);
2026
+ }
2027
+ const [r, g, b] = fc.toArray();
2028
+ const amount = Number.isFinite(c.fogAmount) ? Math.min(1, Math.max(0, c.fogAmount)) : 1;
2029
+ return { r, g, b, near: c.fogNear, far: c.fogFar, amount };
2030
+ }
1780
2031
  /** Lifespan on the global timeline (valid after bindTimeline). */
1781
2032
  window() {
1782
2033
  const start = this.absoluteStart ?? this.at;
@@ -1784,6 +2035,160 @@ var CameraSequence = class extends Sequence {
1784
2035
  }
1785
2036
  };
1786
2037
 
2038
+ // src/space/lighting.ts
2039
+ var LIGHT_KINDS = ["ambient", "point", "spot", "parallel"];
2040
+ var FALLOFFS = ["none", "smooth", "inverseSquare"];
2041
+ var LIGHT_PROPS = ["x", "y", "z", "lookAtX", "lookAtY", "lookAtZ", "intensity", "color", "coneAngle", "coneFeather", "radius", "falloffDistance", "shadowDarkness", "shadowDiffusion"];
2042
+ var MAX_LIGHTS = 8;
2043
+ var MAX_CASTERS = 4;
2044
+ var SHADOW_TAPS = 16;
2045
+ var FALLOFF_ID = { none: 0, smooth: 1, inverseSquare: 2 };
2046
+ var KIND_ID = { point: 1, spot: 2, parallel: 3 };
2047
+ function smoothstep(e0, e1, x) {
2048
+ const t = Math.min(1, Math.max(0, (x - e0) / (e1 - e0)));
2049
+ return t * t * (3 - 2 * t);
2050
+ }
2051
+ var DEG3 = Math.PI / 180;
2052
+ function norm(v) {
2053
+ const l = Math.hypot(v.x, v.y, v.z) || 1;
2054
+ return { x: v.x / l, y: v.y / l, z: v.z / l };
2055
+ }
2056
+ var dot = (a, b) => a.x * b.x + a.y * b.y + a.z * b.z;
2057
+ var sub = (a, b) => ({ x: a.x - b.x, y: a.y - b.y, z: a.z - b.z });
2058
+ function coneCos(l) {
2059
+ const half = Math.min(179, Math.max(0, l.coneAngle)) * DEG3 / 2;
2060
+ const inner = half * (1 - Math.min(1, Math.max(0, l.coneFeather)));
2061
+ const cosOuter = Math.cos(half);
2062
+ const cosInner = Math.max(Math.cos(inner), cosOuter + 1e-4);
2063
+ return { cosOuter, cosInner };
2064
+ }
2065
+ function packLights(lights) {
2066
+ const pos = new Float32Array(4 * MAX_LIGHTS), dir = new Float32Array(4 * MAX_LIGHTS), col = new Float32Array(4 * MAX_LIGHTS), fall = new Float32Array(4 * MAX_LIGHTS), shadow = new Float32Array(4 * MAX_LIGHTS);
2067
+ const ambient = [0, 0, 0];
2068
+ let n = 0;
2069
+ for (const l of lights) {
2070
+ if (l.kind === "ambient") {
2071
+ ambient[0] += l.r * l.intensity;
2072
+ ambient[1] += l.g * l.intensity;
2073
+ ambient[2] += l.b * l.intensity;
2074
+ continue;
2075
+ }
2076
+ if (n >= MAX_LIGHTS) continue;
2077
+ const d = norm({ x: l.lookAtX - l.x, y: l.lookAtY - l.y, z: l.lookAtZ - l.z });
2078
+ const { cosOuter, cosInner } = coneCos(l);
2079
+ pos.set([l.x, l.y, l.z, KIND_ID[l.kind]], 4 * n);
2080
+ dir.set([d.x, d.y, d.z, cosOuter], 4 * n);
2081
+ col.set([l.r * l.intensity, l.g * l.intensity, l.b * l.intensity, cosInner], 4 * n);
2082
+ fall.set([FALLOFF_ID[l.falloff], l.radius, l.falloffDistance, l.castsShadows ? 1 : 0], 4 * n);
2083
+ shadow.set([l.castsShadows ? l.shadowDarkness : 0, l.shadowDiffusion, 0, 0], 4 * n);
2084
+ n++;
2085
+ }
2086
+ return { count: n, ambient, pos, dir, col, fall, shadow };
2087
+ }
2088
+ function shadeReference(p, n, cam, lights) {
2089
+ let N = norm(n);
2090
+ if (dot(N, sub(cam, p)) < 0) N = { x: -N.x, y: -N.y, z: -N.z };
2091
+ const out = [0, 0, 0];
2092
+ for (const l of lights) {
2093
+ if (l.kind === "ambient") {
2094
+ out[0] += l.r * l.intensity;
2095
+ out[1] += l.g * l.intensity;
2096
+ out[2] += l.b * l.intensity;
2097
+ continue;
2098
+ }
2099
+ const dirLA = norm({ x: l.lookAtX - l.x, y: l.lookAtY - l.y, z: l.lookAtZ - l.z });
2100
+ let L;
2101
+ let dist = 0;
2102
+ if (l.kind === "parallel") L = { x: -dirLA.x, y: -dirLA.y, z: -dirLA.z };
2103
+ else {
2104
+ const d = sub({ x: l.x, y: l.y, z: l.z }, p);
2105
+ dist = Math.hypot(d.x, d.y, d.z);
2106
+ L = { x: d.x / dist, y: d.y / dist, z: d.z / dist };
2107
+ }
2108
+ const ndl = Math.max(0, dot(N, L));
2109
+ let att = 1;
2110
+ if (l.kind !== "parallel") {
2111
+ if (l.falloff === "smooth") att = 1 - smoothstep(l.radius, l.radius + Math.max(l.falloffDistance, 1e-3), dist);
2112
+ else if (l.falloff === "inverseSquare") att = Math.min(1, l.radius * l.radius / Math.max(dist * dist, 1e-6));
2113
+ }
2114
+ let cone = 1;
2115
+ if (l.kind === "spot") {
2116
+ const { cosOuter, cosInner } = coneCos(l);
2117
+ cone = smoothstep(cosOuter, cosInner, -dot(L, dirLA));
2118
+ }
2119
+ const k = l.intensity * ndl * att * cone;
2120
+ out[0] += l.r * k;
2121
+ out[1] += l.g * k;
2122
+ out[2] += l.b * k;
2123
+ }
2124
+ return out;
2125
+ }
2126
+ function lightLevel(frame, cam, lights) {
2127
+ const mid = { x: frame.o.x + 0.5 * frame.u.x + 0.5 * frame.v.x, y: frame.o.y + 0.5 * frame.u.y + 0.5 * frame.v.y, z: frame.o.z + 0.5 * frame.u.z + 0.5 * frame.v.z };
2128
+ const n = { x: frame.u.y * frame.v.z - frame.u.z * frame.v.y, y: frame.u.z * frame.v.x - frame.u.x * frame.v.z, z: frame.u.x * frame.v.y - frame.u.y * frame.v.x };
2129
+ const m = shadeReference(mid, n, cam, lights);
2130
+ return 0.2126 * m[0] + 0.7152 * m[1] + 0.0722 * m[2];
2131
+ }
2132
+ var LightSequence = class extends Sequence {
2133
+ color = new Color();
2134
+ async build() {
2135
+ const w = this.parent?.width ?? this.root.width;
2136
+ const h = this.parent?.height ?? this.root.height;
2137
+ if (this.duration === void 0) this.duration = this.parent?.duration ?? this.root.duration;
2138
+ const c = new Container();
2139
+ c.x = w * 0.3;
2140
+ c.y = h * 0.2;
2141
+ c.z = homeDistance(h, 40) * 0.6;
2142
+ c.lookAtX = w / 2;
2143
+ c.lookAtY = h / 2;
2144
+ c.lookAtZ = 0;
2145
+ c.intensity = 1;
2146
+ c.color = "#ffffff";
2147
+ c.coneAngle = 90;
2148
+ c.coneFeather = 0.5;
2149
+ c.radius = 500;
2150
+ c.falloffDistance = 500;
2151
+ c.shadowDarkness = 1;
2152
+ c.shadowDiffusion = 0;
2153
+ this.target = c;
2154
+ }
2155
+ state() {
2156
+ const c = this.target;
2157
+ try {
2158
+ this.color.setValue(c.color);
2159
+ } catch {
2160
+ this.color.setValue(16777215);
2161
+ }
2162
+ const [r, g, b] = this.color.toArray();
2163
+ return {
2164
+ // a kind or falloff nobody knows is the default the warning promises (the shader must never see an unknown id)
2165
+ kind: LIGHT_KINDS.includes(this.spec.kind) ? this.spec.kind : "point",
2166
+ x: c.x,
2167
+ y: c.y,
2168
+ z: c.z,
2169
+ lookAtX: c.lookAtX,
2170
+ lookAtY: c.lookAtY,
2171
+ lookAtZ: c.lookAtZ,
2172
+ r,
2173
+ g,
2174
+ b,
2175
+ intensity: Number.isFinite(c.intensity) ? Math.max(0, c.intensity) : 1,
2176
+ coneAngle: c.coneAngle,
2177
+ coneFeather: c.coneFeather,
2178
+ falloff: FALLOFFS.includes(this.spec.falloff) ? this.spec.falloff : "none",
2179
+ radius: c.radius,
2180
+ falloffDistance: c.falloffDistance,
2181
+ castsShadows: !!this.spec.castsShadows,
2182
+ shadowDarkness: Math.min(1, Math.max(0, c.shadowDarkness)),
2183
+ shadowDiffusion: Math.max(0, c.shadowDiffusion)
2184
+ };
2185
+ }
2186
+ window() {
2187
+ const start = this.absoluteStart ?? this.at;
2188
+ return { start, end: start + (this.duration ?? 0) };
2189
+ }
2190
+ };
2191
+
1787
2192
  // src/core/revertibleSet.ts
1788
2193
  function revertibleSet(timeline, at, read, write, value) {
1789
2194
  let p = 0;
@@ -2153,8 +2558,8 @@ function validateGradientKeyframes(spec, who, warn = (m) => console.warn(m), kin
2153
2558
  }
2154
2559
  } else if (/^fillGradient\./i.test(key) || /^gradient/i.test(key)) {
2155
2560
  const tail = key.replace(/^fillGradient\./i, "").replace(/^gradient/i, "");
2156
- const sub = tail ? tail[0].toLowerCase() + tail.slice(1) : "angle";
2157
- say(`"${key}" is not an animatable property: write fillGradient: { ${PATCH_KEYS.includes(sub) ? sub : "angle"} } (the whole gradient is one object) in the keyframe's to / from / set`);
2561
+ const sub2 = tail ? tail[0].toLowerCase() + tail.slice(1) : "angle";
2562
+ say(`"${key}" is not an animatable property: write fillGradient: { ${PATCH_KEYS.includes(sub2) ? sub2 : "angle"} } (the whole gradient is one object) in the keyframe's to / from / set`);
2158
2563
  }
2159
2564
  }
2160
2565
  }
@@ -2541,7 +2946,7 @@ var AudioSequence = class extends Sequence {
2541
2946
  const raw = spec;
2542
2947
  if (raw.asset !== void 0) console.warn(`pixi-effects: ${who}: has both asset and sfx \u2014 the sfx plays; remove one`);
2543
2948
  if (raw.loop) console.warn(`pixi-effects: ${who}: loop has no effect on an sfx \u2014 to repeat it, add one audio layer per hit (a JS loop)`);
2544
- const { resolveSfx, renderSfx, sfxKey } = await import('./sfx-3IDAJ3UZ.js');
2949
+ const { resolveSfx, renderSfx, sfxKey } = await import('./sfx-VUKARHDX.js');
2545
2950
  const sfx = resolveSfx(spec.sfx, spec.duration, who);
2546
2951
  if (!sfx) return;
2547
2952
  this.duration = sfx.length;
@@ -2560,7 +2965,7 @@ var AudioSequence = class extends Sequence {
2560
2965
  const raw = spec;
2561
2966
  if (raw.asset !== void 0) console.warn(`pixi-effects: ${who}: has both asset and music \u2014 the music plays; remove one`);
2562
2967
  if (raw.sfx !== void 0) console.warn(`pixi-effects: ${who}: has both sfx and music \u2014 the music plays; remove one`);
2563
- const { resolveMusic, renderMusic, musicLength, musicKey } = await import('./music-FUN7N225.js');
2968
+ const { resolveMusic, renderMusic, musicLength, musicKey } = await import('./music-AF4VTFAF.js');
2564
2969
  const music = resolveMusic(spec.music, who);
2565
2970
  if (!music) return;
2566
2971
  const natural = musicLength(music);
@@ -3353,7 +3758,7 @@ function drawEllipseFromState(g, s) {
3353
3758
  const ay = s.anchorY ?? 0.5;
3354
3759
  g.ellipse((0.5 - ax) * 2 * rx, (0.5 - ay) * 2 * ry, rx, ry);
3355
3760
  }
3356
- var DEG2 = Math.PI / 180;
3761
+ var DEG4 = Math.PI / 180;
3357
3762
  function drawArcFromState(g, s) {
3358
3763
  const r = s.radius ?? 0;
3359
3764
  const ri = Math.max(0, Math.min(s.innerRadius ?? 0, r));
@@ -3368,7 +3773,7 @@ function drawArcFromState(g, s) {
3368
3773
  }
3369
3774
  endDeg = startDeg + Math.sign(endDeg - startDeg) * 359.999;
3370
3775
  }
3371
- const a0 = startDeg * DEG2, a1 = endDeg * DEG2;
3776
+ const a0 = startDeg * DEG4, a1 = endDeg * DEG4;
3372
3777
  const ccw = a1 < a0;
3373
3778
  if (filled) g.moveTo(r * Math.cos(a0), r * Math.sin(a0));
3374
3779
  g.arc(0, 0, r, a0, a1, ccw);
@@ -3550,11 +3955,396 @@ function numOrZero(v, scope) {
3550
3955
  return 0;
3551
3956
  }
3552
3957
 
3958
+ // src/core/glShared.ts
3959
+ var shared = null;
3960
+ var generation = 0;
3961
+ var refs = 0;
3962
+ var unavailable = false;
3963
+ function create() {
3964
+ if (typeof document === "undefined") return null;
3965
+ const canvas = document.createElement("canvas");
3966
+ const gl = canvas.getContext("webgl2", { alpha: true, premultipliedAlpha: true, preserveDrawingBuffer: true, antialias: false });
3967
+ if (!gl) return null;
3968
+ const made = { gl, canvas, generation: ++generation };
3969
+ canvas.addEventListener("webglcontextlost", (e) => {
3970
+ e.preventDefault();
3971
+ if (shared === made) shared = null;
3972
+ });
3973
+ return made;
3974
+ }
3975
+ function currentGl() {
3976
+ if (shared) return shared;
3977
+ if (unavailable) return null;
3978
+ shared = create();
3979
+ if (!shared) unavailable = true;
3980
+ return shared;
3981
+ }
3982
+ function acquireGl() {
3983
+ refs++;
3984
+ return currentGl();
3985
+ }
3986
+ function releaseGl() {
3987
+ refs = Math.max(0, refs - 1);
3988
+ if (refs === 0 && shared) {
3989
+ const lose = shared.gl.getExtension?.("WEBGL_lose_context");
3990
+ try {
3991
+ lose?.loseContext();
3992
+ } catch {
3993
+ }
3994
+ shared = null;
3995
+ }
3996
+ }
3997
+
3998
+ // src/core/shaderChecks.ts
3999
+ var SHADER_BUILTINS = ["iResolution", "iTime", "iFrame"];
4000
+ var SHADER_MISSING = ["iMouse", "iChannel0", "iChannel1", "iChannel2", "iChannel3", "iDate", "iTimeDelta", "iSampleRate"];
4001
+ var IDENT = /^[A-Za-z_][A-Za-z0-9_]*$/;
4002
+ var HEX = /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
4003
+ var RESERVED = new Set(`attribute const uniform varying break continue do for while if else in out inout float int void bool true false discard return
4004
+ mat2 mat3 mat4 mat2x2 mat2x3 mat2x4 mat3x2 mat3x3 mat3x4 mat4x2 mat4x3 mat4x4 vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 uvec2 uvec3 uvec4 uint
4005
+ sampler2D sampler3D samplerCube sampler2DShadow samplerCubeShadow sampler2DArray sampler2DArrayShadow isampler2D isampler3D isamplerCube isampler2DArray
4006
+ usampler2D usampler3D usamplerCube usampler2DArray struct layout centroid flat smooth precision invariant highp mediump lowp
4007
+ sample patch subroutine common partition active asm class union enum typedef template this resource goto inline noinline public static extern external
4008
+ interface long short double half fixed unsigned superp input output hvec2 hvec3 hvec4 fvec2 fvec3 fvec4 dvec2 dvec3 dvec4 filter sizeof cast namespace using`.split(/\s+/));
4009
+ var isIdent = (name) => IDENT.test(name) && !name.startsWith("gl_") && !name.includes("__") && !RESERVED.has(name) && !SHADER_BUILTINS.includes(name);
4010
+ function uniformType(v) {
4011
+ if (typeof v === "number") return Number.isFinite(v) ? "float" : null;
4012
+ if (typeof v === "string") return HEX.test(v) ? "vec3" : null;
4013
+ if (Array.isArray(v) && v.length >= 2 && v.length <= 4 && v.every((n) => typeof n === "number" && Number.isFinite(n))) return `vec${v.length}`;
4014
+ return null;
4015
+ }
4016
+ function uniformFloats(v) {
4017
+ if (typeof v === "number") return [v];
4018
+ if (typeof v === "string") {
4019
+ const h = v.length === 4 ? v.slice(1).replace(/./g, (c) => c + c) : v.slice(1);
4020
+ return [0, 2, 4].map((i) => parseInt(h.slice(i, i + 2), 16) / 255);
4021
+ }
4022
+ return v.slice();
4023
+ }
4024
+ function uniformDecls(uniforms) {
4025
+ let out = "";
4026
+ for (const [name, v] of Object.entries(uniforms ?? {})) {
4027
+ const type = uniformType(v);
4028
+ if (type && isIdent(name)) out += `uniform ${type} ${name};
4029
+ `;
4030
+ }
4031
+ return out;
4032
+ }
4033
+ var HEAD = `#version 300 es
4034
+ #line 100001
4035
+ precision highp float;
4036
+ precision highp int;
4037
+ uniform vec3 iResolution;
4038
+ uniform float iTime;
4039
+ uniform int iFrame;
4040
+ out vec4 pe_out;
4041
+ `;
4042
+ var FOOT = (transparent) => `
4043
+ #line 200001
4044
+ void main() { vec4 c = vec4(0.0, 0.0, 0.0, 1.0); mainImage(c, gl_FragCoord.xy); ${transparent ? "pe_out = vec4(c.rgb * c.a, c.a);" : "pe_out = vec4(c.rgb, 1.0);"} }
4045
+ `;
4046
+ function wrapFragment(user, uniforms, transparent) {
4047
+ const prefix = HEAD + uniformDecls(uniforms) + "#line 1\n";
4048
+ return { source: prefix + user + FOOT(transparent), userLine: prefix.split("\n").length };
4049
+ }
4050
+ function glslErrors(log) {
4051
+ const out = [];
4052
+ for (const raw of (log ?? "").split("\n")) {
4053
+ const line = raw.trim();
4054
+ if (!line) continue;
4055
+ const angle = /^ERROR:\s*\d+:(\d+):\s*(.*)$/.exec(line);
4056
+ const mesa = /^\d+:(\d+)\(\d+\):\s*(?:error|warning):\s*(.*)$/.exec(line);
4057
+ const hit = angle ?? mesa;
4058
+ if (!hit) {
4059
+ out.push(line);
4060
+ continue;
4061
+ }
4062
+ const n = Number(hit[1]);
4063
+ if (n >= 200001) out.push(`in the main() made for you, which calls mainImage: ${hit[2]} (write void mainImage(out vec4 fragColor, in vec2 fragCoord))`);
4064
+ else if (n >= 100001) out.push(`in the declarations made from your uniforms: ${hit[2]} (a uniform name GLSL does not allow, such as a reserved word?)`);
4065
+ else out.push(`line ${n}: ${hit[2]}`);
4066
+ }
4067
+ return out;
4068
+ }
4069
+ var stripComments = (code) => code.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/\/\/.*$/gm, " ");
4070
+ function shaderProblems(spec) {
4071
+ const out = [];
4072
+ const raw = spec;
4073
+ if (typeof raw.fragment !== "string" || raw.fragment.trim() === "") {
4074
+ out.push("fragment is the GLSL of the shader: write { type: 'shader', fragment: 'void mainImage(out vec4 fragColor, in vec2 fragCoord) { fragColor = vec4(fragCoord / iResolution.xy, 0.0, 1.0); }' }");
4075
+ } else {
4076
+ const code = stripComments(raw.fragment);
4077
+ if (!/\bvoid\s+mainImage\s*\(/.test(code)) {
4078
+ out.push("there is no mainImage: write void mainImage(out vec4 fragColor, in vec2 fragCoord) { \u2026 } (Shadertoy style; the layer calls it for every pixel)" + (/\bvoid\s+main\s*\(/.test(code) ? " and not main()" : ""));
4079
+ } else {
4080
+ if (/\bvoid\s+main\s*\(/.test(code)) out.push("main() is written for you (it calls your mainImage): remove your main()");
4081
+ if (!/\bvoid\s+mainImage\s*\(\s*(?:out|inout)\s+(?:(?:highp|mediump|lowp)\s+)?vec4\s+\w+\s*,\s*(?:in\s+)?(?:(?:highp|mediump|lowp)\s+)?vec2\s+\w+\s*\)/.test(code)) {
4082
+ out.push("the signature of mainImage must be void mainImage(out vec4 fragColor, in vec2 fragCoord): the colour parameter is out (without out the layer draws black and nothing says why) and the position is a vec2");
4083
+ }
4084
+ }
4085
+ if (/^\s*#version\b/m.test(code)) out.push("#version is added for you (GLSL ES 3.00): remove it");
4086
+ if (/\bgl_FragColor\b/.test(code)) out.push("gl_FragColor does not exist here: write the colour into the fragColor parameter of mainImage");
4087
+ if (/\btexture2D\s*\(|\btextureCube\s*\(/.test(code)) out.push("texture2D is GLSL ES 1.00: this is GLSL ES 3.00, write texture(\u2026) (and note that this version has no textures to read)");
4088
+ if (/\b(?:varying|attribute)\b/.test(code)) out.push("varying and attribute are not used in a fragment-only shader: remove them");
4089
+ for (const b of SHADER_BUILTINS) {
4090
+ if (new RegExp(`\\buniform\\s+\\w+\\s+${b}\\b`).test(code)) out.push(`${b} is declared for you: remove your uniform ${b}`);
4091
+ }
4092
+ const missing = SHADER_MISSING.filter((n) => new RegExp(`\\b${n}\\b`).test(code));
4093
+ if (missing.length) out.push(`${missing.join(", ")} ${missing.length > 1 ? "are" : "is"} not provided in this version (the shader has iResolution, iTime, iFrame and your uniforms); the shader will not compile`);
4094
+ if (/\bwhile\s*\(/.test(code)) out.push("a while loop may never end and a GPU cannot be stopped: use a for loop with a constant bound");
4095
+ const consts = new Set([...code.matchAll(/\bconst\s+(?:int|float|uint)\s+(\w+)/g)].map((m) => m[1]).concat([...code.matchAll(/#define\s+(\w+)/g)].map((m) => m[1])));
4096
+ const constant = (expr) => {
4097
+ const rest = expr.replace(/\d+\.?\d*(?:[eE][-+]?\d+)?[uUfF]?|\.\d+(?:[eE][-+]?\d+)?[fF]?|[A-Za-z_]\w*/g, (t) => /^[A-Za-z_]/.test(t) && !consts.has(t) ? "?" : "");
4098
+ return /^[\s+\-*/%()]*$/.test(rest);
4099
+ };
4100
+ for (const m of code.matchAll(/\bfor\s*\(\s*(?:int|float|uint)\s+\w+\s*=\s*[^;]+;\s*\w+\s*(?:<=|>=|<|>|!=)\s*([^;]+?)\s*;/g)) {
4101
+ const bound = m[1];
4102
+ const ands = bound.split("&&"), ors = bound.split("||");
4103
+ const ok = ors.length > 1 ? ors.every((part) => constant(part.split("&&")[0].replace(/<.*$/, ""))) : ands.length > 1 ? ands.some(constant) || constant(ands[0]) : constant(bound);
4104
+ if (!ok) {
4105
+ out.push(`a for loop with the bound "${bound}" may run for ever: use a constant bound (a number or a const) and break out early`);
4106
+ break;
4107
+ }
4108
+ }
4109
+ }
4110
+ if (raw.uniforms !== void 0) {
4111
+ if (raw.uniforms === null || typeof raw.uniforms !== "object" || Array.isArray(raw.uniforms)) {
4112
+ out.push("uniforms is an object of names to values: { speed: 1, tint: '#ff8040', pos: [0.5, 0.5] }");
4113
+ } else {
4114
+ for (const [name, v] of Object.entries(raw.uniforms)) {
4115
+ if (!isIdent(name)) out.push(`uniform "${name}" is not a name GLSL can use (letters, digits and _, not starting with a digit; not a GLSL keyword or reserved word such as sample, smooth, filter, input; not iResolution / iTime / iFrame)`);
4116
+ else if (uniformType(v) === null) out.push(`uniform "${name}": ${JSON.stringify(v)} is not a number, 2 to 4 numbers or a '#rrggbb' colour`);
4117
+ }
4118
+ }
4119
+ }
4120
+ if (raw.resolution !== void 0 && !(typeof raw.resolution === "number" && raw.resolution > 0 && raw.resolution <= 2)) {
4121
+ out.push(`resolution ${JSON.stringify(raw.resolution)} is not a number above 0 and at most 2 (0.5 draws a quarter of the pixels and scales up); 1 is used`);
4122
+ }
4123
+ if (raw.transparent !== void 0 && typeof raw.transparent !== "boolean") out.push("transparent is true or false (true uses the shader's alpha; the default draws opaque)");
4124
+ return out;
4125
+ }
4126
+
4127
+ // src/sequences/Shader.ts
4128
+ var VERT = `#version 300 es
4129
+ void main() { vec2 p = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2)); gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0); }`;
4130
+ var ShaderSequence = class extends Sequence {
4131
+ prog = null;
4132
+ progGeneration = -1;
4133
+ w = 1;
4134
+ h = 1;
4135
+ c2d = null;
4136
+ fps = 30;
4137
+ failed = false;
4138
+ warnedNoGl = false;
4139
+ acquired = false;
4140
+ warnedPaths = /* @__PURE__ */ new Set();
4141
+ /** The current value of every uniform: what keyframes move (`uniforms.speed`, `uniforms.tint.0`). */
4142
+ carrier = {};
4143
+ /** How many components each vector uniform has (a scalar is not listed). */
4144
+ dims = {};
4145
+ get shaderSpec() {
4146
+ return this.spec;
4147
+ }
4148
+ pathRouters() {
4149
+ return { uniforms: (path) => this.resolveUniform(path) };
4150
+ }
4151
+ async build() {
4152
+ const spec = this.shaderSpec;
4153
+ const who = describeLayer(spec);
4154
+ for (const m of shaderProblems(spec)) console.warn(`pixi-effects: ${who}: ${m}`);
4155
+ if (this.duration === void 0) this.duration = this.parent?.duration ?? this.root.duration;
4156
+ const scope = buildScope(this, this.parent, this.root);
4157
+ const width = resolveDim(spec.width, scope) ?? this.parent?.width ?? this.root.width;
4158
+ const height = resolveDim(spec.height, scope) ?? this.parent?.height ?? this.root.height;
4159
+ const res = typeof spec.resolution === "number" && spec.resolution > 0 && spec.resolution <= 2 ? spec.resolution : 1;
4160
+ this.w = Math.max(1, Math.round(width * res));
4161
+ this.h = Math.max(1, Math.round(height * res));
4162
+ this.fps = this.root.frameRate ?? 30;
4163
+ for (const [name, v] of Object.entries(spec.uniforms ?? {})) {
4164
+ if (uniformType(v) === null) continue;
4165
+ if (typeof v === "number") this.carrier[name] = v;
4166
+ else {
4167
+ const f = uniformFloats(v);
4168
+ this.carrier[name] = Object.fromEntries(f.map((x, i) => [String(i), x]));
4169
+ this.dims[name] = f.length;
4170
+ }
4171
+ }
4172
+ this.c2d = document.createElement("canvas");
4173
+ this.c2d.width = this.w;
4174
+ this.c2d.height = this.h;
4175
+ const sprite = new Sprite({ texture: Texture.from(this.c2d), label: spec.name });
4176
+ sprite.width = width;
4177
+ sprite.height = height;
4178
+ this.target = sprite;
4179
+ this.intrinsicWidth = width;
4180
+ this.intrinsicHeight = height;
4181
+ this.buildFilters();
4182
+ if (typeof spec.fragment === "string" && spec.fragment.trim() !== "") this.acquire();
4183
+ else this.failed = true;
4184
+ this.drawAt(0);
4185
+ }
4186
+ async awaitFrameAt(local) {
4187
+ this.drawAt(Math.max(0, Math.min(local, this.duration ?? local)));
4188
+ }
4189
+ /** Resolve `uniforms.speed` / `uniforms.tint.0` for the keyframe pipeline; a name or index nobody has is said once and dropped. */
4190
+ resolveUniform(path) {
4191
+ const segs = path.split(".");
4192
+ const name = segs[0];
4193
+ const slot = this.carrier[name];
4194
+ const warn = (why) => {
4195
+ if (this.warnedPaths.has(path)) return;
4196
+ this.warnedPaths.add(path);
4197
+ console.warn(`pixi-effects: ${describeLayer(this.spec)}: keyframe path uniforms.${path} ${why}; skipped`);
4198
+ };
4199
+ if (slot === void 0) {
4200
+ const guess = suggestName(name, Object.keys(this.carrier));
4201
+ warn(`names no uniform "${name}"${guess ? `; did you mean "${guess}"?` : ""} (declare it in uniforms with a starting value)`);
4202
+ return null;
4203
+ }
4204
+ if (typeof slot === "number") {
4205
+ if (segs.length !== 1) {
4206
+ warn(`has more than a name, but "${name}" is a single number`);
4207
+ return null;
4208
+ }
4209
+ return { target: this.carrier, prop: name };
4210
+ }
4211
+ const n = this.dims[name];
4212
+ const index = segs.length === 2 ? Number(segs[1]) : NaN;
4213
+ if (!Number.isInteger(index) || index < 0 || index >= n) {
4214
+ warn(`must name a component of "${name}" (0 to ${n - 1}): 'uniforms.${name}.0'`);
4215
+ return null;
4216
+ }
4217
+ return { target: slot, prop: String(index) };
4218
+ }
4219
+ acquire() {
4220
+ const sh = acquireGl();
4221
+ this.acquired = true;
4222
+ if (!sh) {
4223
+ this.noGl();
4224
+ return;
4225
+ }
4226
+ this.compile();
4227
+ }
4228
+ noGl() {
4229
+ this.failed = true;
4230
+ if (!this.warnedNoGl) {
4231
+ this.warnedNoGl = true;
4232
+ console.warn(`pixi-effects: ${describeLayer(this.spec)}: this browser has no WebGL2, so the shader cannot run; the layer is drawn as a checkerboard`);
4233
+ }
4234
+ }
4235
+ compile() {
4236
+ const sh = currentGl();
4237
+ if (!sh) {
4238
+ this.noGl();
4239
+ return;
4240
+ }
4241
+ const { gl } = sh;
4242
+ const spec = this.shaderSpec;
4243
+ const make = (type, src) => {
4244
+ const s = gl.createShader(type);
4245
+ gl.shaderSource(s, src);
4246
+ gl.compileShader(s);
4247
+ return s;
4248
+ };
4249
+ const vs = make(gl.VERTEX_SHADER, VERT);
4250
+ const fs = make(gl.FRAGMENT_SHADER, wrapFragment(spec.fragment, spec.uniforms ?? {}, !!spec.transparent).source);
4251
+ const p = gl.createProgram();
4252
+ gl.attachShader(p, vs);
4253
+ gl.attachShader(p, fs);
4254
+ gl.linkProgram(p);
4255
+ const ok = gl.getProgramParameter(p, gl.LINK_STATUS);
4256
+ const log = ok ? "" : gl.getShaderInfoLog(fs) || gl.getProgramInfoLog(p) || "";
4257
+ gl.deleteShader(vs);
4258
+ gl.deleteShader(fs);
4259
+ if (!ok) {
4260
+ gl.deleteProgram(p);
4261
+ this.failed = true;
4262
+ this.prog = null;
4263
+ console.warn(`pixi-effects: ${describeLayer(this.spec)}: the fragment shader did not compile (the line numbers are the lines of your code):
4264
+ ${glslErrors(log).join("\n")}
4265
+ The layer is drawn as a checkerboard until it is fixed.`);
4266
+ return;
4267
+ }
4268
+ this.prog = p;
4269
+ this.progGeneration = sh.generation;
4270
+ }
4271
+ drawAt(local) {
4272
+ const c = this.c2d;
4273
+ if (!c) return;
4274
+ const ctx2 = c.getContext("2d");
4275
+ if (!ctx2) return;
4276
+ let sh = this.failed ? null : currentGl();
4277
+ if (sh && this.progGeneration !== sh.generation) {
4278
+ this.compile();
4279
+ sh = this.failed ? null : currentGl();
4280
+ }
4281
+ if (!sh || !this.prog) {
4282
+ const s = 32;
4283
+ for (let y = 0; y < c.height; y += s) for (let x = 0; x < c.width; x += s) {
4284
+ ctx2.fillStyle = x / s + y / s & 1 ? "#ff00ff" : "#220022";
4285
+ ctx2.fillRect(x, y, s, s);
4286
+ }
4287
+ } else {
4288
+ const { gl, canvas } = sh;
4289
+ if (canvas.width !== this.w || canvas.height !== this.h) {
4290
+ canvas.width = this.w;
4291
+ canvas.height = this.h;
4292
+ }
4293
+ gl.viewport(0, 0, this.w, this.h);
4294
+ gl.useProgram(this.prog);
4295
+ gl.uniform3f(gl.getUniformLocation(this.prog, "iResolution"), this.w, this.h, 1);
4296
+ gl.uniform1f(gl.getUniformLocation(this.prog, "iTime"), local);
4297
+ gl.uniform1i(gl.getUniformLocation(this.prog, "iFrame"), Math.round(local * this.fps));
4298
+ for (const [name, v] of Object.entries(this.carrier)) {
4299
+ const loc = gl.getUniformLocation(this.prog, name);
4300
+ if (typeof v === "number") {
4301
+ gl.uniform1f(loc, v);
4302
+ continue;
4303
+ }
4304
+ const n = this.dims[name];
4305
+ const comps = Array.from({ length: n }, (_, i) => v[String(i)] ?? 0);
4306
+ if (n === 2) gl.uniform2fv(loc, comps);
4307
+ else if (n === 3) gl.uniform3fv(loc, comps);
4308
+ else gl.uniform4fv(loc, comps);
4309
+ }
4310
+ gl.clearColor(0, 0, 0, 0);
4311
+ gl.clear(gl.COLOR_BUFFER_BIT);
4312
+ gl.drawArrays(gl.TRIANGLES, 0, 3);
4313
+ ctx2.clearRect(0, 0, c.width, c.height);
4314
+ ctx2.drawImage(canvas, 0, 0);
4315
+ }
4316
+ this.target?.texture.source.update();
4317
+ }
4318
+ destroy() {
4319
+ const texture = this.target?.texture;
4320
+ if (this.prog) {
4321
+ const sh = currentGl();
4322
+ if (sh && this.progGeneration === sh.generation) sh.gl.deleteProgram(this.prog);
4323
+ this.prog = null;
4324
+ }
4325
+ if (this.acquired) {
4326
+ this.acquired = false;
4327
+ releaseGl();
4328
+ }
4329
+ if (this.c2d) {
4330
+ this.c2d.width = this.c2d.height = 1;
4331
+ this.c2d = null;
4332
+ }
4333
+ super.destroy();
4334
+ texture?.destroy(true);
4335
+ }
4336
+ };
4337
+ function resolveDim(v, scope) {
4338
+ if (v === void 0) return void 0;
4339
+ if (typeof v === "number") return v;
4340
+ return evaluateExpr(v, scope);
4341
+ }
4342
+
3553
4343
  // src/core/Composition.ts
3554
4344
  var _CompositionSequence = null;
3555
4345
  async function getCompositionSequence() {
3556
4346
  if (!_CompositionSequence) {
3557
- _CompositionSequence = (await import('./Composition-Q5TVG3HM.js')).CompositionSequence;
4347
+ _CompositionSequence = (await import('./Composition-C4FSWJZF.js')).CompositionSequence;
3558
4348
  }
3559
4349
  return _CompositionSequence;
3560
4350
  }
@@ -3565,6 +4355,8 @@ var staticTypes = {
3565
4355
  video: VideoSequence,
3566
4356
  shape: ShapeSequence,
3567
4357
  camera: CameraSequence,
4358
+ light: LightSequence,
4359
+ shader: ShaderSequence,
3568
4360
  null: NullSequence
3569
4361
  };
3570
4362
  var registry2 = {};
@@ -3592,6 +4384,6 @@ async function buildSequenceTree(specs, parent, root) {
3592
4384
  return out;
3593
4385
  }
3594
4386
 
3595
- export { CameraSequence, DEFAULT_FOV, DEG, MANY_BLURRED, MAX_BLUR, MIN_BLUR, NEAR, NullSequence, Sequence, bindClock, blurRadius, buildScope, buildSequenceTree, cameraBasis, checkEase, clockTable, contentLength, ensureFilterLibrary, evaluateExpr, flattenSvgPath, focusProblems, homeCamera, homeDistance, layerInitialZ, noise, projectLayer, projectPoint, rand, random, registerSequenceType, remapOf, resolveAt, timeRemapOf };
3596
- //# sourceMappingURL=chunk-DC4JPY6A.js.map
3597
- //# sourceMappingURL=chunk-DC4JPY6A.js.map
4387
+ export { CameraSequence, DEFAULT_FOV, DEG2 as DEG, FALLOFFS, LIGHT_KINDS, LIGHT_PROPS, LightSequence, MANY_BLURRED, MAX_BLUR, MAX_CASTERS, MAX_LIGHTS, MIN_BLUR, NEAR, NullSequence, SHADOW_TAPS, Sequence, bindClock, blurRadius, buildScope, buildSequenceTree, cameraBasis, checkEase, clockTable, contentLength, ensureFilterLibrary, evaluateExpr, flattenSvgPath, focusProblems, homeCamera, homeDistance, layerInitialZ, layerToWorld, lightLevel, noise, packLights, projectLayer, projectPoint, rand, random, registerSequenceType, remapOf, resolveAt, timeRemapOf };
4388
+ //# sourceMappingURL=chunk-PRZ4U6JN.js.map
4389
+ //# sourceMappingURL=chunk-PRZ4U6JN.js.map