Phaser AE

Sprite shaders

Free packv3.0.0-32DFX

A shader of your own on one sprite, run over the sprite and a margin around it so the effect can reach past the outline: flames rising off the hero's head, a glow in the pickup's own shape, arcs crackling round a sword. Eight recipes come ready, and each shader is a handle you can ease, show and hide on the game clock.

This is a Free pack. Every phaser.io account can use it in their games.

Released October 14, 2026 · updated October 20, 2026

Sprite shaders: a screenshot of its demo
A note about these graphics

Expansion packs don't come with graphics. This screenshot is one way of drawing what the pack does, made for its demo: none of the sprites, tiles or backgrounds in it are in the pack.

That's by design. A pack is a game's logic, mechanics and effects, and it works with whatever art you give it. Some packs draw effects, backdrops or 3D scenes of their own, but none carries a game's sprites.

So the look is yours. Make the art on phaser.io, bring your own, or let your agent draw it in code: the same pack can look like anything.

The pack

spriteShaders

function spriteShaders(): Pack<{ spriteShaders: SpriteShadersApi }>

The sprite shaders pack. Exposes game.spriteShaders; registers drawer 6 so the backend hands it every run of sprites with a shader, in sorted order, and draws each with its own snippet (one draw call per sprite). Tweens and fades run on the game clock. Headless it keeps every value and draws nothing. WebGPU and WebGL2.

Helpers

checkSpriteShader

function checkSpriteShader(def: SpriteShaderDef, opts: { maxCode?: number } = {}): string | null

Check a sprite shader definition the way add takes it, with no GPU: the name, the limits, reserved and redeclared names, while/loop, texture calls, the margin, the length (default 8000 characters) and the WebGL2 translation. A snippet the translator refuses would draw only on WebGPU, so add refuses it too. Returns the problem in one sentence, or null.

SPRITE_SHADER_RECIPES

const SPRITE_SHADER_RECIPES: Readonly<Record<SpriteShaderRecipe, SpriteShaderDef>>

Eight ready sprite shaders, by name: a glow aura, burning (flames rising off the outline), frozen, electric arcs, dissolve to embers (tween amount 0 → 1), hologram scanlines, golden shine, and a damage flash (tween hit; it never strobes). Each is an ordinary definition: add it as it is, or copy it and change it.

spriteShaderEase

function spriteShaderEase(e: SpriteShaderEase | undefined): EaseFn

The curve an easing names: the maths pack's table by its own name (easeOutCubic, linear, sine) or by the title screen file's spelling (cubicOut), or the function itself. Default easeInOutQuad. Unknown names throw.

Functions

checkSpriteShaderWith

function checkSpriteShaderWith(def: CheckedSpriteShader, translate: SnippetTranslator, opts: { maxCode?: number } = {}): string | null

