PluginBench
Skill
Pass
Audit score 90

pixijs-environments

pixijs/pixijs-skills

Run PixiJS v8 outside the browser: Web Workers, OffscreenCanvas, Node/SSR, and CSP-restricted contexts.

What is pixijs-environments?

This skill configures PixiJS v8 to work in non-standard environments by swapping the DOM adapter before initialization. Use it when deploying to Web Workers, headless Node.js, server-side rendering, or Content Security Policy contexts that block unsafe-eval.

  • Set WebWorkerAdapter or BrowserAdapter via DOMAdapter.set() before app.init()
  • Transfer OffscreenCanvas from main thread to Web Worker for rendering
  • Import pixi.js/unsafe-eval polyfill to remove eval() dependency in CSP environments
  • Implement custom Adapter interface for Node.js, headless testing, or SSR
  • Use environment-specific subpath imports (pixi.js/browser, pixi.js/webworker) for static module registration
  • Check current adapter with DOMAdapter.get() for DOM-agnostic code

How to install pixijs-environments

npx skills add https://github.com/pixijs/pixijs-skills --skill pixijs-environments
Prerequisites
  • PixiJS v8 installed
  • For Web Workers: ability to transfer OffscreenCanvas from main thread
  • For Node.js/headless: canvas library and @xmldom/xmldom installed
  • For CSP: understanding of Content Security Policy directives
Claude Code
Cursor
Windsurf
Cline

How to use pixijs-environments

  1. 1.Call DOMAdapter.set(adapter) before creating the Application instance
  2. 2.For Web Workers: transfer OffscreenCanvas from main thread and pass it to app.init()
  3. 3.For CSP: import 'pixi.js/unsafe-eval' at the top of your entry point before any PixiJS imports
  4. 4.For custom environments: implement the full Adapter interface with all required methods (createCanvas, createImage, getCanvasRenderingContext2D, getWebGLRenderingContext, getNavigator, getBaseUrl, getFontFaceSet, fetch, parseXML)
  5. 5.Use DOMAdapter.get() instead of document or Image directly in any DOM-adjacent code

Use cases

Good for
  • Offload rendering to a Web Worker with OffscreenCanvas to keep main thread responsive
  • Deploy PixiJS in a Node.js/headless environment using canvas library and @xmldom/xmldom
  • Run PixiJS under strict Content Security Policy by importing the unsafe-eval polyfill
  • Build server-side rendering pipelines that generate canvas output without browser globals
  • Test PixiJS code in headless CI/CD without DOM or browser APIs
Who it's for
  • Backend/Node.js developers building SSR or headless rendering pipelines
  • Web Workers specialists optimizing rendering performance off the main thread
  • Security-conscious teams enforcing strict Content Security Policy
  • Game and graphics developers targeting multiple runtime environments
  • QA/testing engineers running PixiJS in headless test suites

pixijs-environments FAQ

Why does DOMAdapter.set() have to be called before app.init()?

PixiJS reads the adapter during app.init() when the renderer is created. Calling DOMAdapter.set() after app.init() is too late; the adapter has already been locked in.

What does the pixi.js/unsafe-eval import actually do?

It removes the need for eval() and new Function() by installing static polyfills for shader compilation, uniform syncing, and particle buffer updates. Despite its name suggesting it enables unsafe eval, it does the opposite: it makes PixiJS work under strict CSP that blocks unsafe-eval.

Which PixiJS features don't work in Web Workers?

DOMContainer (no real DOM node), AccessibilitySystem (requires live DOM focus and screen reader hooks), and FontFace loading via the Font Loading API (use pre-converted bitmap fonts instead).

How do I check which adapter is currently active?

Call DOMAdapter.get() to retrieve the current adapter instance, then use its methods like createCanvas() or createImage() for DOM-agnostic code.

Can I use the old settings.ADAPTER pattern from PixiJS v7?

No. The settings object was removed in v8. Use DOMAdapter.set(adapter) instead.

Full instructions (SKILL.md)

Source of truth, from pixijs/pixijs-skills.


name: pixijs-environments description: "Use this skill when running PixiJS v8 outside a standard browser: Web Workers, OffscreenCanvas, Node/SSR, or CSP-restricted contexts. Covers DOMAdapter.set, BrowserAdapter, WebWorkerAdapter, custom Adapter interface, pixi.js/unsafe-eval for strict CSP. Triggers on: DOMAdapter, BrowserAdapter, WebWorkerAdapter, Web Worker, OffscreenCanvas, Node, headless, SSR, CSP, unsafe-eval, Adapter." license: MIT

DOMAdapter abstracts every piece of DOM access PixiJS does (canvas creation, Image loading, fetch, XML parsing) so the library can run in non-browser contexts. Call DOMAdapter.set(...) before app.init() to swap in a different adapter.

