pixi-effects 0.41.0 → 0.43.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 (40) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +5 -5
  3. package/ai/chat-template.html +3 -3
  4. package/dist/{Base-Jgkud1Aw.d.ts → Base-DKFQtqzW.d.ts} +1 -1
  5. package/dist/{Base-DQWIJ6bJ.d.cts → Base-lb5Uhaqu.d.cts} +1 -1
  6. package/dist/Controller.d.cts +2 -2
  7. package/dist/Controller.d.ts +2 -2
  8. package/dist/{Movie-CwqRLOzE.d.ts → Movie-B_qQIYV6.d.ts} +47 -4
  9. package/dist/{Movie-DWtxRiJ2.d.cts → Movie-BdUm2Mc9.d.cts} +47 -4
  10. package/dist/{chunk-Y2N6U3X5.js → chunk-6N5ZBUOU.js} +169 -8
  11. package/dist/chunk-6N5ZBUOU.js.map +1 -0
  12. package/dist/{chunk-RN5FWGGM.cjs → chunk-BEGOKE7Q.cjs} +169 -8
  13. package/dist/chunk-BEGOKE7Q.cjs.map +1 -0
  14. package/dist/index.cjs +25 -25
  15. package/dist/index.d.cts +4 -4
  16. package/dist/index.d.ts +4 -4
  17. package/dist/index.js +1 -1
  18. package/dist/loader.css +1 -1
  19. package/dist/present.cjs +1 -1
  20. package/dist/present.d.cts +2 -2
  21. package/dist/present.d.ts +2 -2
  22. package/dist/present.js +1 -1
  23. package/dist/three.cjs +115 -24
  24. package/dist/three.cjs.map +1 -1
  25. package/dist/three.d.cts +28 -2
  26. package/dist/three.d.ts +28 -2
  27. package/dist/three.js +117 -26
  28. package/dist/three.js.map +1 -1
  29. package/dist/{types-DIh93lFb.d.cts → types-DiNHtdrS.d.cts} +19 -0
  30. package/dist/{types-DIh93lFb.d.ts → types-DiNHtdrS.d.ts} +19 -0
  31. package/docs/api.md +23 -3
  32. package/docs/dsl.md +3 -2
  33. package/llms-full.txt +147 -17
  34. package/package.json +2 -1
  35. package/skills/pixi-effects/SKILL.md +2 -1
  36. package/skills/pixi-effects/reference/cheatsheet.md +2 -0
  37. package/skills/pixi-effects/reference/recipes.md +117 -11
  38. package/skills/pixi-effects/template.html +6 -6
  39. package/dist/chunk-RN5FWGGM.cjs.map +0 -1
  40. package/dist/chunk-Y2N6U3X5.js.map +0 -1
package/dist/three.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { Sequence, buildScope, evaluateExpr, registerSequenceType } from './chunk-4QVQ5UJJ.js';
2
2
  import './chunk-32MMNDDN.js';
3
3
  import './chunk-BXOCEZ4U.js';
4
- import { Texture, Sprite } from 'pixi.js';
5
- import { WebGLRenderer, Scene, PerspectiveCamera, Raycaster, Vector2, Box3, Vector3, Group, AnimationMixer, LoopOnce, LoopRepeat, AmbientLight, DirectionalLight, SpotLight, PointLight, Color, SRGBColorSpace, Fog } from 'three';
4
+ import { Texture, Sprite, TextureSource } from 'pixi.js';
5
+ import { WebGLRenderer, Scene, PerspectiveCamera, Raycaster, Vector2, Vector3, Quaternion, Plane, Box3, RenderTarget, Group, AnimationMixer, LoopOnce, LoopRepeat, AmbientLight, DirectionalLight, SpotLight, PointLight, Color, SRGBColorSpace, Fog } from 'three';
6
6
 
7
7
  // src/three/defaults.ts
8
8
  var pageRenderer = "webgl";