Check a sprite shader definition the way the runtime takes it, with no GPU: the name, the sixteen-param and four-colour limits, reserved and redeclared names, while/loop (a loop needs a constant bound or it can hang the GPU), texture calls (the sprite is read with srcAt), the margin, the length (default 8000 characters) and the WebGL2 translation (translate is render-webgl2's wgslSnippetToGLSL). Returns the problem in one sentence, or null.

ownsFade

function ownsFade(code: string): boolean

Does a snippet read fade (in its code, not its comments)? Then it fades itself: the template leaves color as the snippet wrote it instead of mixing it with src by the fade, and the snippet must leave src at fade 0.

padProblem

function padProblem(pad: unknown): string | null

A margin's problem in one sentence, or null. A number is that fraction of the sprite's size on every side.

resolvePad

function resolvePad(pad: number | SpritePad | undefined, w: number, h: number): [number, number, number, number]

The margin in world units for a sprite of w × h world units: [left, top, right, bottom]. Assumes padProblem found nothing; anything it would refuse reads as 0.

spriteShaderGLSL

function spriteShaderGLSL(code: string, keys: ReadonlyArray<string> = []): string

The GLSL fragment stage for a snippet: the WGSL translated (render-webgl2's wgslSnippetToGLSL, which throws naming what it cannot translate) inside the same template. The dither and the blur's turn read the pixel from the top left, as WebGPU's fragment position does, so both backends draw the same pixels.

spriteShaderScope

function spriteShaderScope(paramKeys: ReadonlyArray<string>): Record<string, string>

What a snippet can see, by GLSL type, as the WebGL2 translator is told it: the template's names and every param.

Constants

PAD_MAX_PX

const PAD_MAX_PX: 1024

The largest side a 'px' margin may take, in world units.

PAD_MAX_SIZE

const PAD_MAX_SIZE: 2

The largest side a 'size' margin may take: twice the sprite's own size.

SPRITE_FLOATS

const SPRITE_FLOATS: 60

Floats of uniform data one sprite draws with: fifteen vec4s, the same on both backends.

SPRITE_SHADER_HELPERS

const SPRITE_SHADER_HELPERS: Readonly<Record<string, { args: string[]; ret: string }>>

The helper functions the template declares beyond the shared hash21, noise2 and fbm2, as the translator is told them.

SPRITE_SHADER_RESERVED

const SPRITE_SHADER_RESERVED: ReadonlySet<string>

The names the sprite shader template declares itself: a param may not take one.

SPRITE_SHADERS_DRAWER_ID

const SPRITE_SHADERS_DRAWER_ID: 6

The drawBy id this pack registers its drawer under.

SPRITE_STRIDE

const SPRITE_STRIDE: 64

Floats between two sprites' data in the WebGPU uniform buffer: 256 bytes, the dynamic-offset alignment.

spriteShaderWGSL

const spriteShaderWGSL = (code: string, keys: ReadonlyArray<string> = []): string=> …

The whole WGSL a sprite shader runs as: the template around a definition's snippet (code), with its params named by keys in order. A snippet that reads fade fades itself; any other is mixed with src by it. For tools and tests; the runtime builds it once per snippet.

Types

CheckedSpriteShader

interface CheckedSpriteShader

The shape a check reads: a sprite shader definition.

  • name: string — Its name.
  • code: string — The WGSL snippet.
  • params?: Record<string, number> — Its params and defaults.
  • colors?: Record<string, string> — Its colours.
  • pad?: number | SpritePad — Its margin.

SnippetTranslator

type SnippetTranslator = (code: string, scope: Record<string, string>, helpers: Record<string, { args: string[]; ret: string }>) => string

The translator a check runs, as render-webgl2's wgslSnippetToGLSL: it throws naming what it cannot translate.

SpritePad

interface SpritePad

The margin a sprite shader draws into around the sprite, per side. unit 'size' (the default) reads each side as a fraction of the sprite's own size on that axis (left and right of its width, top and bottom of its height), so the effect scales with the sprite; 'px' reads them as world units (logical pixels at zoom 1). A side left out is 0.

  • top?: number — Above the sprite.
  • right?: number — Right of it.
  • bottom?: number — Below it.
  • left?: number — Left of it.
  • unit?: 'size' | 'px' — 'size' (default): fractions of the sprite's size; 'px': world units.

SpriteShaderDef

interface SpriteShaderDef

A sprite shader as data: a WGSL snippet run over one sprite and a margin around it. In scope: uv (0..1 over the padded quad), suv (the sprite's own 0..1; outside it is the margin), size (the sprite's displayed size, world units), px (suv * size), time (seconds), fade (the handle's show/hide, 0..1), TAU, hash21, noise2, fbm2, src and srcAt(p) (the sprite's pixel, premultiplied and tinted; transparent outside it), alphaAt(p), edgeAt(p, r) (the most alpha within r px), blurAt(p, r) (the alpha averaged over r px), c0..c3, p0..p15 and every param by name. It leaves the sprite's whole new look, margin included, in color (premultiplied), which starts as src.

  • name: string — A name for messages and tools, e.g. 'burning': a letter, then letters, digits, - or _.
  • description?: string — One line: what it looks like.
  • code: string — WGSL: the fragment body. color starts as the plain sprite (src); leave the premultiplied result in it. Light above alpha (rgb greater than a) adds to what is behind, for glows and flames. No fn, while, loop, return or texture calls: read the sprite with srcAt, alphaAt, edgeAt and blurAt.
  • params?: Record<string, number> — The params and their defaults, in p0..p15 order, each also in scope by its name. At most sixteen.
  • colors?: Record<string, string> — The colours and their default hex strings, in c0..c3 order (straight rgba in the snippet). At most four.
  • pad?: number | SpritePad — The margin the snippet may draw into around the sprite. A number is that fraction of the sprite's size on every side (0.25: a quarter of its width left and right, a quarter of its height above and below); { top, right, bottom, left, unit } sets each side, in fractions of the size (unit: 'size', the default) or world units (unit: 'px'). Default 0: nothing outside the outline.

SpriteShaderEase

type SpriteShaderEase = EaseName | `${'sine' | 'quad' | 'cubic' | 'quart' | 'quint' | 'expo' | 'circ' | 'back' | 'elastic' | 'bounce'}${'In' | 'Out' | 'InOut'}` | EaseFn

An easing for tween, show and hide: a name from the maths pack's EASE table ('easeOutCubic', 'linear', 'sine'), the title screen file's spelling of the same curves ('cubicOut', 'sineInOut'), or a function of 0..1.

SpriteShaderHandle

interface SpriteShaderHandle

One sprite's shader, returned by game.spriteShaders.add(). Once removed it is inert: its calls do nothing.

  • readonly name: string — The definition's name.
  • readonly sprite: Handle — The sprite it draws.
  • readonly def: Readonly<SpriteShaderDef> — The definition, as it was added (a frozen copy).
  • readonly removed: boolean — True once removed (by remove, by the sprite's death, by a later add on the same sprite, or by the scene's end).
  • set(param: string, value: number): void — Set one param live. Throws on a name the definition does not declare, or a value that is not finite. Stops a tween of it. Set params and colours together, live. Throws on an unknown name, a non-finite number or a bad hex before changing anything. Stops tweens of the params it sets.
  • set(values: SpriteShaderValues): void — Set one param live. Throws on a name the definition does not declare, or a value that is not finite. Stops a tween of it. Set params and colours together, live. Throws on an unknown name, a non-finite number or a bad hex before changing anything. Stops tweens of the params it sets.
  • tween(params: Record<string, number>, opts?: SpriteShaderTweenOptions): Promise<void> — Ease params from where they are to params over duration seconds of game time (it pauses with the game). A param already tweening is taken over from where it is. Resolves when they arrive, or when replaced, set or removed. Throws on an unknown name or a non-finite number.
  • show(opts?: SpriteShaderTweenOptions): Promise<void> — Ease the effect in over the plain sprite (fade to 1), default 0.5 s. Resolves when shown, or when interrupted.
  • hide(opts?: SpriteShaderTweenOptions): Promise<void> — Ease the effect out to the plain sprite (fade to 0), default 0.5 s. Hidden, the sprite goes back to the plain sprite path and costs nothing; hide({ duration: 0 }) right after add starts it hidden, ready to show.
  • readonly fade: number — 0..1: how much of the effect is drawn now — 0 the plain sprite, 1 the effect, between them a mix; 1 unless shown or hidden.
  • readonly params: Record<string, number> — Its params' values now, by name (a tween's current point); a fresh object each read.
  • readonly colors: Record<string, string> — Its colours now, by name, as hex strings; a fresh object each read.
  • time: number — The seconds its snippet's time reads now: the game's clock plus this shader's own offset (0 at add). Set it to jump (a tool's scrub, a restart from 0); it then runs on with the clock. Throws when not finite.
  • remove(): void — Back to the plain sprite path. Idempotent; also run when the sprite dies, the scene ends, or another shader is added to the sprite. Its tweens end.

