opción
HogarHogar Skill Otros pixijs-custom-rendering

pixijs-custom-rendering

pixijs/pixijs pixijs/pixijs

Utiliza esta habilidad al escribir shaders, uniformes, filtros o batchers personalizados en PixiJS v8. Abarca Shader.from({gl, gpu, resources}), GlProgram/GpuProgram, UniformGroup con uniformes tipados (f32, vec2, mat4x4), el modo UBO, texturas como recursos, filtros personalizados mediante Filter.from, convenciones de GLSL ES 3.0 (in/out, finalColor, texture()), muestreo de uBackTexture, pixi.js/unsafe-eval para CSP estricto y batchers personalizados mediante extensiones. Se activa en: Shader, GlProgram, GpuProgram, UniformGroup, Batcher, Filter, Filter.from, GLSL, WGSL, UBO, uniform, shader personalizado, finalColor, uBackTexture, blendRequired, unsafe-eval.

...Expandir todo
177
Tiempo actualizado 11 de agosto de 2026

Los shaders personalizados vinculan los programas GLSL y WGSL a los objetos de la escena mediante Shader.from({ gl, gpu, resources }). Las variables uniformes se almacenan en UniformGroupstipados, las texturas se pasan como recursos independientes, y un mismo shader puede estar destinado tanto a WebGL como a WebGPU.

Inicio rápido

const uniforms = new UniformGroup({
  uTime: { value: 0, type: "f32" },
});const shader = Shader.from({
  gl: { vertex: vertexSrc, fragment: fragmentSrc },
 resources: { uniforms },
});const geometry = new MeshGeometry({
  positions: new Float32Array([0, 0, 100, 0, 100, 100, 0, 100]),
 uvs: new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]),
 índices: new Uint32Array([0, 1, 2, 0, 2, 3]),
});const mesh = new Mesh({ geometry, shader });
app.stage.addChild(mesh);app.ticker.add(() => {
  shader.resources.uniforms.uniforms.uTime = performance.now() / 1000;
});

Habilidades relacionadas: pixijs-filters (filtros integrados), pixijs-scene-mesh (geometría personalizada), pixijs-performance (optimización por lotes), pixijs-migration-v8 (migración de la API de shaders desde la v7).

Patrones básicos

Shader con doble renderizador (WebGL + WebGPU)

import { Shader, GlProgram, GpuProgram, UniformGroup } from "pixi.js";const glVertex = `...`; // vértice GLSL (escribe tú mismo `#version 300 es` si quieres WebGL2/GLSL ES 3.0)
const glFragment = `...`; // Fragmento GLSL
const wgslSource = `...`; // WGSLcombinado
 const shader = Shader.from({
  gl: { vertex: glVertex, fragment: glFragment },
 gpu: {
    // Los nombres de los puntos de entrada son arbitrarios; deben coincidir con  los nombres de las funciones @vertex / @fragment
    // de tu código fuente WGSL. PixiJS incluye ejemplos que utilizan
    // «mainVert» / «mainFrag», pero «main» es igualmente válido.
   vertex: { entryPoint: "mainVert", source: wgslSource },
    fragment: { entryPoint: "mainFrag", source: wgslSource },
  },
 resources: {
    myUniforms: new UniformGroup({
      uColor: { value: new Float32Array([1, 0, 0, 1]), type: "vec4" },
     uMatrix: { value: new Float32Array(16), type: "mat4x4" },
    }),
  },
});

Si solo se proporciona «gl», el shader funciona únicamente con WebGL. Si solo se proporciona «gpu», funciona únicamente con WebGPU. La máscara de bits «compatibleRenderers» se establece automáticamente.

GlProgram no inserta automáticamente #version 300 es. Si escribes tú mismo #version 300 es, PixiJS lo conserva y trata el shader como GLSL ES 3.0; de lo contrario, inyecta macros de compatibilidad con WebGL1 (#define en varying, #define texture texture2D) y ejecuta el shader como GLSL al estilo de WebGL1. GlProgram siempre inyecta una precisión predeterminada (highp para vértices, mediump para fragmentos) y el nombre del programa. Para GLSL ES 3.0, utilizain/out en lugar deattribute/varying, texture() en lugar de texture2D(), y un out vec4 en lugar de gl_FragColor.