Quick Start

// worker.ts — OffscreenCanvas posted from main thread
DOMAdapter.set(WebWorkerAdapter);

self.onmessage = async (event) => {
  const app = new Application();
  await app.init({
    canvas: event.data.canvas,
    width: 800,
    height: 600,
  });
};

For CSP contexts that block unsafe-eval, import the polyfill before any renderer init:

import "pixi.js/unsafe-eval";

Related skills: pixijs-application (standard browser init), pixijs-migration-v8 (settings removal, adapter changes).

Core Patterns

Web Worker with OffscreenCanvas

Transfer an OffscreenCanvas from the main thread, then initialize PixiJS in the worker:

// main.ts
const canvas = document.createElement("canvas");
canvas.width = 800;
canvas.height = 600;
document.body.appendChild(canvas);

const offscreen = canvas.transferControlToOffscreen();
const worker = new Worker("worker.ts", { type: "module" });
worker.postMessage({ canvas: offscreen }, [offscreen]);
// worker.ts
import { Application, DOMAdapter, WebWorkerAdapter } from "pixi.js";

DOMAdapter.set(WebWorkerAdapter);

self.onmessage = async (event) => {
  const app = new Application();
  await app.init({
    canvas: event.data.canvas,
    width: 800,
    height: 600,
  });
};

DOMAdapter.set(WebWorkerAdapter) must happen before new Application(). The WebWorkerAdapter uses OffscreenCanvas instead of document.createElement('canvas') and @xmldom/xmldom for XML parsing.

Features that do not work inside a Web Worker (no DOM access):

  • DOMContainer — there is no real DOM node to overlay.
  • AccessibilitySystem — depends on live DOM focus and screen reader hooks.
  • FontFace loading via the Font Loading API — use pre-converted bitmap fonts (BitmapFont.install or .fnt assets) instead.

Environment-specific subpath imports

Instead of importing pixi.js, you can pull in a curated bundle for each environment:

import "pixi.js/browser"; // accessibility, dom, events, spritesheet, rendering, filters
import "pixi.js/webworker"; // spritesheet, rendering, filters (no DOM-only modules)

pixi.js/webworker deliberately omits accessibility, dom, and events because they require the DOM. Use these subpath entries when you want static, synchronous module registration instead of relying on loadEnvironmentExtensions to dynamic-import the right set at renderer init.

loadEnvironmentExtensions

import { loadEnvironmentExtensions } from "pixi.js";

await loadEnvironmentExtensions(false); // false = load defaults; true = skip

loadEnvironmentExtensions(skip) replaces the deprecated autoDetectEnvironment helper (since 8.1.6). Pass true to opt out of auto-loading the default browser extensions when you are bootstrapping a custom environment. autoDetectEnvironment(add) still exists as a shim that forwards to loadEnvironmentExtensions(!add).

CSP-compliant setup

PixiJS uses new Function() internally for shader compilation and uniform syncing. In Content Security Policy environments that block unsafe-eval, import the polyfill:

import "pixi.js/unsafe-eval";
import { Application } from "pixi.js";

const app = new Application();
await app.init({ width: 800, height: 600 });

The pixi.js/unsafe-eval import replaces eval-based code generation with static polyfills for shader sync, UBO sync, uniform sync, and particle buffer updates. The import must come before any PixiJS renderer initialization.

Tension note: The name pixi.js/unsafe-eval is counterintuitive. It does not enable unsafe eval; it removes the need for it. The name refers to the CSP directive it works around.

Custom adapter

For non-standard environments (Node.js, headless testing, SSR), implement the full Adapter interface:

import { DOMAdapter } from "pixi.js";
import type { Adapter } from "pixi.js";
import { createCanvas, Image } from "canvas";
import { DOMParser } from "@xmldom/xmldom";

const HeadlessAdapter: Adapter = {
  createCanvas: (width, height) => createCanvas(width ?? 0, height ?? 0),
  createImage: () => new Image(),
  getCanvasRenderingContext2D: () => CanvasRenderingContext2D,
  getWebGLRenderingContext: () => WebGLRenderingContext,
  getNavigator: () => ({ userAgent: "HeadlessAdapter", gpu: null }),
  getBaseUrl: () => "file://",
  getFontFaceSet: () => null,
  fetch: (url, options) => fetch(url, options),
  parseXML: (xml) => new DOMParser().parseFromString(xml, "text/xml"),
};

DOMAdapter.set(HeadlessAdapter);

The Adapter interface requires these methods: createCanvas, createImage, getCanvasRenderingContext2D, getWebGLRenderingContext, getNavigator, getBaseUrl, getFontFaceSet, fetch, parseXML.

