PixiJS RenderTexture: Offscreen Caching for Dynamic Sprite Content
Learn how to use PixiJS RenderTexture to draw complex Graphics once into an offscreen GPU texture and reuse it as a sprite, reducing per-frame draw calls in v7 and v8.
07 Jan 2026, 04:41 UTC

When vector redraws become the bottleneck
PixiJS renders Graphics objects by re-executing their path instructions on the GPU every frame. A detailed illustration with hundreds of paths, gradients, or repeated shapes can turn a smooth scene into a janky one. If that artwork is static or changes infrequently, you can bake it into a RenderTexture—an offscreen GPU buffer that stores rendered pixels—and display the result through an ordinary Sprite.
Desired outcome
A Sprite whose texture is a RenderTexture containing pre-rendered vector content. The original Graphics or Container is drawn once (or only when its data changes), not on every ticker frame. This reduces per-frame draw calls and GPU state changes.
Prerequisites and version assumptions
- A PixiJS project using v7 or v8. The offscreen rendering pattern is the same, but v8 replaced the legacy
Loaderwith theAssetsAPI for file loading.RenderTexturecreation is a runtime operation and does not depend on the asset pipeline. - A WebGL2-capable browser. Older WebGL1 contexts may work but are not the target for current PixiJS releases.
- Basic familiarity with
Application,Container,Graphics, andSprite.
Because PixiJS has changed renderer signatures between major releases, confirm the exact render argument shape for your installed version in the official API docs before copying this into production.
Baking a container into a RenderTexture
Create the texture with explicit dimensions and an optional resolution. A resolution of 2 doubles the pixel density, which is useful on high-DPI screens but increases memory use.
// PixiJS v8 import style; adjust for v7 if your project uses the legacy bundle.
import { Application, Container, Graphics, RenderTexture, Sprite } from 'pixi.js';
const app = new Application();
await app.init({ width: 800, height: 600, background: '#1099bb' });
document.body.appendChild(app.canvas);
// Offscreen buffer: 256x256 logical units at 2x pixel density.
const cacheTexture = new RenderTexture({
width: 256,
height: 256,
resolution: 2,
});
// Expensive vector content.
const artwork = new Container();
const badge = new Graphics()
.beginFill(0x3498db)
.drawRoundedRect(20, 20, 216, 216, 24)
.endFill()
.beginFill(0xffffff)
.drawCircle(128, 128, 60)
.endFill();
artwork.addChild(badge);
// Draw the container into the texture once.
app.renderer.render(artwork, cacheTexture);
// Display the baked result.
const cachedSprite = new Sprite(cacheTexture);
cachedSprite.x = 40;
cachedSprite.y = 40;
app.stage.addChild(cachedSprite);
Run this in your application entry point (for example, main.ts or a setup module). No special permissions are required beyond the normal browser graphics context. The key call is app.renderer.render(artwork, cacheTexture): it renders the artwork container into the offscreen texture instead of the screen.
Reusing and updating the cached sprite
After baking, the cachedSprite behaves like any other sprite. You can move, scale, tint, or rotate it without touching the original Graphics. When the underlying artwork changes, update the texture rather than redrawing the vector paths on the main stage.
// If the content changes, re-render into the same texture.
function refreshCache() {
app.renderer.render(artwork, cacheTexture);
}
// If the required size changes, resize then re-render.
function resizeCache(newWidth, newHeight) {
cacheTexture.resize(newWidth, newHeight);
app.renderer.render(artwork, cacheTexture);
}
Resizing allocates new GPU storage for the texture. Repeatedly resizing and re-rendering in a tight loop can cause memory churn, so batch changes when possible.
Expected checks
- Visual confirmation: The sprite displays the rounded rectangle and circle even though
badgewas never added toapp.stage. - Texture inspection: In browser DevTools, expand the sprite's
_texture(ortexturein v8) and confirm thebaseTextureis backed by aRenderTexturerather than anImageBitmaporHTMLImageElementsource. - Console health: After calling
resizeCacheandrefreshCacheseveral times in a WebGL2 browser, the console should show no WebGL errors or context-lost warnings.
Limitations and recovery options
Context loss. WebGL context loss destroys the contents of every GPU texture, including RenderTexture. PixiJS will attempt to restore the context, but the pixel data is gone. Re-render your source containers after restoration:
app.renderer.on('resume', () => {
// Context restored; rebuild GPU-side textures.
app.renderer.render(artwork, cacheTexture);
});
If your application creates many cached textures, keep a registry of source containers so you can iterate and re-render them all after a context resume.
Memory cleanup. A RenderTexture holds GPU memory that is not freed by garbage collection alone. When a cached sprite is no longer needed, destroy the sprite, the texture, and its base texture:
cachedSprite.destroy();
cacheTexture.destroy(true); // true also destroys the baseTexture
Destroying with true releases the underlying BaseTexture immediately. If you destroy only the sprite, the texture may remain allocated until the renderer is torn down.
Version sensitivity. Do not copy asset-loading code from PixiJS v6 or v7 into a v8 project. v8 uses Assets.load and related APIs. This does not affect RenderTexture creation, which is purely runtime, but mixing legacy loader patterns with v8 can break initialization before you reach the rendering code.
When not to cache. If the vector content changes every frame—for example, a dynamically plotted chart or a particle trail—baking it into a RenderTexture adds an extra full-texture render pass with no savings. Use direct Graphics rendering for per-frame mutations.
A practical verification loop
- Create the texture and bake a distinctive shape.
- Add the sprite to the stage and confirm the shape appears.
- Remove the source container from the display list entirely and confirm the sprite still renders.
- Resize the texture to a larger size, re-render, and confirm the sprite scales without distortion.
- Reload the page, trigger a context loss if your environment allows it, and verify the resume handler restores the image.
This sequence exercises creation, reuse, resize, and recovery—the four operations that cover most production use of RenderTexture.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.