@pixi-ui-editor/runtime-pixi 0.6.0 → 0.6.1
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/dist/particles.d.ts +5 -2
- package/dist/particles.d.ts.map +1 -1
- package/dist/particles.js +57 -12
- package/dist/particles.js.map +1 -1
- package/dist/scene.d.ts.map +1 -1
- package/dist/scene.js +20 -2
- package/dist/scene.js.map +1 -1
- package/dist/views/NodeView.d.ts +2 -2
- package/dist/views/NodeView.d.ts.map +1 -1
- package/dist/views/NodeView.js.map +1 -1
- package/dist/views/ParticleEmitterNodeView.d.ts +13 -0
- package/dist/views/ParticleEmitterNodeView.d.ts.map +1 -1
- package/dist/views/ParticleEmitterNodeView.js +164 -32
- package/dist/views/ParticleEmitterNodeView.js.map +1 -1
- package/package.json +2 -2
package/dist/particles.d.ts
CHANGED
|
@@ -20,6 +20,8 @@ export declare function sampleSpawnPoint(shape: ParticleSpawnShape, width: numbe
|
|
|
20
20
|
/** A prewarmed pool entry: `render` is an opaque adapter-owned renderer object created by the same factory as the simulation slot. */
|
|
21
21
|
export type ParticleSlot<TRender> = {
|
|
22
22
|
render: TRender;
|
|
23
|
+
/** Adapter-owned static attributes must be uploaded once after this slot is (re)spawned. */
|
|
24
|
+
renderDirty: boolean;
|
|
23
25
|
age: number;
|
|
24
26
|
lifetime: number;
|
|
25
27
|
x: number;
|
|
@@ -113,6 +115,7 @@ export declare class ParticleSimulator<TRender> {
|
|
|
113
115
|
private multiplier;
|
|
114
116
|
private emitting;
|
|
115
117
|
private simulating;
|
|
118
|
+
private stopped;
|
|
116
119
|
private disposed;
|
|
117
120
|
private context;
|
|
118
121
|
constructor(definition: ParticleEffectDefinition, hooks: ParticleRenderHooks<TRender>);
|
|
@@ -129,8 +132,8 @@ export declare class ParticleSimulator<TRender> {
|
|
|
129
132
|
/** Idempotent terminal cleanup: destroys every pooled render object and excludes the view from further updates. */
|
|
130
133
|
dispose(): void;
|
|
131
134
|
/** Advances exactly one fixed step regardless of paused/stopped state, and never changes it. */
|
|
132
|
-
step(context: ParticleSpawnContext):
|
|
133
|
-
update(deltaSeconds: number, context: ParticleSpawnContext):
|
|
135
|
+
step(context: ParticleSpawnContext): boolean;
|
|
136
|
+
update(deltaSeconds: number, context: ParticleSpawnContext): boolean;
|
|
134
137
|
getDiagnostics(): ParticleDiagnostics;
|
|
135
138
|
private tick;
|
|
136
139
|
private spawnParticle;
|
package/dist/particles.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"particles.d.ts","sourceRoot":"","sources":["../src/particles.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAIvE,gFAAgF;AAChF,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAS;gBACV,IAAI,EAAE,MAAM;IACxB,IAAI,IAAI,MAAM;IACd,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM;IACvC,2EAA2E;IAC3E,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;CAC9B;AAED,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAA4B;AAGzF,qGAAqG;AACrG,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAG1E;AAED,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,WAAW,GAAG,QAAQ,CAAC;AAElE,yIAAyI;AACzI,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAOzI;AAED,sIAAsI;AACtI,MAAM,MAAM,YAAY,CAAC,OAAO,IAAI;IAClC,MAAM,EAAE,OAAO,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,2FAA2F;IAC3F,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,sBAAsB,EAAE,MAAM,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,aAAa,EAAE,MAAM,CAAC;IACtB,iKAAiK;IACjK,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;
|
|
1
|
+
{"version":3,"file":"particles.d.ts","sourceRoot":"","sources":["../src/particles.ts"],"names":[],"mappings":"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"}
|
package/dist/particles.js
CHANGED
|
@@ -27,9 +27,32 @@ export function sampleSpawnPoint(shape, width, height, random) {
|
|
|
27
27
|
return { x: cx + Math.cos(angle) * radius * cx, y: cy + Math.sin(angle) * radius * cy };
|
|
28
28
|
}
|
|
29
29
|
function createZeroedSlot(render) {
|
|
30
|
-
return { render, age: 0, lifetime: 0, x: 0, y: 0, vx: 0, vy: 0, spawnX: 0, spawnY: 0, rotationDegrees: 0, angularVelocityDegrees: 0, scaleStart: 1, scaleEnd: 1, sourceIndex: 0, sequenceStart: 0, worldSpawnX: 0, worldSpawnY: 0, spawnMatrixA: 1, spawnMatrixB: 0, spawnMatrixC: 0, spawnMatrixD: 1 };
|
|
30
|
+
return { render, renderDirty: false, age: 0, lifetime: 0, x: 0, y: 0, vx: 0, vy: 0, spawnX: 0, spawnY: 0, rotationDegrees: 0, angularVelocityDegrees: 0, scaleStart: 1, scaleEnd: 1, sourceIndex: 0, sequenceStart: 0, worldSpawnX: 0, worldSpawnY: 0, spawnMatrixA: 1, spawnMatrixB: 0, spawnMatrixC: 0, spawnMatrixD: 1 };
|
|
31
|
+
}
|
|
32
|
+
function resetSlot(slot) {
|
|
33
|
+
// Hot release path: reset in place instead of allocating a temporary zeroed slot for Object.assign.
|
|
34
|
+
slot.renderDirty = false;
|
|
35
|
+
slot.age = 0;
|
|
36
|
+
slot.lifetime = 0;
|
|
37
|
+
slot.x = 0;
|
|
38
|
+
slot.y = 0;
|
|
39
|
+
slot.vx = 0;
|
|
40
|
+
slot.vy = 0;
|
|
41
|
+
slot.spawnX = 0;
|
|
42
|
+
slot.spawnY = 0;
|
|
43
|
+
slot.rotationDegrees = 0;
|
|
44
|
+
slot.angularVelocityDegrees = 0;
|
|
45
|
+
slot.scaleStart = 1;
|
|
46
|
+
slot.scaleEnd = 1;
|
|
47
|
+
slot.sourceIndex = 0;
|
|
48
|
+
slot.sequenceStart = 0;
|
|
49
|
+
slot.worldSpawnX = 0;
|
|
50
|
+
slot.worldSpawnY = 0;
|
|
51
|
+
slot.spawnMatrixA = 1;
|
|
52
|
+
slot.spawnMatrixB = 0;
|
|
53
|
+
slot.spawnMatrixC = 0;
|
|
54
|
+
slot.spawnMatrixD = 1;
|
|
31
55
|
}
|
|
32
|
-
function resetSlot(slot) { Object.assign(slot, createZeroedSlot(slot.render)); }
|
|
33
56
|
/**
|
|
34
57
|
* Prewarmed object pool. `acquire`/`release` never call the factory; only `resize` does, and only for
|
|
35
58
|
* the capacity delta. Shrinking removes idle free slots immediately; active slots beyond the new
|
|
@@ -112,6 +135,7 @@ export class ParticleSimulator {
|
|
|
112
135
|
multiplier = 1;
|
|
113
136
|
emitting = false;
|
|
114
137
|
simulating = false;
|
|
138
|
+
stopped = false;
|
|
115
139
|
disposed = false;
|
|
116
140
|
context = { width: 0, height: 0, space: "local" };
|
|
117
141
|
constructor(definition, hooks) {
|
|
@@ -136,13 +160,18 @@ export class ParticleSimulator {
|
|
|
136
160
|
this.burstCursors = cursors;
|
|
137
161
|
}
|
|
138
162
|
play() { if (this.disposed)
|
|
139
|
-
return; this.emitting = true; this.simulating = true; }
|
|
163
|
+
return; this.emitting = true; this.simulating = true; this.stopped = false; }
|
|
140
164
|
/** Freezes emission and every live particle without resetting time or PRNG. */
|
|
141
165
|
pause() { if (this.disposed)
|
|
142
|
-
return; this.emitting = false; this.simulating = false; }
|
|
166
|
+
return; this.emitting = false; this.simulating = false; this.stopped = false; }
|
|
143
167
|
/** Stops new spawns; already-emitted particles keep simulating to their natural death. */
|
|
144
|
-
stop() {
|
|
145
|
-
|
|
168
|
+
stop() {
|
|
169
|
+
if (this.disposed)
|
|
170
|
+
return;
|
|
171
|
+
this.emitting = false;
|
|
172
|
+
this.simulating = this.pool.values.size > 0;
|
|
173
|
+
this.stopped = true;
|
|
174
|
+
}
|
|
146
175
|
restart() {
|
|
147
176
|
if (this.disposed)
|
|
148
177
|
return;
|
|
@@ -156,6 +185,7 @@ export class ParticleSimulator {
|
|
|
156
185
|
this.random = new SeededRandom(this.definition.seed);
|
|
157
186
|
this.emitting = true;
|
|
158
187
|
this.simulating = true;
|
|
188
|
+
this.stopped = false;
|
|
159
189
|
}
|
|
160
190
|
/** Idempotent terminal cleanup: destroys every pooled render object and excludes the view from further updates. */
|
|
161
191
|
dispose() {
|
|
@@ -164,34 +194,39 @@ export class ParticleSimulator {
|
|
|
164
194
|
this.disposed = true;
|
|
165
195
|
this.emitting = false;
|
|
166
196
|
this.simulating = false;
|
|
197
|
+
this.stopped = false;
|
|
167
198
|
this.pool.clear();
|
|
168
199
|
}
|
|
169
200
|
/** Advances exactly one fixed step regardless of paused/stopped state, and never changes it. */
|
|
170
201
|
step(context) {
|
|
171
202
|
if (this.disposed)
|
|
172
|
-
return;
|
|
203
|
+
return false;
|
|
173
204
|
this.context = context;
|
|
174
205
|
this.tick(ParticleSimulator.stepSeconds);
|
|
206
|
+
return true;
|
|
175
207
|
}
|
|
176
208
|
update(deltaSeconds, context) {
|
|
177
209
|
if (this.disposed || !this.simulating)
|
|
178
|
-
return;
|
|
210
|
+
return false;
|
|
179
211
|
this.context = context;
|
|
180
212
|
this.stepAccumulator = Math.min(this.stepAccumulator + Math.max(0, deltaSeconds), ParticleSimulator.stepSeconds * 8);
|
|
213
|
+
let advanced = false;
|
|
181
214
|
while (this.stepAccumulator >= ParticleSimulator.stepSeconds) {
|
|
182
215
|
this.stepAccumulator -= ParticleSimulator.stepSeconds;
|
|
183
216
|
this.tick(ParticleSimulator.stepSeconds);
|
|
217
|
+
advanced = true;
|
|
184
218
|
}
|
|
219
|
+
return advanced;
|
|
185
220
|
}
|
|
186
221
|
getDiagnostics() {
|
|
187
|
-
return { active: this.pool.values.size, dropped: this.pool.dropped, playing: this.emitting, stopped: this.
|
|
222
|
+
return { active: this.pool.values.size, dropped: this.pool.dropped, playing: this.emitting, stopped: this.stopped && !this.disposed, disposed: this.disposed };
|
|
188
223
|
}
|
|
189
224
|
tick(dt) {
|
|
190
225
|
// Age and move existing particles before spawning: a particle created this tick starts at age 0
|
|
191
226
|
// and receives its first dt on the next tick, instead of being silently pre-aged by one step.
|
|
192
227
|
const movement = this.definition.particle.movement;
|
|
193
228
|
const drag = Math.max(0, 1 - movement.drag * dt);
|
|
194
|
-
for (const slot of
|
|
229
|
+
for (const slot of this.pool.values) {
|
|
195
230
|
slot.age += dt;
|
|
196
231
|
if (slot.age >= slot.lifetime) {
|
|
197
232
|
this.releaseSlot(slot);
|
|
@@ -216,7 +251,8 @@ export class ParticleSimulator {
|
|
|
216
251
|
this.spawnParticle();
|
|
217
252
|
}
|
|
218
253
|
}
|
|
219
|
-
e.bursts.
|
|
254
|
+
for (let index = 0; index < e.bursts.length; index++) {
|
|
255
|
+
const burst = e.bursts[index];
|
|
220
256
|
const triggerBase = e.delay + burst.time;
|
|
221
257
|
for (;;) {
|
|
222
258
|
const cursor = this.burstCursors[index] ?? 0;
|
|
@@ -229,8 +265,16 @@ export class ParticleSimulator {
|
|
|
229
265
|
this.spawnParticle();
|
|
230
266
|
this.burstCursors[index] = cursor + 1;
|
|
231
267
|
}
|
|
232
|
-
}
|
|
268
|
+
}
|
|
269
|
+
if (!e.loop && this.elapsed >= e.delay + e.duration) {
|
|
270
|
+
this.emitting = false;
|
|
271
|
+
this.stopped = true;
|
|
272
|
+
}
|
|
233
273
|
}
|
|
274
|
+
// A completed one-shot or a graceful stop must not keep an otherwise idle emitter on the hot
|
|
275
|
+
// ticker path forever. Preserve the stopped diagnostic while putting simulation fully to sleep.
|
|
276
|
+
if (!this.emitting && this.pool.values.size === 0)
|
|
277
|
+
this.simulating = false;
|
|
234
278
|
}
|
|
235
279
|
spawnParticle() {
|
|
236
280
|
const slot = this.pool.acquire();
|
|
@@ -239,6 +283,7 @@ export class ParticleSimulator {
|
|
|
239
283
|
const p = this.definition.particle;
|
|
240
284
|
const rand = this.random;
|
|
241
285
|
const point = sampleSpawnPoint(p.spawnShape.type, this.context.width, this.context.height, rand);
|
|
286
|
+
slot.renderDirty = true;
|
|
242
287
|
slot.age = 0;
|
|
243
288
|
slot.lifetime = rand.range(p.lifetime.min, p.lifetime.max);
|
|
244
289
|
slot.spawnX = point.x;
|
package/dist/particles.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"particles.js","sourceRoot":"","sources":["../src/particles.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ParticleEffectDefinition } from \"@pixi-ui-editor/schema\";\r\n\r\nconst DEG_TO_RAD = Math.PI / 180;\r\n\r\n/** Deterministic xorshift32 generator; it has no DOM/Pixi/ticker dependency. */\r\nexport class SeededRandom {\r\n private state: number;\r\n constructor(seed: number) { this.state = seed === 0 ? 0x9e3779b9 : seed >>> 0; }\r\n next(): number { this.state ^= this.state << 13; this.state ^= this.state >>> 17; this.state ^= this.state << 5; return (this.state >>> 0) / 0x1_0000_0000; }\r\n range(min: number, max: number): number { return min + (max - min) * this.next(); }\r\n /** A uniform index in `[0, length)`; used to pick a random asset/frame. */\r\n index(length: number): number { return Math.min(length - 1, Math.floor(this.next() * length)); }\r\n}\r\n\r\nexport function lerp(a: number, b: number, t: number): number { return a + (b - a) * t; }\r\n\r\nfunction hexChannel(hex: string, offset: number): number { return parseInt(hex.slice(offset, offset + 2), 16); }\r\n/** Lerps two `#RRGGBB[AA]` strings channel-by-channel; a trailing alpha byte, if any, is ignored. */\r\nexport function lerpColorHex(start: string, end: string, t: number): string {\r\n const channel = (offset: number) => Math.round(lerp(hexChannel(start, offset), hexChannel(end, offset), t)).toString(16).padStart(2, \"0\");\r\n return `#${channel(1)}${channel(3)}${channel(5)}`;\r\n}\r\n\r\nexport type ParticleSpawnShape = \"point\" | \"rectangle\" | \"circle\";\r\n\r\n/** `point` returns the rect centre; `rectangle` is uniform over the area; `circle` is uniform over the ellipse inscribed in the rect. */\r\nexport function sampleSpawnPoint(shape: ParticleSpawnShape, width: number, height: number, random: SeededRandom): { x: number; y: number } {\r\n const cx = width / 2, cy = height / 2;\r\n if (shape === \"point\") return { x: cx, y: cy };\r\n if (shape === \"rectangle\") return { x: random.next() * width, y: random.next() * height };\r\n const angle = random.next() * Math.PI * 2;\r\n const radius = Math.sqrt(random.next());\r\n return { x: cx + Math.cos(angle) * radius * cx, y: cy + Math.sin(angle) * radius * cy };\r\n}\r\n\r\n/** A prewarmed pool entry: `render` is an opaque adapter-owned renderer object created by the same factory as the simulation slot. */\r\nexport type ParticleSlot<TRender> = {\r\n render: TRender;\r\n age: number;\r\n lifetime: number;\r\n x: number;\r\n y: number;\r\n vx: number;\r\n vy: number;\r\n /** Spawn-local position; used to derive the physics delta for world-space reprojection. */\r\n spawnX: number;\r\n spawnY: number;\r\n rotationDegrees: number;\r\n angularVelocityDegrees: number;\r\n scaleStart: number;\r\n scaleEnd: number;\r\n /** Index into `random`/`sequence` source `assetIds`, picked once at spawn. */\r\n sourceIndex: number;\r\n /** Starting frame offset for a `sequence` source with `randomStartFrame`. */\r\n sequenceStart: number;\r\n /** World-space spawn position and the linear (rotate+scale) part of the emitter's world transform at spawn time; only meaningful for `world` space particles. */\r\n worldSpawnX: number;\r\n worldSpawnY: number;\r\n spawnMatrixA: number;\r\n spawnMatrixB: number;\r\n spawnMatrixC: number;\r\n spawnMatrixD: number;\r\n};\r\n\r\nfunction createZeroedSlot<TRender>(render: TRender): ParticleSlot<TRender> {\r\n return { render, age: 0, lifetime: 0, x: 0, y: 0, vx: 0, vy: 0, spawnX: 0, spawnY: 0, rotationDegrees: 0, angularVelocityDegrees: 0, scaleStart: 1, scaleEnd: 1, sourceIndex: 0, sequenceStart: 0, worldSpawnX: 0, worldSpawnY: 0, spawnMatrixA: 1, spawnMatrixB: 0, spawnMatrixC: 0, spawnMatrixD: 1 };\r\n}\r\nfunction resetSlot<TRender>(slot: ParticleSlot<TRender>): void { Object.assign(slot, createZeroedSlot(slot.render)); }\r\n\r\n/**\r\n * Prewarmed object pool. `acquire`/`release` never call the factory; only `resize` does, and only for\r\n * the capacity delta. Shrinking removes idle free slots immediately; active slots beyond the new\r\n * capacity keep running and are permanently destroyed (via `onRemove`, never recycled) the next time\r\n * they are released instead of returning to the free list.\r\n */\r\nexport class ParticlePool<T> {\r\n private readonly free: T[] = [];\r\n private readonly active = new Set<T>();\r\n private capacity: number;\r\n public dropped = 0;\r\n constructor(private readonly factory: () => T, capacity: number, private readonly onRemove?: (value: T) => void) {\r\n this.capacity = capacity;\r\n for (let i = 0; i < capacity; i++) this.free.push(factory());\r\n }\r\n acquire(): T | undefined {\r\n const value = this.free.pop();\r\n if (value === undefined) { this.dropped++; return undefined; }\r\n this.active.add(value);\r\n return value;\r\n }\r\n release(value: T): void {\r\n if (!this.active.has(value)) return;\r\n const overCapacity = this.free.length + this.active.size > this.capacity;\r\n this.active.delete(value);\r\n if (overCapacity) this.onRemove?.(value);\r\n else this.free.push(value);\r\n }\r\n resize(capacity: number): void {\r\n if (capacity > this.capacity) {\r\n const total = this.free.length + this.active.size;\r\n for (let i = total; i < capacity; i++) this.free.push(this.factory());\r\n } else if (capacity < this.capacity) {\r\n while (this.free.length + this.active.size > capacity && this.free.length > 0) this.onRemove?.(this.free.pop()!);\r\n }\r\n this.capacity = capacity;\r\n }\r\n /** Permanently destroys every slot, free and active alike; used by `dispose()`. */\r\n clear(): void {\r\n for (const value of this.free.splice(0, this.free.length)) this.onRemove?.(value);\r\n for (const value of this.active) this.onRemove?.(value);\r\n this.active.clear();\r\n this.capacity = 0;\r\n }\r\n get values(): ReadonlySet<T> { return this.active; }\r\n get limit(): number { return this.capacity; }\r\n}\r\n\r\nexport type ParticleSpawnContext = { width: number; height: number; space: \"local\" | \"world\" };\r\nexport type ParticleDiagnostics = { active: number; dropped: number; playing: boolean; stopped: boolean; disposed: boolean };\r\n\r\n/** Adapter-supplied, renderer-specific operations. The simulator never imports Pixi. */\r\nexport type ParticleRenderHooks<TRender> = {\r\n createRender(): TRender;\r\n hideRender(render: TRender): void;\r\n destroyRender(render: TRender): void;\r\n /** The emitter's current world transform linear part `{a,b,c,d}` and translation `{tx,ty}`; read only when a `world`-space particle spawns. */\r\n getWorldTransform(): { a: number; b: number; c: number; d: number; tx: number; ty: number };\r\n};\r\n\r\n/**\r\n * Schema-neutral, deterministic particle simulation over a prewarmed pool. Owns lifecycle\r\n * (`play`/`pause`/`step`/`restart`/`stop`/`dispose`), fixed-step ticking, seeded spawn parameters and\r\n * burst/rate scheduling. Rendering (texture, tint, local/world projection) is the adapter's job; this\r\n * class only exposes the pool's active slots and the effect definition for it to read.\r\n */\r\nexport class ParticleSimulator<TRender> {\r\n static readonly stepSeconds = 1 / 60;\r\n private readonly pool: ParticlePool<ParticleSlot<TRender>>;\r\n private random: SeededRandom;\r\n private elapsed = 0;\r\n private stepAccumulator = 0;\r\n private emissionAccumulator = 0;\r\n private burstCursors: number[];\r\n private multiplier = 1;\r\n private emitting = false;\r\n private simulating = false;\r\n private disposed = false;\r\n private context: ParticleSpawnContext = { width: 0, height: 0, space: \"local\" };\r\n\r\n constructor(public definition: ParticleEffectDefinition, private readonly hooks: ParticleRenderHooks<TRender>) {\r\n this.random = new SeededRandom(definition.seed);\r\n this.burstCursors = definition.emission.bursts.map(() => 0);\r\n this.pool = new ParticlePool<ParticleSlot<TRender>>(\r\n () => createZeroedSlot(hooks.createRender()),\r\n definition.maxParticles,\r\n (slot) => hooks.destroyRender(slot.render),\r\n );\r\n }\r\n\r\n get activeSlots(): ReadonlySet<ParticleSlot<TRender>> { return this.pool.values; }\r\n\r\n setEmissionMultiplier(value: number): void {\r\n if (!Number.isFinite(value) || value < 0) throw new RangeError(\"Emission multiplier must be finite and non-negative.\");\r\n this.multiplier = value;\r\n }\r\n\r\n /** Adopts a new definition reference without ever comparing identity: unrelated edits, seed changes and texture changes never reset accumulator, PRNG or live particles. Only `maxParticles` triggers a pool resize. */\r\n syncEffect(effect: ParticleEffectDefinition): void {\r\n this.definition = effect;\r\n if (this.pool.limit !== effect.maxParticles) this.pool.resize(effect.maxParticles);\r\n const cursors = effect.emission.bursts.map((_, index) => this.burstCursors[index] ?? 0);\r\n this.burstCursors = cursors;\r\n }\r\n\r\n play(): void { if (this.disposed) return; this.emitting = true; this.simulating = true; }\r\n /** Freezes emission and every live particle without resetting time or PRNG. */\r\n pause(): void { if (this.disposed) return; this.emitting = false; this.simulating = false; }\r\n /** Stops new spawns; already-emitted particles keep simulating to their natural death. */\r\n stop(): void { if (this.disposed) return; this.emitting = false; this.simulating = true; }\r\n\r\n restart(): void {\r\n if (this.disposed) return;\r\n for (const slot of [...this.pool.values]) this.releaseSlot(slot);\r\n this.elapsed = 0;\r\n this.stepAccumulator = 0;\r\n this.emissionAccumulator = 0;\r\n this.burstCursors = this.definition.emission.bursts.map(() => 0);\r\n this.pool.dropped = 0;\r\n this.random = new SeededRandom(this.definition.seed);\r\n this.emitting = true;\r\n this.simulating = true;\r\n }\r\n\r\n /** Idempotent terminal cleanup: destroys every pooled render object and excludes the view from further updates. */\r\n dispose(): void {\r\n if (this.disposed) return;\r\n this.disposed = true;\r\n this.emitting = false;\r\n this.simulating = false;\r\n this.pool.clear();\r\n }\r\n\r\n /** Advances exactly one fixed step regardless of paused/stopped state, and never changes it. */\r\n step(context: ParticleSpawnContext): void {\r\n if (this.disposed) return;\r\n this.context = context;\r\n this.tick(ParticleSimulator.stepSeconds);\r\n }\r\n\r\n update(deltaSeconds: number, context: ParticleSpawnContext): void {\r\n if (this.disposed || !this.simulating) return;\r\n this.context = context;\r\n this.stepAccumulator = Math.min(this.stepAccumulator + Math.max(0, deltaSeconds), ParticleSimulator.stepSeconds * 8);\r\n while (this.stepAccumulator >= ParticleSimulator.stepSeconds) {\r\n this.stepAccumulator -= ParticleSimulator.stepSeconds;\r\n this.tick(ParticleSimulator.stepSeconds);\r\n }\r\n }\r\n\r\n getDiagnostics(): ParticleDiagnostics {\r\n return { active: this.pool.values.size, dropped: this.pool.dropped, playing: this.emitting, stopped: this.simulating && !this.emitting && !this.disposed, disposed: this.disposed };\r\n }\r\n\r\n private tick(dt: number): void {\r\n // Age and move existing particles before spawning: a particle created this tick starts at age 0\r\n // and receives its first dt on the next tick, instead of being silently pre-aged by one step.\r\n const movement = this.definition.particle.movement;\r\n const drag = Math.max(0, 1 - movement.drag * dt);\r\n for (const slot of [...this.pool.values]) {\r\n slot.age += dt;\r\n if (slot.age >= slot.lifetime) { this.releaseSlot(slot); continue; }\r\n slot.vx = (slot.vx + movement.accelerationX * dt) * drag;\r\n slot.vy = (slot.vy + movement.accelerationY * dt) * drag;\r\n slot.x += slot.vx * dt;\r\n slot.y += slot.vy * dt;\r\n slot.rotationDegrees += slot.angularVelocityDegrees * dt;\r\n }\r\n\r\n const e = this.definition.emission;\r\n const cycle = e.duration + e.delay;\r\n this.elapsed += dt;\r\n if (this.emitting) {\r\n const cycleElapsed = e.loop ? this.elapsed % cycle : this.elapsed;\r\n const inWindow = cycleElapsed >= e.delay && cycleElapsed <= e.delay + e.duration;\r\n if (inWindow && e.rate > 0) {\r\n this.emissionAccumulator += e.rate * this.multiplier * dt;\r\n while (this.emissionAccumulator >= 1) { this.emissionAccumulator -= 1; this.spawnParticle(); }\r\n }\r\n e.bursts.forEach((burst, index) => {\r\n const triggerBase = e.delay + burst.time;\r\n for (;;) {\r\n const cursor = this.burstCursors[index] ?? 0;\r\n if (!e.loop && cursor >= 1) break;\r\n const triggerAt = e.loop ? cursor * cycle + triggerBase : triggerBase;\r\n if (this.elapsed < triggerAt) break;\r\n for (let i = 0; i < burst.count; i++) this.spawnParticle();\r\n this.burstCursors[index] = cursor + 1;\r\n }\r\n });\r\n }\r\n }\r\n\r\n private spawnParticle(): void {\r\n const slot = this.pool.acquire();\r\n if (!slot) return;\r\n const p = this.definition.particle;\r\n const rand = this.random;\r\n const point = sampleSpawnPoint(p.spawnShape.type, this.context.width, this.context.height, rand);\r\n slot.age = 0;\r\n slot.lifetime = rand.range(p.lifetime.min, p.lifetime.max);\r\n slot.spawnX = point.x;\r\n slot.spawnY = point.y;\r\n slot.x = point.x;\r\n slot.y = point.y;\r\n const speed = rand.range(p.movement.speed.min, p.movement.speed.max);\r\n const angle = (p.movement.directionDegrees + (rand.next() - 0.5) * p.movement.spreadDegrees) * DEG_TO_RAD;\r\n slot.vx = Math.cos(angle) * speed;\r\n slot.vy = Math.sin(angle) * speed;\r\n slot.rotationDegrees = rand.range(p.visual.rotation.initialDegrees.min, p.visual.rotation.initialDegrees.max);\r\n slot.angularVelocityDegrees = rand.range(p.visual.rotation.angularVelocityDegrees.min, p.visual.rotation.angularVelocityDegrees.max);\r\n slot.scaleStart = rand.range(p.visual.scale.start.min, p.visual.scale.start.max);\r\n slot.scaleEnd = rand.range(p.visual.scale.end.min, p.visual.scale.end.max);\r\n const source = p.visual.source;\r\n slot.sourceIndex = source.type === \"single\" ? 0 : rand.index(source.assetIds.length);\r\n slot.sequenceStart = source.type === \"sequence\" && source.randomStartFrame ? rand.index(source.assetIds.length) : 0;\r\n if (this.context.space === \"world\") {\r\n const m = this.hooks.getWorldTransform();\r\n slot.worldSpawnX = m.a * point.x + m.c * point.y + m.tx;\r\n slot.worldSpawnY = m.b * point.x + m.d * point.y + m.ty;\r\n slot.spawnMatrixA = m.a;\r\n slot.spawnMatrixB = m.b;\r\n slot.spawnMatrixC = m.c;\r\n slot.spawnMatrixD = m.d;\r\n }\r\n }\r\n\r\n private releaseSlot(slot: ParticleSlot<TRender>): void {\r\n resetSlot(slot);\r\n this.hooks.hideRender(slot.render);\r\n this.pool.release(slot);\r\n }\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"particles.js","sourceRoot":"","sources":["../src/particles.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ParticleEffectDefinition } from \"@pixi-ui-editor/schema\";\r\n\r\nconst DEG_TO_RAD = Math.PI / 180;\r\n\r\n/** Deterministic xorshift32 generator; it has no DOM/Pixi/ticker dependency. */\r\nexport class SeededRandom {\r\n private state: number;\r\n constructor(seed: number) { this.state = seed === 0 ? 0x9e3779b9 : seed >>> 0; }\r\n next(): number { this.state ^= this.state << 13; this.state ^= this.state >>> 17; this.state ^= this.state << 5; return (this.state >>> 0) / 0x1_0000_0000; }\r\n range(min: number, max: number): number { return min + (max - min) * this.next(); }\r\n /** A uniform index in `[0, length)`; used to pick a random asset/frame. */\r\n index(length: number): number { return Math.min(length - 1, Math.floor(this.next() * length)); }\r\n}\r\n\r\nexport function lerp(a: number, b: number, t: number): number { return a + (b - a) * t; }\r\n\r\nfunction hexChannel(hex: string, offset: number): number { return parseInt(hex.slice(offset, offset + 2), 16); }\r\n/** Lerps two `#RRGGBB[AA]` strings channel-by-channel; a trailing alpha byte, if any, is ignored. */\r\nexport function lerpColorHex(start: string, end: string, t: number): string {\r\n const channel = (offset: number) => Math.round(lerp(hexChannel(start, offset), hexChannel(end, offset), t)).toString(16).padStart(2, \"0\");\r\n return `#${channel(1)}${channel(3)}${channel(5)}`;\r\n}\r\n\r\nexport type ParticleSpawnShape = \"point\" | \"rectangle\" | \"circle\";\r\n\r\n/** `point` returns the rect centre; `rectangle` is uniform over the area; `circle` is uniform over the ellipse inscribed in the rect. */\r\nexport function sampleSpawnPoint(shape: ParticleSpawnShape, width: number, height: number, random: SeededRandom): { x: number; y: number } {\r\n const cx = width / 2, cy = height / 2;\r\n if (shape === \"point\") return { x: cx, y: cy };\r\n if (shape === \"rectangle\") return { x: random.next() * width, y: random.next() * height };\r\n const angle = random.next() * Math.PI * 2;\r\n const radius = Math.sqrt(random.next());\r\n return { x: cx + Math.cos(angle) * radius * cx, y: cy + Math.sin(angle) * radius * cy };\r\n}\r\n\r\n/** A prewarmed pool entry: `render` is an opaque adapter-owned renderer object created by the same factory as the simulation slot. */\r\nexport type ParticleSlot<TRender> = {\n render: TRender;\n /** Adapter-owned static attributes must be uploaded once after this slot is (re)spawned. */\n renderDirty: boolean;\n age: number;\r\n lifetime: number;\r\n x: number;\r\n y: number;\r\n vx: number;\r\n vy: number;\r\n /** Spawn-local position; used to derive the physics delta for world-space reprojection. */\r\n spawnX: number;\r\n spawnY: number;\r\n rotationDegrees: number;\r\n angularVelocityDegrees: number;\r\n scaleStart: number;\r\n scaleEnd: number;\r\n /** Index into `random`/`sequence` source `assetIds`, picked once at spawn. */\r\n sourceIndex: number;\r\n /** Starting frame offset for a `sequence` source with `randomStartFrame`. */\r\n sequenceStart: number;\r\n /** World-space spawn position and the linear (rotate+scale) part of the emitter's world transform at spawn time; only meaningful for `world` space particles. */\r\n worldSpawnX: number;\r\n worldSpawnY: number;\r\n spawnMatrixA: number;\r\n spawnMatrixB: number;\r\n spawnMatrixC: number;\r\n spawnMatrixD: number;\r\n};\r\n\r\nfunction createZeroedSlot<TRender>(render: TRender): ParticleSlot<TRender> {\n return { render, renderDirty: false, age: 0, lifetime: 0, x: 0, y: 0, vx: 0, vy: 0, spawnX: 0, spawnY: 0, rotationDegrees: 0, angularVelocityDegrees: 0, scaleStart: 1, scaleEnd: 1, sourceIndex: 0, sequenceStart: 0, worldSpawnX: 0, worldSpawnY: 0, spawnMatrixA: 1, spawnMatrixB: 0, spawnMatrixC: 0, spawnMatrixD: 1 };\n}\nfunction resetSlot<TRender>(slot: ParticleSlot<TRender>): void {\n // Hot release path: reset in place instead of allocating a temporary zeroed slot for Object.assign.\n slot.renderDirty = false; slot.age = 0; slot.lifetime = 0; slot.x = 0; slot.y = 0; slot.vx = 0; slot.vy = 0;\n slot.spawnX = 0; slot.spawnY = 0; slot.rotationDegrees = 0; slot.angularVelocityDegrees = 0;\n slot.scaleStart = 1; slot.scaleEnd = 1; slot.sourceIndex = 0; slot.sequenceStart = 0;\n slot.worldSpawnX = 0; slot.worldSpawnY = 0;\n slot.spawnMatrixA = 1; slot.spawnMatrixB = 0; slot.spawnMatrixC = 0; slot.spawnMatrixD = 1;\n}\n\r\n/**\r\n * Prewarmed object pool. `acquire`/`release` never call the factory; only `resize` does, and only for\r\n * the capacity delta. Shrinking removes idle free slots immediately; active slots beyond the new\r\n * capacity keep running and are permanently destroyed (via `onRemove`, never recycled) the next time\r\n * they are released instead of returning to the free list.\r\n */\r\nexport class ParticlePool<T> {\r\n private readonly free: T[] = [];\r\n private readonly active = new Set<T>();\r\n private capacity: number;\r\n public dropped = 0;\r\n constructor(private readonly factory: () => T, capacity: number, private readonly onRemove?: (value: T) => void) {\r\n this.capacity = capacity;\r\n for (let i = 0; i < capacity; i++) this.free.push(factory());\r\n }\r\n acquire(): T | undefined {\r\n const value = this.free.pop();\r\n if (value === undefined) { this.dropped++; return undefined; }\r\n this.active.add(value);\r\n return value;\r\n }\r\n release(value: T): void {\r\n if (!this.active.has(value)) return;\r\n const overCapacity = this.free.length + this.active.size > this.capacity;\r\n this.active.delete(value);\r\n if (overCapacity) this.onRemove?.(value);\r\n else this.free.push(value);\r\n }\r\n resize(capacity: number): void {\r\n if (capacity > this.capacity) {\r\n const total = this.free.length + this.active.size;\r\n for (let i = total; i < capacity; i++) this.free.push(this.factory());\r\n } else if (capacity < this.capacity) {\r\n while (this.free.length + this.active.size > capacity && this.free.length > 0) this.onRemove?.(this.free.pop()!);\r\n }\r\n this.capacity = capacity;\r\n }\r\n /** Permanently destroys every slot, free and active alike; used by `dispose()`. */\r\n clear(): void {\r\n for (const value of this.free.splice(0, this.free.length)) this.onRemove?.(value);\r\n for (const value of this.active) this.onRemove?.(value);\r\n this.active.clear();\r\n this.capacity = 0;\r\n }\r\n get values(): ReadonlySet<T> { return this.active; }\r\n get limit(): number { return this.capacity; }\r\n}\r\n\r\nexport type ParticleSpawnContext = { width: number; height: number; space: \"local\" | \"world\" };\r\nexport type ParticleDiagnostics = { active: number; dropped: number; playing: boolean; stopped: boolean; disposed: boolean };\r\n\r\n/** Adapter-supplied, renderer-specific operations. The simulator never imports Pixi. */\r\nexport type ParticleRenderHooks<TRender> = {\n createRender(): TRender;\r\n hideRender(render: TRender): void;\r\n destroyRender(render: TRender): void;\r\n /** The emitter's current world transform linear part `{a,b,c,d}` and translation `{tx,ty}`; read only when a `world`-space particle spawns. */\r\n getWorldTransform(): { a: number; b: number; c: number; d: number; tx: number; ty: number };\r\n};\n\r\n/**\r\n * Schema-neutral, deterministic particle simulation over a prewarmed pool. Owns lifecycle\r\n * (`play`/`pause`/`step`/`restart`/`stop`/`dispose`), fixed-step ticking, seeded spawn parameters and\r\n * burst/rate scheduling. Rendering (texture, tint, local/world projection) is the adapter's job; this\r\n * class only exposes the pool's active slots and the effect definition for it to read.\r\n */\r\nexport class ParticleSimulator<TRender> {\n static readonly stepSeconds = 1 / 60;\r\n private readonly pool: ParticlePool<ParticleSlot<TRender>>;\r\n private random: SeededRandom;\r\n private elapsed = 0;\r\n private stepAccumulator = 0;\r\n private emissionAccumulator = 0;\r\n private burstCursors: number[];\r\n private multiplier = 1;\r\n private emitting = false;\n private simulating = false;\n private stopped = false;\n private disposed = false;\n private context: ParticleSpawnContext = { width: 0, height: 0, space: \"local\" };\r\n\r\n constructor(public definition: ParticleEffectDefinition, private readonly hooks: ParticleRenderHooks<TRender>) {\r\n this.random = new SeededRandom(definition.seed);\r\n this.burstCursors = definition.emission.bursts.map(() => 0);\r\n this.pool = new ParticlePool<ParticleSlot<TRender>>(\r\n () => createZeroedSlot(hooks.createRender()),\r\n definition.maxParticles,\r\n (slot) => hooks.destroyRender(slot.render),\r\n );\r\n }\r\n\r\n get activeSlots(): ReadonlySet<ParticleSlot<TRender>> { return this.pool.values; }\r\n\r\n setEmissionMultiplier(value: number): void {\r\n if (!Number.isFinite(value) || value < 0) throw new RangeError(\"Emission multiplier must be finite and non-negative.\");\r\n this.multiplier = value;\r\n }\r\n\r\n /** Adopts a new definition reference without ever comparing identity: unrelated edits, seed changes and texture changes never reset accumulator, PRNG or live particles. Only `maxParticles` triggers a pool resize. */\r\n syncEffect(effect: ParticleEffectDefinition): void {\r\n this.definition = effect;\r\n if (this.pool.limit !== effect.maxParticles) this.pool.resize(effect.maxParticles);\r\n const cursors = effect.emission.bursts.map((_, index) => this.burstCursors[index] ?? 0);\r\n this.burstCursors = cursors;\r\n }\r\n\r\n play(): void { if (this.disposed) return; this.emitting = true; this.simulating = true; this.stopped = false; }\n /** Freezes emission and every live particle without resetting time or PRNG. */\n pause(): void { if (this.disposed) return; this.emitting = false; this.simulating = false; this.stopped = false; }\n /** Stops new spawns; already-emitted particles keep simulating to their natural death. */\n stop(): void {\n if (this.disposed) return;\n this.emitting = false;\n this.simulating = this.pool.values.size > 0;\n this.stopped = true;\n }\n\r\n restart(): void {\r\n if (this.disposed) return;\r\n for (const slot of [...this.pool.values]) this.releaseSlot(slot);\r\n this.elapsed = 0;\r\n this.stepAccumulator = 0;\r\n this.emissionAccumulator = 0;\r\n this.burstCursors = this.definition.emission.bursts.map(() => 0);\n this.pool.dropped = 0;\n this.random = new SeededRandom(this.definition.seed);\n this.emitting = true;\n this.simulating = true;\n this.stopped = false;\n }\r\n\r\n /** Idempotent terminal cleanup: destroys every pooled render object and excludes the view from further updates. */\r\n dispose(): void {\r\n if (this.disposed) return;\r\n this.disposed = true;\n this.emitting = false;\n this.simulating = false;\n this.stopped = false;\n this.pool.clear();\r\n }\r\n\r\n /** Advances exactly one fixed step regardless of paused/stopped state, and never changes it. */\r\n step(context: ParticleSpawnContext): boolean {\n if (this.disposed) return false;\n this.context = context;\n this.tick(ParticleSimulator.stepSeconds);\n return true;\n }\n\n update(deltaSeconds: number, context: ParticleSpawnContext): boolean {\n if (this.disposed || !this.simulating) return false;\n this.context = context;\n this.stepAccumulator = Math.min(this.stepAccumulator + Math.max(0, deltaSeconds), ParticleSimulator.stepSeconds * 8);\n let advanced = false;\n while (this.stepAccumulator >= ParticleSimulator.stepSeconds) {\n this.stepAccumulator -= ParticleSimulator.stepSeconds;\n this.tick(ParticleSimulator.stepSeconds);\n advanced = true;\n }\n return advanced;\n }\n\n getDiagnostics(): ParticleDiagnostics {\n return { active: this.pool.values.size, dropped: this.pool.dropped, playing: this.emitting, stopped: this.stopped && !this.disposed, disposed: this.disposed };\n }\r\n\r\n private tick(dt: number): void {\r\n // Age and move existing particles before spawning: a particle created this tick starts at age 0\r\n // and receives its first dt on the next tick, instead of being silently pre-aged by one step.\r\n const movement = this.definition.particle.movement;\r\n const drag = Math.max(0, 1 - movement.drag * dt);\r\n for (const slot of this.pool.values) {\n slot.age += dt;\r\n if (slot.age >= slot.lifetime) { this.releaseSlot(slot); continue; }\r\n slot.vx = (slot.vx + movement.accelerationX * dt) * drag;\r\n slot.vy = (slot.vy + movement.accelerationY * dt) * drag;\r\n slot.x += slot.vx * dt;\r\n slot.y += slot.vy * dt;\r\n slot.rotationDegrees += slot.angularVelocityDegrees * dt;\r\n }\r\n\r\n const e = this.definition.emission;\r\n const cycle = e.duration + e.delay;\r\n this.elapsed += dt;\r\n if (this.emitting) {\r\n const cycleElapsed = e.loop ? this.elapsed % cycle : this.elapsed;\r\n const inWindow = cycleElapsed >= e.delay && cycleElapsed <= e.delay + e.duration;\r\n if (inWindow && e.rate > 0) {\r\n this.emissionAccumulator += e.rate * this.multiplier * dt;\r\n while (this.emissionAccumulator >= 1) { this.emissionAccumulator -= 1; this.spawnParticle(); }\r\n }\r\n for (let index = 0; index < e.bursts.length; index++) {\n const burst = e.bursts[index]!;\n const triggerBase = e.delay + burst.time;\n for (;;) {\r\n const cursor = this.burstCursors[index] ?? 0;\r\n if (!e.loop && cursor >= 1) break;\r\n const triggerAt = e.loop ? cursor * cycle + triggerBase : triggerBase;\r\n if (this.elapsed < triggerAt) break;\r\n for (let i = 0; i < burst.count; i++) this.spawnParticle();\r\n this.burstCursors[index] = cursor + 1;\n }\n }\n if (!e.loop && this.elapsed >= e.delay + e.duration) {\n this.emitting = false;\n this.stopped = true;\n }\n }\n // A completed one-shot or a graceful stop must not keep an otherwise idle emitter on the hot\n // ticker path forever. Preserve the stopped diagnostic while putting simulation fully to sleep.\n if (!this.emitting && this.pool.values.size === 0) this.simulating = false;\n }\r\n\r\n private spawnParticle(): void {\r\n const slot = this.pool.acquire();\r\n if (!slot) return;\r\n const p = this.definition.particle;\n const rand = this.random;\r\n const point = sampleSpawnPoint(p.spawnShape.type, this.context.width, this.context.height, rand);\n slot.renderDirty = true;\n slot.age = 0;\r\n slot.lifetime = rand.range(p.lifetime.min, p.lifetime.max);\r\n slot.spawnX = point.x;\r\n slot.spawnY = point.y;\r\n slot.x = point.x;\r\n slot.y = point.y;\r\n const speed = rand.range(p.movement.speed.min, p.movement.speed.max);\r\n const angle = (p.movement.directionDegrees + (rand.next() - 0.5) * p.movement.spreadDegrees) * DEG_TO_RAD;\r\n slot.vx = Math.cos(angle) * speed;\r\n slot.vy = Math.sin(angle) * speed;\r\n slot.rotationDegrees = rand.range(p.visual.rotation.initialDegrees.min, p.visual.rotation.initialDegrees.max);\r\n slot.angularVelocityDegrees = rand.range(p.visual.rotation.angularVelocityDegrees.min, p.visual.rotation.angularVelocityDegrees.max);\r\n slot.scaleStart = rand.range(p.visual.scale.start.min, p.visual.scale.start.max);\r\n slot.scaleEnd = rand.range(p.visual.scale.end.min, p.visual.scale.end.max);\r\n const source = p.visual.source;\r\n slot.sourceIndex = source.type === \"single\" ? 0 : rand.index(source.assetIds.length);\r\n slot.sequenceStart = source.type === \"sequence\" && source.randomStartFrame ? rand.index(source.assetIds.length) : 0;\r\n if (this.context.space === \"world\") {\r\n const m = this.hooks.getWorldTransform();\r\n slot.worldSpawnX = m.a * point.x + m.c * point.y + m.tx;\r\n slot.worldSpawnY = m.b * point.x + m.d * point.y + m.ty;\r\n slot.spawnMatrixA = m.a;\r\n slot.spawnMatrixB = m.b;\r\n slot.spawnMatrixC = m.c;\r\n slot.spawnMatrixD = m.d;\r\n }\r\n }\r\n\r\n private releaseSlot(slot: ParticleSlot<TRender>): void {\r\n resetSlot(slot);\r\n this.hooks.hideRender(slot.render);\r\n this.pool.release(slot);\r\n }\r\n}\r\n"]}
|
package/dist/scene.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scene.d.ts","sourceRoot":"","sources":["../src/scene.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,iCAAiC,CAAC;AACpE,OAAO,EAAsG,KAAK,gBAAgB,EAA2B,KAAK,eAAe,EAAE,KAAK,eAAe,EAAE,KAAK,KAAK,EAAE,KAAK,mBAAmB,EAAE,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC3R,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,SAAS,CAAC;AAE1D,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAG/E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAA2F,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AACvI,OAAO,EAAY,KAAK,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"scene.d.ts","sourceRoot":"","sources":["../src/scene.ts"],"names":[],"mappings":"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"}
|
package/dist/scene.js
CHANGED
|
@@ -15,8 +15,10 @@ import { PageGroupNodeView } from "./views/PageGroupNodeView.js";
|
|
|
15
15
|
import { ScrollItemContainer } from "./scrollView.js";
|
|
16
16
|
import { ScrollViewNodeView } from "./views/ScrollViewNodeView.js";
|
|
17
17
|
import { SpineNodeView } from "./views/SpineNodeView.js";
|
|
18
|
+
import { ParticleEmitterNodeView } from "./views/ParticleEmitterNodeView.js";
|
|
18
19
|
import { SceneLocalization } from "./localization.js";
|
|
19
20
|
import { SceneViewport } from "./SceneViewport.js";
|
|
21
|
+
const particleEmitterRegistry = new WeakMap();
|
|
20
22
|
function spineReferenceFrameFor(document, node) {
|
|
21
23
|
if (node.type !== "spine")
|
|
22
24
|
return undefined;
|
|
@@ -32,6 +34,7 @@ export function buildSceneView(document, sceneId, profile, options) {
|
|
|
32
34
|
throw new Error(`Scene '${sceneId}' does not exist in the project document.`);
|
|
33
35
|
}
|
|
34
36
|
const nodeViews = new Map();
|
|
37
|
+
const particleEmitters = [];
|
|
35
38
|
// Materialized prefab children use instance-scoped IDs, so authoring and runtime can address
|
|
36
39
|
// multiple instances independently without changing canonical definition IDs.
|
|
37
40
|
const screenSize = scene.layout.referenceViewports[profile];
|
|
@@ -56,6 +59,8 @@ export function buildSceneView(document, sceneId, profile, options) {
|
|
|
56
59
|
// Yoga owns only the group's inner layoutContent; the outer NodeView keeps authored transform.
|
|
57
60
|
view.update(node, profile, parentSize);
|
|
58
61
|
nodeViews.set(node.id, view);
|
|
62
|
+
if (view instanceof ParticleEmitterNodeView)
|
|
63
|
+
particleEmitters.push(view);
|
|
59
64
|
// Прямые дети корня сцены разрешают якоря относительно логического Canvas, а не размера корня.
|
|
60
65
|
// Прямой ребёнок grid-layout (сам `node` здесь) не владеет своим отрисованным размером: Unity-подобная
|
|
61
66
|
// фиксированная ячейка полностью переопределяет authored transform (см. applyLayoutItem). Его
|
|
@@ -114,6 +119,7 @@ export function buildSceneView(document, sceneId, profile, options) {
|
|
|
114
119
|
const canvasRoot = buildOwner(canvasSize);
|
|
115
120
|
canvasRoot.scale.set(canvasScale);
|
|
116
121
|
const hostRoot = new SceneViewport(canvasRoot, screenSize, options.clipToViewport ?? interaction === "runtime");
|
|
122
|
+
particleEmitterRegistry.set(hostRoot, particleEmitters);
|
|
117
123
|
// Контроллер применяет переводы сразу к уже созданным views, поэтому keyed Text показывает
|
|
118
124
|
// базовую локаль без единого дополнительного вызова со стороны хоста.
|
|
119
125
|
const localization = new SceneLocalization(document, scene, nodeViews, options.localization);
|
|
@@ -199,8 +205,20 @@ export function previewNodeView(view, node, profile, transform) {
|
|
|
199
205
|
}
|
|
200
206
|
/** Hosts call this from their own Application ticker; runtime never subscribes to Ticker.shared. */
|
|
201
207
|
export function updateParticleEmitters(root, deltaSeconds) {
|
|
202
|
-
const
|
|
203
|
-
|
|
208
|
+
const registered = particleEmitterRegistry.get(root);
|
|
209
|
+
if (registered !== undefined) {
|
|
210
|
+
for (const emitter of registered)
|
|
211
|
+
emitter.updateParticles(deltaSeconds);
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
// Backward-compatible fallback for hosts that assemble a display tree manually instead of using
|
|
215
|
+
// buildSceneView. Built scenes always take the O(emitter count) registry path above.
|
|
216
|
+
const visit = (view) => {
|
|
217
|
+
if (view instanceof ParticleEmitterNodeView)
|
|
218
|
+
view.updateParticles(deltaSeconds);
|
|
219
|
+
for (const child of view.children)
|
|
220
|
+
visit(child);
|
|
221
|
+
};
|
|
204
222
|
visit(root);
|
|
205
223
|
}
|
|
206
224
|
/** Lists the nodes a scene renders, including nodes of prefab definitions its prefab instances expand to. */
|
package/dist/scene.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scene.js","sourceRoot":"","sources":["../src/scene.ts"],"names":[],"mappings":"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","sourcesContent":["import { type SkeletonData } from \"@esotericsoftware/spine-pixi-v8\";\r\nimport { createStableId, isLayoutGroup, isParticleEffect, resolveLayoutGroupSettings, resolveOwnerNodeGraph, type EffectDefinition, type GridLayoutSettings, type LayoutProfileId, type ProjectDocument, type Scene, type SpineReferenceFrame, type UINode } from \"@pixi-ui-editor/schema\";\r\nimport { Container, Texture, type Ticker } from \"pixi.js\";\r\nimport { loadSceneSpines } from \"./assets/spine.js\";\r\nimport { loadSceneTextures, type FileUrlResolver } from \"./assets/textures.js\";\r\nimport { loadSceneFonts } from \"./assets/fonts.js\";\r\nimport { loadSceneBitmapFonts } from \"./assets/bitmapFonts.js\";\r\nimport type { SceneAssetCache } from \"./assets/cache.js\";\r\nimport { getCanvasLogicalSize, getCanvasScale, resolveAnchoredTransform, resolveProfileTransform, type LayoutSize } from \"./layout.js\";\r\nimport { NodeView, type SceneInteractionMode } from \"./views/NodeView.js\";\r\nimport { CheckboxNodeView } from \"./views/CheckboxNodeView.js\";\r\nimport { createNodeView } from \"./views/createNodeView.js\";\r\nimport { applyLayoutGroup, applyLayoutItem, createGridLineBreak, initializePixiLayout, LayoutItemContainer } from \"./layoutGroups.js\";\r\nimport { LayoutGroupNodeView } from \"./views/basic.js\";\r\nimport { PageItemContainer } from \"./pageGroup.js\";\r\nimport { PageGroupNodeView } from \"./views/PageGroupNodeView.js\";\r\nimport { ScrollItemContainer } from \"./scrollView.js\";\r\nimport { ScrollViewNodeView } from \"./views/ScrollViewNodeView.js\";\r\nimport { SpineNodeView } from \"./views/SpineNodeView.js\";\r\nimport { SceneLocalization, type SceneLocalizationOptions } from \"./localization.js\";\r\nimport { SceneViewport } from \"./SceneViewport.js\";\r\nimport type { Sound } from \"@pixi/sound\";\r\n\r\nexport type BuildSceneViewOptions = {\r\n /** Explicit: an editor canvas must pass \"authoring\", Preview and the consuming app \"runtime\". */\r\n interaction: SceneInteractionMode;\r\n textures?: ReadonlyMap<string, Texture>;\r\n spines?: ReadonlyMap<string, SkeletonData>;\r\n fonts?: ReadonlyMap<string, string>;\r\n bitmapFonts?: ReadonlyMap<string, string>;\r\n sounds?: ReadonlyMap<string, Sound>;\r\n /**\r\n * The host's own Application ticker, driving self-updating content such as Spine skeletons.\r\n * Without it they fall back to `Ticker.shared`, which runs a second rAF loop independent of the\r\n * renderer that draws them — see the same rule as `updateParticleEmitters`.\r\n */\r\n ticker?: Ticker;\r\n /** Called after Yoga changes a managed rectangle; authoring hosts use it to refresh overlays. */\r\n onLayout?: () => void;\r\n /**\r\n * Начальное состояние локализации. Опция необязательна: при наличии `Text.textKey` base locale\r\n * каталога применяется и без неё, а документ без ключей выглядит ровно как раньше.\r\n */\r\n localization?: SceneLocalizationOptions;\r\n /** Internal host boundary override: prefab views are spawnable content, not screen viewports. */\r\n clipToViewport?: boolean;\r\n};\r\n\r\nexport type SceneViewResult = { root: SceneViewport; nodeViews: Map<string, Container>; localization: SceneLocalization };\r\n\r\nfunction spineReferenceFrameFor(document: ProjectDocument, node: UINode): SpineReferenceFrame | undefined {\r\n if (node.type !== \"spine\") return undefined;\r\n const asset = document.assets.find((candidate) => candidate.id === node.assetId);\r\n return asset?.type === \"spine\" ? asset.referenceFrame : undefined;\r\n}\r\n\r\n/** Builds a PixiJS display tree for a scene without depending on DOM or editor state. */\r\nexport function buildSceneView(\r\n document: ProjectDocument,\r\n sceneId: string,\r\n profile: LayoutProfileId,\r\n options: BuildSceneViewOptions,\r\n): SceneViewResult {\r\n initializePixiLayout();\r\n const { interaction, textures, spines, fonts, bitmapFonts, sounds, ticker, onLayout } = options;\r\n const scene = document.scenes.find((candidate) => candidate.id === sceneId);\r\n\r\n if (scene === undefined) {\r\n throw new Error(`Scene '${sceneId}' does not exist in the project document.`);\r\n }\r\n\r\n const nodeViews = new Map<string, Container>();\r\n\r\n // Materialized prefab children use instance-scoped IDs, so authoring and runtime can address\r\n // multiple instances independently without changing canonical definition IDs.\r\n const screenSize = scene.layout.referenceViewports[profile];\r\n const referenceResolution = scene.layout.preferredViewports[profile];\r\n const canvasScale = getCanvasScale(screenSize, referenceResolution);\r\n const canvasSize = getCanvasLogicalSize(screenSize, referenceResolution);\r\n\r\n // Единый резолвер иерархии: тот же граф, что видит редактор, включая вложенные пресеты.\r\n const owner = resolveOwnerNodeGraph(document, scene);\r\n const prefabIds = new Set(document.prefabs.map((prefab) => prefab.id));\r\n\r\n const buildOwner = (rootSize: LayoutSize): Container => {\r\n const nodesById = new Map(owner.nodes.map((node) => [node.id, node]));\r\n\r\n const buildNode = (nodeId: string, parentSize: LayoutSize): NodeView => {\r\n const node = nodesById.get(nodeId);\r\n\r\n if (node === undefined) {\r\n throw new Error(`Scene '${sceneId}' references missing node '${nodeId}'.`);\r\n }\r\n\r\n const resolved = resolveProfileTransform(node, profile);\r\n const transform = resolveAnchoredTransform(resolved.transform, parentSize);\r\n const view = createNodeView(node, interaction, textures, spines, (prefabId) => prefabIds.has(prefabId), fonts, sounds, node.type === \"particle-emitter\" ? document.effects.find((effect) => effect.id === node.effectId && isParticleEffect(effect)) : undefined, spineReferenceFrameFor(document, node), ticker, bitmapFonts);\r\n if (isLayoutGroup(node)) applyLayoutGroup(view, node, profile, parentSize);\r\n // Yoga owns only the group's inner layoutContent; the outer NodeView keeps authored transform.\r\n view.update(node, profile, parentSize);\r\n nodeViews.set(node.id, view);\r\n\r\n // Прямые дети корня сцены разрешают якоря относительно логического Canvas, а не размера корня.\r\n // Прямой ребёнок grid-layout (сам `node` здесь) не владеет своим отрисованным размером: Unity-подобная\r\n // фиксированная ячейка полностью переопределяет authored transform (см. applyLayoutItem). Его\r\n // собственным потомкам нужен именно cellWidth/cellHeight, а не anchor-resolved authored-размер —\r\n // иначе они не отслеживают изменение Cell width/height и якорятся относительно устаревшего размера.\r\n const gridParent = node.parentId === null ? undefined : nodesById.get(node.parentId);\r\n const gridCell = gridParent?.type === \"grid-layout\" ? resolveLayoutGroupSettings<GridLayoutSettings>(gridParent, profile) : undefined;\r\n const childSize = node.parentId === null\r\n ? rootSize\r\n : gridCell !== undefined\r\n ? { width: gridCell.cellWidth, height: gridCell.cellHeight }\r\n : { width: transform.width, height: transform.height };\r\n for (const [childIndex, childId] of node.children.entries()) {\r\n const childNode = nodesById.get(childId);\r\n const childView = buildNode(childId, childSize);\r\n if (isLayoutGroup(node) && childNode !== undefined && view instanceof LayoutGroupNodeView) {\r\n const layoutItem = new LayoutItemContainer(childView, onLayout);\r\n applyLayoutItem(layoutItem, childNode, node, profile);\r\n view.addLayoutChild(layoutItem);\r\n } else if (node.type === \"scroll-view\" && childNode !== undefined && view instanceof ScrollViewNodeView) {\r\n const scrollItem = new ScrollItemContainer(childView, onLayout);\r\n // Как и у layout-item: собственный (не растянутый якорями) размер ребёнка — List не\r\n // предоставляет per-item override размера, в отличие от Yoga flexGrow/cellSize.\r\n const own = resolveProfileTransform(childNode, profile).transform;\r\n scrollItem.sync(childNode, profile, { width: own.width, height: own.height });\r\n view.addScrollItem(scrollItem);\r\n } else if (node.type === \"page-group\" && childNode !== undefined && view instanceof PageGroupNodeView) {\r\n // Unlike a scroll-view item, a page fills the group's own resolved rect completely\r\n // (`childSize`, computed above): a page is a full sub-screen, not content sized to itself.\r\n const pageItem = new PageItemContainer(childView);\r\n pageItem.sync(childNode, profile, childSize);\r\n view.addPageItem(pageItem);\r\n } else {\r\n view.addChild(childView);\r\n }\r\n if (node.type === \"grid-layout\") {\r\n const settings = node.layoutGroup.overrides?.[profile] === undefined ? node.layoutGroup.base : { ...node.layoutGroup.base, ...node.layoutGroup.overrides[profile] };\r\n if (settings.constraint !== \"flexible\" && settings.constraintCount !== undefined && (childIndex + 1) % settings.constraintCount === 0 && childIndex + 1 < node.children.length) {\r\n const lineBreak = createGridLineBreak(node, profile);\r\n if (lineBreak !== undefined && view instanceof LayoutGroupNodeView) view.addLayoutChild(lineBreak);\r\n }\r\n }\r\n }\r\n\r\n return view;\r\n };\r\n\r\n const ownerRoot = new Container();\r\n for (const rootNodeId of owner.rootNodeIds) {\r\n ownerRoot.addChild(buildNode(rootNodeId, rootSize));\r\n }\r\n\r\n return ownerRoot;\r\n };\r\n\r\n const canvasRoot = buildOwner(canvasSize);\r\n canvasRoot.scale.set(canvasScale);\r\n const hostRoot = new SceneViewport(canvasRoot, screenSize, options.clipToViewport ?? interaction === \"runtime\");\r\n // Контроллер применяет переводы сразу к уже созданным views, поэтому keyed Text показывает\r\n // базовую локаль без единого дополнительного вызова со стороны хоста.\r\n const localization = new SceneLocalization(document, scene, nodeViews, options.localization);\r\n wireCheckboxGroups(owner.nodes, nodeViews);\r\n wireSpineConnectors(owner.nodes, nodeViews);\r\n return { root: hostRoot, nodeViews, localization };\r\n}\r\n\r\nfunction wireSpineConnectors(nodes: readonly UINode[], nodeViews: ReadonlyMap<string, Container>): void {\r\n for (const node of nodes) {\r\n if (node.type !== \"spine\") continue;\r\n const view = nodeViews.get(node.id);\r\n if (!(view instanceof SpineNodeView)) continue;\r\n view.setConnectorBones((node.connectors ?? []).flatMap((connector) => {\r\n const target = nodeViews.get(connector.targetNodeId);\r\n return target === undefined ? [] : [{ ...connector, target }];\r\n }));\r\n }\r\n}\r\n\r\n/**\r\n * Authored `group` gives sibling checkboxes radio-button behavior: checking one force-unchecks its\r\n * live group-mates (same `parentId`, same `group`), without touching the document. Runs once per\r\n * scene build; `CheckboxNodeView.forceCheck` never re-emits `onCheck`, so this can't recurse.\r\n */\r\nfunction wireCheckboxGroups(nodes: readonly UINode[], nodeViews: ReadonlyMap<string, Container>): void {\r\n const byGroup = new Map<string, CheckboxNodeView[]>();\r\n for (const node of nodes) {\r\n if (node.type !== \"checkbox\" || node.group === undefined) continue;\r\n const view = nodeViews.get(node.id);\r\n if (!(view instanceof CheckboxNodeView)) continue;\r\n const key = `${node.parentId ?? \"\"}::${node.group}`;\r\n const group = byGroup.get(key) ?? [];\r\n group.push(view);\r\n byGroup.set(key, group);\r\n }\r\n for (const group of byGroup.values()) {\r\n if (group.length < 2) continue;\r\n for (const view of group) {\r\n view.onCheck.connect((checked) => {\r\n if (!checked) return;\r\n for (const other of group) if (other !== view) other.forceCheck(false);\r\n });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Applies a node's resolved transform, visibility, and content to an existing display object,\r\n * so editors can update views in place without rebuilding the scene tree.\r\n */\r\nexport function updateNodeView(view: Container, node: UINode, profile: LayoutProfileId, parentSize?: LayoutSize, parentNode?: UINode, effect?: EffectDefinition, spineReferenceFrame?: SpineReferenceFrame): void {\r\n if (isLayoutGroup(node)) applyLayoutGroup(view, node, profile, parentSize);\r\n if (!(view instanceof NodeView)) return;\r\n if (view instanceof SpineNodeView) view.setReferenceFrame(spineReferenceFrame);\r\n if (node.type === \"particle-emitter\" && effect !== undefined && isParticleEffect(effect) && \"syncEffect\" in view && typeof (view as { syncEffect?: unknown }).syncEffect === \"function\") (view as { syncEffect(effect: import(\"@pixi-ui-editor/schema\").ParticleEffectDefinition): void }).syncEffect(effect);\r\n if (parentNode !== undefined && isLayoutGroup(parentNode) && view.parent instanceof LayoutItemContainer) {\r\n applyLayoutItem(view.parent, node, parentNode, profile);\r\n } else if (parentNode !== undefined && parentNode.type === \"scroll-view\" && view.parent instanceof ScrollItemContainer) {\r\n const own = resolveProfileTransform(node, profile).transform;\r\n view.parent.sync(node, profile, { width: own.width, height: own.height });\r\n } else {\r\n view.update(node, profile, parentSize);\r\n }\r\n}\r\n\r\n/** Previews a resolved editor rectangle without consulting content bounds or rebuilding the view. */\r\nexport function previewNodeView(view: Container, node: UINode, profile: LayoutProfileId, transform: UINode[\"transform\"]): void {\r\n if (isLayoutGroup(node)) applyLayoutGroup(view, node, profile, undefined, { width: transform.width, height: transform.height });\r\n if (view instanceof NodeView) view.preview(node, transform, resolveProfileTransform(node, profile).visible, profile);\r\n}\r\n\r\n/** Hosts call this from their own Application ticker; runtime never subscribes to Ticker.shared. */\r\nexport function updateParticleEmitters(root: Container, deltaSeconds: number): void {\r\n const visit = (view: Container): void => { if (\"updateParticles\" in view && typeof (view as { updateParticles?: unknown }).updateParticles === \"function\") (view as { updateParticles(delta: number): void }).updateParticles(deltaSeconds); view.children.forEach(visit); };\r\n visit(root);\r\n}\r\n\r\n/** Lists the nodes a scene renders, including nodes of prefab definitions its prefab instances expand to. */\r\nexport function collectRenderedNodes(document: ProjectDocument, scene: Scene): UINode[] {\r\n return resolveOwnerNodeGraph(document, scene).nodes;\r\n}\r\n\r\nexport type PrefabViewConfiguration = Pick<Extract<UINode, { type: \"prefab-instance\" }>, \"propertyOverrides\" | \"locallyAddedNodes\"> & { instanceId?: string };\r\n\r\nfunction prefabScene(document: ProjectDocument, prefabId: string, configuration: PrefabViewConfiguration = {}): { document: ProjectDocument; sceneId: string; instanceId: string } {\r\n const prefab = document.prefabs.find((candidate) => candidate.id === prefabId);\r\n if (prefab === undefined) throw new Error(`Prefab '${prefabId}' does not exist in the project document.`);\r\n const width = Math.max(1, ...prefab.nodes.map((node) => Math.abs(node.transform.x) + Math.max(0, node.transform.width)));\r\n const height = Math.max(1, ...prefab.nodes.map((node) => Math.abs(node.transform.y) + Math.max(0, node.transform.height)));\r\n const instanceId = configuration.instanceId ?? createStableId();\r\n const instance: Extract<UINode, { type: \"prefab-instance\" }> = {\r\n id: instanceId, name: prefab.name, type: \"prefab-instance\", prefabId, parentId: null, children: [],\r\n visible: true, transform: { x: 0, y: 0, width, height, scaleX: 1, scaleY: 1, rotation: 0, anchorMinX: 0, anchorMaxX: 0, anchorMinY: 0, anchorMaxY: 0, pivotX: 0, pivotY: 0 },\r\n ...(configuration.propertyOverrides === undefined ? {} : { propertyOverrides: structuredClone(configuration.propertyOverrides) }),\r\n ...(configuration.locallyAddedNodes === undefined ? {} : { locallyAddedNodes: structuredClone(configuration.locallyAddedNodes) }),\r\n };\r\n const sceneId = createStableId();\r\n const viewport = { width, height };\r\n const scene: Scene = { id: sceneId, name: prefab.name, rootNodeIds: [instance.id], nodes: [instance], layout: { referenceViewports: { desktop: viewport, mobile: viewport }, preferredViewports: { desktop: viewport, mobile: viewport } } };\r\n return { document: { ...document, scenes: [...document.scenes, scene] }, sceneId, instanceId };\r\n}\r\n\r\n/** Builds a fresh runtime prefab instance without requiring it to already exist in a scene. */\r\nexport function buildPrefabView(document: ProjectDocument, prefabId: string, profile: LayoutProfileId, options: BuildSceneViewOptions, configuration: PrefabViewConfiguration = {}): SceneViewResult & { instanceId: string } {\r\n const synthetic = prefabScene(document, prefabId, configuration);\r\n return { ...buildSceneView(synthetic.document, synthetic.sceneId, profile, { ...options, clipToViewport: false }), instanceId: synthetic.instanceId };\r\n}\r\n\r\n/** Loads a prefab's assets and returns a fresh display tree suitable for dynamic game-code spawning. */\r\nexport async function loadPrefabView(document: ProjectDocument, prefabId: string, profile: LayoutProfileId, resolveFileUrl: FileUrlResolver, options: { interaction: SceneInteractionMode; ticker?: Ticker; localization?: SceneLocalizationOptions; assetCache?: SceneAssetCache }, configuration: PrefabViewConfiguration = {}): Promise<SceneViewResult & { instanceId: string }> {\r\n const synthetic = prefabScene(document, prefabId, configuration);\r\n return { ...await loadSceneView(synthetic.document, synthetic.sceneId, profile, resolveFileUrl, { ...options, clipToViewport: false }), instanceId: synthetic.instanceId };\r\n}\r\n\r\n/** Loads a scene's textures and Spine data, then builds its display tree in one call. */\r\nexport async function loadSceneView(\r\n document: ProjectDocument,\r\n sceneId: string,\r\n profile: LayoutProfileId,\r\n resolveFileUrl: FileUrlResolver,\r\n options: { interaction: SceneInteractionMode; ticker?: Ticker; localization?: SceneLocalizationOptions; clipToViewport?: boolean; assetCache?: SceneAssetCache },\r\n): Promise<SceneViewResult> {\r\n // Без assetCache каждый вызов начинает с пустых кэшей: для одиночной загрузки сцены это нормально, а вот\r\n // игровой код, который поднимает пресеты по одному, обязан передать собственный кэш — иначе один и тот же\r\n // скелет, атлас и текстура парсятся заново на каждую вьюху и дублируются в видеопамяти.\r\n const cache = options.assetCache;\r\n const [textures, spines, fonts, bitmapFonts] = await Promise.all([\r\n loadSceneTextures(document, sceneId, (asset) => (asset.type === \"image\" ? resolveFileUrl(asset.source.uri) : undefined), resolveFileUrl, cache?.textures, cache?.spritesheets, cache?.bitmapFonts),\r\n loadSceneSpines(document, sceneId, resolveFileUrl, cache?.spines),\r\n loadSceneFonts(document, sceneId, resolveFileUrl, cache?.fonts),\r\n loadSceneBitmapFonts(document, sceneId, resolveFileUrl, cache?.bitmapFonts),\r\n ]);\r\n return buildSceneView(document, sceneId, profile, { interaction: options.interaction, textures, spines, fonts, bitmapFonts, ticker: options.ticker, localization: options.localization, clipToViewport: options.clipToViewport });\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"scene.js","sourceRoot":"","sources":["../src/scene.ts"],"names":[],"mappings":"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","sourcesContent":["import { type SkeletonData } from \"@esotericsoftware/spine-pixi-v8\";\r\nimport { createStableId, isLayoutGroup, isParticleEffect, resolveLayoutGroupSettings, resolveOwnerNodeGraph, type EffectDefinition, type GridLayoutSettings, type LayoutProfileId, type ProjectDocument, type Scene, type SpineReferenceFrame, type UINode } from \"@pixi-ui-editor/schema\";\r\nimport { Container, Texture, type Ticker } from \"pixi.js\";\r\nimport { loadSceneSpines } from \"./assets/spine.js\";\r\nimport { loadSceneTextures, type FileUrlResolver } from \"./assets/textures.js\";\r\nimport { loadSceneFonts } from \"./assets/fonts.js\";\r\nimport { loadSceneBitmapFonts } from \"./assets/bitmapFonts.js\";\r\nimport type { SceneAssetCache } from \"./assets/cache.js\";\r\nimport { getCanvasLogicalSize, getCanvasScale, resolveAnchoredTransform, resolveProfileTransform, type LayoutSize } from \"./layout.js\";\r\nimport { NodeView, type SceneInteractionMode } from \"./views/NodeView.js\";\r\nimport { CheckboxNodeView } from \"./views/CheckboxNodeView.js\";\r\nimport { createNodeView } from \"./views/createNodeView.js\";\r\nimport { applyLayoutGroup, applyLayoutItem, createGridLineBreak, initializePixiLayout, LayoutItemContainer } from \"./layoutGroups.js\";\r\nimport { LayoutGroupNodeView } from \"./views/basic.js\";\r\nimport { PageItemContainer } from \"./pageGroup.js\";\r\nimport { PageGroupNodeView } from \"./views/PageGroupNodeView.js\";\r\nimport { ScrollItemContainer } from \"./scrollView.js\";\r\nimport { ScrollViewNodeView } from \"./views/ScrollViewNodeView.js\";\r\nimport { SpineNodeView } from \"./views/SpineNodeView.js\";\nimport { ParticleEmitterNodeView } from \"./views/ParticleEmitterNodeView.js\";\nimport { SceneLocalization, type SceneLocalizationOptions } from \"./localization.js\";\r\nimport { SceneViewport } from \"./SceneViewport.js\";\r\nimport type { Sound } from \"@pixi/sound\";\r\n\r\nexport type BuildSceneViewOptions = {\r\n /** Explicit: an editor canvas must pass \"authoring\", Preview and the consuming app \"runtime\". */\r\n interaction: SceneInteractionMode;\r\n textures?: ReadonlyMap<string, Texture>;\r\n spines?: ReadonlyMap<string, SkeletonData>;\r\n fonts?: ReadonlyMap<string, string>;\r\n bitmapFonts?: ReadonlyMap<string, string>;\r\n sounds?: ReadonlyMap<string, Sound>;\r\n /**\r\n * The host's own Application ticker, driving self-updating content such as Spine skeletons.\r\n * Without it they fall back to `Ticker.shared`, which runs a second rAF loop independent of the\r\n * renderer that draws them — see the same rule as `updateParticleEmitters`.\r\n */\r\n ticker?: Ticker;\r\n /** Called after Yoga changes a managed rectangle; authoring hosts use it to refresh overlays. */\r\n onLayout?: () => void;\r\n /**\r\n * Начальное состояние локализации. Опция необязательна: при наличии `Text.textKey` base locale\r\n * каталога применяется и без неё, а документ без ключей выглядит ровно как раньше.\r\n */\r\n localization?: SceneLocalizationOptions;\r\n /** Internal host boundary override: prefab views are spawnable content, not screen viewports. */\r\n clipToViewport?: boolean;\r\n};\r\n\r\nexport type SceneViewResult = { root: SceneViewport; nodeViews: Map<string, Container>; localization: SceneLocalization };\nconst particleEmitterRegistry = new WeakMap<Container, readonly ParticleEmitterNodeView[]>();\n\r\nfunction spineReferenceFrameFor(document: ProjectDocument, node: UINode): SpineReferenceFrame | undefined {\r\n if (node.type !== \"spine\") return undefined;\r\n const asset = document.assets.find((candidate) => candidate.id === node.assetId);\r\n return asset?.type === \"spine\" ? asset.referenceFrame : undefined;\r\n}\r\n\r\n/** Builds a PixiJS display tree for a scene without depending on DOM or editor state. */\r\nexport function buildSceneView(\r\n document: ProjectDocument,\r\n sceneId: string,\r\n profile: LayoutProfileId,\r\n options: BuildSceneViewOptions,\r\n): SceneViewResult {\r\n initializePixiLayout();\r\n const { interaction, textures, spines, fonts, bitmapFonts, sounds, ticker, onLayout } = options;\r\n const scene = document.scenes.find((candidate) => candidate.id === sceneId);\r\n\r\n if (scene === undefined) {\r\n throw new Error(`Scene '${sceneId}' does not exist in the project document.`);\r\n }\r\n\r\n const nodeViews = new Map<string, Container>();\n const particleEmitters: ParticleEmitterNodeView[] = [];\n\r\n // Materialized prefab children use instance-scoped IDs, so authoring and runtime can address\r\n // multiple instances independently without changing canonical definition IDs.\r\n const screenSize = scene.layout.referenceViewports[profile];\r\n const referenceResolution = scene.layout.preferredViewports[profile];\r\n const canvasScale = getCanvasScale(screenSize, referenceResolution);\r\n const canvasSize = getCanvasLogicalSize(screenSize, referenceResolution);\r\n\r\n // Единый резолвер иерархии: тот же граф, что видит редактор, включая вложенные пресеты.\r\n const owner = resolveOwnerNodeGraph(document, scene);\r\n const prefabIds = new Set(document.prefabs.map((prefab) => prefab.id));\r\n\r\n const buildOwner = (rootSize: LayoutSize): Container => {\r\n const nodesById = new Map(owner.nodes.map((node) => [node.id, node]));\r\n\r\n const buildNode = (nodeId: string, parentSize: LayoutSize): NodeView => {\r\n const node = nodesById.get(nodeId);\r\n\r\n if (node === undefined) {\r\n throw new Error(`Scene '${sceneId}' references missing node '${nodeId}'.`);\r\n }\r\n\r\n const resolved = resolveProfileTransform(node, profile);\r\n const transform = resolveAnchoredTransform(resolved.transform, parentSize);\r\n const view = createNodeView(node, interaction, textures, spines, (prefabId) => prefabIds.has(prefabId), fonts, sounds, node.type === \"particle-emitter\" ? document.effects.find((effect) => effect.id === node.effectId && isParticleEffect(effect)) : undefined, spineReferenceFrameFor(document, node), ticker, bitmapFonts);\r\n if (isLayoutGroup(node)) applyLayoutGroup(view, node, profile, parentSize);\r\n // Yoga owns only the group's inner layoutContent; the outer NodeView keeps authored transform.\r\n view.update(node, profile, parentSize);\r\n nodeViews.set(node.id, view);\n if (view instanceof ParticleEmitterNodeView) particleEmitters.push(view);\n\r\n // Прямые дети корня сцены разрешают якоря относительно логического Canvas, а не размера корня.\r\n // Прямой ребёнок grid-layout (сам `node` здесь) не владеет своим отрисованным размером: Unity-подобная\r\n // фиксированная ячейка полностью переопределяет authored transform (см. applyLayoutItem). Его\r\n // собственным потомкам нужен именно cellWidth/cellHeight, а не anchor-resolved authored-размер —\r\n // иначе они не отслеживают изменение Cell width/height и якорятся относительно устаревшего размера.\r\n const gridParent = node.parentId === null ? undefined : nodesById.get(node.parentId);\r\n const gridCell = gridParent?.type === \"grid-layout\" ? resolveLayoutGroupSettings<GridLayoutSettings>(gridParent, profile) : undefined;\r\n const childSize = node.parentId === null\r\n ? rootSize\r\n : gridCell !== undefined\r\n ? { width: gridCell.cellWidth, height: gridCell.cellHeight }\r\n : { width: transform.width, height: transform.height };\r\n for (const [childIndex, childId] of node.children.entries()) {\r\n const childNode = nodesById.get(childId);\r\n const childView = buildNode(childId, childSize);\r\n if (isLayoutGroup(node) && childNode !== undefined && view instanceof LayoutGroupNodeView) {\r\n const layoutItem = new LayoutItemContainer(childView, onLayout);\r\n applyLayoutItem(layoutItem, childNode, node, profile);\r\n view.addLayoutChild(layoutItem);\r\n } else if (node.type === \"scroll-view\" && childNode !== undefined && view instanceof ScrollViewNodeView) {\r\n const scrollItem = new ScrollItemContainer(childView, onLayout);\r\n // Как и у layout-item: собственный (не растянутый якорями) размер ребёнка — List не\r\n // предоставляет per-item override размера, в отличие от Yoga flexGrow/cellSize.\r\n const own = resolveProfileTransform(childNode, profile).transform;\r\n scrollItem.sync(childNode, profile, { width: own.width, height: own.height });\r\n view.addScrollItem(scrollItem);\r\n } else if (node.type === \"page-group\" && childNode !== undefined && view instanceof PageGroupNodeView) {\r\n // Unlike a scroll-view item, a page fills the group's own resolved rect completely\r\n // (`childSize`, computed above): a page is a full sub-screen, not content sized to itself.\r\n const pageItem = new PageItemContainer(childView);\r\n pageItem.sync(childNode, profile, childSize);\r\n view.addPageItem(pageItem);\r\n } else {\r\n view.addChild(childView);\r\n }\r\n if (node.type === \"grid-layout\") {\r\n const settings = node.layoutGroup.overrides?.[profile] === undefined ? node.layoutGroup.base : { ...node.layoutGroup.base, ...node.layoutGroup.overrides[profile] };\r\n if (settings.constraint !== \"flexible\" && settings.constraintCount !== undefined && (childIndex + 1) % settings.constraintCount === 0 && childIndex + 1 < node.children.length) {\r\n const lineBreak = createGridLineBreak(node, profile);\r\n if (lineBreak !== undefined && view instanceof LayoutGroupNodeView) view.addLayoutChild(lineBreak);\r\n }\r\n }\r\n }\r\n\r\n return view;\r\n };\r\n\r\n const ownerRoot = new Container();\r\n for (const rootNodeId of owner.rootNodeIds) {\r\n ownerRoot.addChild(buildNode(rootNodeId, rootSize));\r\n }\r\n\r\n return ownerRoot;\r\n };\r\n\r\n const canvasRoot = buildOwner(canvasSize);\r\n canvasRoot.scale.set(canvasScale);\r\n const hostRoot = new SceneViewport(canvasRoot, screenSize, options.clipToViewport ?? interaction === \"runtime\");\n particleEmitterRegistry.set(hostRoot, particleEmitters);\n // Контроллер применяет переводы сразу к уже созданным views, поэтому keyed Text показывает\r\n // базовую локаль без единого дополнительного вызова со стороны хоста.\r\n const localization = new SceneLocalization(document, scene, nodeViews, options.localization);\r\n wireCheckboxGroups(owner.nodes, nodeViews);\r\n wireSpineConnectors(owner.nodes, nodeViews);\r\n return { root: hostRoot, nodeViews, localization };\r\n}\r\n\r\nfunction wireSpineConnectors(nodes: readonly UINode[], nodeViews: ReadonlyMap<string, Container>): void {\r\n for (const node of nodes) {\r\n if (node.type !== \"spine\") continue;\r\n const view = nodeViews.get(node.id);\r\n if (!(view instanceof SpineNodeView)) continue;\r\n view.setConnectorBones((node.connectors ?? []).flatMap((connector) => {\r\n const target = nodeViews.get(connector.targetNodeId);\r\n return target === undefined ? [] : [{ ...connector, target }];\r\n }));\r\n }\r\n}\r\n\r\n/**\r\n * Authored `group` gives sibling checkboxes radio-button behavior: checking one force-unchecks its\r\n * live group-mates (same `parentId`, same `group`), without touching the document. Runs once per\r\n * scene build; `CheckboxNodeView.forceCheck` never re-emits `onCheck`, so this can't recurse.\r\n */\r\nfunction wireCheckboxGroups(nodes: readonly UINode[], nodeViews: ReadonlyMap<string, Container>): void {\r\n const byGroup = new Map<string, CheckboxNodeView[]>();\r\n for (const node of nodes) {\r\n if (node.type !== \"checkbox\" || node.group === undefined) continue;\r\n const view = nodeViews.get(node.id);\r\n if (!(view instanceof CheckboxNodeView)) continue;\r\n const key = `${node.parentId ?? \"\"}::${node.group}`;\r\n const group = byGroup.get(key) ?? [];\r\n group.push(view);\r\n byGroup.set(key, group);\r\n }\r\n for (const group of byGroup.values()) {\r\n if (group.length < 2) continue;\r\n for (const view of group) {\r\n view.onCheck.connect((checked) => {\r\n if (!checked) return;\r\n for (const other of group) if (other !== view) other.forceCheck(false);\r\n });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Applies a node's resolved transform, visibility, and content to an existing display object,\r\n * so editors can update views in place without rebuilding the scene tree.\r\n */\r\nexport function updateNodeView(view: Container, node: UINode, profile: LayoutProfileId, parentSize?: LayoutSize, parentNode?: UINode, effect?: EffectDefinition, spineReferenceFrame?: SpineReferenceFrame): void {\r\n if (isLayoutGroup(node)) applyLayoutGroup(view, node, profile, parentSize);\r\n if (!(view instanceof NodeView)) return;\r\n if (view instanceof SpineNodeView) view.setReferenceFrame(spineReferenceFrame);\r\n if (node.type === \"particle-emitter\" && effect !== undefined && isParticleEffect(effect) && \"syncEffect\" in view && typeof (view as { syncEffect?: unknown }).syncEffect === \"function\") (view as { syncEffect(effect: import(\"@pixi-ui-editor/schema\").ParticleEffectDefinition): void }).syncEffect(effect);\r\n if (parentNode !== undefined && isLayoutGroup(parentNode) && view.parent instanceof LayoutItemContainer) {\r\n applyLayoutItem(view.parent, node, parentNode, profile);\r\n } else if (parentNode !== undefined && parentNode.type === \"scroll-view\" && view.parent instanceof ScrollItemContainer) {\r\n const own = resolveProfileTransform(node, profile).transform;\r\n view.parent.sync(node, profile, { width: own.width, height: own.height });\r\n } else {\r\n view.update(node, profile, parentSize);\r\n }\r\n}\r\n\r\n/** Previews a resolved editor rectangle without consulting content bounds or rebuilding the view. */\r\nexport function previewNodeView(view: Container, node: UINode, profile: LayoutProfileId, transform: UINode[\"transform\"]): void {\r\n if (isLayoutGroup(node)) applyLayoutGroup(view, node, profile, undefined, { width: transform.width, height: transform.height });\r\n if (view instanceof NodeView) view.preview(node, transform, resolveProfileTransform(node, profile).visible, profile);\r\n}\r\n\r\n/** Hosts call this from their own Application ticker; runtime never subscribes to Ticker.shared. */\r\nexport function updateParticleEmitters(root: Container, deltaSeconds: number): void {\n const registered = particleEmitterRegistry.get(root);\n if (registered !== undefined) {\n for (const emitter of registered) emitter.updateParticles(deltaSeconds);\n return;\n }\n // Backward-compatible fallback for hosts that assemble a display tree manually instead of using\n // buildSceneView. Built scenes always take the O(emitter count) registry path above.\n const visit = (view: Container): void => {\n if (view instanceof ParticleEmitterNodeView) view.updateParticles(deltaSeconds);\n for (const child of view.children) visit(child);\n };\n visit(root);\n}\n\r\n/** Lists the nodes a scene renders, including nodes of prefab definitions its prefab instances expand to. */\r\nexport function collectRenderedNodes(document: ProjectDocument, scene: Scene): UINode[] {\r\n return resolveOwnerNodeGraph(document, scene).nodes;\r\n}\r\n\r\nexport type PrefabViewConfiguration = Pick<Extract<UINode, { type: \"prefab-instance\" }>, \"propertyOverrides\" | \"locallyAddedNodes\"> & { instanceId?: string };\r\n\r\nfunction prefabScene(document: ProjectDocument, prefabId: string, configuration: PrefabViewConfiguration = {}): { document: ProjectDocument; sceneId: string; instanceId: string } {\r\n const prefab = document.prefabs.find((candidate) => candidate.id === prefabId);\r\n if (prefab === undefined) throw new Error(`Prefab '${prefabId}' does not exist in the project document.`);\r\n const width = Math.max(1, ...prefab.nodes.map((node) => Math.abs(node.transform.x) + Math.max(0, node.transform.width)));\r\n const height = Math.max(1, ...prefab.nodes.map((node) => Math.abs(node.transform.y) + Math.max(0, node.transform.height)));\r\n const instanceId = configuration.instanceId ?? createStableId();\r\n const instance: Extract<UINode, { type: \"prefab-instance\" }> = {\r\n id: instanceId, name: prefab.name, type: \"prefab-instance\", prefabId, parentId: null, children: [],\r\n visible: true, transform: { x: 0, y: 0, width, height, scaleX: 1, scaleY: 1, rotation: 0, anchorMinX: 0, anchorMaxX: 0, anchorMinY: 0, anchorMaxY: 0, pivotX: 0, pivotY: 0 },\r\n ...(configuration.propertyOverrides === undefined ? {} : { propertyOverrides: structuredClone(configuration.propertyOverrides) }),\r\n ...(configuration.locallyAddedNodes === undefined ? {} : { locallyAddedNodes: structuredClone(configuration.locallyAddedNodes) }),\r\n };\r\n const sceneId = createStableId();\r\n const viewport = { width, height };\r\n const scene: Scene = { id: sceneId, name: prefab.name, rootNodeIds: [instance.id], nodes: [instance], layout: { referenceViewports: { desktop: viewport, mobile: viewport }, preferredViewports: { desktop: viewport, mobile: viewport } } };\r\n return { document: { ...document, scenes: [...document.scenes, scene] }, sceneId, instanceId };\r\n}\r\n\r\n/** Builds a fresh runtime prefab instance without requiring it to already exist in a scene. */\r\nexport function buildPrefabView(document: ProjectDocument, prefabId: string, profile: LayoutProfileId, options: BuildSceneViewOptions, configuration: PrefabViewConfiguration = {}): SceneViewResult & { instanceId: string } {\r\n const synthetic = prefabScene(document, prefabId, configuration);\r\n return { ...buildSceneView(synthetic.document, synthetic.sceneId, profile, { ...options, clipToViewport: false }), instanceId: synthetic.instanceId };\r\n}\r\n\r\n/** Loads a prefab's assets and returns a fresh display tree suitable for dynamic game-code spawning. */\r\nexport async function loadPrefabView(document: ProjectDocument, prefabId: string, profile: LayoutProfileId, resolveFileUrl: FileUrlResolver, options: { interaction: SceneInteractionMode; ticker?: Ticker; localization?: SceneLocalizationOptions; assetCache?: SceneAssetCache }, configuration: PrefabViewConfiguration = {}): Promise<SceneViewResult & { instanceId: string }> {\r\n const synthetic = prefabScene(document, prefabId, configuration);\r\n return { ...await loadSceneView(synthetic.document, synthetic.sceneId, profile, resolveFileUrl, { ...options, clipToViewport: false }), instanceId: synthetic.instanceId };\r\n}\r\n\r\n/** Loads a scene's textures and Spine data, then builds its display tree in one call. */\r\nexport async function loadSceneView(\r\n document: ProjectDocument,\r\n sceneId: string,\r\n profile: LayoutProfileId,\r\n resolveFileUrl: FileUrlResolver,\r\n options: { interaction: SceneInteractionMode; ticker?: Ticker; localization?: SceneLocalizationOptions; clipToViewport?: boolean; assetCache?: SceneAssetCache },\r\n): Promise<SceneViewResult> {\r\n // Без assetCache каждый вызов начинает с пустых кэшей: для одиночной загрузки сцены это нормально, а вот\r\n // игровой код, который поднимает пресеты по одному, обязан передать собственный кэш — иначе один и тот же\r\n // скелет, атлас и текстура парсятся заново на каждую вьюху и дублируются в видеопамяти.\r\n const cache = options.assetCache;\r\n const [textures, spines, fonts, bitmapFonts] = await Promise.all([\r\n loadSceneTextures(document, sceneId, (asset) => (asset.type === \"image\" ? resolveFileUrl(asset.source.uri) : undefined), resolveFileUrl, cache?.textures, cache?.spritesheets, cache?.bitmapFonts),\r\n loadSceneSpines(document, sceneId, resolveFileUrl, cache?.spines),\r\n loadSceneFonts(document, sceneId, resolveFileUrl, cache?.fonts),\r\n loadSceneBitmapFonts(document, sceneId, resolveFileUrl, cache?.bitmapFonts),\r\n ]);\r\n return buildSceneView(document, sceneId, profile, { interaction: options.interaction, textures, spines, fonts, bitmapFonts, ticker: options.ticker, localization: options.localization, clipToViewport: options.clipToViewport });\r\n}\r\n"]}
|
package/dist/views/NodeView.d.ts
CHANGED
|
@@ -20,8 +20,8 @@ export declare abstract class NodeView extends Container {
|
|
|
20
20
|
/** Node's own grab rectangle in local space, kept equal to its resolved layout rectangle. */
|
|
21
21
|
private readonly grabRect;
|
|
22
22
|
/** Authored/computed RectTransform-like rectangle; unlike Pixi bounds it also exists without content. */
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
protected layoutWidth: number;
|
|
24
|
+
protected layoutHeight: number;
|
|
25
25
|
constructor(textures?: ReadonlyMap<string, Texture>);
|
|
26
26
|
protected textureFor(assetId: string): Texture | undefined;
|
|
27
27
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeView.d.ts","sourceRoot":"","sources":["../../src/views/NodeView.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAC;AACxD,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAa,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EAAqD,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAElG;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,WAAW,GAAG,SAAS,CAAC;AAE3D;;;;GAIG;AACH,8BAAsB,QAAS,SAAQ,SAAS;IAC9C,SAAS,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;IAC9B,4FAA4F;IAC5F,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IACtE,6FAA6F;IAC7F,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmB;IAC5C,yGAAyG;IACzG,
|
|
1
|
+
{"version":3,"file":"NodeView.d.ts","sourceRoot":"","sources":["../../src/views/NodeView.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAC;AACxD,OAAO,EAAE,KAAK,eAAe,EAAE,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAa,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EAAqD,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAElG;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,WAAW,GAAG,SAAS,CAAC;AAE3D;;;;GAIG;AACH,8BAAsB,QAAS,SAAQ,SAAS;IAC9C,SAAS,CAAC,OAAO,CAAC,EAAE,SAAS,CAAC;IAC9B,4FAA4F;IAC5F,SAAS,CAAC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IACtE,6FAA6F;IAC7F,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAmB;IAC5C,yGAAyG;IACzG,SAAS,CAAC,WAAW,SAAK;IAC1B,SAAS,CAAC,YAAY,SAAK;gBAEf,QAAQ,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC;IAKnD,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS;IAI1D;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO;IAIxC,mGAAmG;IACnG,SAAS,CAAC,UAAU,CAAC,OAAO,EAAE,SAAS,GAAG,IAAI;IAM9C,kGAAkG;IAClG,SAAS,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,WAAW,CAAC,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI;IAE5G,OAAO,CAAC,sBAAsB;IAuB9B,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,UAAU,CAAC,EAAE,UAAU,GAAG,IAAI;IAK7E,mGAAmG;IACnG,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,CAAC,WAAW,CAAC,EAAE,OAAO,UAAO,EAAE,OAAO,GAAE,eAA2B,GAAG,IAAI;IAIjH,sEAAsE;IACtE,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI;IAK7E,IAAI,eAAe,IAAI,UAAU,CAEhC;IAED,QAAQ,IAAI,KAAK,GAAG,SAAS;IAI7B;;;;;;OAMG;IACH,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;CAChD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NodeView.js","sourceRoot":"","sources":["../../src/views/NodeView.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAC;AAExD,OAAO,EAAE,SAAS,EAAE,SAAS,EAA2B,MAAM,SAAS,CAAC;AACxE,OAAO,EAAE,wBAAwB,EAAE,uBAAuB,EAAmB,MAAM,cAAc,CAAC;AASlG;;;;GAIG;AACH,MAAM,OAAgB,QAAS,SAAQ,SAAS;IACpC,OAAO,CAAa;IAC9B,4FAA4F;IACzE,QAAQ,CAA2C;IACtE,6FAA6F;IAC5E,QAAQ,GAAG,IAAI,SAAS,EAAE,CAAC;IAC5C,yGAAyG;
|
|
1
|
+
{"version":3,"file":"NodeView.js","sourceRoot":"","sources":["../../src/views/NodeView.ts"],"names":[],"mappings":"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","sourcesContent":["import { Spine } from \"@esotericsoftware/spine-pixi-v8\";\r\nimport { type LayoutProfileId, type UINode } from \"@pixi-ui-editor/schema\";\r\nimport { Container, Rectangle, Texture, type PointData } from \"pixi.js\";\r\nimport { resolveAnchoredTransform, resolveProfileTransform, type LayoutSize } from \"../layout.js\";\r\n\r\n/**\r\n * Whether a built scene is an inert authoring surface or a live one.\r\n * The editor canvas builds `authoring` scenes so controls never swallow selection and drag\r\n * gestures; Preview and the consuming app build `runtime` scenes with real pointer handling.\r\n */\r\nexport type SceneInteractionMode = \"authoring\" | \"runtime\";\r\n\r\n/**\r\n * Base display object for every schema node type. The whole layout contract — profile overrides,\r\n * anchors, pivot, position, scale, visibility — lives here once; subclasses only synchronize their\r\n * type-specific content against the resolved layout rectangle.\r\n */\r\nexport abstract class NodeView extends Container {\r\n protected content?: Container;\r\n /** A mutable scene texture map: assets may be loaded after this stable view was created. */\r\n protected readonly textures: ReadonlyMap<string, Texture> | undefined;\r\n /** Node's own grab rectangle in local space, kept equal to its resolved layout rectangle. */\r\n private readonly grabRect = new Rectangle();\r\n /** Authored/computed RectTransform-like rectangle; unlike Pixi bounds it also exists without content. */\r\n protected layoutWidth = 0;\n protected layoutHeight = 0;\n\r\n constructor(textures?: ReadonlyMap<string, Texture>) {\r\n super();\r\n this.textures = textures;\r\n }\r\n\r\n protected textureFor(assetId: string): Texture | undefined {\r\n return this.textures?.get(assetId);\r\n }\r\n\r\n /**\r\n * Makes every node selectable and draggable by its layout rectangle, whatever it renders.\r\n *\r\n * Lives here rather than in a subclass because a bare `Container` has no `containsPoint` of its\r\n * own: without this, Pixi could only find a node through whatever content the subclass happens to\r\n * draw, so nodes that draw nothing (container) or keep their content out of hit testing (button,\r\n * whose `@pixi/ui` view is inert while authoring) would silently stop being selectable.\r\n *\r\n * Deliberately `containsPoint` and NOT `hitArea`: Pixi's `hitPruneFn` drops a container together\r\n * with its whole subtree once the point falls outside its `hitArea`, which would make any child\r\n * reaching past its parent's rectangle visible but unclickable. `containsPoint` never clips\r\n * children — they are hit-tested first and independently, so a child always stays grabbable.\r\n */\r\n containsPoint(point: PointData): boolean {\r\n return this.grabRect.contains(point.x, point.y);\r\n }\r\n\r\n /** Заменяет содержимое ноды: прежнее снимается со сцены и уничтожается, чтобы не копить сироты. */\r\n protected setContent(content: Container): void {\r\n if (this.content !== undefined) { this.removeChild(this.content); this.content.destroy(); }\r\n this.content = content;\r\n this.addChild(content);\r\n }\r\n\r\n /** Syncs type-specific content to the resolved layout rectangle; layout math itself is shared. */\r\n protected abstract syncContent(node: UINode, transform: UINode[\"transform\"], profile: LayoutProfileId): void;\r\n\r\n private applyResolvedTransform(node: UINode, transform: UINode[\"transform\"], visible: boolean, managedByLayout: boolean, profile: LayoutProfileId): void {\r\n this.syncContent(node, transform, profile);\r\n\r\n const pivotX = (transform.pivotX ?? 0) * transform.width;\r\n const pivotY = (transform.pivotY ?? 0) * transform.height;\r\n this.pivot.set(pivotX, pivotY);\r\n // x/y are the pivot offset from the resolved anchor. Thus a centred anchor and pivot at\r\n // zero offsets place the visual centre exactly at the parent's centre.\r\n // A managed child is positioned by its technical Yoga item. Its own NodeView keeps only the\r\n // pivot offset inside that computed rectangle; authored x/y and anchors do not participate.\r\n this.position.set(managedByLayout ? pivotX : transform.x, managedByLayout ? pivotY : transform.y);\r\n this.rotation = transform.rotation;\r\n this.scale.set(transform.scaleX, transform.scaleY);\r\n this.visible = visible;\r\n this.layoutWidth = transform.width;\r\n this.layoutHeight = transform.height;\r\n // Тот же прямоугольник, что видит пользователь: grab-зона не зависит от содержимого ноды.\r\n this.grabRect.x = 0;\r\n this.grabRect.y = 0;\r\n this.grabRect.width = transform.width;\r\n this.grabRect.height = transform.height;\r\n }\r\n\r\n update(node: UINode, profile: LayoutProfileId, parentSize?: LayoutSize): void {\r\n const resolved = resolveProfileTransform(node, profile);\r\n this.applyResolvedTransform(node, resolveAnchoredTransform(resolved.transform, parentSize), resolved.visible, false, profile);\r\n }\r\n\r\n /** Applies a transient editor rectangle without deriving it from content-dependent Pixi bounds. */\r\n preview(node: UINode, transform: UINode[\"transform\"], visible = true, profile: LayoutProfileId = \"desktop\"): void {\r\n this.applyResolvedTransform(node, transform, visible, false, profile);\r\n }\r\n\r\n /** Applies the rectangle owned by a direct parent's layout solver. */\r\n updateManaged(node: UINode, profile: LayoutProfileId, size: LayoutSize): void {\r\n const resolved = resolveProfileTransform(node, profile);\r\n this.applyResolvedTransform(node, { ...resolved.transform, x: 0, y: 0, width: size.width, height: size.height }, resolved.visible, true, profile);\r\n }\r\n\r\n get layoutRectangle(): LayoutSize {\r\n return { width: this.layoutWidth, height: this.layoutHeight };\r\n }\r\n\r\n getSpine(): Spine | undefined {\r\n return this.content instanceof Spine ? this.content : undefined;\r\n }\r\n\r\n /**\r\n * Rasterizes canvas-based content (`TextNodeView`) at a higher pixel density than the renderer's\r\n * own backing resolution, so an authoring camera zoomed in doesn't magnify an already-rasterized\r\n * bitmap past its source resolution and read as blurred. A no-op base implementation: sprite/\r\n * graphics/bitmap-text content is either GPU-native (always crisp under zoom) or, for bitmap-text,\r\n * has its resolution fixed by the installed `BitmapFont` and can't be changed per instance.\r\n */\r\n setContentResolution(_resolution: number): void {}\r\n}\r\n"]}
|
|
@@ -5,8 +5,18 @@ import { NodeView } from "./NodeView.js";
|
|
|
5
5
|
export declare class ParticleEmitterNodeView extends NodeView {
|
|
6
6
|
private readonly contentRoot;
|
|
7
7
|
private readonly simulator;
|
|
8
|
+
private readonly renderGroups;
|
|
8
9
|
private simulationSpace;
|
|
9
10
|
private autoplayHandled;
|
|
11
|
+
private renderDirty;
|
|
12
|
+
private tintStart;
|
|
13
|
+
private tintEnd;
|
|
14
|
+
private staticColor;
|
|
15
|
+
private dynamicProperties;
|
|
16
|
+
private readonly spawnContext;
|
|
17
|
+
private renderSignature;
|
|
18
|
+
private sourceSignature;
|
|
19
|
+
private sourceTextures;
|
|
10
20
|
constructor(effect: ParticleEffectDefinition, textures?: ReadonlyMap<string, Texture>);
|
|
11
21
|
updateParticles(deltaSeconds: number): void;
|
|
12
22
|
play(): void;
|
|
@@ -22,5 +32,8 @@ export declare class ParticleEmitterNodeView extends NodeView {
|
|
|
22
32
|
destroy(options?: DestroyOptions): void;
|
|
23
33
|
protected syncContent(node: UINode): void;
|
|
24
34
|
private syncRender;
|
|
35
|
+
private cacheEffect;
|
|
36
|
+
private groupFor;
|
|
37
|
+
private destroyRenderGroups;
|
|
25
38
|
}
|
|
26
39
|
//# sourceMappingURL=ParticleEmitterNodeView.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ParticleEmitterNodeView.d.ts","sourceRoot":"","sources":["../../src/views/ParticleEmitterNodeView.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC/E,OAAO,
|
|
1
|
+
{"version":3,"file":"ParticleEmitterNodeView.d.ts","sourceRoot":"","sources":["../../src/views/ParticleEmitterNodeView.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC/E,OAAO,EAA0C,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAE/F,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAIzC,uFAAuF;AACvF,qBAAa,uBAAwB,SAAQ,QAAQ;IACnD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAmB;IAC/C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA8B;IACxD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAqD;IAClF,OAAO,CAAC,eAAe,CAA8B;IACrD,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,WAAW,CAAQ;IAC3B,OAAO,CAAC,SAAS,CAAY;IAC7B,OAAO,CAAC,OAAO,CAAY;IAC3B,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,iBAAiB,CAA2G;IACpI,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAiE;IAC9F,OAAO,CAAC,eAAe,CAAM;IAC7B,OAAO,CAAC,eAAe,CAAM;IAC7B,OAAO,CAAC,cAAc,CAAwC;gBAElD,MAAM,EAAE,wBAAwB,EAAE,QAAQ,CAAC,EAAE,WAAW,CAAC,MAAM,EAAE,OAAO,CAAC;IAcrF,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAU3C,IAAI,IAAI,IAAI;IACZ,KAAK,IAAI,IAAI;IACb,OAAO,IAAI,IAAI;IACf,IAAI,IAAI,IAAI;IACZ,sGAAsG;IACtG,IAAI,IAAI,IAAI;IAOZ,OAAO,IAAI,IAAI;IAIf,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAC1C,cAAc;IAEd,UAAU,CAAC,MAAM,EAAE,wBAAwB,GAAG,IAAI;IAKzC,OAAO,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,IAAI;IAKhD,SAAS,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAazC,OAAO,CAAC,UAAU;IAyDlB,OAAO,CAAC,WAAW;IA8BnB,OAAO,CAAC,QAAQ;IAchB,OAAO,CAAC,mBAAmB;CAO5B"}
|
|
@@ -1,33 +1,45 @@
|
|
|
1
|
-
import { Container,
|
|
2
|
-
import { lerp,
|
|
1
|
+
import { Container, Particle, ParticleContainer, Texture } from "pixi.js";
|
|
2
|
+
import { lerp, ParticleSimulator } from "../particles.js";
|
|
3
3
|
import { NodeView } from "./NodeView.js";
|
|
4
4
|
const DEG_TO_RAD = Math.PI / 180;
|
|
5
5
|
/** Thin Pixi adapter: NodeView continues to own transforms, layout and hit testing. */
|
|
6
6
|
export class ParticleEmitterNodeView extends NodeView {
|
|
7
7
|
contentRoot = new Container();
|
|
8
8
|
simulator;
|
|
9
|
+
renderGroups = new Map();
|
|
9
10
|
simulationSpace = "local";
|
|
10
11
|
autoplayHandled = false;
|
|
12
|
+
renderDirty = true;
|
|
13
|
+
tintStart = 0xffffff;
|
|
14
|
+
tintEnd = 0xffffff;
|
|
15
|
+
staticColor = 0xffffffff;
|
|
16
|
+
dynamicProperties = { position: true, rotation: false, vertex: false, uvs: false, color: false };
|
|
17
|
+
spawnContext = { width: 0, height: 0, space: "local" };
|
|
18
|
+
renderSignature = "";
|
|
19
|
+
sourceSignature = "";
|
|
20
|
+
sourceTextures = [];
|
|
11
21
|
constructor(effect, textures) {
|
|
12
22
|
super(textures);
|
|
13
23
|
this.setContent(this.contentRoot);
|
|
24
|
+
this.cacheEffect(effect);
|
|
14
25
|
this.simulator = new ParticleSimulator(effect, {
|
|
15
26
|
createRender: () => {
|
|
16
|
-
|
|
17
|
-
sprite.anchor.set(0.5);
|
|
18
|
-
sprite.visible = false;
|
|
19
|
-
this.contentRoot.addChild(sprite);
|
|
20
|
-
return sprite;
|
|
27
|
+
return new Particle({ texture: Texture.EMPTY, anchorX: 0.5, anchorY: 0.5 });
|
|
21
28
|
},
|
|
22
|
-
hideRender: (
|
|
23
|
-
destroyRender: (
|
|
29
|
+
hideRender: () => undefined,
|
|
30
|
+
destroyRender: () => undefined,
|
|
24
31
|
getWorldTransform: () => this.worldTransform,
|
|
25
32
|
});
|
|
26
33
|
}
|
|
27
34
|
updateParticles(deltaSeconds) {
|
|
28
|
-
|
|
29
|
-
this.
|
|
30
|
-
this.
|
|
35
|
+
this.spawnContext.width = this.layoutWidth;
|
|
36
|
+
this.spawnContext.height = this.layoutHeight;
|
|
37
|
+
this.spawnContext.space = this.simulationSpace;
|
|
38
|
+
const advanced = this.simulator.update(deltaSeconds, this.spawnContext);
|
|
39
|
+
// World-space particles must also be reprojected when an ancestor moves between simulation
|
|
40
|
+
// steps. Local particles need no work: Pixi applies their container transform itself.
|
|
41
|
+
if (advanced || this.renderDirty || (this.simulationSpace === "world" && this.simulator.activeSlots.size > 0))
|
|
42
|
+
this.syncRender();
|
|
31
43
|
}
|
|
32
44
|
play() { this.simulator.play(); }
|
|
33
45
|
pause() { this.simulator.pause(); }
|
|
@@ -35,14 +47,22 @@ export class ParticleEmitterNodeView extends NodeView {
|
|
|
35
47
|
stop() { this.simulator.stop(); }
|
|
36
48
|
/** Advances exactly one fixed step even while paused, preserving the current playing/paused state. */
|
|
37
49
|
step() {
|
|
38
|
-
|
|
39
|
-
this.
|
|
50
|
+
this.spawnContext.width = this.layoutWidth;
|
|
51
|
+
this.spawnContext.height = this.layoutHeight;
|
|
52
|
+
this.spawnContext.space = this.simulationSpace;
|
|
53
|
+
this.simulator.step(this.spawnContext);
|
|
40
54
|
this.syncRender();
|
|
41
55
|
}
|
|
42
|
-
dispose() {
|
|
56
|
+
dispose() {
|
|
57
|
+
this.simulator.dispose();
|
|
58
|
+
this.destroyRenderGroups();
|
|
59
|
+
}
|
|
43
60
|
setEmissionMultiplier(value) { this.simulator.setEmissionMultiplier(value); }
|
|
44
61
|
getDiagnostics() { return this.simulator.getDiagnostics(); }
|
|
45
|
-
syncEffect(effect) {
|
|
62
|
+
syncEffect(effect) {
|
|
63
|
+
this.simulator.syncEffect(effect);
|
|
64
|
+
this.renderDirty ||= this.cacheEffect(effect);
|
|
65
|
+
}
|
|
46
66
|
destroy(options) {
|
|
47
67
|
this.dispose();
|
|
48
68
|
super.destroy(options);
|
|
@@ -50,6 +70,8 @@ export class ParticleEmitterNodeView extends NodeView {
|
|
|
50
70
|
syncContent(node) {
|
|
51
71
|
if (node.type !== "particle-emitter")
|
|
52
72
|
return;
|
|
73
|
+
if (this.simulationSpace !== node.simulationSpace)
|
|
74
|
+
this.renderDirty = true;
|
|
53
75
|
this.simulationSpace = node.simulationSpace;
|
|
54
76
|
// Autoplay only fires once, right after construction: syncContent also runs on every unrelated
|
|
55
77
|
// document edit (via the shared node-sync pass), and re-arming play() there would silently
|
|
@@ -65,32 +87,115 @@ export class ParticleEmitterNodeView extends NodeView {
|
|
|
65
87
|
const source = p.visual.source;
|
|
66
88
|
const space = this.simulationSpace;
|
|
67
89
|
const inverse = space === "world" ? this.worldTransform : undefined;
|
|
90
|
+
const determinant = inverse === undefined ? 0 : inverse.a * inverse.d - inverse.b * inverse.c;
|
|
91
|
+
const inverseDeterminant = determinant === 0 ? 0 : 1 / determinant;
|
|
92
|
+
for (const group of this.renderGroups.values()) {
|
|
93
|
+
group.nextCount = 0;
|
|
94
|
+
group.dirty ||= this.renderDirty;
|
|
95
|
+
}
|
|
68
96
|
for (const slot of this.simulator.activeSlots) {
|
|
69
|
-
const
|
|
97
|
+
const particle = slot.render;
|
|
70
98
|
const t = slot.lifetime > 0 ? Math.min(1, slot.age / slot.lifetime) : 1;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
99
|
+
const sourceIndex = source.type === "single" ? 0 : source.type === "random" ? slot.sourceIndex : sequenceFrame(source, slot);
|
|
100
|
+
const texture = this.sourceTextures[sourceIndex] ?? Texture.EMPTY;
|
|
101
|
+
const textureChanged = particle.texture !== texture;
|
|
102
|
+
if (textureChanged)
|
|
103
|
+
particle.texture = texture;
|
|
104
|
+
const initializeStatic = slot.renderDirty || this.renderDirty;
|
|
105
|
+
if (this.dynamicProperties.vertex || initializeStatic) {
|
|
106
|
+
const scale = lerp(slot.scaleStart, slot.scaleEnd, t);
|
|
107
|
+
particle.scaleX = scale;
|
|
108
|
+
particle.scaleY = scale;
|
|
109
|
+
}
|
|
110
|
+
if (this.dynamicProperties.rotation || initializeStatic)
|
|
111
|
+
particle.rotation = slot.rotationDegrees * DEG_TO_RAD;
|
|
112
|
+
if (this.dynamicProperties.color)
|
|
113
|
+
particle.color = packParticleColor(lerpRgb(this.tintStart, this.tintEnd, t), lerp(p.visual.alpha.start, p.visual.alpha.end, t));
|
|
114
|
+
else if (initializeStatic)
|
|
115
|
+
particle.color = this.staticColor;
|
|
82
116
|
if (space === "world" && inverse !== undefined) {
|
|
83
117
|
const dx = slot.x - slot.spawnX, dy = slot.y - slot.spawnY;
|
|
84
118
|
const worldX = slot.worldSpawnX + slot.spawnMatrixA * dx + slot.spawnMatrixC * dy;
|
|
85
119
|
const worldY = slot.worldSpawnY + slot.spawnMatrixB * dx + slot.spawnMatrixD * dy;
|
|
86
|
-
|
|
87
|
-
|
|
120
|
+
// Inline Matrix.applyInverse to avoid allocating one point per particle per rendered frame.
|
|
121
|
+
const translatedX = worldX - inverse.tx;
|
|
122
|
+
const translatedY = worldY - inverse.ty;
|
|
123
|
+
particle.x = (inverse.d * translatedX - inverse.c * translatedY) * inverseDeterminant;
|
|
124
|
+
particle.y = (-inverse.b * translatedX + inverse.a * translatedY) * inverseDeterminant;
|
|
88
125
|
}
|
|
89
126
|
else {
|
|
90
|
-
|
|
127
|
+
particle.x = slot.x;
|
|
128
|
+
particle.y = slot.y;
|
|
91
129
|
}
|
|
92
|
-
|
|
130
|
+
const group = this.groupFor(texture, p.visual.blendMode);
|
|
131
|
+
group.dirty ||= slot.renderDirty || textureChanged || group.container.particleChildren[group.nextCount] !== particle;
|
|
132
|
+
group.container.particleChildren[group.nextCount++] = particle;
|
|
133
|
+
slot.renderDirty = false;
|
|
134
|
+
}
|
|
135
|
+
for (const group of this.renderGroups.values()) {
|
|
136
|
+
const children = group.container.particleChildren;
|
|
137
|
+
if (children.length !== group.nextCount) {
|
|
138
|
+
children.length = group.nextCount;
|
|
139
|
+
group.dirty = true;
|
|
140
|
+
}
|
|
141
|
+
if (group.dirty)
|
|
142
|
+
group.container.update();
|
|
143
|
+
group.dirty = false;
|
|
144
|
+
}
|
|
145
|
+
this.renderDirty = false;
|
|
146
|
+
}
|
|
147
|
+
cacheEffect(effect) {
|
|
148
|
+
const visual = effect.particle.visual;
|
|
149
|
+
const sourceIds = visual.source.type === "single" ? [visual.source.assetId] : visual.source.assetIds;
|
|
150
|
+
const sourceTextures = sourceIds.map((id) => this.textureFor(id));
|
|
151
|
+
const signature = JSON.stringify(visual);
|
|
152
|
+
const sourceSignature = JSON.stringify(visual.source);
|
|
153
|
+
const sourceChanged = sourceSignature !== this.sourceSignature
|
|
154
|
+
|| sourceTextures.length !== this.sourceTextures.length
|
|
155
|
+
|| sourceTextures.some((texture, index) => texture !== this.sourceTextures[index]);
|
|
156
|
+
const changed = signature !== this.renderSignature
|
|
157
|
+
|| sourceChanged;
|
|
158
|
+
if (!changed)
|
|
159
|
+
return false;
|
|
160
|
+
this.renderSignature = signature;
|
|
161
|
+
this.sourceSignature = sourceSignature;
|
|
162
|
+
this.sourceTextures = sourceTextures;
|
|
163
|
+
// Source edits and late texture loads invalidate the source-keyed groups. Rebuild containers,
|
|
164
|
+
// but keep every pooled Particle and live simulation slot intact.
|
|
165
|
+
if (sourceChanged)
|
|
166
|
+
this.destroyRenderGroups();
|
|
167
|
+
const dynamicProperties = particleDynamicProperties(effect);
|
|
168
|
+
if (!sameDynamicProperties(this.dynamicProperties, dynamicProperties)) {
|
|
169
|
+
this.destroyRenderGroups();
|
|
170
|
+
this.dynamicProperties = dynamicProperties;
|
|
93
171
|
}
|
|
172
|
+
this.tintStart = parseRgb(effect.particle.visual.tint.start);
|
|
173
|
+
this.tintEnd = parseRgb(effect.particle.visual.tint.end);
|
|
174
|
+
this.staticColor = packParticleColor(this.tintStart, effect.particle.visual.alpha.start);
|
|
175
|
+
for (const group of this.renderGroups.values())
|
|
176
|
+
group.container.blendMode = effect.particle.visual.blendMode;
|
|
177
|
+
return true;
|
|
178
|
+
}
|
|
179
|
+
groupFor(texture, blendMode) {
|
|
180
|
+
let group = this.renderGroups.get(texture.source);
|
|
181
|
+
if (group !== undefined)
|
|
182
|
+
return group;
|
|
183
|
+
const container = new ParticleContainer({
|
|
184
|
+
texture,
|
|
185
|
+
dynamicProperties: this.dynamicProperties,
|
|
186
|
+
});
|
|
187
|
+
container.blendMode = blendMode;
|
|
188
|
+
this.contentRoot.addChild(container);
|
|
189
|
+
group = { container, nextCount: 0, dirty: true };
|
|
190
|
+
this.renderGroups.set(texture.source, group);
|
|
191
|
+
return group;
|
|
192
|
+
}
|
|
193
|
+
destroyRenderGroups() {
|
|
194
|
+
for (const group of this.renderGroups.values()) {
|
|
195
|
+
this.contentRoot.removeChild(group.container);
|
|
196
|
+
group.container.destroy();
|
|
197
|
+
}
|
|
198
|
+
this.renderGroups.clear();
|
|
94
199
|
}
|
|
95
200
|
}
|
|
96
201
|
function sequenceFrame(source, slot) {
|
|
@@ -98,4 +203,31 @@ function sequenceFrame(source, slot) {
|
|
|
98
203
|
const raw = slot.sequenceStart + Math.floor(slot.age * source.fps);
|
|
99
204
|
return source.loop ? ((raw % length) + length) % length : Math.min(raw, length - 1);
|
|
100
205
|
}
|
|
206
|
+
function parseRgb(hex) { return Number.parseInt(hex.slice(1, 7), 16); }
|
|
207
|
+
function lerpRgb(start, end, t) {
|
|
208
|
+
const r = Math.round(lerp((start >>> 16) & 0xff, (end >>> 16) & 0xff, t));
|
|
209
|
+
const g = Math.round(lerp((start >>> 8) & 0xff, (end >>> 8) & 0xff, t));
|
|
210
|
+
const b = Math.round(lerp(start & 0xff, end & 0xff, t));
|
|
211
|
+
return (r << 16) | (g << 8) | b;
|
|
212
|
+
}
|
|
213
|
+
/** Pixi Particle buffers store packed ABGR, unlike the public RGB tint number. */
|
|
214
|
+
function packParticleColor(rgb, alpha) {
|
|
215
|
+
const bgr = ((rgb & 0xff) << 16) | (rgb & 0xff00) | ((rgb >>> 16) & 0xff);
|
|
216
|
+
return (bgr | (Math.round(Math.max(0, Math.min(1, alpha)) * 255) << 24)) >>> 0;
|
|
217
|
+
}
|
|
218
|
+
function particleDynamicProperties(effect) {
|
|
219
|
+
const visual = effect.particle.visual;
|
|
220
|
+
const angular = visual.rotation.angularVelocityDegrees;
|
|
221
|
+
const scale = visual.scale;
|
|
222
|
+
return {
|
|
223
|
+
position: true,
|
|
224
|
+
rotation: angular.min !== 0 || angular.max !== 0,
|
|
225
|
+
vertex: !(scale.start.min === scale.start.max && scale.start.min === scale.end.min && scale.start.min === scale.end.max),
|
|
226
|
+
uvs: visual.source.type === "sequence",
|
|
227
|
+
color: visual.tint.start !== visual.tint.end || visual.alpha.start !== visual.alpha.end,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function sameDynamicProperties(a, b) {
|
|
231
|
+
return a.rotation === b.rotation && a.vertex === b.vertex && a.uvs === b.uvs && a.color === b.color;
|
|
232
|
+
}
|
|
101
233
|
//# sourceMappingURL=ParticleEmitterNodeView.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ParticleEmitterNodeView.js","sourceRoot":"","sources":["../../src/views/ParticleEmitterNodeView.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ParticleEffectDefinition, UINode } from \"@pixi-ui-editor/schema\";\r\nimport { Container, Sprite, Texture, type DestroyOptions } from \"pixi.js\";\r\nimport { lerp, lerpColorHex, ParticleSimulator, type ParticleSlot } from \"../particles.js\";\r\nimport { NodeView } from \"./NodeView.js\";\r\n\r\nconst DEG_TO_RAD = Math.PI / 180;\r\n\r\n/** Thin Pixi adapter: NodeView continues to own transforms, layout and hit testing. */\r\nexport class ParticleEmitterNodeView extends NodeView {\r\n private readonly contentRoot = new Container();\r\n private readonly simulator: ParticleSimulator<Sprite>;\r\n private simulationSpace: \"local\" | \"world\" = \"local\";\r\n private autoplayHandled = false;\r\n\r\n constructor(effect: ParticleEffectDefinition, textures?: ReadonlyMap<string, Texture>) {\r\n super(textures);\r\n this.setContent(this.contentRoot);\r\n this.simulator = new ParticleSimulator<Sprite>(effect, {\r\n createRender: () => {\r\n const sprite = new Sprite(Texture.EMPTY);\r\n sprite.anchor.set(0.5);\r\n sprite.visible = false;\r\n this.contentRoot.addChild(sprite);\r\n return sprite;\r\n },\r\n hideRender: (sprite) => { sprite.visible = false; },\r\n destroyRender: (sprite) => { this.contentRoot.removeChild(sprite); sprite.destroy(); },\r\n getWorldTransform: () => this.worldTransform,\r\n });\r\n }\r\n\r\n updateParticles(deltaSeconds: number): void {\r\n const rect = this.layoutRectangle;\r\n this.simulator.update(deltaSeconds, { width: rect.width, height: rect.height, space: this.simulationSpace });\r\n this.syncRender();\r\n }\r\n\r\n play(): void { this.simulator.play(); }\r\n pause(): void { this.simulator.pause(); }\r\n restart(): void { this.simulator.restart(); }\r\n stop(): void { this.simulator.stop(); }\r\n /** Advances exactly one fixed step even while paused, preserving the current playing/paused state. */\r\n step(): void {\r\n const rect = this.layoutRectangle;\r\n this.simulator.step({ width: rect.width, height: rect.height, space: this.simulationSpace });\r\n this.syncRender();\r\n }\r\n dispose(): void { this.simulator.dispose(); }\r\n setEmissionMultiplier(value: number): void { this.simulator.setEmissionMultiplier(value); }\r\n getDiagnostics() { return this.simulator.getDiagnostics(); }\r\n\r\n syncEffect(effect: ParticleEffectDefinition): void { this.simulator.syncEffect(effect); }\r\n\r\n override destroy(options?: DestroyOptions): void {\r\n this.dispose();\r\n super.destroy(options);\r\n }\r\n\r\n protected syncContent(node: UINode): void {\r\n if (node.type !== \"particle-emitter\") return;\r\n this.simulationSpace = node.simulationSpace;\r\n // Autoplay only fires once, right after construction: syncContent also runs on every unrelated\r\n // document edit (via the shared node-sync pass), and re-arming play() there would silently\r\n // override an explicit pause()/stop() the moment the author touches anything else in the project.\r\n if (!this.autoplayHandled) {\r\n this.autoplayHandled = true;\r\n if (node.autoplay) this.simulator.play();\r\n }\r\n }\r\n\r\n private syncRender(): void {\r\n const p = this.simulator.definition.particle;\r\n const source = p.visual.source;\r\n const space = this.simulationSpace;\r\n const inverse = space === \"world\" ? this.worldTransform : undefined;\r\n for (const slot of this.simulator.activeSlots) {\r\n const sprite = slot.render;\r\n const t = slot.lifetime > 0 ? Math.min(1, slot.age / slot.lifetime) : 1;\r\n sprite.alpha = lerp(p.visual.alpha.start, p.visual.alpha.end, t);\r\n sprite.tint = lerpColorHex(p.visual.tint.start, p.visual.tint.end, t);\r\n sprite.scale.set(lerp(slot.scaleStart, slot.scaleEnd, t));\r\n sprite.rotation = slot.rotationDegrees * DEG_TO_RAD;\r\n sprite.blendMode = p.visual.blendMode;\r\n const assetId = source.type === \"single\" ? source.assetId\r\n : source.type === \"random\" ? source.assetIds[slot.sourceIndex]!\r\n : source.assetIds[sequenceFrame(source, slot)]!;\r\n const texture = this.textureFor(assetId);\r\n if (texture) sprite.texture = texture;\r\n if (space === \"world\" && inverse !== undefined) {\r\n const dx = slot.x - slot.spawnX, dy = slot.y - slot.spawnY;\r\n const worldX = slot.worldSpawnX + slot.spawnMatrixA * dx + slot.spawnMatrixC * dy;\r\n const worldY = slot.worldSpawnY + slot.spawnMatrixB * dx + slot.spawnMatrixD * dy;\r\n const local = inverse.applyInverse({ x: worldX, y: worldY });\r\n sprite.position.set(local.x, local.y);\r\n } else {\r\n sprite.position.set(slot.x, slot.y);\r\n }\r\n sprite.visible = true;\r\n }\r\n }\r\n}\r\n\r\ntype SequenceSource = Extract<ParticleEffectDefinition[\"particle\"][\"visual\"][\"source\"], { type: \"sequence\" }>;\r\nfunction sequenceFrame(source: SequenceSource, slot: ParticleSlot<Sprite>): number {\r\n const length = source.assetIds.length;\r\n const raw = slot.sequenceStart + Math.floor(slot.age * source.fps);\r\n return source.loop ? ((raw % length) + length) % length : Math.min(raw, length - 1);\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"ParticleEmitterNodeView.js","sourceRoot":"","sources":["../../src/views/ParticleEmitterNodeView.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ParticleEffectDefinition, UINode } from \"@pixi-ui-editor/schema\";\nimport { Container, Particle, ParticleContainer, Texture, type DestroyOptions } from \"pixi.js\";\nimport { lerp, ParticleSimulator, type ParticleSlot, type ParticleSpawnContext } from \"../particles.js\";\nimport { NodeView } from \"./NodeView.js\";\n\r\nconst DEG_TO_RAD = Math.PI / 180;\r\n\r\n/** Thin Pixi adapter: NodeView continues to own transforms, layout and hit testing. */\r\nexport class ParticleEmitterNodeView extends NodeView {\n private readonly contentRoot = new Container();\n private readonly simulator: ParticleSimulator<Particle>;\n private readonly renderGroups = new Map<Texture[\"source\"], ParticleRenderGroup>();\n private simulationSpace: \"local\" | \"world\" = \"local\";\n private autoplayHandled = false;\n private renderDirty = true;\n private tintStart = 0xffffff;\n private tintEnd = 0xffffff;\n private staticColor = 0xffffffff;\n private dynamicProperties: DynamicParticleProperties = { position: true, rotation: false, vertex: false, uvs: false, color: false };\n private readonly spawnContext: ParticleSpawnContext = { width: 0, height: 0, space: \"local\" };\n private renderSignature = \"\";\n private sourceSignature = \"\";\n private sourceTextures: readonly (Texture | undefined)[] = [];\n\r\n constructor(effect: ParticleEffectDefinition, textures?: ReadonlyMap<string, Texture>) {\r\n super(textures);\n this.setContent(this.contentRoot);\n this.cacheEffect(effect);\n this.simulator = new ParticleSimulator<Particle>(effect, {\n createRender: () => {\n return new Particle({ texture: Texture.EMPTY, anchorX: 0.5, anchorY: 0.5 });\n },\n hideRender: () => undefined,\n destroyRender: () => undefined,\n getWorldTransform: () => this.worldTransform,\n });\n }\n\n updateParticles(deltaSeconds: number): void {\n this.spawnContext.width = this.layoutWidth;\n this.spawnContext.height = this.layoutHeight;\n this.spawnContext.space = this.simulationSpace;\n const advanced = this.simulator.update(deltaSeconds, this.spawnContext);\n // World-space particles must also be reprojected when an ancestor moves between simulation\n // steps. Local particles need no work: Pixi applies their container transform itself.\n if (advanced || this.renderDirty || (this.simulationSpace === \"world\" && this.simulator.activeSlots.size > 0)) this.syncRender();\n }\r\n\r\n play(): void { this.simulator.play(); }\r\n pause(): void { this.simulator.pause(); }\r\n restart(): void { this.simulator.restart(); }\r\n stop(): void { this.simulator.stop(); }\r\n /** Advances exactly one fixed step even while paused, preserving the current playing/paused state. */\r\n step(): void {\n this.spawnContext.width = this.layoutWidth;\n this.spawnContext.height = this.layoutHeight;\n this.spawnContext.space = this.simulationSpace;\n this.simulator.step(this.spawnContext);\n this.syncRender();\r\n }\r\n dispose(): void {\n this.simulator.dispose();\n this.destroyRenderGroups();\n }\n setEmissionMultiplier(value: number): void { this.simulator.setEmissionMultiplier(value); }\r\n getDiagnostics() { return this.simulator.getDiagnostics(); }\r\n\r\n syncEffect(effect: ParticleEffectDefinition): void {\n this.simulator.syncEffect(effect);\n this.renderDirty ||= this.cacheEffect(effect);\n }\n\r\n override destroy(options?: DestroyOptions): void {\r\n this.dispose();\r\n super.destroy(options);\r\n }\r\n\r\n protected syncContent(node: UINode): void {\n if (node.type !== \"particle-emitter\") return;\n if (this.simulationSpace !== node.simulationSpace) this.renderDirty = true;\n this.simulationSpace = node.simulationSpace;\n // Autoplay only fires once, right after construction: syncContent also runs on every unrelated\r\n // document edit (via the shared node-sync pass), and re-arming play() there would silently\r\n // override an explicit pause()/stop() the moment the author touches anything else in the project.\r\n if (!this.autoplayHandled) {\r\n this.autoplayHandled = true;\r\n if (node.autoplay) this.simulator.play();\r\n }\r\n }\r\n\r\n private syncRender(): void {\n const p = this.simulator.definition.particle;\r\n const source = p.visual.source;\r\n const space = this.simulationSpace;\r\n const inverse = space === \"world\" ? this.worldTransform : undefined;\n const determinant = inverse === undefined ? 0 : inverse.a * inverse.d - inverse.b * inverse.c;\n const inverseDeterminant = determinant === 0 ? 0 : 1 / determinant;\n for (const group of this.renderGroups.values()) {\n group.nextCount = 0;\n group.dirty ||= this.renderDirty;\n }\n for (const slot of this.simulator.activeSlots) {\n const particle = slot.render;\n const t = slot.lifetime > 0 ? Math.min(1, slot.age / slot.lifetime) : 1;\n const sourceIndex = source.type === \"single\" ? 0 : source.type === \"random\" ? slot.sourceIndex : sequenceFrame(source, slot);\n const texture = this.sourceTextures[sourceIndex] ?? Texture.EMPTY;\n const textureChanged = particle.texture !== texture;\n if (textureChanged) particle.texture = texture;\n const initializeStatic = slot.renderDirty || this.renderDirty;\n if (this.dynamicProperties.vertex || initializeStatic) {\n const scale = lerp(slot.scaleStart, slot.scaleEnd, t);\n particle.scaleX = scale;\n particle.scaleY = scale;\n }\n if (this.dynamicProperties.rotation || initializeStatic) particle.rotation = slot.rotationDegrees * DEG_TO_RAD;\n if (this.dynamicProperties.color) particle.color = packParticleColor(lerpRgb(this.tintStart, this.tintEnd, t), lerp(p.visual.alpha.start, p.visual.alpha.end, t));\n else if (initializeStatic) particle.color = this.staticColor;\n if (space === \"world\" && inverse !== undefined) {\n const dx = slot.x - slot.spawnX, dy = slot.y - slot.spawnY;\n const worldX = slot.worldSpawnX + slot.spawnMatrixA * dx + slot.spawnMatrixC * dy;\n const worldY = slot.worldSpawnY + slot.spawnMatrixB * dx + slot.spawnMatrixD * dy;\n // Inline Matrix.applyInverse to avoid allocating one point per particle per rendered frame.\n const translatedX = worldX - inverse.tx;\n const translatedY = worldY - inverse.ty;\n particle.x = (inverse.d * translatedX - inverse.c * translatedY) * inverseDeterminant;\n particle.y = (-inverse.b * translatedX + inverse.a * translatedY) * inverseDeterminant;\n } else {\n particle.x = slot.x;\n particle.y = slot.y;\n }\n const group = this.groupFor(texture, p.visual.blendMode);\n group.dirty ||= slot.renderDirty || textureChanged || group.container.particleChildren[group.nextCount] !== particle;\n group.container.particleChildren[group.nextCount++] = particle;\n slot.renderDirty = false;\n }\n for (const group of this.renderGroups.values()) {\n const children = group.container.particleChildren;\n if (children.length !== group.nextCount) {\n children.length = group.nextCount;\n group.dirty = true;\n }\n if (group.dirty) group.container.update();\n group.dirty = false;\n }\n this.renderDirty = false;\n }\n\n private cacheEffect(effect: ParticleEffectDefinition): boolean {\n const visual = effect.particle.visual;\n const sourceIds = visual.source.type === \"single\" ? [visual.source.assetId] : visual.source.assetIds;\n const sourceTextures = sourceIds.map((id) => this.textureFor(id));\n const signature = JSON.stringify(visual);\n const sourceSignature = JSON.stringify(visual.source);\n const sourceChanged = sourceSignature !== this.sourceSignature\n || sourceTextures.length !== this.sourceTextures.length\n || sourceTextures.some((texture, index) => texture !== this.sourceTextures[index]);\n const changed = signature !== this.renderSignature\n || sourceChanged;\n if (!changed) return false;\n this.renderSignature = signature;\n this.sourceSignature = sourceSignature;\n this.sourceTextures = sourceTextures;\n // Source edits and late texture loads invalidate the source-keyed groups. Rebuild containers,\n // but keep every pooled Particle and live simulation slot intact.\n if (sourceChanged) this.destroyRenderGroups();\n const dynamicProperties = particleDynamicProperties(effect);\n if (!sameDynamicProperties(this.dynamicProperties, dynamicProperties)) {\n this.destroyRenderGroups();\n this.dynamicProperties = dynamicProperties;\n }\n this.tintStart = parseRgb(effect.particle.visual.tint.start);\n this.tintEnd = parseRgb(effect.particle.visual.tint.end);\n this.staticColor = packParticleColor(this.tintStart, effect.particle.visual.alpha.start);\n for (const group of this.renderGroups.values()) group.container.blendMode = effect.particle.visual.blendMode;\n return true;\n }\n\n private groupFor(texture: Texture, blendMode: ParticleEffectDefinition[\"particle\"][\"visual\"][\"blendMode\"]): ParticleRenderGroup {\n let group = this.renderGroups.get(texture.source);\n if (group !== undefined) return group;\n const container = new ParticleContainer<Particle>({\n texture,\n dynamicProperties: this.dynamicProperties,\n });\n container.blendMode = blendMode;\n this.contentRoot.addChild(container);\n group = { container, nextCount: 0, dirty: true };\n this.renderGroups.set(texture.source, group);\n return group;\n }\n\n private destroyRenderGroups(): void {\n for (const group of this.renderGroups.values()) {\n this.contentRoot.removeChild(group.container);\n group.container.destroy();\n }\n this.renderGroups.clear();\n }\n}\n\ntype SequenceSource = Extract<ParticleEffectDefinition[\"particle\"][\"visual\"][\"source\"], { type: \"sequence\" }>;\ntype ParticleRenderGroup = { container: ParticleContainer<Particle>; nextCount: number; dirty: boolean };\ntype DynamicParticleProperties = { position: true; rotation: boolean; vertex: boolean; uvs: boolean; color: boolean };\n\nfunction sequenceFrame(source: SequenceSource, slot: ParticleSlot<Particle>): number {\n const length = source.assetIds.length;\r\n const raw = slot.sequenceStart + Math.floor(slot.age * source.fps);\r\n return source.loop ? ((raw % length) + length) % length : Math.min(raw, length - 1);\r\n}\n\nfunction parseRgb(hex: string): number { return Number.parseInt(hex.slice(1, 7), 16); }\nfunction lerpRgb(start: number, end: number, t: number): number {\n const r = Math.round(lerp((start >>> 16) & 0xff, (end >>> 16) & 0xff, t));\n const g = Math.round(lerp((start >>> 8) & 0xff, (end >>> 8) & 0xff, t));\n const b = Math.round(lerp(start & 0xff, end & 0xff, t));\n return (r << 16) | (g << 8) | b;\n}\n/** Pixi Particle buffers store packed ABGR, unlike the public RGB tint number. */\nfunction packParticleColor(rgb: number, alpha: number): number {\n const bgr = ((rgb & 0xff) << 16) | (rgb & 0xff00) | ((rgb >>> 16) & 0xff);\n return (bgr | (Math.round(Math.max(0, Math.min(1, alpha)) * 255) << 24)) >>> 0;\n}\n\nfunction particleDynamicProperties(effect: ParticleEffectDefinition): DynamicParticleProperties {\n const visual = effect.particle.visual;\n const angular = visual.rotation.angularVelocityDegrees;\n const scale = visual.scale;\n return {\n position: true,\n rotation: angular.min !== 0 || angular.max !== 0,\n vertex: !(scale.start.min === scale.start.max && scale.start.min === scale.end.min && scale.start.min === scale.end.max),\n uvs: visual.source.type === \"sequence\",\n color: visual.tint.start !== visual.tint.end || visual.alpha.start !== visual.alpha.end,\n };\n}\n\nfunction sameDynamicProperties(a: DynamicParticleProperties, b: DynamicParticleProperties): boolean {\n return a.rotation === b.rotation && a.vertex === b.vertex && a.uvs === b.uvs && a.color === b.color;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixi-ui-editor/runtime-pixi",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "PixiJS runtime that renders Pixi UI Editor scene documents in a game.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"pixi.js": "^8.19.0",
|
|
31
31
|
"typed-signals": "^2.5.0",
|
|
32
32
|
"yoga-layout": "^3.2.1",
|
|
33
|
-
"@pixi-ui-editor/schema": "0.6.
|
|
33
|
+
"@pixi-ui-editor/schema": "0.6.1"
|
|
34
34
|
},
|
|
35
35
|
"scripts": {
|
|
36
36
|
"build": "tsc -p tsconfig.json",
|