Skip to main content

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
}
info

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.

API Reference