pixi-effects 0.45.0 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/README.md +5 -5
- package/ai/chat-template.html +3 -3
- package/dist/Composition-NSY7A32Y.js +7 -0
- package/dist/{Composition-YGBQX3HZ.js.map → Composition-NSY7A32Y.js.map} +1 -1
- package/dist/Composition-PME3P5LP.cjs +16 -0
- package/dist/{Composition-N6BOROJ2.cjs.map → Composition-PME3P5LP.cjs.map} +1 -1
- package/dist/Controller.d.cts +2 -2
- package/dist/Controller.d.ts +2 -2
- package/dist/{Movie-C-d4zN-N.d.cts → Movie-BqrAWN0g.d.cts} +6 -1
- package/dist/{Movie-lMSS9JwX.d.ts → Movie-sV8nJr_f.d.ts} +6 -1
- package/dist/{Spans-XTIWYSNO.cjs → Spans-2TZCNREQ.cjs} +9 -9
- package/dist/{Spans-XTIWYSNO.cjs.map → Spans-2TZCNREQ.cjs.map} +1 -1
- package/dist/{Spans-6L2ZVECX.js → Spans-TESJPQKX.js} +4 -4
- package/dist/{Spans-6L2ZVECX.js.map → Spans-TESJPQKX.js.map} +1 -1
- package/dist/{chunk-Z6JQO7GX.js → chunk-2E74SP63.js} +47 -13
- package/dist/chunk-2E74SP63.js.map +1 -0
- package/dist/{chunk-3IO5RWE4.cjs → chunk-7M63Y6MO.cjs} +85 -51
- package/dist/chunk-7M63Y6MO.cjs.map +1 -0
- package/dist/{chunk-3HZV3UHU.cjs → chunk-DKCMJILW.cjs} +67 -65
- package/dist/chunk-DKCMJILW.cjs.map +1 -0
- package/dist/{chunk-4QVQ5UJJ.js → chunk-DM2OLQOJ.js} +5 -6
- package/dist/chunk-DM2OLQOJ.js.map +1 -0
- package/dist/{chunk-ICI6ACHY.js → chunk-FPV3NPYC.js} +8 -6
- package/dist/chunk-FPV3NPYC.js.map +1 -0
- package/dist/{chunk-X62H3RBG.cjs → chunk-LALEBV63.cjs} +5 -6
- package/dist/chunk-LALEBV63.cjs.map +1 -0
- package/dist/index.cjs +33 -33
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/loader.css +1 -1
- package/dist/present.cjs +3 -3
- package/dist/present.d.cts +2 -2
- package/dist/present.d.ts +2 -2
- package/dist/present.js +3 -3
- package/dist/three.cjs +194 -15
- package/dist/three.cjs.map +1 -1
- package/dist/three.d.cts +75 -4
- package/dist/three.d.ts +75 -4
- package/dist/three.js +191 -13
- package/dist/three.js.map +1 -1
- package/dist/{types-C5xo0fzb.d.ts → types-CTSrPvY3.d.cts} +64 -58
- package/dist/{types-C5xo0fzb.d.cts → types-CTSrPvY3.d.ts} +64 -58
- package/docs/api.md +1 -0
- package/docs/dsl.md +24 -0
- package/llms-full.txt +61 -2
- package/package.json +1 -1
- package/skills/pixi-effects/SKILL.md +1 -1
- package/skills/pixi-effects/reference/cheatsheet.md +1 -1
- package/skills/pixi-effects/reference/recipes.md +34 -0
- package/skills/pixi-effects/template.html +6 -6
- package/dist/Composition-N6BOROJ2.cjs +0 -16
- package/dist/Composition-YGBQX3HZ.js +0 -7
- package/dist/chunk-3HZV3UHU.cjs.map +0 -1
- package/dist/chunk-3IO5RWE4.cjs.map +0 -1
- package/dist/chunk-4QVQ5UJJ.js.map +0 -1
- package/dist/chunk-ICI6ACHY.js.map +0 -1
- package/dist/chunk-X62H3RBG.cjs.map +0 -1
- package/dist/chunk-Z6JQO7GX.js.map +0 -1
package/dist/three.d.cts
CHANGED
|
@@ -1,11 +1,66 @@
|
|
|
1
|
-
import { b as
|
|
2
|
-
import {
|
|
1
|
+
import { b as Sequence, c as SpaceNow, d as SequenceCommon, e as PropValue, f as PathRouters, S as SequenceSpec } from './types-CTSrPvY3.cjs';
|
|
2
|
+
import { Renderer } from 'pixi.js';
|
|
3
|
+
import { Material, Texture, Scene, Camera, WebGLRenderer, Object3D, Group, Vector3, PerspectiveCamera } from 'three';
|
|
3
4
|
import { WebGPURenderer } from 'three/webgpu';
|
|
4
|
-
import 'pixi.js';
|
|
5
5
|
|
|
6
6
|
/** The page-level default renderer of the three layers: `registerThree({ renderer })` sets it, a layer's own `renderer` wins. */
|
|
7
7
|
type ThreeRendererKind = 'webgl' | 'webgpu';
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* `threeLayerTexture(ctx, 'screen')`: a live 2D layer (a `composition`) as the picture on a mesh of a `three` layer (a phone's screen, a television, a billboard, a label).
|
|
11
|
+
*
|
|
12
|
+
* The 2D layer stays a layer of the movie: the timeline drives it, its own `at` / `duration` / keyframes / filters apply. It is not drawn on the stage any more: just before the three layer draws,
|
|
13
|
+
* PixiJS draws it into a texture, and the mesh shows that texture. Two routes, chosen by what the layer has:
|
|
14
|
+
* - the three layer draws on PixiJS's own GPU device (`renderer: 'webgpu'` in a WebGPU movie, the default): the texture is PixiJS's GPUTexture itself, used through three's `ExternalTexture`
|
|
15
|
+
* (no copy; 0.3 ms a frame measured). It is not decoded from sRGB by three (the texture is plain rgba8), so the material decodes it in its shader and the picture is flipped by its UV.
|
|
16
|
+
* - otherwise (the layer has a canvas of its own, or PixiJS is on WebGL): the pixels are read back into a canvas (1.6 ms a frame at 480 x 270, 4 ms at 1280 x 720) and three treats it as an ordinary
|
|
17
|
+
* sRGB canvas texture.
|
|
18
|
+
* Both give the 2D layer's colours exactly (tests/films/three-layer-texture).
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
interface ThreeLayerTextureOptions {
|
|
22
|
+
/** Pixels of the texture per pixel of the 2D layer: 2 for a screen that is seen large. Default 1. */
|
|
23
|
+
resolution?: number;
|
|
24
|
+
/**
|
|
25
|
+
* The 2D layer's empty and half-transparent parts let what is behind the mesh show through (a sticker, a label with rounded corners, a hologram). Default `false`: an opaque screen, empty parts black,
|
|
26
|
+
* which is cheaper and never has the sorting trouble of transparent meshes (give the composition a background rect and use that). With `true` the material blends and does not write depth.
|
|
27
|
+
*/
|
|
28
|
+
transparent?: boolean;
|
|
29
|
+
}
|
|
30
|
+
interface ThreeLayerTexture {
|
|
31
|
+
/** An unlit material that shows the 2D layer: put it on a mesh (or on one face of a box: an array of materials). A screen shines by itself, so scene lights do not shade it. */
|
|
32
|
+
material: Material;
|
|
33
|
+
/** The three texture behind the material (colours are only right through `material`, which decodes them). */
|
|
34
|
+
texture: Texture;
|
|
35
|
+
/** The size of the texture in pixels. */
|
|
36
|
+
width: number;
|
|
37
|
+
height: number;
|
|
38
|
+
/** Stop showing the layer (it is drawn on the stage again). Called when the three layer is destroyed. */
|
|
39
|
+
dispose(): void;
|
|
40
|
+
}
|
|
41
|
+
/** What a three layer lends to `threeLayerTexture` (set on `ctx._host` by the layer itself). */
|
|
42
|
+
interface ThreeLayerHost {
|
|
43
|
+
/** A layer of the same composition by its name, among those built before this one. */
|
|
44
|
+
findLayer(name: string): Sequence | null;
|
|
45
|
+
/** The names of those layers, for the message when the name is wrong. */
|
|
46
|
+
layerNames(): string[];
|
|
47
|
+
pixiRenderer: Renderer | null;
|
|
48
|
+
/** The three layer draws on PixiJS's GPU device (no copy is needed). */
|
|
49
|
+
shared: boolean;
|
|
50
|
+
/** Run `fn` just before every draw of the three layer; returns the function that stops it. */
|
|
51
|
+
beforeDraw(fn: () => void): () => void;
|
|
52
|
+
/** Remember a handle: a rebuild that keeps the three layer gives it the new tree's layer (`rebind`). */
|
|
53
|
+
track(handle: Rebindable): void;
|
|
54
|
+
}
|
|
55
|
+
/** What a rebuild that keeps the three layer needs: show the layer of the new tree with the same name. */
|
|
56
|
+
interface Rebindable {
|
|
57
|
+
material: Material;
|
|
58
|
+
source(): Sequence;
|
|
59
|
+
rebind(host: ThreeLayerHost): void;
|
|
60
|
+
dispose(): void;
|
|
61
|
+
}
|
|
62
|
+
declare function threeLayerTexture(ctx: ThreeContext, name: string, options?: ThreeLayerTextureOptions): Promise<ThreeLayerTexture>;
|
|
63
|
+
|
|
9
64
|
/** Handed to setup / update / dispose. One per three sequence. */
|
|
10
65
|
interface ThreeContext {
|
|
11
66
|
scene: Scene;
|
|
@@ -18,6 +73,8 @@ interface ThreeContext {
|
|
|
18
73
|
height: number;
|
|
19
74
|
/** The composition's camera and the lights alive at this moment, set before every `update` when the layer has `followCamera` or `followLights`; undefined otherwise. */
|
|
20
75
|
space?: SpaceNow;
|
|
76
|
+
/** Internal: what `threeLayerTexture` needs from the layer that owns this context. */
|
|
77
|
+
_host?: ThreeLayerHost;
|
|
21
78
|
}
|
|
22
79
|
interface ThreeSetupResult {
|
|
23
80
|
/** Objects addressable from keyframes as `three.<name>.<path>`. `camera` is added implicitly unless present. */
|
|
@@ -111,6 +168,9 @@ declare class ThreeSequence extends Sequence {
|
|
|
111
168
|
private _borrowed;
|
|
112
169
|
/** True once another layer owns this layer's state: destroying this one must not let it go. */
|
|
113
170
|
private _donated;
|
|
171
|
+
/** Things to do just before every draw (the 2D layers shown on meshes: `threeLayerTexture`), and those layers' handles. Both go with the state to a layer that takes it over. */
|
|
172
|
+
private _drawHooks;
|
|
173
|
+
private _layerTextures;
|
|
114
174
|
private _scene;
|
|
115
175
|
private _camera;
|
|
116
176
|
private _ctx;
|
|
@@ -128,6 +188,12 @@ declare class ThreeSequence extends Sequence {
|
|
|
128
188
|
protected pathRouters(): PathRouters;
|
|
129
189
|
build(): Promise<void>;
|
|
130
190
|
private _makeSprite;
|
|
191
|
+
/** The 2D layer that a material shows (`threeLayerTexture`), for a click on the mesh to reach it (movie.pick); null for any other material. */
|
|
192
|
+
screenOf(material: unknown): {
|
|
193
|
+
source: Sequence;
|
|
194
|
+
} | null;
|
|
195
|
+
/** What `threeLayerTexture` asks of this layer: the layers listed before it, PixiJS's renderer, whether the GPU device is shared, and a place to hook in before every draw. */
|
|
196
|
+
private _makeHost;
|
|
131
197
|
/** Reuse (core/reuse.ts): the key this layer is matched by, while it can still lend its state. */
|
|
132
198
|
reuseKey(): string | null;
|
|
133
199
|
private _lendable;
|
|
@@ -151,6 +217,11 @@ declare class ThreeSequence extends Sequence {
|
|
|
151
217
|
point: [number, number, number];
|
|
152
218
|
distance: number;
|
|
153
219
|
object3d: Object3D;
|
|
220
|
+
uv?: {
|
|
221
|
+
u: number;
|
|
222
|
+
v: number;
|
|
223
|
+
};
|
|
224
|
+
material?: unknown;
|
|
154
225
|
} | null;
|
|
155
226
|
/**
|
|
156
227
|
* `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
|
|
@@ -268,4 +339,4 @@ declare function registerThree(options?: {
|
|
|
268
339
|
*/
|
|
269
340
|
declare function three(spec: ThreeSequenceSpec): SequenceSpec;
|
|
270
341
|
|
|
271
|
-
export { type ThreeContext, type ThreeFrameCameraOptions, type ThreeGltfModel, type ThreeGltfOptions, type ThreeRendererKind, ThreeSequence, type ThreeSequenceSpec, type ThreeSetupResult, registerThree, three, threeFrameCamera, threeGltf };
|
|
342
|
+
export { type ThreeContext, type ThreeFrameCameraOptions, type ThreeGltfModel, type ThreeGltfOptions, type ThreeLayerTexture, type ThreeLayerTextureOptions, type ThreeRendererKind, ThreeSequence, type ThreeSequenceSpec, type ThreeSetupResult, registerThree, three, threeFrameCamera, threeGltf, threeLayerTexture };
|
package/dist/three.d.ts
CHANGED
|
@@ -1,11 +1,66 @@
|
|
|
1
|
-
import { b as
|
|
2
|
-
import {
|
|
1
|
+
import { b as Sequence, c as SpaceNow, d as SequenceCommon, e as PropValue, f as PathRouters, S as SequenceSpec } from './types-CTSrPvY3.js';
|
|
2
|
+
import { Renderer } from 'pixi.js';
|
|
3
|
+
import { Material, Texture, Scene, Camera, WebGLRenderer, Object3D, Group, Vector3, PerspectiveCamera } from 'three';
|
|
3
4
|
import { WebGPURenderer } from 'three/webgpu';
|
|
4
|
-
import 'pixi.js';
|
|
5
5
|
|
|
6
6
|
/** The page-level default renderer of the three layers: `registerThree({ renderer })` sets it, a layer's own `renderer` wins. */
|
|
7
7
|
type ThreeRendererKind = 'webgl' | 'webgpu';
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* `threeLayerTexture(ctx, 'screen')`: a live 2D layer (a `composition`) as the picture on a mesh of a `three` layer (a phone's screen, a television, a billboard, a label).
|
|
11
|
+
*
|
|
12
|
+
* The 2D layer stays a layer of the movie: the timeline drives it, its own `at` / `duration` / keyframes / filters apply. It is not drawn on the stage any more: just before the three layer draws,
|
|
13
|
+
* PixiJS draws it into a texture, and the mesh shows that texture. Two routes, chosen by what the layer has:
|
|
14
|
+
* - the three layer draws on PixiJS's own GPU device (`renderer: 'webgpu'` in a WebGPU movie, the default): the texture is PixiJS's GPUTexture itself, used through three's `ExternalTexture`
|
|
15
|
+
* (no copy; 0.3 ms a frame measured). It is not decoded from sRGB by three (the texture is plain rgba8), so the material decodes it in its shader and the picture is flipped by its UV.
|
|
16
|
+
* - otherwise (the layer has a canvas of its own, or PixiJS is on WebGL): the pixels are read back into a canvas (1.6 ms a frame at 480 x 270, 4 ms at 1280 x 720) and three treats it as an ordinary
|
|
17
|
+
* sRGB canvas texture.
|
|
18
|
+
* Both give the 2D layer's colours exactly (tests/films/three-layer-texture).
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
interface ThreeLayerTextureOptions {
|
|
22
|
+
/** Pixels of the texture per pixel of the 2D layer: 2 for a screen that is seen large. Default 1. */
|
|
23
|
+
resolution?: number;
|
|
24
|
+
/**
|
|
25
|
+
* The 2D layer's empty and half-transparent parts let what is behind the mesh show through (a sticker, a label with rounded corners, a hologram). Default `false`: an opaque screen, empty parts black,
|
|
26
|
+
* which is cheaper and never has the sorting trouble of transparent meshes (give the composition a background rect and use that). With `true` the material blends and does not write depth.
|
|
27
|
+
*/
|
|
28
|
+
transparent?: boolean;
|
|
29
|
+
}
|
|
30
|
+
interface ThreeLayerTexture {
|
|
31
|
+
/** An unlit material that shows the 2D layer: put it on a mesh (or on one face of a box: an array of materials). A screen shines by itself, so scene lights do not shade it. */
|
|
32
|
+
material: Material;
|
|
33
|
+
/** The three texture behind the material (colours are only right through `material`, which decodes them). */
|
|
34
|
+
texture: Texture;
|
|
35
|
+
/** The size of the texture in pixels. */
|
|
36
|
+
width: number;
|
|
37
|
+
height: number;
|
|
38
|
+
/** Stop showing the layer (it is drawn on the stage again). Called when the three layer is destroyed. */
|
|
39
|
+
dispose(): void;
|
|
40
|
+
}
|
|
41
|
+
/** What a three layer lends to `threeLayerTexture` (set on `ctx._host` by the layer itself). */
|
|
42
|
+
interface ThreeLayerHost {
|
|
43
|
+
/** A layer of the same composition by its name, among those built before this one. */
|
|
44
|
+
findLayer(name: string): Sequence | null;
|
|
45
|
+
/** The names of those layers, for the message when the name is wrong. */
|
|
46
|
+
layerNames(): string[];
|
|
47
|
+
pixiRenderer: Renderer | null;
|
|
48
|
+
/** The three layer draws on PixiJS's GPU device (no copy is needed). */
|
|
49
|
+
shared: boolean;
|
|
50
|
+
/** Run `fn` just before every draw of the three layer; returns the function that stops it. */
|
|
51
|
+
beforeDraw(fn: () => void): () => void;
|
|
52
|
+
/** Remember a handle: a rebuild that keeps the three layer gives it the new tree's layer (`rebind`). */
|
|
53
|
+
track(handle: Rebindable): void;
|
|
54
|
+
}
|
|
55
|
+
/** What a rebuild that keeps the three layer needs: show the layer of the new tree with the same name. */
|
|
56
|
+
interface Rebindable {
|
|
57
|
+
material: Material;
|
|
58
|
+
source(): Sequence;
|
|
59
|
+
rebind(host: ThreeLayerHost): void;
|
|
60
|
+
dispose(): void;
|
|
61
|
+
}
|
|
62
|
+
declare function threeLayerTexture(ctx: ThreeContext, name: string, options?: ThreeLayerTextureOptions): Promise<ThreeLayerTexture>;
|
|
63
|
+
|
|
9
64
|
/** Handed to setup / update / dispose. One per three sequence. */
|
|
10
65
|
interface ThreeContext {
|
|
11
66
|
scene: Scene;
|
|
@@ -18,6 +73,8 @@ interface ThreeContext {
|
|
|
18
73
|
height: number;
|
|
19
74
|
/** The composition's camera and the lights alive at this moment, set before every `update` when the layer has `followCamera` or `followLights`; undefined otherwise. */
|
|
20
75
|
space?: SpaceNow;
|
|
76
|
+
/** Internal: what `threeLayerTexture` needs from the layer that owns this context. */
|
|
77
|
+
_host?: ThreeLayerHost;
|
|
21
78
|
}
|
|
22
79
|
interface ThreeSetupResult {
|
|
23
80
|
/** Objects addressable from keyframes as `three.<name>.<path>`. `camera` is added implicitly unless present. */
|
|
@@ -111,6 +168,9 @@ declare class ThreeSequence extends Sequence {
|
|
|
111
168
|
private _borrowed;
|
|
112
169
|
/** True once another layer owns this layer's state: destroying this one must not let it go. */
|
|
113
170
|
private _donated;
|
|
171
|
+
/** Things to do just before every draw (the 2D layers shown on meshes: `threeLayerTexture`), and those layers' handles. Both go with the state to a layer that takes it over. */
|
|
172
|
+
private _drawHooks;
|
|
173
|
+
private _layerTextures;
|
|
114
174
|
private _scene;
|
|
115
175
|
private _camera;
|
|
116
176
|
private _ctx;
|
|
@@ -128,6 +188,12 @@ declare class ThreeSequence extends Sequence {
|
|
|
128
188
|
protected pathRouters(): PathRouters;
|
|
129
189
|
build(): Promise<void>;
|
|
130
190
|
private _makeSprite;
|
|
191
|
+
/** The 2D layer that a material shows (`threeLayerTexture`), for a click on the mesh to reach it (movie.pick); null for any other material. */
|
|
192
|
+
screenOf(material: unknown): {
|
|
193
|
+
source: Sequence;
|
|
194
|
+
} | null;
|
|
195
|
+
/** What `threeLayerTexture` asks of this layer: the layers listed before it, PixiJS's renderer, whether the GPU device is shared, and a place to hook in before every draw. */
|
|
196
|
+
private _makeHost;
|
|
131
197
|
/** Reuse (core/reuse.ts): the key this layer is matched by, while it can still lend its state. */
|
|
132
198
|
reuseKey(): string | null;
|
|
133
199
|
private _lendable;
|
|
@@ -151,6 +217,11 @@ declare class ThreeSequence extends Sequence {
|
|
|
151
217
|
point: [number, number, number];
|
|
152
218
|
distance: number;
|
|
153
219
|
object3d: Object3D;
|
|
220
|
+
uv?: {
|
|
221
|
+
u: number;
|
|
222
|
+
v: number;
|
|
223
|
+
};
|
|
224
|
+
material?: unknown;
|
|
154
225
|
} | null;
|
|
155
226
|
/**
|
|
156
227
|
* `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
|
|
@@ -268,4 +339,4 @@ declare function registerThree(options?: {
|
|
|
268
339
|
*/
|
|
269
340
|
declare function three(spec: ThreeSequenceSpec): SequenceSpec;
|
|
270
341
|
|
|
271
|
-
export { type ThreeContext, type ThreeFrameCameraOptions, type ThreeGltfModel, type ThreeGltfOptions, type ThreeRendererKind, ThreeSequence, type ThreeSequenceSpec, type ThreeSetupResult, registerThree, three, threeFrameCamera, threeGltf };
|
|
342
|
+
export { type ThreeContext, type ThreeFrameCameraOptions, type ThreeGltfModel, type ThreeGltfOptions, type ThreeLayerTexture, type ThreeLayerTextureOptions, type ThreeRendererKind, ThreeSequence, type ThreeSequenceSpec, type ThreeSetupResult, registerThree, three, threeFrameCamera, threeGltf, threeLayerTexture };
|
package/dist/three.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { Sequence, buildScope, evaluateExpr, registerSequenceType } from './chunk-
|
|
1
|
+
import { Sequence, buildScope, evaluateExpr, registerSequenceType } from './chunk-DM2OLQOJ.js';
|
|
2
2
|
import './chunk-32MMNDDN.js';
|
|
3
3
|
import './chunk-BXOCEZ4U.js';
|
|
4
|
-
import { Texture, Sprite, TextureSource } from 'pixi.js';
|
|
4
|
+
import { Texture, Sprite, TextureSource, RenderTexture, Matrix } from 'pixi.js';
|
|
5
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
|
|
@@ -189,6 +189,9 @@ var ThreeSequence = class extends Sequence {
|
|
|
189
189
|
_borrowed = null;
|
|
190
190
|
/** True once another layer owns this layer's state: destroying this one must not let it go. */
|
|
191
191
|
_donated = false;
|
|
192
|
+
/** Things to do just before every draw (the 2D layers shown on meshes: `threeLayerTexture`), and those layers' handles. Both go with the state to a layer that takes it over. */
|
|
193
|
+
_drawHooks = /* @__PURE__ */ new Set();
|
|
194
|
+
_layerTextures = [];
|
|
192
195
|
_scene = null;
|
|
193
196
|
_camera = null;
|
|
194
197
|
_ctx = null;
|
|
@@ -287,7 +290,7 @@ var ThreeSequence = class extends Sequence {
|
|
|
287
290
|
renderer.setClearColor(0, 0);
|
|
288
291
|
const scene = new Scene();
|
|
289
292
|
const camera = new PerspectiveCamera(50, width / height, 0.1, 2e3);
|
|
290
|
-
const ctx = { scene, camera, renderer, width, height };
|
|
293
|
+
const ctx = { scene, camera, renderer, width, height, _host: this._makeHost() };
|
|
291
294
|
if (spec.followCamera) this._checkFollowShape(width, height, spec.name);
|
|
292
295
|
let result;
|
|
293
296
|
try {
|
|
@@ -320,6 +323,29 @@ var ThreeSequence = class extends Sequence {
|
|
|
320
323
|
this.intrinsicHeight = height;
|
|
321
324
|
this.buildFilters();
|
|
322
325
|
}
|
|
326
|
+
/** The 2D layer that a material shows (`threeLayerTexture`), for a click on the mesh to reach it (movie.pick); null for any other material. */
|
|
327
|
+
screenOf(material) {
|
|
328
|
+
const handle = this._layerTextures.find((h) => h.material === material);
|
|
329
|
+
return handle ? { source: handle.source() } : null;
|
|
330
|
+
}
|
|
331
|
+
/** What `threeLayerTexture` asks of this layer: the layers listed before it, PixiJS's renderer, whether the GPU device is shared, and a place to hook in before every draw. */
|
|
332
|
+
_makeHost() {
|
|
333
|
+
return {
|
|
334
|
+
findLayer: (name) => this.parent?.findLayer?.(name) ?? null,
|
|
335
|
+
layerNames: () => this.parent?.layerNames?.() ?? [],
|
|
336
|
+
pixiRenderer: this.root.pixiRenderer ?? null,
|
|
337
|
+
shared: this.sharedGpu,
|
|
338
|
+
beforeDraw: (fn) => {
|
|
339
|
+
this._drawHooks.add(fn);
|
|
340
|
+
return () => {
|
|
341
|
+
this._drawHooks.delete(fn);
|
|
342
|
+
};
|
|
343
|
+
},
|
|
344
|
+
track: (handle) => {
|
|
345
|
+
this._layerTextures.push(handle);
|
|
346
|
+
}
|
|
347
|
+
};
|
|
348
|
+
}
|
|
323
349
|
/** Reuse (core/reuse.ts): the key this layer is matched by, while it can still lend its state. */
|
|
324
350
|
reuseKey() {
|
|
325
351
|
return this._renderer && !this._donated && !this._closing ? this._key : null;
|
|
@@ -345,6 +371,10 @@ var ThreeSequence = class extends Sequence {
|
|
|
345
371
|
this._fogMirror = d._fogMirror;
|
|
346
372
|
this._tracked = d._tracked;
|
|
347
373
|
this._borrowed = d;
|
|
374
|
+
this._drawHooks = d._drawHooks;
|
|
375
|
+
this._layerTextures = d._layerTextures;
|
|
376
|
+
const host = this._makeHost();
|
|
377
|
+
for (const h of this._layerTextures) h.rebind(host);
|
|
348
378
|
if (this.spec && this._threeSpec.followCamera) this._checkFollowShape(width, height, name);
|
|
349
379
|
this._makeSprite(this._texture, width, height, name);
|
|
350
380
|
}
|
|
@@ -402,7 +432,9 @@ var ThreeSequence = class extends Sequence {
|
|
|
402
432
|
name = n.name;
|
|
403
433
|
break;
|
|
404
434
|
}
|
|
405
|
-
|
|
435
|
+
const m = hit.object.material;
|
|
436
|
+
const material = Array.isArray(m) ? m[hit.face?.materialIndex ?? 0] : m;
|
|
437
|
+
return { object: name, point: hit.point.toArray(), distance: hit.distance, object3d: hit.object, ...hit.uv ? { uv: { u: hit.uv.x, v: hit.uv.y } } : {}, material };
|
|
406
438
|
}
|
|
407
439
|
return null;
|
|
408
440
|
}
|
|
@@ -573,6 +605,7 @@ var ThreeSequence = class extends Sequence {
|
|
|
573
605
|
*/
|
|
574
606
|
_draw(t, toCanvas = false) {
|
|
575
607
|
if (!this._renderer || !this._scene || !this._camera) return;
|
|
608
|
+
for (const hook of this._drawHooks) hook();
|
|
576
609
|
if (this._gpu) this._advanceNodeFrame(t);
|
|
577
610
|
if (!this._rt || toCanvas) {
|
|
578
611
|
this._renderer.render(this._scene, this._camera);
|
|
@@ -623,9 +656,9 @@ var ThreeSequence = class extends Sequence {
|
|
|
623
656
|
if (!m || typeof m !== "object" || seen.has(m)) return;
|
|
624
657
|
seen.add(m);
|
|
625
658
|
const mat = m;
|
|
626
|
-
const
|
|
627
|
-
if (mat.isShaderMaterial || mat.isRawShaderMaterial) bad.push(`${
|
|
628
|
-
else if (Object.prototype.hasOwnProperty.call(mat, "onBeforeCompile")) bad.push(`${
|
|
659
|
+
const label2 = `${mat.name ? `"${mat.name}" ` : ""}${mat.type ?? "material"}`;
|
|
660
|
+
if (mat.isShaderMaterial || mat.isRawShaderMaterial) bad.push(`${label2} is a ShaderMaterial (it cannot run on the WebGPU renderer)`);
|
|
661
|
+
else if (Object.prototype.hasOwnProperty.call(mat, "onBeforeCompile")) bad.push(`${label2} sets onBeforeCompile (the WebGPU renderer ignores it)`);
|
|
629
662
|
};
|
|
630
663
|
scene.traverse?.((o) => {
|
|
631
664
|
const mats = o.material;
|
|
@@ -722,6 +755,12 @@ var ThreeSequence = class extends Sequence {
|
|
|
722
755
|
}
|
|
723
756
|
const texture = this._texture;
|
|
724
757
|
if (!kept) {
|
|
758
|
+
for (const h of this._layerTextures) {
|
|
759
|
+
try {
|
|
760
|
+
h.dispose();
|
|
761
|
+
} catch {
|
|
762
|
+
}
|
|
763
|
+
}
|
|
725
764
|
this._lightMirror?.dispose();
|
|
726
765
|
this._fogMirror?.dispose();
|
|
727
766
|
this._disposeRenderer();
|
|
@@ -757,19 +796,19 @@ function idOf(fn) {
|
|
|
757
796
|
return id;
|
|
758
797
|
}
|
|
759
798
|
async function threeGltf(url, options = {}) {
|
|
760
|
-
const
|
|
761
|
-
if (typeof url !== "string" || !url) throw new Error(`${
|
|
799
|
+
const label2 = "pixi-effects: threeGltf";
|
|
800
|
+
if (typeof url !== "string" || !url) throw new Error(`${label2}: the first argument is the URL of a .glb or .gltf file`);
|
|
762
801
|
let GLTFLoader;
|
|
763
802
|
try {
|
|
764
803
|
({ GLTFLoader } = await import('three/addons/loaders/GLTFLoader.js'));
|
|
765
804
|
} catch (err) {
|
|
766
|
-
throw new Error(`${
|
|
805
|
+
throw new Error(`${label2}: needs "three/addons/" in the import map next to "three" (${err instanceof Error ? err.message : err})`);
|
|
767
806
|
}
|
|
768
807
|
let gltf;
|
|
769
808
|
try {
|
|
770
809
|
gltf = await new GLTFLoader().loadAsync(url);
|
|
771
810
|
} catch (err) {
|
|
772
|
-
throw new Error(`${
|
|
811
|
+
throw new Error(`${label2}: could not load "${url}" (${err instanceof Error ? err.message : err})`, { cause: err });
|
|
773
812
|
}
|
|
774
813
|
const clips = gltf.animations ?? [];
|
|
775
814
|
let clip;
|
|
@@ -778,7 +817,7 @@ async function threeGltf(url, options = {}) {
|
|
|
778
817
|
else if (wanted === void 0) clip = clips[0];
|
|
779
818
|
else {
|
|
780
819
|
clip = typeof wanted === "number" ? clips[wanted] : clips.find((c) => c.name === wanted);
|
|
781
|
-
if (!clip) throw new Error(`${
|
|
820
|
+
if (!clip) throw new Error(`${label2}: "${url}" has no animation ${JSON.stringify(wanted)}; its clips: ${clips.length ? clips.map((c, i) => `${i}: "${c.name}"`).join(", ") : "(none)"}`);
|
|
782
821
|
}
|
|
783
822
|
const root = gltf.scene;
|
|
784
823
|
root.traverse((o) => {
|
|
@@ -840,6 +879,145 @@ function threeFrameCamera(camera, object, options = {}) {
|
|
|
840
879
|
cam.lookAt(centre);
|
|
841
880
|
cam.updateProjectionMatrix();
|
|
842
881
|
}
|
|
882
|
+
var label = "pixi-effects: threeLayerTexture";
|
|
883
|
+
async function threeLayerTexture(ctx, name, options = {}) {
|
|
884
|
+
const host = ctx._host;
|
|
885
|
+
if (!host) throw new Error(`${label}: call it from the setup of a three layer: const screen = await threeLayerTexture(ctx, 'screen')`);
|
|
886
|
+
if (typeof name !== "string" || !name) throw new Error(`${label}: the second argument is the name of a 2D layer: threeLayerTexture(ctx, 'screen')`);
|
|
887
|
+
const resolution = options.resolution ?? 1;
|
|
888
|
+
const transparent = options.transparent === true;
|
|
889
|
+
if (!(Number.isFinite(resolution) && resolution > 0 && resolution <= 4)) throw new Error(`${label}: resolution is a number from above 0 to 4 (2 = twice the pixels), got ${JSON.stringify(options.resolution)}`);
|
|
890
|
+
const pixi = host.pixiRenderer;
|
|
891
|
+
if (!pixi) throw new Error(`${label}: PixiJS's renderer is not available here (the movie is not ready)`);
|
|
892
|
+
const source = host.findLayer(name);
|
|
893
|
+
if (!source) {
|
|
894
|
+
const names = host.layerNames();
|
|
895
|
+
throw new Error(`${label}: no layer named "${name}" before this three layer${names.length ? ` (the layers built before it: ${names.map((n) => `"${n}"`).join(", ")})` : ""}. A layer shown on a mesh must be listed BEFORE the three layer, in the same composition, and have that name.`);
|
|
896
|
+
}
|
|
897
|
+
if (source.spec.type !== "composition") {
|
|
898
|
+
throw new Error(`${label}: "${name}" is a ${source.spec.type} layer: a layer shown on a mesh must be a composition (wrap it: { type: 'composition', name: '${name}', width: 480, height: 270, sequences: [ \u2026 ] })`);
|
|
899
|
+
}
|
|
900
|
+
const width = Math.max(1, Math.round(source.intrinsicWidth * resolution)), height = Math.max(1, Math.round(source.intrinsicHeight * resolution));
|
|
901
|
+
const sharedRoute = host.shared && pixi.name === "webgpu";
|
|
902
|
+
const rt = RenderTexture.create({ width, height, resolution: 1, ...sharedRoute ? { autoGenerateMipmaps: true } : {} });
|
|
903
|
+
const gpuTexture = sharedRoute ? pixi.texture.getGpuSource?.(rt.source) : void 0;
|
|
904
|
+
let texture, material, readCanvas = null;
|
|
905
|
+
if (gpuTexture) {
|
|
906
|
+
let webgpu, tsl;
|
|
907
|
+
try {
|
|
908
|
+
[webgpu, tsl] = await Promise.all([import('three/webgpu'), import('three/tsl')]);
|
|
909
|
+
} catch (err) {
|
|
910
|
+
throw new Error(`${label}: needs "three/webgpu" and "three/tsl" in the import map (${err instanceof Error ? err.message : err})`);
|
|
911
|
+
}
|
|
912
|
+
const ext = new webgpu.ExternalTexture(gpuTexture);
|
|
913
|
+
ext.colorSpace = webgpu.NoColorSpace;
|
|
914
|
+
ext.minFilter = webgpu.LinearMipmapLinearFilter;
|
|
915
|
+
ext.magFilter = webgpu.LinearFilter;
|
|
916
|
+
ext.generateMipmaps = false;
|
|
917
|
+
ext.anisotropy = 4;
|
|
918
|
+
ext.repeat.set(1, -1);
|
|
919
|
+
ext.offset.set(0, 1);
|
|
920
|
+
const m = new webgpu.MeshBasicNodeMaterial();
|
|
921
|
+
const t = tsl.texture(ext);
|
|
922
|
+
const tex = t, vec4 = tsl.vec4, eotf = tsl.sRGBTransferEOTF, max = tsl.max;
|
|
923
|
+
const straight = eotf(vec4(tex.rgb.div(max(tex.a, 1e-4)), 1));
|
|
924
|
+
m.colorNode = transparent ? vec4(straight.rgb, tex.a) : vec4(eotf(vec4(tex.rgb, 1)).rgb, 1);
|
|
925
|
+
m.toneMapped = false;
|
|
926
|
+
if (transparent) {
|
|
927
|
+
m.transparent = true;
|
|
928
|
+
m.depthWrite = false;
|
|
929
|
+
}
|
|
930
|
+
texture = ext;
|
|
931
|
+
material = m;
|
|
932
|
+
} else {
|
|
933
|
+
const three2 = await import('three');
|
|
934
|
+
readCanvas = document.createElement("canvas");
|
|
935
|
+
readCanvas.width = width;
|
|
936
|
+
readCanvas.height = height;
|
|
937
|
+
const ct = new three2.CanvasTexture(readCanvas);
|
|
938
|
+
ct.colorSpace = three2.SRGBColorSpace;
|
|
939
|
+
texture = ct;
|
|
940
|
+
material = new three2.MeshBasicMaterial({ map: ct, toneMapped: false, ...transparent ? { transparent: true, depthWrite: false } : {} });
|
|
941
|
+
}
|
|
942
|
+
let current = source;
|
|
943
|
+
let display = source.target;
|
|
944
|
+
let sx = width / source.intrinsicWidth, sy = height / source.intrinsicHeight;
|
|
945
|
+
let hidden = false;
|
|
946
|
+
const hide = () => {
|
|
947
|
+
display.visible = false;
|
|
948
|
+
hidden = true;
|
|
949
|
+
};
|
|
950
|
+
hide();
|
|
951
|
+
const uncull = (c) => {
|
|
952
|
+
if (c.culled) c.culled = false;
|
|
953
|
+
for (const k of c.children) uncull(k);
|
|
954
|
+
};
|
|
955
|
+
const refresh = () => {
|
|
956
|
+
const m = new Matrix().scale(sx, sy);
|
|
957
|
+
display.visible = true;
|
|
958
|
+
uncull(display);
|
|
959
|
+
try {
|
|
960
|
+
pixi.render({ container: display, target: rt, transform: m, clear: true, clearColor: [0, 0, 0, 0] });
|
|
961
|
+
} finally {
|
|
962
|
+
display.visible = false;
|
|
963
|
+
}
|
|
964
|
+
if (gpuTexture) rt.source.updateMipmaps();
|
|
965
|
+
if (readCanvas) {
|
|
966
|
+
const g = readCanvas.getContext("2d");
|
|
967
|
+
if (transparent) {
|
|
968
|
+
const { pixels, width: w, height: h } = pixi.extract.pixels(rt);
|
|
969
|
+
for (let i = 0; i < pixels.length; i += 4) {
|
|
970
|
+
const a = pixels[i + 3];
|
|
971
|
+
if (a > 0 && a < 255) {
|
|
972
|
+
const k = 255 / a;
|
|
973
|
+
pixels[i] = pixels[i] * k;
|
|
974
|
+
pixels[i + 1] = pixels[i + 1] * k;
|
|
975
|
+
pixels[i + 2] = pixels[i + 2] * k;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
g.putImageData(new ImageData(pixels, w, h), 0, 0);
|
|
979
|
+
} else {
|
|
980
|
+
g.clearRect(0, 0, width, height);
|
|
981
|
+
g.drawImage(pixi.extract.canvas(rt), 0, 0);
|
|
982
|
+
}
|
|
983
|
+
texture.needsUpdate = true;
|
|
984
|
+
}
|
|
985
|
+
};
|
|
986
|
+
const stop = host.beforeDraw(refresh);
|
|
987
|
+
refresh();
|
|
988
|
+
const handle = {
|
|
989
|
+
material,
|
|
990
|
+
texture,
|
|
991
|
+
width,
|
|
992
|
+
height,
|
|
993
|
+
source: () => current,
|
|
994
|
+
rebind(next) {
|
|
995
|
+
const again = next.findLayer(name);
|
|
996
|
+
if (!again) throw new Error(`${label}: after a rebuild there is no layer "${name}" before the three layer any more`);
|
|
997
|
+
current = again;
|
|
998
|
+
display = again.target;
|
|
999
|
+
sx = width / again.intrinsicWidth;
|
|
1000
|
+
sy = height / again.intrinsicHeight;
|
|
1001
|
+
hide();
|
|
1002
|
+
refresh();
|
|
1003
|
+
},
|
|
1004
|
+
dispose() {
|
|
1005
|
+
stop();
|
|
1006
|
+
if (hidden) {
|
|
1007
|
+
display.visible = true;
|
|
1008
|
+
hidden = false;
|
|
1009
|
+
}
|
|
1010
|
+
try {
|
|
1011
|
+
rt.destroy(true);
|
|
1012
|
+
} catch {
|
|
1013
|
+
}
|
|
1014
|
+
texture.dispose?.();
|
|
1015
|
+
material.dispose?.();
|
|
1016
|
+
}
|
|
1017
|
+
};
|
|
1018
|
+
host.track(handle);
|
|
1019
|
+
return handle;
|
|
1020
|
+
}
|
|
843
1021
|
|
|
844
1022
|
// src/three/index.ts
|
|
845
1023
|
function registerThree(options = {}) {
|
|
@@ -852,6 +1030,6 @@ function three(spec) {
|
|
|
852
1030
|
return spec;
|
|
853
1031
|
}
|
|
854
1032
|
|
|
855
|
-
export { ThreeSequence, registerThree, three, threeFrameCamera, threeGltf };
|
|
1033
|
+
export { ThreeSequence, registerThree, three, threeFrameCamera, threeGltf, threeLayerTexture };
|
|
856
1034
|
//# sourceMappingURL=three.js.map
|
|
857
1035
|
//# sourceMappingURL=three.js.map
|