commit 61a492078f769639adb94e5628161816a49714a9
parent 9f8aae03c3ed6b82ab37b0e80c93c11a84a5fc34
Author: Kyle Barlow <kb@kylebarlow.com>
Date: Sat, 25 Apr 2026 17:53:34 -0700
Optimize letter-find fireworks to avoid frame rate drops
Pre-bake a 4-color texture atlas so particles use frame selection
instead of per-particle tinting. Cut simultaneous particle count
from ~275 (5 bursts × 55 tinted) to ~56 (2 bursts × 28 untinted)
by widening burst intervals to 500ms and shortening lifespan to 800ms.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Diffstat:
1 file changed, 33 insertions(+), 20 deletions(-)
diff --git a/games/letter-find/game.js b/games/letter-find/game.js
@@ -36,6 +36,20 @@ class LetterFindScene extends Phaser.Scene {
g.fillRect(0, 0, 8, 8);
g.generateTexture('sq', 8, 8);
g.destroy();
+
+ // Pre-baked 4-color atlas — avoids per-particle tinting at render time
+ const fw = this.make.graphics({ add: false });
+ fw.fillStyle(0xE63946); fw.fillRect(0, 0, 6, 6);
+ fw.fillStyle(0x1D7CF2); fw.fillRect(6, 0, 6, 6);
+ fw.fillStyle(0xFFD23F); fw.fillRect(12, 0, 6, 6);
+ fw.fillStyle(0x2EC4B6); fw.fillRect(18, 0, 6, 6);
+ fw.generateTexture('fwsq', 24, 6);
+ fw.destroy();
+ const tex = this.textures.get('fwsq');
+ tex.add(0, 0, 0, 0, 6, 6);
+ tex.add(1, 0, 6, 0, 6, 6);
+ tex.add(2, 0, 12, 0, 6, 6);
+ tex.add(3, 0, 18, 0, 6, 6);
}
create() {
@@ -230,17 +244,17 @@ class LetterFindScene extends Phaser.Scene {
burstConfetti() {
const { width: W, height: H } = this.scale;
- const emitter = this.add.particles(W / 2, H * 0.47, 'sq', {
+ const emitter = this.add.particles(W / 2, H * 0.47, 'fwsq', {
+ frame: [0, 1, 2, 3],
speed: { min: 100, max: 350 },
angle: { min: 0, max: 360 },
scale: { start: 1.2, end: 0 },
gravityY: 500,
- lifespan: 900,
- tint: TINTS,
+ lifespan: 750,
explode: true,
- quantity: 45,
+ quantity: 30,
});
- this.time.delayedCall(1050, () => { if (emitter.active) emitter.destroy(); });
+ this.time.delayedCall(850, () => { if (emitter.active) emitter.destroy(); });
}
// ── Win Screen ────────────────────────────────────────────────────────
@@ -335,30 +349,29 @@ class LetterFindScene extends Phaser.Scene {
launchFireworks() {
const { width: W, height: H } = this.scale;
+ // 6 bursts at 500ms intervals; 800ms lifespan means at most 2 bursts alive at once
const bursts = [
[W * 0.3, H * 0.30, 0],
- [W * 0.7, H * 0.25, 350],
- [W * 0.5, H * 0.20, 700],
- [W * 0.2, H * 0.35, 1050],
- [W * 0.8, H * 0.30, 1400],
- [W * 0.5, H * 0.40, 1750],
- [W * 0.35, H * 0.22, 2100],
- [W * 0.65, H * 0.32, 2450],
+ [W * 0.7, H * 0.25, 500],
+ [W * 0.5, H * 0.20, 1000],
+ [W * 0.2, H * 0.35, 1500],
+ [W * 0.78, H * 0.28, 2000],
+ [W * 0.5, H * 0.32, 2500],
];
bursts.forEach(([x, y, delay]) => {
this.time.delayedCall(delay, () => {
if (!this.scene.isActive()) return;
- const em = this.add.particles(x, y, 'sq', {
- speed: { min: 60, max: 280 },
+ const em = this.add.particles(x, y, 'fwsq', {
+ frame: [0, 1, 2, 3],
+ speed: { min: 60, max: 240 },
angle: { min: 0, max: 360 },
- scale: { start: 1.6, end: 0 },
- gravityY: 120,
- lifespan: 1400,
- tint: TINTS,
+ scale: { start: 1.2, end: 0 },
+ gravityY: 150,
+ lifespan: 800,
explode: true,
- quantity: 55,
+ quantity: 28,
});
- this.time.delayedCall(1600, () => { if (em.active) em.destroy(); });
+ this.time.delayedCall(900, () => { if (em.active) em.destroy(); });
});
});
}