Checking the current adapter

import { DOMAdapter } from "pixi.js";

const adapter = DOMAdapter.get();
const canvas = adapter.createCanvas(256, 256);
const img = adapter.createImage();

DOMAdapter.get() returns whatever adapter is currently set. Use this for any DOM access within PixiJS-adjacent code instead of calling document or Image directly.

Common Mistakes

[CRITICAL] Not setting adapter before app.init()

Wrong:

const app = new Application();
await app.init({ width: 800, height: 600 });
DOMAdapter.set(WebWorkerAdapter); // too late; adapter already read during init

Correct:

DOMAdapter.set(WebWorkerAdapter);
const app = new Application();
await app.init({ width: 800, height: 600 });

DOMAdapter.set() must be called before app.init() in non-browser environments. PixiJS reads the adapter during app.init() when the renderer is created. new Application() itself only creates the stage Container and does not read the adapter.

[HIGH] Using document or Image directly

Wrong:

const img = new Image();
img.src = "texture.png";

Correct:

import { DOMAdapter } from "pixi.js";

const img = DOMAdapter.get().createImage();
img.src = "texture.png";

All DOM access in PixiJS goes through DOMAdapter. Direct use of document, Image, or other browser globals breaks Web Worker and SSR compatibility.

[HIGH] CSP unsafe-eval import name confusion

Wrong:

// CSP environment, omitting the import
import { Application } from "pixi.js";
// Throws: "Current environment does not allow unsafe-eval,
// please use pixi.js/unsafe-eval module to enable support."

Correct:

import "pixi.js/unsafe-eval";
import { Application } from "pixi.js";

The pixi.js/unsafe-eval import removes the need for eval() / new Function() in shader compilation. Despite the name suggesting it enables unsafe eval, it does the opposite: it installs static polyfills so PixiJS works under strict CSP.

PixiJS detects CSP blocking at renderer init and throws the error above. The browser may also log its own CSP violation before PixiJS reports; both point to the same fix.

[HIGH] Using old settings.ADAPTER pattern

Wrong:

import { settings, WebWorkerAdapter } from "pixi.js";
settings.ADAPTER = WebWorkerAdapter;

Correct:

import { DOMAdapter, WebWorkerAdapter } from "pixi.js";
DOMAdapter.set(WebWorkerAdapter);

The settings object was removed in v8. All adapter configuration uses DOMAdapter.set().

API Reference

Related skills

More from pixijs/pixijs-skills and the wider catalog.

PIpixijs-events logo

pixijs-events

pixijs/pixijs-skills

Handle pointer, mouse, touch, and wheel input in PixiJS v8 with federated events.

2.0k installsAudited
PIpixijs-filters logo

pixijs-filters

pixijs/pixijs-skills

Apply visual effects to PixiJS v8 containers using built-in and custom filters with GLSL/WGSL shaders.

2.0k installsAudited
PIpixijs-html-source logo

pixijs-html-source

pixijs/pixijs-skills

Use this skill when rendering live HTML/DOM elements (or frozen snapshots of them) as PixiJS v8 textures via the EXPERIMENTAL HTML-in-Canvas browser APIs. Covers the pixi.js/html-source side-effect import, feature-detection with canvas.requestPaint, HTMLSource for a live, repainting element kept interactive in the browser (autoLayout/autoUpdate/autoRequestPaint, requestPaint, isReady, the direct-child-of-canvas + layoutsubtree requirement), ElementImageSource for an immutable captureElementImage() snapshot (autoClose, ready immediately), using the source on a Sprite/Texture/Mesh, fallback-only auto-detection via Texture.from at priority -10, and destroy/cleanup. Triggers on: HTMLSource, ElementImageSource, pixi.js/html-source, requestPaint, captureElementImage, ElementImage, layoutsubtree, autoRequestPaint, autoUpdate, autoClose, HTML in canvas, render DOM to texture, HTMLSourceOptions, ElementImageSourceOptions, HTMLSourceCanvas, experimental.

773 installsAudited
PIpixijs-math logo

pixijs-math

pixijs/pixijs-skills

PixiJS v8 math primitives: points, matrices, shapes, hit testing, and coordinate transforms.

2.0k installsAudited
PIpixijs-migration-v8 logo

pixijs-migration-v8

pixijs/pixijs-skills

Migrate PixiJS v7 code to v8: async init, new Graphics API, single package, shader rework.

1.7k installsAudited
PIpixijs-performance logo

pixijs-performance

pixijs/pixijs-skills

Profile and optimize PixiJS v8 apps for FPS, draw calls, and GPU memory with targeted patterns.

2.0k installsAudited