skills/phaserjs/phaser/sprites-and-images

sprites-and-images

Installation
SKILL.md

Sprites and Images

Creating and manipulating Sprite and Image game objects in Phaser 4 -- factory methods, texture/frame selection, the component mixin system, and common visual operations (position, scale, rotation, tint, flip, alpha, origin, depth).

Key source paths: src/gameobjects/sprite/, src/gameobjects/image/, src/gameobjects/GameObject.js, src/gameobjects/components/ Related skills: ../loading-assets/SKILL.md, ../animations/SKILL.md, ../physics-arcade/SKILL.md, ../game-object-components/SKILL.md

Quick Start

// In a Scene's create() method:

// Static image (no animation support, slightly cheaper)
const bg = this.add.image(400, 300, 'background');

// Sprite (supports animations)
const player = this.add.sprite(100, 200, 'player', 'idle-0');

// Common operations -- all methods return `this` for chaining
player.setPosition(200, 300);
player.setScale(2);
player.setAngle(45);
player.setTint(0xff0000);
player.setAlpha(0.8);
player.setOrigin(0, 1);       // bottom-left
player.setDepth(10);
player.setFlip(true, false);  // flip horizontally
player.setVisible(false);

// Chained
this.add.sprite(100, 100, 'coin')
    .setScale(0.5)
    .setTint(0xffff00)
    .play('spin');

Core Concepts

Sprite vs Image

Both extend GameObject and share the same set of component mixins. The only difference is that Sprite includes an AnimationState instance (sprite.anims) and animation convenience methods (play, stop, chain, etc.).

Feature Image Sprite
Static texture display Yes Yes
Tint, alpha, flip, scale, rotate Yes Yes
Physics body Yes Yes
Input / hit area Yes Yes
Animation (play, stop, chain) No Yes
preUpdate called each frame No Yes (updates animation)
Added to Scene updateList No Yes

Rule of thumb: Use Image for anything that does not need frame-by-frame animation. It skips the per-frame preUpdate cost and has a smaller API surface. Use Sprite only when you need the Animation component.

The Component Mixin System

Phaser builds Game Object classes by mixing component objects into the prototype. Both Sprite and Image share this identical Mixins array (sourced from src/gameobjects/sprite/Sprite.js and src/gameobjects/image/Image.js):

Mixins: [
    Components.Alpha,
    Components.BlendMode,
    Components.Depth,
    Components.Flip,
    Components.GetBounds,
    Components.Lighting,
    Components.Mask,
    Components.Origin,
    Components.RenderNodes,
    Components.ScrollFactor,
    Components.Size,
    Components.TextureCrop,
    Components.Tint,
    Components.Transform,
    Components.Visible,
    SpriteRender / ImageRender   // render-specific (differs per class)
]

The base GameObject class itself mixes in:

Mixins: [
    Components.Filters,
    Components.RenderSteps
]

Each component adds specific properties and methods to every instance. For example, Components.Transform adds x, y, scale, rotation, setPosition(), etc. The full list of available components is in src/gameobjects/components/index.js.

Key point for agents: When you see a method like setAlpha() on a Sprite, it comes from Components.Alpha, not from the Sprite class itself. The component source file is the authoritative reference for that method's signature and behavior.

Texture and Frame

Both Sprite and Image use the TextureCrop component which provides:

  • texture -- the Phaser.Textures.Texture instance
  • frame -- the current Phaser.Textures.Frame instance
  • setTexture(key, frame) -- change the texture (and optionally the frame)
  • setFrame(frame, updateSize, updateOrigin) -- change only the frame
  • setCrop(x, y, width, height) -- crop a rectangular region of the texture
  • isCropped -- boolean, toggle cropping on/off after setCrop

The texture parameter in factory methods and constructors accepts either a string key (as registered in the Texture Manager) or a Phaser.Textures.Texture instance.

The frame parameter accepts a string name or numeric index into the texture's frame collection. If omitted, the base frame (frame 0 / '__BASE') is used.

// Change texture at runtime
sprite.setTexture('enemies', 'goblin-walk-1');

// Change only the frame (must belong to current texture)
sprite.setFrame('goblin-walk-2');

// setFrame signature:
// setFrame(frame, updateSize=true, updateOrigin=true)
// Pass false to prevent automatic resize/origin recalculation
sprite.setFrame('small-frame', false, false);

// Crop to show only a 50x50 region starting at (10, 10)
sprite.setCrop(10, 10, 50, 50);
// Reset crop
sprite.setCrop();

Common Patterns

Creating and Positioning

Transform component (src/gameobjects/components/Transform.js):

// Properties (all read/write)
sprite.x           // horizontal position (default: 0)
sprite.y           // vertical position (default: 0)
sprite.z           // z position (does NOT control render order -- use depth)
sprite.w           // w position

