PixiJS 8.23 halves global move events on parent containers
PixiJS 8.23.0 stops interactive parents getting each global move event twice, so drag code that adds up movement per callback will move half as far.

PixiJS v8.23.0 landed on 11 November 2026, and one line in its release notes matters more than the new features. Interactive ancestors of the object under the pointer now receive globalpointermove, globalmousemove and globaltouchmove once per move. Before this release they got each event twice. The change came in pull request #12329, and the notes list it as a behaviour change rather than calling it breaking. The notes also warn that code which counted these calls or added up movement per call will now see half as many.
What changed in the event system
A global move event fires on an interactive object whenever the pointer moves anywhere on the canvas, not only over that object. That makes it the usual tool for drags. You start a drag on pointerdown, then listen for globalpointermove so the drag keeps working when the cursor slips off the sprite.
The bug sat with ancestors. If your stage or a parent container was interactive and the pointer was over one of its children, the parent’s global move handler ran twice for a single physical move. According to the 8.23.0 notes, this applied to both on() listeners and handler properties such as onglobalpointermove. From 8.23.0, each listener runs once per move.
If your handler reads an absolute position, the extra call did no harm. Reading event.global twice in a row gives the same point twice. The trouble starts when the handler does arithmetic on each call:
- adding
event.movementXto a running total - counting move events to drive an animation or a “shake” detector
- nudging a camera by a fixed step per callback
- tuning a sensitivity constant until the double rate felt right
Each of these will now run at half the rate on a parent container. A camera pan that felt right in 8.22 will feel sluggish in 8.23, and nothing will throw an error.
The other headline changes
The rest of the release is additive. The notes list these as the main new features:
- SmoothGraphics (#12002). A
Graphicsvariant that anti-aliases edges in the shader instead of relying on MSAA, the GPU’s multisample anti-aliasing. It keeps the same drawing API. It also supports dashed strokes through aDashLineShader. One catch from the notes: aGraphicsContextshared between aGraphicsand aSmoothGraphicscan render blank in one of them without an error, so clone the context for one of them. - HTML-in-Canvas for Chrome 155 and later (#12341).
HTMLSourcenow uses the newer browser calls, with fallbacks to the old ones. NewupdateElementGeometryandclearElementGeometryhooks tell the browser where the element sits, which helps hit testing and screen readers. The notes say WebGPU in Chrome 156 still needs the element as a direct child of the canvas. safariFontDelay(#12324). A renderer option forHTMLTextthat sets how long Safari waits before drawing. The default is 100 ms. Set it to 0 if your fonts are already loaded.- WebGPU changes. The canvas now defaults to the browser’s preferred format (#12380), bind group resources can match a shader by name (#12293), and colour attachments can each have their own format (#12357).
There are also more than 25 fixes, mostly WebGL and WebGPU edge cases around depth, buffer uploads, blend modes and texture extraction. Finally, the separate pixijs-* agent skills shipped in the package are now one pixijs skill (#12384). If you point an AI coding agent at node_modules/pixi.js/skills/, update any config that names an old skill such as pixijs-scene-sprite.
What it means for a solo dev or small team
If you build directly on PixiJS v8, check your input code before you ship an update. The fix is correct, but it changes how your game feels, and playtesters may report it as “drag is slow” rather than a bug.
Frameworks built on PixiJS pass this change through. @pixi/react describes itself as a thin wrapper over PixiJS, and its getting-started guide installs pixi.js@^8.2.6 alongside it. That caret range means a fresh install or a lockfile refresh pulls in 8.23.0 without you asking. React components that accumulate movement in a global move handler will halve too.
The Spine runtime for PixiJS 8, @esotericsoftware/spine-pixi-v8, needs PixiJS 8.16 or later according to Esoteric Software’s docs. It runs on top of your own PixiJS install, so any drag or pointer code you wrote around Spine objects falls under the same check. We found nothing in the Spine docs suggesting the runtime itself sums global move events.
Phaser is a different story. Phaser 2 used a modified PixiJS 2, but Phaser 3 and later use their own renderer, as Phaser’s lead developer confirmed on the HTML5 Game Devs forum. Phaser projects are not affected. Projects still on PixiJS v7 are also untouched, since this is a v8 release.
What to do now
Before you bump the version, search your project for the three event names and their handler properties:
globalpointermove onglobalpointermove
globalmousemove onglobalmousemove
globaltouchmove onglobaltouchmove
For each hit, ask two questions. Is the listener on a container that has interactive children? Does the handler add, count or step something on each call? If both answers are yes, that code will behave differently in 8.23.0.
Then test it properly:
- Pin
pixi.jsto 8.22.0, log how many times the handler fires during one slow drag, and note the final value it produces. - Upgrade to 8.23.0 and repeat the same drag. Expect the count to halve when the pointer is over a child.
- Check any value you tuned by feel, such as drag sensitivity or pan speed. If you doubled a constant years ago to make a drag feel right, this is probably why.
The cleaner fix is to stop summing deltas. Store the pointer’s event.global position when the drag starts, then compute the offset from that start point on every move. That approach gives the same result however many times the handler runs, so it survives this change and any future one.
If you can’t audit your input code yet, stay on 8.22.0 with an exact version pin. Remove the caret in package.json and commit your lockfile. Upgrade when you have time to test drags on a real touch device as well as a mouse, since globaltouchmove changed too.
If you use SmoothGraphics or the HTML-in-Canvas hooks, try them in a branch first. Both are new in this release, and the notes already list one silent rendering issue with shared contexts.