Texturas como recursos

Las texturas son recursos, no uniformes. Pasa la fuente y el estilo de la textura por separado:

import { Shader, UniformGroup, Texture, Assets } from "pixi.js";const texture = await Assets.load("myImage.png");const shader = Shader.from({
  gl: { vertex: vertSrc, fragment: fragSrc },
 resources: {
    uTexture: texture.source,
    uSampler: texture.source.style,
    myUniforms: new UniformGroup({
      uAlpha: { value: 1.0, type: "f32" },
    }),
  },
});// Cambiar la textura en tiempo de ejecución
shader.resources.uTexture = otherTexture.source;

Los recursos son un mapa plano de clave-valor. La clave debe coincidir con el nombre del uniforme o del enlace en el código fuente del sombreador.

Los recursos también pueden ser objetos simples (que se envuelven automáticamente en un `UniformGroup`):

const shader = Shader.from({
  gl: { vertex: vertSrc, fragment: fragSrc },
 resources: {
    myUniforms: {
      uTime: { value: 0, type: "f32" },
    },
  },
});

Modo UBO (Uniform Buffer Objects)

El modo UBO agrupa los uniformes en un único búfer de la GPU. Es obligatorio para WebGPU; opcional (WebGL2+) para WebGL.

import { UniformGroup } from "pixi.js";const ubo = new UniformGroup(
  {
    uProjection: { value: new Float32Array(16), type: "mat4x4" },
   uAlpha: { value: 1.0, type: "f32" },
  },
  { ubo: true, isStatic: true },
);// Hay que llamar a update() manualmente cuando isStatic es true
ubo.uniforms.uAlpha = 0.5;
ubo.update();

Reglas de UBO:

  • Solo se admiten tipos basados en f32 e i32 (no u32). Las matrices son únicamente de tipo float.
  • Los muestreadores y las texturas no pueden incluirse en un UBO.
  • El nombre del UniformGroup en los recursos debe coincidir exactamente con el nombre del bloque UBO en el shader.
  • La estructura y el orden deben coincidir exactamente con la disposición del shader.
  • La sincronización de UBO utiliza la nueva función «Function» en segundo plano. En entornos CSP estrictos (sin «unsafe-eval»), importa «pixi.js/unsafe-eval» una vez al iniciar para activar la ruta de sincronización alternativa; sin ello, los shaders basados en UBO (y, por lo tanto, WebGPU) generarán un error en su primer uso.

Filtro personalizado

Filter.from({ gl, resources }) es la sintaxis abreviada. Pasa únicamente un sombreador de fragmentos; PixiJS proporciona un sombreador de vértices predeterminado que se encarga del posicionamiento del fotograma de salida.

import { Filter } from "pixi.js";const filter = Filter.from({
  gl: {
    fragment: `
            in vec2 vTextureCoord;
            out vec4 finalColor;
            uniform sampler2D uTexture;
            uniform float uStrength;            void main(void) {
                vec4 color = texture(uTexture, vTextureCoord);
                finalColor = mix(color, vec4(1.0 - color.rgb, color.a), uStrength);
            }
        `,
  },
  resources: {
    filterUniforms: {
      uStrength: { value: 0.5, type: "f32" },
    },
  },
});filter.resources.filterUniforms.uniforms.uStrength = 1.0;

Para un sombreador de vértices personalizado, utiliza new Filter({ glProgram: new GlProgram({ vertex, fragment }), resources }).

Convenciones de los sombreadores de Filter (GLSL ES 3.0)
  • en vec2 vTextureCoord; en lugar de varying vec2 vTextureCoord;
  • out vec4 finalColor; en lugar de gl_FragColor
  • texture(uTexture, uv) en lugar de texture2D(uTexture, uv)
  • El sombreador de vértices predeterminado expone uInputSize, uOutputFrame, uOutputTexture y las funciones auxiliares filterVertexPosition() / filterTextureCoord()