@@ -159,7 +159,7 @@ function trackThree(kind) {
159
159
  live[kind]++;
160
160
  if (live[kind] > WARN_ABOVE[kind] && !warned.has(kind)) {
161
161
  warned.add(kind);
162
- console.warn(`pixi-effects: ${live[kind]} three layers are alive with renderer: '${kind}', and a browser keeps ${LIMIT[kind]} for the whole page; layers beyond that draw nothing, without an error. Put several objects in one three layer, destroy layers that are over, ` + (kind === "webgl" ? `or use renderer: 'webgpu' for some (its limit is about 32)` : `or use renderer: 'webgl' for some of them (a different pool of contexts)`));
162
+ console.warn(`pixi-effects: ${live[kind]} three layers are alive with renderer: '${kind}', and a browser keeps ${LIMIT[kind]} for the whole page; layers beyond that draw nothing, without an error. Put several objects in one three layer, destroy layers that are over, ` + (kind === "webgl" ? `or use renderer: 'webgpu' for some (in a movie PixiJS draws on WebGPU they share its GPU device and have no limit; otherwise it is about 32)` : `or use renderer: 'webgl' for some of them (a different pool of contexts), or leave shareGpu on in a movie PixiJS draws on WebGPU (the layers then share its device)`));
163
163
  }
164
164
  }
