kgames

KGames — free keyboard games for kids
git clone https://www.keyboard.games/code/kgames.git
Log | Files | Refs | README | LICENSE

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:
Mgames/letter-find/game.js | 53+++++++++++++++++++++++++++++++++--------------------
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(); }); }); }); }