PixiJS Update - June
Welcome to the June update, covering v8.18.0 and v8.19.0: live HTML-in-Canvas textures, Graphics โ SVG export, official AI agent skills, sprite mask channels, and a milestone we're very proud of.
500,000 weekly downloadsโ
PixiJS crossed 500,000 weekly downloads on npm, and the number has kept climbing since. That's half a million projects, prototypes, games, and experiments pulling PixiJS every single week.
This library exists because of the people who build with it, report bugs, send fixes, and answer questions on Discord. Thank you for building with PixiJS.
Official PixiJS Agent Skillsโ
AI coding agents are now part of many workflows, so we've shipped 25 official PixiJS skills that teach them how to use PixiJS v8 correctly: modern APIs, current best practices, and none of the v7 patterns they tend to hallucinate.
Install them into Claude Code, Cursor, Codex, Copilot, or Windsurf with one command:
npx skills add https://github.com/pixijs/pixijs-skills
As of v8.19.0 the skills also ship inside the npm package itself, available at node_modules/pixi.js/skills/ after install, so your tools can pick them up without a separate step.
Check out the pixijs-skills repository for the full list, and see pixijs.com/llms for everything PixiJS offers AI tooling, from install instructions for 40+ agents to plain-text llms.txt docs.
HTML-in-Canvas texturesโ
The headline feature of v8.19.0: a new opt-in pixi.js/html-source subpath that renders live DOM elements into PixiJS textures. The element stays fully interactive in the browser while it's mirrored to the GPU: inputs stay editable, links stay clickable, and CSS animations keep running.
Here it is running on a real website. Everything you see, including the text being selected and the form being typed into, is a PixiJS texture:
Use HTMLSource for a live element, or ElementImageSource for an immutable snapshot. The element must be a direct child of the Pixi canvas:
import { Application, Sprite } from 'pixi.js';
import { HTMLSource } from 'pixi.js/html-source';
const app = new Application();
await app.init({ resizeTo: window });
document.body.appendChild(app.canvas);
const form = document.createElement('form');
form.innerHTML = '<input value="still editable" />';
app.canvas.appendChild(form); // must be a direct child of the Pixi canvas
const sprite = Sprite.from(new HTMLSource({ resource: form, autoUpdate: true }));
app.stage.addChild(sprite); // live DOM mirrored to the GPU; the form stays interactive
Importing the subpath also registers a lowest-priority Texture.from fallback for generic HTML elements, so apps that don't import it are completely unaffected.
This is built on the experimental HTML-in-Canvas browser API, currently available in Chrome behind a flag. If the API isn't enabled in the browser, the texture uploaders throw a clear error. Treat this as a preview of where the web platform is heading.
Thanks to @Zyie for this contribution.
Graphics โ SVG exportโ
v8.18.0 adds graphicsContextToSvg(), a pure function that serializes a Graphics or GraphicsContext into a self-contained SVG string. It supports rects, circles, ellipses, rounded rects, polygons, bezier/quadratic/arc paths, strokes, holes, and linear/radial gradients.
import { Graphics, graphicsContextToSvg } from 'pixi.js';
const g = new Graphics()
.rect(0, 0, 100, 50)
.fill({ color: 0xff0000 })
.circle(150, 25, 25)
.stroke({ color: 0x0000ff, width: 4 });
const svgString = graphicsContextToSvg(g, 2);
await navigator.clipboard.writeText(svgString);
The example below proves the round trip: the right-hand badge is built by feeding the exported SVG string straight back into new Graphics().svg():
Thanks to @GoodBoyDigital for this contribution.
Sprite mask channelsโ
setMask() gains a channel option in v8.18.0, letting you pick which texture channel drives visibility: 'red' (the default, matching previous behavior) or 'alpha'. This matches how design tools like Figma apply PNG masks, so masks exported from design files now work without preprocessing:
import { Assets, Sprite } from 'pixi.js';
const photo = new Sprite(await Assets.load('photo.png'));
const maskSprite = new Sprite(await Assets.load('mask-alpha.png'));
photo.setMask({
mask: maskSprite,
channel: 'alpha',
});
Both sides below use the same mask texture: a transparent-backed circle with a red star painted on it. The red channel only sees the star; the alpha channel sees the whole circle:
FillPattern textureSpaceโ
FillPattern gains a textureSpace option in v8.19.0, alongside fixes for several long-standing pattern sizing bugs:
'global'(the new default): the pattern tiles continuously across world space, so adjacent shapes share one seamless grid instead of each remapping the pattern.'local': one tile is fitted to each shape, andsetTransform()lets you subdivide or transform it per shape.
import { Assets, FillPattern, Graphics } from 'pixi.js';
const texture = await Assets.load('pattern.png');
const pattern = new FillPattern({ texture, repetition: 'repeat', textureSpace: 'local' });
const g = new Graphics().rect(0, 0, 200, 100).fill({ fill: pattern });
Existing pattern fills can render differently after upgrading. setTransform(matrix) now applies the matrix you pass directly (it previously inverted and rescaled it by the texture size), and textureSpace: 'local' radial gradients now scale to the gradient's outer radius. If you hand-compensated for the old setTransform behavior, remove that compensation.
Particles inherit blend modesโ
ParticleContainer now respects the blend mode inherited from its ancestors. Previously, setting a blend mode on a parent (for example stage.blendMode = 'add') was silently ignored by particles; now they resolve the inherited blend mode like every other container. A blendMode set directly on the ParticleContainer works exactly as before.
Both galaxies below are identical ParticleContainers. The only difference is the blendMode set on the right one's parent:
Particles nested under a parent with a non-default blend mode will now render differently (e.g. additive brightening) where the parent's blend mode was previously ignored.
Thanks to @DmitriyGolub for this contribution.
More additionsโ
- Renderer preference arrays:
autoDetectRendererandApplication.initnow accept an array forpreference(e.g.['webgl', 'canvas']), letting you restrict the fallback chain rather than only reorder it (@Zyie). app.domContainerRoot: A read-only getter for theHTMLDivElementthat wraps allDOMContainerelements, so you can add CSS classes or styles to the DOM overlay root (@carlos22).- Default anchors for generated textures:
renderer.generateTexture()accepts adefaultAnchoroption, andRenderTexture.create()gains atextureOptionsparameter (@ksv90). - Transient MSAA attachments (WebGPU): Texture sources gain an opt-in
transientflag that lets the WebGPU backend discard MSAA buffers at the end of a render pass instead of writing them back to memory, cutting memory bandwidth on mobile GPUs (@GoodBoyDigital).
Bug fixesโ
Across both releases:
- Stroke-only Graphics masks now render correctly on the Canvas renderer (@DmitriyGolub).
- iOS 18.0โ18.1 textures:
_applyMipRangeis skipped for single-mip textures, working around a WebKit bug (@GoodBoyDigital). - Stale
TextureMatrixwhen pooled textures reuse the same reference (@GoodBoyDigital). GraphicsPath.transform()now handles all path actions (@Zyie).VideoSourceno longer recurses between play and mediaReady before video dimensions are known (@satoren).- Tagged text handles literal
<characters inparseTaggedText(@glennflanagan). SplitTextbaseline mismatch fixed whentagStylesis used withlineHeight, and a crash fixed when text begins with whitespace (@Zyie).TilingSprite:tilePositionis no longer divided by resolution on the Canvas renderer, andtileRotationno longer shears the pattern on non-square sprites (@Zyie).BitmapTextno longer renders a trailing glyph after a glyph-less word-break character (@Zyie).- Canvas renderer rounds the anchor offset when
roundPixelsis enabled (@Clonex). - Custom batchers now receive the renderer's
maxBatchableTextures(@SerG-Y). - Lost contexts no longer crash shader compilation logging (@Zyie).
GCSystemunloads resources before nulling their hash entry (@Zyie).CanvasFilterSystemmoved to the filters module (@Zyie).
You can view the full changelogs on GitHub: v8.18.0 and v8.19.0.
New contributorsโ
Welcome to our newest contributors:
Thank you for your contributions!
Get the latest PixiJSโ
Install via npm:
npm install pixi.js@8.19.0
Or use via CDN:
Development builds:
- https://cdn.jsdelivr.net/npm/pixi.js@8.19.0/dist/pixi.js
- https://cdn.jsdelivr.net/npm/pixi.js@8.19.0/dist/pixi.mjs
Production builds:
- https://cdn.jsdelivr.net/npm/pixi.js@8.19.0/dist/pixi.min.js
- https://cdn.jsdelivr.net/npm/pixi.js@8.19.0/dist/pixi.min.mjs
Documentation: https://pixijs.download/v8.19.0/docs/index.html
Wrapping upโ
That covers June's updates. The FillPattern and particle blend mode changes are behavior changes, so check your output after upgrading; the sections above explain how each one moved.
Thanks to everyone who contributed fixes and features to these releases.
- See the full release notes on GitHub: v8.18.0 / v8.19.0
- Sponsor PixiJS
- Submit your project to the Showcase
- Join the discussion on Discord
- Follow us on Twitter / Bluesky
Thank you to our sponsorsโ
PixiJS is made possible by our sponsors. A special thanks to our Silver tier and above supporters; you can join them and keep the engine moving.
Happy creating!
The PixiJS Team


