From 17f32a590c1956e1872646567ca7ac8085f75210 Mon Sep 17 00:00:00 2001 From: Skigim Date: Mon, 2 Mar 2026 12:56:37 -0600 Subject: [PATCH] fix: resolve drawImage scaling penalty on non-square sprite height (#3320) ## Description: This PR resolves a performance parsing penalty in the `UnitLayer` rendering loop by fixing two issues with non-square sprites: 1. `drawImage` was incorrectly using `sprite.width` for both width and height, causing aspect ratio squashing and forcing the browser to perform a scaling operation on the image instead of hitting the canvas fast-path. It now correctly uses `sprite.height` for the vertical dimension. 2. `clearUnitsCells` was previously configured to only clear a square grid (`clearsize`) based solely on width, meaning taller sprites would leave visual artifact "ghosts" on the map. The clearing bounds have been corrected to leverage discrete `sprite.width` and `sprite.height`. Additionally, these values are wrapped in `Math.round()` prior to offset calculation to prevent subpixel anti-aliasing CPU penalties during `clearRect`. ## Please complete the following: - [x] I have added screenshots for all UI updates (not needed) - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file (no new text) - [x] I have added relevant tests to the test directory (existing tests suffice, change was minuscule and non-breaking) - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced ## Please put your Discord username so you can be contacted if a bug or regression is found: skigim --- src/client/graphics/layers/UnitLayer.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/client/graphics/layers/UnitLayer.ts b/src/client/graphics/layers/UnitLayer.ts index e5d72f0e8..9414b8406 100644 --- a/src/client/graphics/layers/UnitLayer.ts +++ b/src/client/graphics/layers/UnitLayer.ts @@ -290,14 +290,15 @@ export class UnitLayer implements Layer { .filter((unitView) => isSpriteReady(unitView)) .forEach((unitView) => { const sprite = getColoredSprite(unitView, this.theme); - const clearsize = sprite.width + 1; const lastX = this.game.x(unitView.lastTile()); const lastY = this.game.y(unitView.lastTile()); + const clearX = Math.round(lastX - sprite.width / 2); + const clearY = Math.round(lastY - sprite.height / 2); this.context.clearRect( - lastX - clearsize / 2, - lastY - clearsize / 2, - clearsize, - clearsize, + clearX - 1, + clearY - 1, + sprite.width + 2, + sprite.height + 2, ); }); } @@ -611,7 +612,7 @@ export class UnitLayer implements Layer { Math.round(x - sprite.width / 2), Math.round(y - sprite.height / 2), sprite.width, - sprite.width, + sprite.height, ); if (!targetable) { this.context.restore();