// Methods
sprite.setPosition(x, y, z, w)        // y defaults to x if omitted
sprite.setRandomPosition(x, y, w, h)  // random within area; defaults to game size
sprite.copyPosition(source)            // copy from any {x, y} object

Size component (src/gameobjects/components/Size.js):

sprite.width            // native (un-scaled) width
sprite.height           // native (un-scaled) height
sprite.displayWidth      // scaled width (read/write -- setting adjusts scaleX)
sprite.displayHeight     // scaled height (read/write -- setting adjusts scaleY)

sprite.setSize(width, height)           // set internal size (not visual)
sprite.setDisplaySize(width, height)    // set visual size (adjusts scale)
sprite.setSizeToFrame(frame)            // reset size to match frame

Scaling and Rotation

Transform component (continued):

// Scale properties
sprite.scale       // uniform scale (getter returns average of scaleX+scaleY)
sprite.scaleX      // horizontal scale (default: 1)
sprite.scaleY      // vertical scale (default: 1)

// Scale methods
sprite.setScale(x, y)    // y defaults to x if omitted

// Rotation properties
sprite.rotation    // in radians (right-hand clockwise: 0=right, PI/2=down)
sprite.angle       // in degrees (0=right, 90=down, 180/-180=left, -90=up)

// Rotation methods
sprite.setRotation(radians)   // defaults to 0
sprite.setAngle(degrees)      // defaults to 0

Tinting and Alpha

Tint component (src/gameobjects/components/Tint.js) -- WebGL only:

// Properties
sprite.tint             // overall tint (getter returns tintTopLeft)
sprite.tintTopLeft      // default: 0xffffff
sprite.tintTopRight     // default: 0xffffff
sprite.tintBottomLeft   // default: 0xffffff
sprite.tintBottomRight  // default: 0xffffff
sprite.tintMode         // default: Phaser.TintModes.MULTIPLY
sprite.isTinted         // read-only boolean

// Methods
sprite.setTint(topLeft, topRight, bottomLeft, bottomRight)
// If only topLeft given, applies uniformly to all four corners
sprite.setTintMode(mode)   // Phaser.TintModes.MULTIPLY | FILL | ADD | SCREEN | OVERLAY | HARD_LIGHT
sprite.clearTint()         // resets to 0xffffff + MULTIPLY mode

Phaser 4 change: setTintFill() is removed. Use setTint(color).setTintMode(Phaser.TintModes.FILL) instead.

Alpha component (src/gameobjects/components/Alpha.js):

// Properties
sprite.alpha             // global alpha 0-1 (default: 1)
sprite.alphaTopLeft      // per-corner alpha (WebGL only)
sprite.alphaTopRight
sprite.alphaBottomLeft
sprite.alphaBottomRight

// Methods
sprite.setAlpha(topLeft, topRight, bottomLeft, bottomRight)
// If only topLeft given, applies uniformly to whole object
sprite.clearAlpha()     // resets to 1 (fully opaque)

Setting alpha to 0 clears the render flag so the object is not drawn. Setting it back to any non-zero value restores it.

Flipping

Flip component (src/gameobjects/components/Flip.js):

// Properties
sprite.flipX    // boolean (default: false)
sprite.flipY    // boolean (default: false)

// Methods
sprite.setFlipX(value)        // set horizontal flip
sprite.setFlipY(value)        // set vertical flip
sprite.setFlip(x, y)          // set both at once
sprite.toggleFlipX()          // invert current horizontal flip
sprite.toggleFlipY()          // invert current vertical flip
sprite.resetFlip()            // set both to false

Flipping is a rendering toggle only. It does not affect physics bodies or hit areas. Flip occurs from the middle of the texture and does not change the scale value.

Origin and Depth

Origin component (src/gameobjects/components/Origin.js):

// Properties (normalized 0-1)
sprite.originX          // default: 0.5 (center)
sprite.originY          // default: 0.5 (center)
sprite.displayOriginX   // pixel value (originX * width)
sprite.displayOriginY   // pixel value (originY * height)

// Methods
sprite.setOrigin(x, y)           // y defaults to x; defaults to 0.5
sprite.setDisplayOrigin(x, y)    // set origin in pixels; y defaults to x
sprite.setOriginFromFrame()      // use Frame pivot if set, else 0.5
sprite.updateDisplayOrigin()     // recalculate pixel origin from normalized

Depth component (src/gameobjects/components/Depth.js):

// Properties
sprite.depth    // default: 0 (higher = renders on top)