Muestreo del destino de renderizado detrás del filtro

Establece blendRequired: true y muestrea uBackTexture en el sombreador de fragmentos. PixiJS copia los píxeles de destino en ese uniforme antes de ejecutar el filtro:

const blendFilter = Filter.from({
  gl: { fragment: blendFragSrc },
  resources: { uniforms: { uAmount: { value: 0.5, type: "f32" } } },
  blendRequired: true,
});

Activa blendRequired solo cuando lo necesites; obliga a realizar una copia adicional en la GPU en cada fotograma.

Actualización de uniformes en tiempo de ejecución

// Accede al UniformGroup a través de resources
shader.resources.myUniforms.uniforms.uTime = performance.now() / 1000;// Para los UBO de tipo isStatic, llama a update() después de cambiar los valores
shader.resources.myUniforms.update();

Referencia de tipos de uniformes

Consulta references/uniform-types.md para ver la tabla completa de tipos admitidos, sus equivalentes en WGSL/GLSL y los formatos de valor.

Batcher personalizado (basado en extensiones)

La clase abstracta ` Batcher ` permite la agrupación personalizada para un renderizado especializado. Crea una subclase y regístrala mediante extensiones:

import { Batcher, extensions, ExtensionType } from "pixi.js";
import type {
  BatcherOptions,
  BatchableMeshElement,
  BatchableQuadElement,
  Geometry,
  Shader,
} from "pixi.js";class MyBatcher extends Batcher {
 public static extension = {
    type: [ExtensionType.Batcher],
    name: "my-batcher",
  };  public name = "my-batcher";
 protected vertexSize = 6; // flotantes por vértice
  public geometry: Geometry;
  public shader: Shader;  constructor(options: BatcherOptions) {
    super(options);
    // Inicializar la geometría y el shader
  }  public packAttributes(
    element: BatchableMeshElement,
    float32View: Float32Array,
    uint32View: Uint32Array,
    index: number,
    textureId: number,
  ): void {
   // Empaqueta los atributos de vértices de la malla en el búfer de lotes
  }  public packQuadAttributes(
    element: BatchableQuadElement,
    float32View: Float32Array,
    uint32View: Uint32Array,
    index: number,
    textureId: number,
  ): void {
   // Empaqueta los atributos de vértices del cuadrilátero en el búfer de lote
  }
}extensions.add(MyBatcher);

Los elementos hacen referencia al «batcher» mediante «batcherName». La interfaz «BatchableElement» requiere: «batcherName», «texture», «blendMode», «indexSize», «attributeSize», «topology» y «packAsQuad».

Errores comunes

[CRÍTICO] Antiguo constructor Shader.from(vertex, fragment, uniforms)

Incorrecto:

const shader = Shader.from(vertex, fragment, { uTime: 1 });

Correcto:

const shader = Shader.from({
  gl: { vertex, fragment },
  resources: {
    uniforms: new UniformGroup({
      uTime: { value: 1, type: "f32" },
    }),
  },
});

v8 requiere un objeto de opciones con programasgl/gpu y recursos. Se ha eliminado la API posicional.

[CRÍTICO] UniformGroup sin anotación de tipo

Incorrecto:

new UniformGroup({ uTime: 1 });

Correcto:

new UniformGroup({ uTime: { value: 1, type: "f32" } });

Cada uniforme requiere un par explícito { valor, tipo }. Si se omite el tipo, se produce un error en tiempo de ejecución: «El tipo de uniforme indefinido no es compatible».

[ALTO] UBO con tipos no admitidos o estructura incorrecta

El modo UBO admite tipos basados en f32 e i32 (escalares y vectores). u32 no figura en la lista de tipos admitidos por UniformGroup y provocará un error. Las matrices son solo de tipo float (mat*). Los muestreadores no se pueden colocar en UBO.

