Skip to main content

PixiJS Update - v8.17.0

ยท 7 min read
Zyie
PixiJS Admin

PixiJS v8.17.0 delivers an optimized BlurFilter with a new halving strength scheme, improved text renderer parity bringing Text, BitmapText, and HTMLText alignment closer together, tagStyles support in SplitText, and a new visibleChanged event on containers. This release also includes a wave of stability fixes across graphics, filters, and event handling.

Optimized BlurFilterโ€‹

BlurFilter now uses a halving strength scheme by default. Instead of applying the full blur strength on every pass, the filter progressively reduces strength across passes. The result is higher visual quality at high strengths with less GPU work.

The difference is most visible at high strength values, where the legacy approach produces banding artifacts while the optimized version stays smooth:

// New default behavior (optimized)
const blur = new BlurFilter({ strength: 20, quality: 4 });

// Restore old behavior if needed
const legacyBlur = new BlurFilter({ strength: 20, quality: 4, legacy: true });

// Or set globally
BlurFilter.defaultOptions.legacy = true;
Behavior Change

This changes the visual output of BlurFilter compared to previous versions. If you need the old behavior, set legacy: true.


Thanks to @Zyie and @Sertion for the blur improvements.


Improved text renderer parityโ€‹

Continued text updates keep Text, BitmapText, and HTMLText alignment more consistent. This release closes several gaps where the three renderers disagreed on layout.

Justify alignment now uses wordWrapWidth for width calculation instead of maxLineWidth, matching CSS behavior. The last line of a paragraph is no longer stretched. Canvas text and split text also render align: 'justify' by distributing extra word spacing, so all three text types produce the same justified output.

Bitmap text gains full whiteSpace support (normal, pre, nowrap, pre-line, pre-wrap) with proper space and newline collapsing. Word wrapping now supports break-after characters like hyphens, en-dashes, em-dashes, and soft hyphens.

HTMLText breakWords: true now correctly uses CSS word-break: break-word instead of break-all, matching the behavior of Text and BitmapText.

Other improvements:

  • Dynamic bitmap fonts scale drop shadow blur and distance proportionally to font size.
  • Bitmap font xAdvance now uses true advance width from measureText() instead of bounding-box width.
  • Kerning values are correctly scaled by fontScale in dynamic bitmap fonts.
Behavior Change

align: 'justify' now uses wordWrapWidth for width calculation, and breakWords in HTMLText uses break-word instead of break-all. If your text layout looks different after upgrading, the new behavior is more consistent across renderers and matches CSS standards.


SplitText tagStylesโ€‹

SplitText now supports tagStyles, so styled text runs like <red>Hello</red> <blue>World</blue> are correctly split into per-character Text objects with individual styles preserved. This makes it straightforward to combine inline styling with per-character animation:

const splitText = new SplitText({
text: '<bold>Important:</bold> animate <highlight>each character</highlight> individually',
style: {
fontSize: 32,
fill: 'white',
tagStyles: {
bold: { fontWeight: 'bold', fill: 'yellow' },
highlight: { fill: 'cyan' },
},
},
});

// Each char retains its tag style
splitText.chars.forEach((char, i) => {
// animate per character...
});

visibleChanged eventโ€‹

Containers now emit a visibleChanged event when their visible property changes. This removes the need for manual polling or wrapper functions to detect visibility changes:

container.on('visibleChanged', (visible) => {
console.log('Visibility changed to:', visible);
});

container.visible = false; // fires the event

This is useful for triggering animations, analytics, or cleanup logic when objects enter or leave visibility.

Thanks to @ikigai-bjorn-s for this contribution.


More additionsโ€‹

  • Resolver alias removal: New function for removing aliases from the Resolver, useful for dynamic asset management (@Sertion).

Bug fixesโ€‹

This release addresses a broad set of stability issues:

  • Filter corruption: TexturePool now separates mipmap textures, preventing filter corruption when multiple filters share pool textures (@vkarponen).
  • ColorMatrixFilter offset: Offset values are now correctly applied (@Sertion).
  • ParticleContainer filter offset: Global filter offsets now apply correctly to particle rendering (@GoodBoyDigital).
  • NineSliceSprite trim: Texture trim offsets are now respected (@shtse8).
  • Empty Graphics bounds: getBounds() on an empty Graphics now returns valid empty bounds instead of throwing (@GoodBoyDigital).
  • Graphics stale bounds: getLocalBounds() no longer returns stale data between operations in the same frame (@GoodBoyDigital).
  • Miter join bounds: Graphics bounds now account for miter joins at sharp angles (@GoodBoyDigital).
  • BindGroup crash: Fixed crash when a resource is destroyed while in a batched group (@GoodBoyDigital).
  • BindGroup listener leak: Old resource listeners are now removed in setResource (@GoodBoyDigital).
  • Renderer destroy: removeAllListeners() is now called on Renderer.destroy() (@taye).
  • Ticker clamping: minFPS/maxFPS mutual clamping now works correctly (@Zyie).
  • Color alpha cache: color.setAlpha() now invalidates the cached source, preventing stale alpha reuse (@darthvader58).
  • addChildAt event: The removed event now fires correctly when using addChildAt (@aSipz).
  • Bitmap text guards: Missing characters and kerning data no longer cause crashes (@stargazer-2697).
  • Touch modifier keys: TouchEvent modifier keys are now copied to normalized touch objects (@kaigritun).
  • Web font loading: Font names are now quoted to support older Chrome versions (@adngdb).
  • Web Worker support: DOMPipe registration moved to init.ts to fix Web Worker environments (@Zyie).

You can view the full changelog on GitHub.


Pausing the bug bounty programโ€‹

We're pausing the PixiJS bug bounty program starting with this release.

When we launched the program, the goal was simple: reward contributors who find and fix real bugs. We wanted to give back to the community that makes PixiJS possible.

Unfortunately, the monetary incentive has led to a rise in low-effort, AI-generated pull requests that don't meet the bar for merging, and the review burden on maintainers has grown faster than the value the program delivers.

To be clear: we are not against AI-assisted development. We actively support it. We maintain llms.txt files, copy-to-markdown features in our documentation, and other tooling specifically to help AI tools understand PixiJS better. AI is a powerful tool when used well.

The issue is that the bounty has incentivized quantity over quality, and the program is no longer achieving its original goal.

We still want to find ways to give back to our contributors. We're exploring alternatives that reward meaningful contributions without creating the wrong incentives. If you have ideas, we'd love to hear them on Discord.


New contributorsโ€‹

Welcome to our newest contributors:

Thank you for your contributions!


Get the latest PixiJSโ€‹

Install via npm:

npm install pixi.js@8.17.0

Or use via CDN:

Development builds:

Production builds:

Documentation: https://pixijs.download/v8.17.0/docs/index.html


Wrapping upโ€‹

That covers what's new in v8.17.0. The blur and text changes are behavior changes, so check your output after upgrading. If anything looks off, the release notes above explain how to restore previous behavior.

Thanks to everyone who contributed fixes and features to this release.


Happy creating!

The PixiJS Team