Skip to content

fix: Harden gizmos: shared layers, layer setter, enabled state, theme hover, multi-touch, arc mesh leak, uniform plane scaling and picking order - #9800

Merged
kpal81xd merged 2 commits into
mainfrom
fix/gizmo-review-fixes-2
Oct 19, 2026
Merged

kpal81xd merged 2 commits into
mainfrom
fix/gizmo-review-fixes-2

Conversation

@kpal81xd

@kpal81xd kpal81xd commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Description

Follow-up to #9799 with further fixes to the gizmos in src/extras/gizmo:

  • Shared layers: the camera and layer setters removed every copy of the gizmo layer from the camera, so moving one gizmo to another camera stopped the other gizmos sharing that layer from rendering. Each gizmo now adds and removes a single reference, and destroy() releases its reference too, so the layer leaves the camera when the last gizmo using it there is gone.
  • Layer setter: setting layer changed the camera layers but left every gizmo mesh, including the rotate guide lines, on the old layer. The meshes now move to the new layer.
  • Destroy twice: destroy() can run twice, for example from the app destroy event and from app code. It now returns early on the second call, so it never releases another gizmo's layer reference.
  • Enabled state: the camera and layer setters forced enabled = true, which re-showed a gizmo the app had disabled. They now keep the requested enabled state, and still re-check the camera distance as before.
  • setTheme while hovering: every shape switched to its hover color whenever anything was hovered. Only the hovered shapes keep their hover color now.
  • Multi-touch: lifting any pointer ended the current drag, and other pointers' moves were forwarded as drag moves. The gizmo now follows only the pointer that started the press.
  • ArcShape mesh leak: every change to xyzRingRadius, xyzTubeRadius, faceRingRadius, faceTubeRadius or ringTolerance created new ring meshes without destroying the old ones, and the constructor built every ring twice. Replaced meshes are now destroyed, and the constructor builds each ring once.
  • Uniform plane scaling: ScaleGizmo with uniform projected plane drags onto an unnormalized diagonal, so uniform plane drags scaled twice as fast as the cursor. They now match the non-uniform plane drag.
  • Picking order: picking sorted hits with a comparator that is not transitive, so in some places it returned a shape behind a nearer one, for example a plane behind an arrow line. It now keeps the best hit in a single pass with the same rule (priority between prioritized hits, otherwise distance), without sorting or allocating per hit.

Behavior changes

  • Uniform plane scaling is half as fast as before, matching the cursor.
  • Where an arrow line passes in front of a plane, the arrow is now picked instead of the plane behind it.
  • setTheme during a drag keeps the dragged shape highlighted.
  • Only the pointer that started a press can end or move it.

Manual smoke test

In each example, add window.gizmo = gizmo; at the end of the example code, then run this in the console to make a second camera: const c = new pc.Entity(); c.addComponent('camera', { priority: -1 }); c.setPosition(6, 6, 6); pc.AppBase.getApplication().root.addChild(c);

  1. Open gizmos/transform-translate, run setTimeout(() => gizmo.setTheme({}), 3000) and hover the X arrow until it fires. Expected: only the X arrow stays highlighted.
  2. Run const r = new pc.RotateGizmo(gizmo.camera, gizmo.layer); r.camera = c.camera;. Expected: the translate gizmo is still drawn.
  3. Run gizmo.enabled = false; gizmo.camera = c.camera;. Expected: the gizmo stays hidden.
  4. On a touch device, drag an arrow with one finger and tap with a second finger. Expected: the drag continues until the first finger lifts.
  5. Open gizmos/transform-rotate and change the ring radius in the controls several times. Expected: the rings resize and GPU memory does not grow.
  6. Open gizmos/transform-scale, enable uniform scaling and drag a plane. Expected: the scale follows the cursor at the same rate as a non-uniform plane drag.
  7. Run const l = pc.Gizmo.createLayer(pc.AppBase.getApplication(), 'Gizmo2'); gizmo.layer = l; in gizmos/transform-rotate, then drag a ring. Expected: the rings and the angle guide lines still render.

Fixes #

Checklist

  • I have read the contributing guidelines
  • My code follows the project's coding standards
  • This PR focuses on a single change

…c mesh leak, uniform plane scaling and picking order
@github-actions

github-actions Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Build size report

This PR changes the size of the minified bundles.

Bundle Minified Gzip Brotli
playcanvas.min.js 2673.8 KB (+667 B, +0.02%) 693.5 KB (+225 B, +0.03%) 537.8 KB (+229 B, +0.04%)
playcanvas.min.mjs 2670.6 KB (+667 B, +0.02%) 692.2 KB (+270 B, +0.04%) 537.0 KB (+10 B, +0.00%)

@kpal81xd kpal81xd self-assigned this Oct 19, 2026
@kpal81xd kpal81xd changed the title fix: Gizmo shared layers, enabled state, theme hover, multi-touch, arc mesh leak, uniform plane scaling and picking order fix: Harden gizmos: shared layers, layer setter, enabled state, theme hover, multi-touch, arc mesh leak, uniform plane scaling and picking order Oct 19, 2026
@kpal81xd
kpal81xd merged commit 982f5a6 into main Oct 19, 2026
11 checks passed
@kpal81xd
kpal81xd deleted the fix/gizmo-review-fixes-2 branch October 19, 2026 13:59
@ilimtvtr-alt

Copy link
Copy Markdown

Build size report

This PR changes the size of the minified bundles.

Bundle Minified Gzip Brotli
playcanvas.min.js 2673.8 KB (+667 B, +0.02%) 693.5 KB (+225 B, +0.03%) 537.8 KB (+229 B, +0.04%)
playcanvas.min.mjs 2670.6 KB (+667 B, +0.02%) 692.2 KB (+270 B, +0.04%) 537.0 KB (+10 B, +0.00%)

This branch was successfully deployed

2 active deployments
Preview – engine — 796d7b36 Deployed Oct 19, 2026 by vercel[bot]
Preview – engine-api-docs — 796d7b36 Deployed Oct 19, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants