Graphics renders shapes such as rectangles, circles, stars, and custom polygons. You can combine multiple primitives into complex shapes, and it supports gradients, textures, and masks.
import { Graphics } from 'pixi.js';
const graphics = new Graphics().rect(50, 50, 100, 100).fill(0xff0000);
PixiJS v8 supports these shape primitives:
const graphics = new Graphics()
.rect(50, 50, 100, 100)
.fill(0xff0000)
.circle(200, 200, 50)
.stroke(0x00ff00)
.moveTo(300, 300)
.lineTo(400, 400)
.stroke({ width: 5 });
You can load SVG path data, though complex hole geometries may render inaccurately due to Pixi's performance-optimized triangulation system.
let shape = new Graphics().svg(`
<svg>
<path d="M 100 350 q 150 -300 300 0" stroke="blue" />
</svg>
`);
GraphicsContext is the core of the PixiJS graphics model. It holds all drawing commands and styles, allowing the same shape data to be reused by multiple Graphics instances:
const context = new GraphicsContext().circle(100, 100, 50).fill('red');
const shapeA = new Graphics(context);
const shapeB = new Graphics(context); // Shares the same geometry
This pattern is effective when rendering repeated or animated shapes, such as frame-based SVG swaps:
let frames = [
new GraphicsContext().circle(100, 100, 50).fill('red'),
new GraphicsContext().rect(0, 0, 100, 100).fill('red'),
];
let graphic = new Graphics(frames[0]);
function update() {
graphic.context = frames[1]; // Very cheap operation
}
If you don't explicitly pass a GraphicsContext when creating a Graphics object, then internally, it will have its own context, accessible via myGraphics.context.
Destroying a GraphicsContext also destroys all Graphics instances that share it.
const context = new GraphicsContext().circle(100, 100, 50).fill('red');
const shapeA = new Graphics(context);
const shapeB = new Graphics(context); // Shares the same geometry
shapeA.destroy({ context: true }); // Destroys both shapeA and shapeB
Use .cut() to remove a shape from the previous one:
const g = new Graphics().rect(0, 0, 100, 100).fill(0x00ff00).circle(50, 50, 20).cut(); // Creates a hole in the green rectangle
Ensure the hole is fully enclosed within the shape to avoid triangulation errors.
Methods like .rect() and .circle() don't render anything. They build a list of shapes stored in a GraphicsContext. Rendering happens when the Graphics object is added to the scene and the renderer processes it.
const graphic = new Graphics().rect(0, 0, 200, 100).fill(0xff0000);
app.stage.addChild(graphic); // Rendering happens here
This means you can build, reuse, and transform Graphics objects freely without triggering GPU work.
.clear() and rebuild every frame. Rebuilding triggers geometry re-triangulation on the CPU. For dynamic content, swap prebuilt GraphicsContext objects instead (see the context-swapping example above).Graphics.destroy() to clean up when done. Shared contexts are not auto-destroyed.Graphics objects over one complex one to maintain GPU batching.cacheAsTexture() or renderer.generateTexture()..destroy() when no longer needed..clear() sparingly. Prefer swapping contexts.RenderTexture to flatten effects.Graphics object with no drawing instructions returns bounds of (0, 0, 0, 0). This prevents Infinity values from contaminating parent container bounds calculations.