Graphics
Graphics is a powerful and flexible tool for rendering shapes such as rectangles, circles, stars, and custom polygons. It can also be used to create complex shapes by combining multiple primitives, and it supports advanced features like gradients, textures, and masks.
import { Graphics } from 'pixi.js';
const graphics = new Graphics()
.rect(50, 50, 100, 100)
.fill(0xff0000);
Available Shapes
PixiJS v8 supports a variety of shape primitives:
Basic Primitives
- Line
- Rectangle
- Rounded Rectangle
- Circle
- Ellipse
- Arc
- Bezier / Quadratic Curves
Advanced Primitives
- Chamfer Rect
- Fillet Rect
- Regular Polygon
- Star
- Rounded Polygon
- Rounded Shape
const graphics = new Graphics()
.rect(50, 50, 100, 100)
.fill(0xff0000)
.circle(200, 200, 50)
.stroke(0x00ff00)
.lineStyle(5)
.moveTo(300, 300)
.lineTo(400, 400);
SVG Support
You can also load SVG path data, although 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
The GraphicsContext
class is the core of PixiJS's new graphics model. It holds all the 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 particularly 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
When you destroy a GraphicsContext
, all Graphics
instances that share it will also be destroyed. This is a crucial point to remember, as it can lead to unexpected behavior if you're not careful.
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
Creating Holes
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.
Graphics Is About Building, Not Drawing
Despite the terminology of functions like .rect()
or .circle()
, Graphics
does not immediately draw anything. Instead, each method builds up a list of geometry primitives stored inside a GraphicsContext
. These are then rendered when the object is drawn to the screen or used in another context, such as a mask.
const graphic = new Graphics().rect(0, 0, 200, 100).fill(0xff0000);
app.stage.addChild(graphic); // The rendering happens here
You can think of Graphics
as a blueprint builder: it defines what to draw, but not when to draw it. This is why Graphics
objects can be reused, cloned, masked, and transformed without incurring extra computation until they're actually rendered.
Performance Best Practices
- Do not clear and rebuild graphics every frame. If your content is dynamic, prefer swapping prebuilt
GraphicsContext
objects instead of recreating them. - Use
Graphics.destroy()
to clean up when done. Shared contexts are not auto-destroyed. - Use many simple
Graphics
objects over one complex one to maintain GPU batching. - Avoid transparent overlap unless you understand blend modes; overlapping semi-transparent primitives will interact per primitive, not post-composition.
Caveats and Gotchas
- Memory Leaks: Call
.destroy()
when no longer needed. - SVG and Holes: Not all SVG hole paths triangulate correctly.
- Changing Geometry: Use
.clear()
sparingly. Prefer swapping contexts. - Transparency and Blend Modes: These apply per primitive. Use
RenderTexture
if you want to flatten effects.