165
165
  function releaseThree(kind) {
@@ -176,6 +176,11 @@ var ThreeSequence = class extends Sequence {
176
176
  backend = null;
177
177
  _gpu = false;
178
178
  // renderer: 'webgpu': async init and async render
179
+ /** True when the layer draws on PixiJS's own GPU device into a texture PixiJS samples directly (no canvas of its own, no copy, no share of the page's context cap). */
180
+ sharedGpu = false;
181
+ _rt = null;
182
+ // the texture a shared layer draws into
183
+ _sharedTexture = null;
179
184
  _scene = null;
180
185
  _camera = null;
181
186
  _ctx = null;
@@ -187,6 +192,8 @@ var ThreeSequence = class extends Sequence {
187
192
  _fogMirror = null;
188
193
  _warnedSpace = /* @__PURE__ */ new Set();
189
194
  _tracked = false;
195
+ /** Set when this layer lets its renderer go on purpose: the context loss that follows is its own doing, not the browser's. */
196
+ _closing = false;
190
197
  get _threeSpec() {
191
198
  return this.spec;
192
199
  }
@@ -219,31 +226,43 @@ var ThreeSequence = class extends Sequence {
219
226
  } catch (err) {
220
227
  throw new Error(`pixi-effects: renderer: 'webgpu' needs three 0.17x or later with "three/webgpu" in the import map (${err instanceof Error ? err.message : err})`);
221
228
  }
222
- renderer = new mod.WebGPURenderer({ canvas, alpha: true, antialias });
223
- this._renderer = renderer;
224
- this._track();
225
- const warn = console.warn;
226
- let noGpu = false;
227
- console.warn = (...args) => {
228
- if (/WebGPU is not available/.test(String(args[0]))) noGpu = true;
229
- else warn.apply(console, args);
230
- };
231
- try {
232
- await renderer.init();
233
- } catch (err) {
234
- this._disposeRenderer();
235
- throw err;
236
- } finally {
237
- console.warn = warn;
229
+ let shared = spec.shareGpu === false ? void 0 : this.root.gpu;
230
+ for (; ; ) {
231
+ renderer = new mod.WebGPURenderer(shared ? { device: shared.device, alpha: true, antialias } : { canvas, alpha: true, antialias });
232
+ this._renderer = renderer;
233
+ if (!shared) this._track();
234
+ const warn = console.warn;
235
+ let noGpu = false;
236
+ console.warn = (...args) => {
237
+ if (/WebGPU is not available/.test(String(args[0]))) noGpu = true;
238
+ else warn.apply(console, args);
239
+ };
240
+ try {
241
+ await renderer.init();
242
+ if (shared) {
243
+ renderer.setSize(Math.round(width * resolution), Math.round(height * resolution), false);
244
+ renderer.setClearColor(0, 0);
245
+ this._prepareShared(renderer, shared, width, height, resolution, antialias);
246
+ }
247
+ this.backend = noGpu ? "webgl2" : "webgpu";
248
+ break;
249
+ } catch (err) {
250
+ this._disposeRenderer();
251
+ if (!shared) throw err;
252
+ console.warn(`pixi-effects: three layer${spec.name ? ` "${spec.name}"` : ""}: could not draw on PixiJS's GPU device (${err instanceof Error ? err.message : err}); it uses a canvas of its own (shareGpu: false does this on purpose)`);
253
+ shared = void 0;
254
+ this._closing = false;
255
+ } finally {
256
+ console.warn = warn;
257
+ }
238
258
  }
239
- this.backend = noGpu ? "webgl2" : "webgpu";
240
259
  } else {
241
260
  renderer = new WebGLRenderer({ canvas, alpha: true, antialias });
242
261
  this._renderer = renderer;
243
262
  this._track();
244
263
  let said = false;
245
264
  canvas.addEventListener("webglcontextlost", () => {
246
- if (said) return;
265
+ if (said || this._closing) return;
247
266
  said = true;
248
267
  console.warn(`pixi-effects: three layer${spec.name ? ` "${spec.name}"` : ""}: the browser took this layer's WebGL context away (a page keeps about 16 for all its layers, PixiJS and shader layers: too many were alive), so the layer draws nothing. Put several objects in one three layer, or destroy layers that are over`);
249
268
  });
@@ -270,7 +289,7 @@ var ThreeSequence = class extends Sequence {
270
289
  if (!("camera" in this._objects)) this._objects.camera = this._camera;
271
290
  if (this._gpu) this._checkWebGpuMaterials(scene, spec.name);
272
291
  this._draw(0);
273
- const texture = Texture.from(canvas);
292
+ const texture = this._sharedTexture ?? Texture.from(canvas);
274
293
  const sprite = new Sprite({ texture, label: spec.name });
275
294
  sprite.cullable = true;
276
295
  sprite.width = width;
@@ -306,7 +325,7 @@ var ThreeSequence = class extends Sequence {
306
325
  }
307
326
  }
308
327
  this._draw(t);
309
- this.target?.texture.source.update();
328
+ if (!this.sharedGpu) this.target?.texture.source.update();
310
329
  }
311
330
  /**
312
331
  * `movie.pick`: a ray through the point (u, v) of the layer's picture (0..1, v down) from the layer's camera, and what it meets first: the object's name (its own, or its nearest
@@ -334,6 +353,36 @@ var ThreeSequence = class extends Sequence {
334
353
  }
335
354
  return null;
336
355
  }
356
+ /**
357
+ * `hit.three.grab(plane)`: drag a grabbed point of the scene. Returns a function of a point (u, v) of the layer's picture (0..1, v down) that gives where the pointer's ray through the layer's
358
+ * camera meets a plane through the grabbed point, and how far that is from the grabbed point (`delta`): move the object by it and it follows the pointer exactly. `plane`: `'screen'` (facing the
359
+ * camera: the default), `'floor'` (horizontal, the three y up), `'wall'` (z constant), or a normal `[x, y, z]`. null where the ray never meets it (a floor seen edge-on, behind the camera).
360
+ */
361
+ dragPlane(point, plane = "screen") {
362
+ const grabbed = new Vector3(...point);
363
+ let normal;
364
+ if (plane === "floor") normal = new Vector3(0, 1, 0);
365
+ else if (plane === "wall") normal = new Vector3(0, 0, 1);
366
+ else if (Array.isArray(plane)) normal = new Vector3(...plane).normalize();
367
+ else {
368
+ const turn = new Quaternion();
369
+ this._camera?.updateMatrixWorld();
370
+ this._camera?.getWorldQuaternion(turn);
371
+ normal = new Vector3(0, 0, 1).applyQuaternion(turn);
372
+ }
373
+ const surface = new Plane().setFromNormalAndCoplanarPoint(normal, grabbed);
374
+ return (u, v) => {
375
+ const scene = this._scene, camera = this._camera;
376
+ if (!scene || !camera) return null;
377
+ scene.updateMatrixWorld();
378
+ camera.updateMatrixWorld();
379
+ const ray = new Raycaster();
380
+ ray.setFromCamera(new Vector2(u * 2 - 1, -(v * 2 - 1)), camera);
381
+ const at = ray.ray.intersectPlane(surface, new Vector3());
382
+ if (!at) return null;
383
+ return { point: at.toArray(), delta: at.clone().sub(grabbed).toArray() };
384
+ };
385
+ }
337
386
  /**
338
387
  * The determinism check (`check`, `movie.review()`): the scene drawn at a few moments in two orders, with one draw thrown away first, and the pictures compared, as the canvas layer
339
388
  * does. A layer whose same frame is not the same picture (a clock, `Math.random`, a mixer advanced with `update(dt)`, any state that builds up from call to call) is reported.
@@ -366,7 +415,7 @@ var ThreeSequence = class extends Sequence {
366
415
  try {
367
416
  this._followSpace(t);
368
417
  this._threeSpec.update?.(t, ctx);
369
- this._draw(t);
418
+ this._draw(t, true);
370
419
  g.clearRect(0, 0, w, h);
371
420
  g.drawImage(source, 0, 0);
372
421
  } catch {
@@ -469,10 +518,45 @@ var ThreeSequence = class extends Sequence {
469
518
  * follow each other in one task (a seek, an export) would all show the lights of the last animation frame: a lamp keyframed with `three.lamp.intensity` would not move.
470
519
  * So before each render the layer advances the node frame itself, and gives `time` the layer's own time (not three's wall clock).
471
520
  */
472
- _draw(t) {
521
+ _draw(t, toCanvas = false) {
473
522
  if (!this._renderer || !this._scene || !this._camera) return;
474
523
  if (this._gpu) this._advanceNodeFrame(t);
475
- this._renderer.render(this._scene, this._camera);
524
+ if (!this._rt || toCanvas) {
525
+ this._renderer.render(this._scene, this._camera);
526
+ return;
527
+ }
528
+ const r = this._renderer;
529
+ r.setOutputRenderTarget(this._rt);
530
+ try {
531
+ this._renderer.render(this._scene, this._camera);
532
+ } finally {
533
+ r.setOutputRenderTarget(null);
534
+ r.setRenderTarget(null);
535
+ }
536
+ }
537
+ /**
538
+ * A shared layer's texture: a render target of the layer's size, drawn into once (the GPU texture exists only after a draw) and adopted by a PixiJS texture source. Throws when something
539
+ * is not as this expects (the build then makes the layer again on a canvas of its own). Done before `setup`, so nothing the author made yet depends on the renderer.
540
+ */
541
+ _prepareShared(renderer, shared, width, height, resolution, antialias) {
542
+ const w = Math.round(width * resolution), h = Math.round(height * resolution);
543
+ const rt = new RenderTarget(w, h, { depthBuffer: true, samples: antialias ? 4 : 0 });
544
+ this._rt = rt;
545
+ const r = renderer;
546
+ if (typeof r.setOutputRenderTarget !== "function") throw new Error("this three has no setOutputRenderTarget");
547
+ r.setOutputRenderTarget(rt);
548
+ try {
549
+ renderer.render(new Scene(), new PerspectiveCamera());
550
+ } finally {
551
+ r.setOutputRenderTarget(null);
552
+ r.setRenderTarget(null);
553
+ }
554
+ const gpuTexture = r.backend?.get?.(rt.texture)?.texture;
555
+ if (!gpuTexture || typeof gpuTexture.createView !== "function") throw new Error("three keeps no GPU texture for a render target");
556
+ const source = new TextureSource({ width: w, height: h, format: gpuTexture.format, label: "three layer (shared GPU)" });
557
+ shared.adopt(source, gpuTexture);
558
+ this._sharedTexture = new Texture({ source });
559
+ this.sharedGpu = true;
476
560
  }
477
561
  /**
478
562
  * The author chose renderer: 'webgpu'. Three's WebGPU renderer turns materials into node materials: a ShaderMaterial / RawShaderMaterial cannot run there (three logs an error on
@@ -555,6 +639,7 @@ var ThreeSequence = class extends Sequence {
555
639
  }
556
640
  _disposeRenderer() {
557
641
  if (!this._renderer) return;
642
+ this._closing = true;
558
643
  if (this._tracked) {
559
644
  this._tracked = false;
560
645
  releaseThree(this._gpu ? "webgpu" : "webgl");
@@ -566,6 +651,11 @@ var ThreeSequence = class extends Sequence {
566
651
  console.warn("pixi-effects: three renderer dispose threw \u2014", err);
567
652
  }
568
653
  this._renderer = null;
654
+ try {
655
+ this._rt?.dispose();
656
+ } catch {
657
+ }
658
+ this._rt = null;
569
659
  }
570
660
  destroy() {
571
661
  const spec = this._threeSpec;
@@ -588,6 +678,7 @@ var ThreeSequence = class extends Sequence {
588
678
  this._objects = {};
589
679
  super.destroy();
590
680
  texture?.destroy(true);
681
+ this._sharedTexture = null;
591
682
  }
592
683
  };
593
684
  function resolveDim(v, scope) {