El nombre de la estructura y el orden de los campos deben coincidir exactamente con la declaración del UBO en el shader. Las discrepancias producen un renderizado distorsionado sin que se muestre ningún error.

[ALTO] Colocar texturas en UniformGroup

Incorrecto:

new UniformGroup({
  uTexture: { value: texture, type: "f32" },
});

Correcto:

const shader = Shader.from({
  gl: { vertex, fragment },
  resources: {
   uTexture: texture.source,
    uSampler: texture.source.style,
    myUniforms: new UniformGroup({
      uAlpha: { value: 1.0, type: "f32" },
    }),
  },
});

Las texturas son recursos, no uniformes. Pasa texture.source (TextureSource) y texture.source.style (TextureStyle) como entradas de recursos de primer nivel.

Referencia de la API

Ver en GitHub

Custom shaders bind GLSL and WGSL programs to scene objects via Shader.from({ gl, gpu, resources }). Uniforms live in typed UniformGroups, textures are passed as separate resources, and the same shader can target both WebGL and WebGPU.

Quick Start

const uniforms = new UniformGroup({
  uTime: { value: 0, type: "f32" },
});const shader = Shader.from({
  gl: { vertex: vertexSrc, fragment: fragmentSrc },
  resources: { uniforms },
});const geometry = new MeshGeometry({
  positions: new Float32Array([0, 0, 100, 0, 100, 100, 0, 100]),
  uvs: new Float32Array([0, 0, 1, 0, 1, 1, 0, 1]),
  indices: new Uint32Array([0, 1, 2, 0, 2, 3]),
});const mesh = new Mesh({ geometry, shader });
app.stage.addChild(mesh);app.ticker.add(() => {
  shader.resources.uniforms.uniforms.uTime = performance.now() / 1000;
});

Related skills: pixijs-filters (built-in filters), pixijs-scene-mesh (custom geometry), pixijs-performance (batch optimization), pixijs-migration-v8 (shader API migration from v7).

Core Patterns

Dual-renderer shader (WebGL + WebGPU)

import { Shader, GlProgram, GpuProgram, UniformGroup } from "pixi.js";const glVertex = `...`; // GLSL vertex (write `#version 300 es` yourself if you want WebGL2/GLSL ES 3.0)
const glFragment = `...`; // GLSL fragment
const wgslSource = `...`; // WGSL combinedconst shader = Shader.from({
  gl: { vertex: glVertex, fragment: glFragment },
  gpu: {
    // entryPoint names are arbitrary; they must match the @vertex / @fragment
    // function names in your WGSL source. PixiJS ships examples using
    // 'mainVert' / 'mainFrag' but `main` is equally valid.
    vertex: { entryPoint: "mainVert", source: wgslSource },
    fragment: { entryPoint: "mainFrag", source: wgslSource },
  },
  resources: {
    myUniforms: new UniformGroup({
      uColor: { value: new Float32Array([1, 0, 0, 1]), type: "vec4<f32>" },
      uMatrix: { value: new Float32Array(16), type: "mat4x4<f32>" },
    }),
  },
});

If only gl is provided, the shader works with WebGL only. If only gpu is provided, it works with WebGPU only. The compatibleRenderers bitmask is set automatically.

GlProgram does not auto-inject #version 300 es. If you write #version 300 es yourself, PixiJS preserves it and treats the shader as GLSL ES 3.0; otherwise it injects WebGL1 compat macros (#define in varying, #define texture texture2D) and runs the shader as WebGL1-style GLSL. GlProgram always injects a default precision (highp vertex, mediump fragment) and the program name. For GLSL ES 3.0, use in/out instead of attribute/varying, texture() instead of texture2D(), and an out vec4 instead of gl_FragColor.

Textures as resources

Textures are resources, not uniforms. Pass the texture's source and style separately:

