phaserjs / phaserjs/phaser

DOMElement with a non-zero origin drifts under camera zoom (scene-level only)

Open
#7,329 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
40.3k
Forks
7.2k
PR merge metrics
No merged PRs in 30d

Description

Version: Phaser 4.2.0 / 4.2.1 (logic also present in 3.x); WebGL & Canvas; any browser.

Description

A DOMElement added directly to the Scene with a non-zero origin (default 0.5, 0.5) drifts from its world position when camera.zoom !== 1, by exactly (originX·width, originY·height)·(1 − camera.zoom). It is sliding bottom-right as you zoom out. The same DOMElement nested in a Container does not drift, so the two render paths are inconsistent.

Minimal example

https://phaser.io/sandbox/f0eb3f05

Root cause (found by Claude Code after some digging around)

In DOMElementCSSRenderer.js, camMatrix.translate(-dx, -dy) bakes the origin offset into the CSS matrix in both branches. The parentMatrix branch then keeps transform-origin: 0% 0% (offset applied once → correct). The else branch also sets transform-origin: (100·origin)% (offset applied twice). The two cancel only when the matrix's linear scale (camera zoom) is 1; under zoom the residual is originX·width·(1 − zoom). The transform-origin percentage lines date to 2019 (v3); the March-2025 v4 refactor preserved the behavior: it typically surfaces once an app drives a real camera zoom on scene-level DOM elements. I tested on v3.80 and the bug was already present.

I'll provide a PR to fix the issue.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in DOMElementCSSRenderer.js and reproduce the scene-level case from the linked sandbox with a non-zero origin and camera zoom. Compare the parentMatrix and else branches, then verify that scene-level DOMElements remain aligned with their world position under zoom while nested elements retain their current behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript
Domain
game-dev
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.