// Methods
sprite.setDepth(value)
sprite.setToTop()              // move to top of display list (no depth change)
sprite.setToBack()             // move to back of display list (no depth change)
sprite.setAbove(gameObject)    // position above another object in the list
sprite.setBelow(gameObject)    // position below another object in the list

Setting depth queues a depth sort in the Scene. The setToTop/setToBack/setAbove/setBelow methods change display list position without modifying the depth value.

Destroying Game Objects

sprite.destroy();           // removes from display list, update list, and cleans up
sprite.ignoreDestroy = true; // prevent destruction (you manage lifecycle manually)
sprite.isDestroyed           // boolean, true after destroy() has been called

For Sprites, destroy() also calls this.anims.destroy() to clean up the AnimationState.

Additional Components

Visible (src/gameobjects/components/Visible.js):

sprite.visible              // boolean (default: true)
sprite.setVisible(value)    // invisible objects skip rendering but still update

ScrollFactor (src/gameobjects/components/ScrollFactor.js):

sprite.scrollFactorX        // default: 1 (moves with camera)
sprite.scrollFactorY        // default: 1
sprite.setScrollFactor(x, y)  // 0 = fixed to camera; y defaults to x

BlendMode (src/gameobjects/components/BlendMode.js):

sprite.blendMode            // default: Phaser.BlendModes.NORMAL
sprite.setBlendMode(value)  // Phaser.BlendModes.ADD, MULTIPLY, SCREEN, ERASE, etc.

Performance note: Changing blend mode breaks WebGL batches. Group objects by blend mode when possible (e.g., render all ADD-mode sprites together) to minimize draw calls.

Factory Methods

this.add.sprite

Source: src/gameobjects/sprite/SpriteFactory.js

// Signature
this.add.sprite(x, y, texture, frame);
Param Type Required Description
x number Yes Horizontal position in world coordinates
y number Yes Vertical position in world coordinates
texture string | Phaser.Textures.Texture Yes Texture key or Texture instance
frame string | number No Frame name or index within the texture

Returns: Phaser.GameObjects.Sprite

Internally does: this.displayList.add(new Sprite(this.scene, x, y, texture, frame))

The Sprite constructor calls: setTexture -> setPosition -> setSizeToFrame -> setOriginFromFrame -> initRenderNodes.

this.add.image

Source: src/gameobjects/image/ImageFactory.js

// Signature
this.add.image(x, y, texture, frame);
Param Type Required Description
x number Yes Horizontal position in world coordinates
y number Yes Vertical position in world coordinates
texture string | Phaser.Textures.Texture Yes Texture key or Texture instance
frame string | number No Frame name or index within the texture

Returns: Phaser.GameObjects.Image

Internally does: this.displayList.add(new Image(this.scene, x, y, texture, frame))

The Image constructor calls the same init sequence as Sprite: setTexture -> setPosition -> setSizeToFrame -> setOriginFromFrame -> initRenderNodes.

Specialized Game Objects

NineSlice

Scalable UI panels with fixed-size corners and stretchable edges/center. Ideal for buttons, panels, and dialog boxes that need to resize without distorting borders.

// nineslice(x, y, texture, frame, width, height, leftWidth, rightWidth, topHeight, bottomHeight)
const panel = this.add.nineslice(400, 300, 'panel', null, 300, 200, 20, 20, 20, 20);

// Resize at runtime -- corners stay fixed, edges stretch
panel.setSize(500, 400);

TileSprite

Repeating texture that fills an area. Supports atlas frames in v4 and a new tileRotation property.

const bg = this.add.tileSprite(400, 300, 800, 600, 'grass');

// Scroll the tile in update() for parallax backgrounds
bg.tilePositionX += 0.5;
bg.tilePositionY += 0.25;

// v4: rotate the tile pattern
bg.tileRotation = 0.1;

Blitter

High-performance batched rendering for large numbers of static or semi-static sprites. Blitter children (Bobs) have no rotation, scale, or physics, but render significantly faster than individual Sprites.

const blitter = this.add.blitter(0, 0, 'particles');

// Create Bobs (lightweight display objects)
for (let i = 0; i < 1000; i++) {
    const bob = blitter.create(
        Phaser.Math.Between(0, 800),
        Phaser.Math.Between(0, 600),
        'particle_01'   // frame name within the texture
    );
    bob.setAlpha(Math.random());
}

Video

Video playback as a game object with position, scale, and filter support.

// Load in preload:
this.load.video('intro', 'intro.mp4');

// Create in create:
const video = this.add.video(400, 300, 'intro');
video.play();

For detailed configuration options, API reference tables, and source file maps, see the reference guide.

Weekly Installs
20
Repository
phaserjs/phaser
GitHub Stars
39.4K
First Seen
9 days ago
Installed on
opencode20
gemini-cli20
amp20
cline20
github-copilot20
codex20