import { Shader, UniformGroup, Texture, Assets } from "pixi.js";const texture = await Assets.load("myImage.png");const shader = Shader.from({
  gl: { vertex: vertSrc, fragment: fragSrc },
  resources: {
    uTexture: texture.source,
    uSampler: texture.source.style,
    myUniforms: new UniformGroup({
      uAlpha: { value: 1.0, type: "f32" },
    }),
  },
});// Swap texture at runtime
shader.resources.uTexture = otherTexture.source;

Resources are a flat key-value map. The key must match the uniform/binding name in the shader source.

Resources can also be plain objects (auto-wrapped into UniformGroup):

const shader = Shader.from({
  gl: { vertex: vertSrc, fragment: fragSrc },
  resources: {
    myUniforms: {
      uTime: { value: 0, type: "f32" },
    },
  },
});

UBO mode (Uniform Buffer Objects)

UBO mode packs uniforms into a single GPU buffer. Required for WebGPU; optional (WebGL2+) for WebGL.

import { UniformGroup } from "pixi.js";const ubo = new UniformGroup(
  {
    uProjection: { value: new Float32Array(16), type: "mat4x4<f32>" },
    uAlpha: { value: 1.0, type: "f32" },
  },
  { ubo: true, isStatic: true },
);// Must call update() manually when isStatic is true
ubo.uniforms.uAlpha = 0.5;
ubo.update();

UBO rules:

  • Only f32 and i32 based types are supported (no u32). Matrices are float-only.
  • Samplers/textures cannot go in a UBO.
  • The UniformGroup name in resources must exactly match the UBO block name in the shader.
  • Structure and order must exactly match the shader layout.
  • UBO sync uses new Function under the hood. In strict-CSP environments (no unsafe-eval), import pixi.js/unsafe-eval once at startup to swap in the fallback sync path; without it, UBO-backed shaders (and therefore WebGPU) will throw on first use.

Custom filter

Filter.from({ gl, resources }) is the shorthand. Pass only a fragment shader; PixiJS supplies a default vertex shader that handles output frame positioning.

import { Filter } from "pixi.js";const filter = Filter.from({
  gl: {
    fragment: `
            in vec2 vTextureCoord;
            out vec4 finalColor;
            uniform sampler2D uTexture;
            uniform float uStrength;            void main(void) {
                vec4 color = texture(uTexture, vTextureCoord);
                finalColor = mix(color, vec4(1.0 - color.rgb, color.a), uStrength);
            }
        `,
  },
  resources: {
    filterUniforms: {
      uStrength: { value: 0.5, type: "f32" },
    },
  },
});filter.resources.filterUniforms.uniforms.uStrength = 1.0;

For a custom vertex shader, use new Filter({ glProgram: new GlProgram({ vertex, fragment }), resources }).

Filter shader conventions (GLSL ES 3.0)
  • in vec2 vTextureCoord; instead of varying vec2 vTextureCoord;
  • out vec4 finalColor; instead of gl_FragColor
  • texture(uTexture, uv) instead of texture2D(uTexture, uv)
  • The default vertex shader exposes uInputSize, uOutputFrame, uOutputTexture and helpers filterVertexPosition() / filterTextureCoord()
Sampling the render target behind the filter

Set blendRequired: true and sample uBackTexture in the fragment shader. PixiJS copies the destination pixels into that uniform before running the filter:

const blendFilter = Filter.from({
  gl: { fragment: blendFragSrc },
  resources: { uniforms: { uAmount: { value: 0.5, type: "f32" } } },
  blendRequired: true,
});

Only enable blendRequired when you need it; it forces an extra GPU copy every frame.

Updating uniforms at runtime

// Access the UniformGroup via resources
shader.resources.myUniforms.uniforms.uTime = performance.now() / 1000;// For isStatic UBOs, call update() after changing values
shader.resources.myUniforms.update();

Uniform type reference

See references/uniform-types.md for the complete table of supported types, their WGSL/GLSL equivalents, and value formats.

Custom Batcher (extension-based)