SpriteShaderOptions

interface SpriteShaderOptions extends SpriteShaderValues

What add takes beside the definition: values that override its defaults.

SpriteShaderRecipe

type SpriteShaderRecipe = 'glow' | 'burning' | 'frozen' | 'electric' | 'embers' | 'hologram' | 'gold' | 'damage'

The names of the ready looks in SPRITE_SHADER_RECIPES.

SpriteShadersApi

interface SpriteShadersApi

game.spriteShaders: custom shaders on single sprites.

  • add(sprite: Handle, def: SpriteShaderDef, opts?: SpriteShaderOptions): SpriteShaderHandle — Draw sprite through def from the next frame, in its sorted place, until removed. opts overrides the definition's params and colours. One shader per sprite: adding another replaces it (the old handle is removed). Scene-scoped. Throws when the sprite is dead or an aggregate (a tilemap, a particle pool), when the definition fails checkSpriteShader (the message says why), or on an unknown param or colour name.
  • of(sprite: Handle): SpriteShaderHandle | null — The shader on a sprite, or null.
  • check(def: SpriteShaderDef): string | null — checkSpriteShader: a definition's problem in one sentence, or null.
  • clear(): void — Remove every shader.
  • failure(name: string): string | null — Why the shader named name draws as the plain sprite on this device: its compile error (WGSL on WebGPU, GLSL on WebGL2), or null. It arrives a frame or two after the shader is first drawn. For tools that show a shader's errors.
  • readonly count: number — Sprites with a shader now.
  • readonly drawn: number — Sprites drawn through a shader last frame.

SpriteShaderTweenOptions

interface SpriteShaderTweenOptions

How long a tween, show or hide takes and along which curve.

  • duration?: number — Seconds of game time; default 0.5. 0 is at once. Throws when negative or not finite.
  • ease?: SpriteShaderEase — The curve; default 'easeInOutQuad' (the tween pack's). An unknown name throws.

SpriteShaderValues

interface SpriteShaderValues

Params and colours to set together: handle.set({ params: { heat: 2 }, colors: { flame: '#ff0' } }).

  • params?: Record<string, number> — Params by name.
  • colors?: Record<string, string> — Colours by name, as hex strings (#rgb, #rgba, #rrggbb, #rrggbbaa; a missing alpha is opaque).