From b0b08886ce97953459a8d1307fd098473bfd07bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Mon, 29 Jun 2026 17:44:48 +0200 Subject: [PATCH] Fix DOMElement origin drift under camera zoom A scene-level DOMElement with a non-zero origin (the default is 0.5, 0.5) drifted away from its world position when the camera zoom was not 1, by `originX * width * (1 - zoom)` horizontally and the equivalent vertically. The same DOMElement nested in a Container did not drift. DOMElementCSSRenderer always bakes the origin offset into the CSS matrix via `camMatrix.translate(-dx, -dy)`. The parentMatrix branch correctly leaves `transform-origin` at 0% 0%, so the offset is applied once. The scene-level (else) branch additionally set `transform-origin: (100 * origin)%`, applying the offset a second time; the two only cancel when the camera zoom is 1. Make the scene-level path match the container path: bake the scale-aware offset into the matrix and keep `transform-origin` at 0% 0%. Scaled and rotated scene-level elements now stay correctly anchored at any zoom too. Co-Authored-By: Claude Opus 4.8 --- .../domelement/DOMElementCSSRenderer.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/gameobjects/domelement/DOMElementCSSRenderer.js b/src/gameobjects/domelement/DOMElementCSSRenderer.js index f1ef710aca..2f539be262 100644 --- a/src/gameobjects/domelement/DOMElementCSSRenderer.js +++ b/src/gameobjects/domelement/DOMElementCSSRenderer.js @@ -61,8 +61,14 @@ var DOMElementCSSRenderer = function (renderer, src, camera, parentMatrix) var srcMatrix = tempMatrix2; var calcMatrix = tempMatrix3; - var dx = src.width * src.originX; - var dy = src.height * src.originY; + // Bake the (scale-aware) origin offset into the matrix and keep `transform-origin` at 0,0. + // This is what the `parentMatrix` branch already did; applying it to scene-level elements too + // keeps both paths consistent. Previously the scene-level (else) branch set + // `transform-origin: (100 * origin)%` while ALSO baking the offset into the matrix below, + // applying the origin offset twice. The two only cancel at camera zoom 1, so under camera + // zoom the element drifted by `origin * size * (1 - zoom)`. + var dx = src.width * src.originX * src.scaleX; + var dy = src.height * src.originY * src.scaleY; var tx = '0%'; var ty = '0%'; @@ -76,13 +82,6 @@ var DOMElementCSSRenderer = function (renderer, src, camera, parentMatrix) if (parentMatrix) { camMatrix.multiply(parentMatrix); - dx *= src.scaleX; - dy *= src.scaleY; - } - else - { - tx = (100 * src.originX) + '%'; - ty = (100 * src.originY) + '%'; } camMatrix.translate(-dx, -dy);