The Batcher abstract class enables custom batching for specialized rendering. Subclass it and register via extensions:

import { Batcher, extensions, ExtensionType } from "pixi.js";
import type {
  BatcherOptions,
  BatchableMeshElement,
  BatchableQuadElement,
  Geometry,
  Shader,
} from "pixi.js";class MyBatcher extends Batcher {
  public static extension = {
    type: [ExtensionType.Batcher],
    name: "my-batcher",
  };  public name = "my-batcher";
  protected vertexSize = 6; // floats per vertex
  public geometry: Geometry;
  public shader: Shader;  constructor(options: BatcherOptions) {
    super(options);
    // Initialize geometry and shader
  }  public packAttributes(
    element: BatchableMeshElement,
    float32View: Float32Array,
    uint32View: Uint32Array,
    index: number,
    textureId: number,
  ): void {
    // Pack mesh vertex attributes into the batch buffer
  }  public packQuadAttributes(
    element: BatchableQuadElement,
    float32View: Float32Array,
    uint32View: Uint32Array,
    index: number,
    textureId: number,
  ): void {
    // Pack quad vertex attributes into the batch buffer
  }
}extensions.add(MyBatcher);

Elements reference the batcher by batcherName. The BatchableElement interface requires: batcherName, texture, blendMode, indexSize, attributeSize, topology, and packAsQuad.

Common Mistakes

[CRITICAL] Old Shader.from(vertex, fragment, uniforms) constructor

Wrong:

const shader = Shader.from(vertex, fragment, { uTime: 1 });

Correct:

const shader = Shader.from({
  gl: { vertex, fragment },
  resources: {
    uniforms: new UniformGroup({
      uTime: { value: 1, type: "f32" },
    }),
  },
});

v8 requires an options object with gl/gpu programs and resources. The positional API was removed.

[CRITICAL] UniformGroup without type annotation

Wrong:

new UniformGroup({ uTime: 1 });

Correct:

new UniformGroup({ uTime: { value: 1, type: "f32" } });

Every uniform requires an explicit { value, type } pair. Omitting the type causes a runtime error: "Uniform type undefined is not supported."

[HIGH] UBO with unsupported types or wrong structure

UBO mode supports f32 and i32 based types (scalars and vectors). u32 is not in the supported UniformGroup type list and will throw. Matrices are float-only (mat*<f32>). Samplers cannot be placed in UBOs.

The struct name and field order must exactly match the shader's UBO declaration. Mismatches produce garbled rendering with no error.

[HIGH] Putting textures in UniformGroup

Wrong:

new UniformGroup({
  uTexture: { value: texture, type: "f32" },
});

Correct:

const shader = Shader.from({
  gl: { vertex, fragment },
  resources: {
    uTexture: texture.source,
    uSampler: texture.source.style,
    myUniforms: new UniformGroup({
      uAlpha: { value: 1.0, type: "f32" },
    }),
  },
});

Textures are resources, not uniforms. Pass texture.source (TextureSource) and texture.source.style (TextureStyle) as top-level resource entries.

API Reference

Todos los archivos

2 archivos

Instalar pixijs-custom-rendering

Descarga y descomprime los archivos de las habilidades en tu directorio .claude/skills/.

Descargar ZIP

Clona el repositorio y copia los archivos de la habilidad a tu proyecto.

git clone https://github.com/pixijs/pixijs/tree/dev/skills/pixijs-custom-rendering # Copy the skill folder to .claude/skills/ or .codex/skills/

Copiar Copiar
Configuración rápida: Copia la carpeta de la habilidad en .claude/skills/. Claude la detectará automáticamente y utilizará la habilidad.
Repositorio pixijs/pixijs

Habilidades relacionadas

v4-new-features
Tiempo actualizado 4 de agosto de 2026
pixijs-application
Tiempo actualizado 4 de agosto de 2026
multica-creating-agents
Tiempo actualizado 12 de agosto de 2026
agent-project-board-sync
Tiempo actualizado 3 de agosto de 2026
OR