
Pixijs Scene Sprite
- 3k installs
- 293 repo stars
- Updated June 4, 2026
- pixijs/pixijs-skills
pixijs-scene-sprite is a PixiJS v8 skill for Sprite, AnimatedSprite, NineSliceSprite, and TilingSprite drawing and animation patterns.
About
The pixijs-scene-sprite skill covers PixiJS v8 sprite classes for drawing images on canvas. Sprite is the default single-texture leaf, AnimatedSprite cycles frames, NineSliceSprite preserves border art for resizable UI panels, and TilingSprite repeats textures for scrolling backgrounds. Quick start loads textures with Assets.load, constructs sprites via options objects with anchor and tint, and positions after construction when depending on renderer screen size. Variant table maps use cases to trade-offs and reference files for sprite, animated-sprite, nineslice, and tiling variants. Guidance contrasts anchor versus pivot, requires Assets.load before Sprite.from cache reads, and notes dynamic texture update patterns. Common mistakes include Texture.from URL loading, pivot misuse when centering, NineSlicePlane rename to NineSliceSprite, and adding children to leaf sprites that require a wrapping Container. Related skills point to assets loading, particle containers, graphics, and performance batching references.
- Sprite, AnimatedSprite, NineSliceSprite, and TilingSprite variant routing.
- Constructor options with anchor, tint, and Assets.load prerequisites.
- Anchor versus pivot centering guidance for sprites.
- NineSliceSprite resizable UI panel border preservation.
- TilingSprite tilePosition scrolling background patterns.
Pixijs Scene Sprite by the numbers
- 3,050 all-time installs (skills.sh)
- +222 installs in the week ending Jul 28, 2026 (Skillselion tracking)
- Ranked #162 of 2,277 Frontend Development skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Jul 28, 2026 (Skillselion catalog sync)
pixijs-scene-sprite capabilities & compatibility
- Capabilities
- sprite construction with anchor and tint options · animatedsprite frame cycling from spritesheets · nineslicesprite resizable ui panel borders · tilingsprite scrolling and parallax backgrounds · anchor versus pivot positioning guidance · leaf node constraints and container wrapping pat
- Use cases
- frontend · ui design
- Pricing
- Free
What pixijs-scene-sprite says it does
`Sprite.from(id)` only reads the Assets cache; it does not fetch.
`anchor` shifts only the draw origin. `pivot` shifts the transform origin AND the visual position
`NineSlicePlane` was renamed to `NineSliceSprite` in v8
npx skills add https://github.com/pixijs/pixijs-skills --skill pixijs-scene-spriteAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 3k |
|---|---|
| repo stars | ★ 293 |
| Security audit | 3 / 3 scanners passed |
| Last updated | June 4, 2026 |
| Repository | pixijs/pixijs-skills ↗ |
How do I choose and configure the right PixiJS sprite type for images, UI panels, animations, and scrolling backgrounds?
Draw and animate images in PixiJS v8 with Sprite, AnimatedSprite, NineSliceSprite, and TilingSprite patterns.
Who is it for?
PixiJS v8 projects rendering 2D images, UI chrome, frame animations, or parallax backgrounds.
Skip if: Skip for vector Graphics drawing, ParticleContainer mass sprites, or asset loading setup without scene sprites.
When should I use this skill?
User mentions Sprite, AnimatedSprite, NineSliceSprite, TilingSprite, anchor, tint, or tilePosition in PixiJS v8.
What you get
Correct sprite variant selection, texture loading, anchor setup, and patterns for animation or tiling without leaf-child mistakes.
- AnimatedSprite scene object
- Configured spritesheet animation
- Stage-ready frame loop
Files
PixiJS has three sprite classes for different drawing tasks. Sprite is the default image-drawing leaf; NineSliceSprite is a resizable UI-panel variant that preserves corner art; TilingSprite repeats a texture across an area. The AnimatedSprite subclass of Sprite cycles through texture frames for frame-based animation.
Assumes familiarity with pixijs-scene-core-concepts. All sprite classes are leaf nodes; they cannot have children. Wrap multiple sprites in a Container to group them.
Quick Start
const texture = await Assets.load("bunny.png");
const sprite = new Sprite({
texture,
anchor: 0.5,
tint: 0xff8888,
});
sprite.x = app.screen.width / 2;
sprite.y = app.screen.height / 2;
app.stage.addChild(sprite);Position is set after construction because app.screen.width / 2 depends on the live renderer size. Literal positions can go directly in the options object via x/y (inherited from Container).
Related skills: pixijs-scene-core-concepts (leaves, transforms), pixijs-assets (texture loading), pixijs-scene-particle-container (thousands of sprites), pixijs-performance (spritesheets, batching).
Variants
| Variant | Use when | Trade-offs | Reference |
|---|---|---|---|
Sprite | Draw a single texture at a position | Fixed size = texture size | references/sprite.md |
AnimatedSprite | Frame-based animation from a texture array or spritesheet | Pre-rendered frames only; no tweening | references/animated-sprite.md |
NineSliceSprite | Resizable UI panels, buttons, dialog frames | Border width is fixed; center stretches | references/nineslice-sprite.md |
TilingSprite | Scrolling backgrounds, parallax, repeating patterns | Single texture repeated; tilePosition scrolls | references/tiling-sprite.md |
AnimatedSprite is a subclass of Sprite; all Sprite properties (anchor, tint, position) apply.
Each variant's constructor options are documented in its sub-reference file (references/{variant}.md). All variants also accept the Container options (position, scale, tint, label, filters, zIndex, etc.) — see skills/pixijs-scene-core-concepts/references/constructor-options.md.
When to use what
- "I want to draw a single image at a position" →
Sprite. The default choice for 90% of 2D game and app content. - "I want to animate a character through a series of frames" →
AnimatedSprite. Load a spritesheet via Assets and passsheet.animations['walk']. Seereferences/animated-sprite.md. - "I want a UI button/panel that resizes without stretching the borders" →
NineSliceSprite. Set border widths, then setwidth/height. Seereferences/nineslice-sprite.md. - "I want a scrolling repeating background" →
TilingSprite. AnimatetilePositionto scroll. Seereferences/tiling-sprite.md. - "I want thousands of identical sprites" → Use
ParticleContainerwithParticleinstances (seepixijs-scene-particle-container), not plain sprites. - "I want to draw shapes or paths" → Use
Graphics(seepixijs-scene-graphics), not a sprite.
Quick concepts
Anchor vs pivot
Sprite.anchor is normalized [0, 1] and shifts only the texture draw origin; no position offset. Container.pivot is pixel-space and shifts both the transform origin and the visual position. For centering a sprite, always use anchor.set(0.5).
Loading before creating
Sprite.from(id) only reads the Assets cache; it does not fetch. Always await Assets.load(...) first, or pass the returned Texture directly to new Sprite(texture).
Dynamic textures
Once a texture is loaded, modifying its frame or swapping its source does not automatically notify sprites. Set texture.dynamic = true once, or call sprite['onViewUpdate']() manually after changes.
Common Mistakes
[HIGH] Using Texture.from(url) to load
Wrong:
const texture = Texture.from("https://example.com/image.png");Correct:
const texture = await Assets.load("https://example.com/image.png");Texture.from() only reads the cache in v8. Use Assets.load() first; its return value is the texture.
[HIGH] Confusing anchor and pivot
Wrong:
sprite.pivot.set(sprite.width / 2, sprite.height / 2);Correct:
sprite.anchor.set(0.5);anchor shifts only the draw origin. pivot shifts the transform origin AND the visual position, causing the sprite to move unexpectedly.
[HIGH] Old NineSlicePlane name
NineSlicePlane was renamed to NineSliceSprite in v8 and switched to an options-object constructor: new NineSliceSprite({ texture, leftWidth, topHeight, rightWidth, bottomHeight }).
[MEDIUM] Adding children to a sprite
Sprite, NineSliceSprite, and TilingSprite all set allowChildren = false. Wrap in a Container to group sprites with other content.
API Reference
AnimatedSprite
A Sprite subclass that cycles through an array of textures for frame-based animation. Use for character walk cycles, explosions, UI icon loops, or any sequence driven by pre-rendered frames from a spritesheet.
Quick Start
const sheet = await Assets.load("character.json");
const walk = new AnimatedSprite({
textures: sheet.animations["walk"],
animationSpeed: 0.15,
loop: true,
autoPlay: true,
});
app.stage.addChild(walk);AnimatedSprite extends Sprite, so anchor, tint, position, and scale all work the same way. It adds frame playback on top. Inherits allowChildren = false from Sprite.
Core Patterns
Construction
new AnimatedSprite(frames, autoUpdate?);
new AnimatedSprite({ textures, autoUpdate, autoPlay, loop, animationSpeed });Two constructor forms are supported. The options form accepts all SpriteOptions (anchor, tint, position, etc.) plus the animation-specific fields below. The positional form takes a frames array and an optional autoUpdate flag.
const sheet = await Assets.load("character.json");
const walk = new AnimatedSprite({
textures: sheet.animations["walk"],
animationSpeed: 0.2,
loop: true,
autoPlay: true,
anchor: 0.5,
x: 200,
y: 300,
});AnimatedSpriteOptions
| Option | Type | Default | Description |
|---|---|---|---|
textures | AnimatedSpriteFrames | — | Frame list: a Texture[] or FrameObject[] (each { texture, time } with time in ms). Required. |
animationSpeed | number | 1 | Playback multiplier; negative values reverse direction. |
autoPlay | boolean | false | Start playback immediately on construction. |
autoUpdate | boolean | true | Drive playback from Ticker.shared; set false to call update(ticker) manually. |
loop | boolean | true | Restart after the last frame; set false for one-shot animations. |
onComplete | () => void | null | Fires when a non-looping animation reaches its end. |
onFrameChange | (currentFrame: number) => void | null | Fires every time the displayed texture changes. |
onLoop | () => void | null | Fires when a looping animation wraps back to the start. |
updateAnchor | boolean | false | Copy texture.defaultAnchor onto the sprite's anchor on every frame change. Overrides any previously set anchor. |
Also inherits SpriteOptions minus texture (use textures for frames) — see sprite.md. All Container options (position, scale, tint, label, filters, zIndex, etc.) are also valid here — see skills/pixijs-scene-core-concepts/references/constructor-options.md.
Playback control
walk.play();
walk.stop();
walk.gotoAndStop(3);
walk.gotoAndPlay(0);
walk.currentFrame = 2;
console.log(walk.totalFrames);
console.log(walk.playing);play()/stop(): start or freeze playback at the current frame.gotoAndStop(frame)/gotoAndPlay(frame): jump to a specific frame index.currentFrame: readable and writable. The setter throws if the value is outside[0, totalFrames - 1].totalFrames(readonly): number of frames in the current texture list.playing(readonly): current playback state.
Speed and looping
walk.animationSpeed = 0.15;
walk.animationSpeed = -1;
walk.loop = false;animationSpeed(default1): playback multiplier. Negative reverses direction.loop(defaulttrue): restart after last frame. Set tofalseand useonCompletefor one-shot animations.
Callbacks
walk.onComplete = () => console.log("animation done");
walk.onFrameChange = (frame) => console.log(`now on frame ${frame}`);
walk.onLoop = () => console.log("looped back to start");onComplete: fires when a non-looping animation reaches its end.onFrameChange(frameIndex): fires every time the displayed texture changes.onLoop: fires when a looping animation wraps around to the start.
Auto update
const walk = new AnimatedSprite({
textures: sheet.animations["walk"],
autoUpdate: false,
});
app.ticker.add((ticker) => {
walk.update(ticker);
});autoUpdate (default true): uses Ticker.shared. Set false and call update(ticker) manually to drive playback from a custom ticker or pause it with game logic.
Per-frame timing
const explosion = new AnimatedSprite({
textures: [
{ texture: frame0, time: 100 },
{ texture: frame1, time: 200 },
{ texture: frame2, time: 300 },
],
});FrameObject entries use { texture, time } where time is in milliseconds, not seconds. Mix per-frame timing for effects that linger on key frames (impact, reveal, pause).
Spritesheets loaded via Assets.load expose per-frame duration values at sheet.data.frames[key].duration. Build a FrameObject[] from those durations when you need pre-authored timing:
const sheet = await Assets.load("0123456789.json");
const frames = [];
for (let i = 0; i < 10; i++) {
const key = `0123456789 ${i}.ase`;
frames.push({
texture: Texture.from(key),
time: sheet.data.frames[key].duration,
});
}
const sprite = new AnimatedSprite(frames);Factories
const walk = AnimatedSprite.fromFrames(["walk0.png", "walk1.png", "walk2.png"]);
const idle = AnimatedSprite.fromImages(["idle0.png", "idle1.png"]);fromFrames(aliases): builds textures viaTexture.fromfrom Assets cache aliases. Requires the spritesheet to already be loaded.fromImages(urls): builds textures from URLs. Does not await loading; textures resolve asynchronously.
Prefer new AnimatedSprite({ textures: sheet.animations[...] }) after await Assets.load(...) for deterministic loading.
updateAnchor
const walk = new AnimatedSprite({
textures: sheet.animations["walk"],
updateAnchor: true,
});updateAnchor (default false): when true, the sprite's anchor is copied from the current texture's defaultAnchor on every frame change. Useful when exporting frames with per-frame pivot points (e.g., to pin the animation to a moving foot or hand). Overrides any previously set anchor on each frame change.
Common Mistakes
[HIGH] Using Texture.from on unloaded frames
Wrong:
const walk = new AnimatedSprite([
Texture.from("walk0.png"),
Texture.from("walk1.png"),
]);Correct:
const sheet = await Assets.load("character.json");
const walk = new AnimatedSprite(sheet.animations["walk"]);Texture.from() only reads the cache in v8. If the spritesheet has not been loaded, the textures resolve to Texture.EMPTY and the sprite shows nothing. Always await Assets.load() the spritesheet first, then use sheet.animations[key].
[HIGH] Forgetting to call play() or set autoPlay
Wrong:
const walk = new AnimatedSprite({ textures: sheet.animations["walk"] });
app.stage.addChild(walk);Correct:
const walk = new AnimatedSprite({
textures: sheet.animations["walk"],
autoPlay: true,
});
app.stage.addChild(walk);autoPlay defaults to false. Without autoPlay: true or a manual walk.play() call, the sprite displays only the first frame.
[MEDIUM] Using seconds instead of milliseconds for FrameObject.time
Wrong:
new AnimatedSprite([
{ texture: frame0, time: 0.1 },
{ texture: frame1, time: 0.2 },
]);Correct:
new AnimatedSprite([
{ texture: frame0, time: 100 },
{ texture: frame1, time: 200 },
]);FrameObject.time is in milliseconds. A value of 0.1 will advance frames almost instantly.
[MEDIUM] Setting currentFrame out of range
Wrong:
walk.currentFrame = walk.totalFrames;Correct:
walk.currentFrame = walk.totalFrames - 1;The setter throws if the value is outside [0, totalFrames - 1]. Use totalFrames - 1 for the last frame.
API Reference
NineSliceSprite
A sprite variant that stretches a texture using 9-slice scaling. The four corner regions stay unscaled, the top and bottom edges stretch horizontally, the left and right edges stretch vertically, and the center stretches both ways. Use this for resizable UI panels, buttons, and dialog frames where you want the border art to remain crisp at any size.
Quick Start
const texture = await Assets.load("panel.png");
const panel = new NineSliceSprite({
texture,
leftWidth: 20,
topHeight: 20,
rightWidth: 20,
bottomHeight: 20,
width: 400,
height: 200,
});
app.stage.addChild(panel);All four border values default to 10. Assign width / height on the sprite (not the texture) to control the stretch region.
Construction
const panel = new NineSliceSprite({
texture,
leftWidth: 20,
topHeight: 20,
rightWidth: 20,
bottomHeight: 20,
width: 400,
height: 200,
anchor: 0.5,
});NineSliceSpriteOptions
| Option | Type | Default | Description |
|---|---|---|---|
texture | Texture | Texture.EMPTY | Source texture for the 9-slice. |
leftWidth | number | 10 | Width of the left border column that stays unscaled. |
topHeight | number | 10 | Height of the top border row that stays unscaled. |
rightWidth | number | 10 | Width of the right border column that stays unscaled. |
bottomHeight | number | 10 | Height of the bottom border row that stays unscaled. |
width | number | texture.width (else 100) | Width of the stretched sprite region; modifies vertices, not UVs. |
height | number | texture.height (else 100) | Height of the stretched sprite region; modifies vertices, not UVs. |
anchor | `PointData \ | number` | 0 |
roundPixels | boolean | false | Snap rendering coordinates to integers for crisp pixel art. |
All Container options (position, scale, tint, label, filters, zIndex, etc.) are also valid here — see skills/pixijs-scene-core-concepts/references/constructor-options.md.
Border values fall back to texture.defaultBorders if set on the texture; see the Texture-defined borders section below.
Core Patterns
The 9-slice grid
leftWidth rightWidth
+---+--------------------+---+
| 1 | 2 | 3 | topHeight
+---+--------------------+---+
| | | |
| 4 | 5 | 6 |
| | | |
+---+--------------------+---+
| 7 | 8 | 9 | bottomHeight
+---+--------------------+---+- Corners (1, 3, 7, 9): unscaled
- Top and bottom edges (2, 8): stretched horizontally
- Left and right edges (4, 6): stretched vertically
- Center (5): stretched both ways
Runtime resize
panel.width = 600;
panel.height = 300;
panel.setSize(600, 300);
const size = panel.getSize();Setting width / height modifies the sprite's vertices directly. It does not scale the underlying texture. The corners stay fixed-size regardless of how small or large you make the panel. setSize(value, height?) and getSize(out?) are the override pair used to avoid recomputing bounds twice when both axes change.
Texture-defined borders
const texture = new Texture({
source: baseSource,
defaultBorders: { left: 15, top: 15, right: 15, bottom: 15 },
});
const panel = new NineSliceSprite({ texture, width: 400, height: 200 });defaultBorders is a readonly Texture property. Pass it in the constructor options (or set it on the spritesheet data so Assets.load bakes it into the loaded texture). If the texture has borders set, the sprite picks them up automatically when no explicit border values are passed to the NineSliceSprite constructor. Define them once per texture and reuse across multiple panels.
Border updates
panel.leftWidth = 25;
panel.rightWidth = 25;
panel.topHeight = 15;
panel.bottomHeight = 15;All four border values are mutable at runtime. The sprite rebuilds its geometry on the next render.
Source texture dimensions
console.log(panel.originalWidth, panel.originalHeight);
panel.setSize(panel.originalWidth, panel.originalHeight);originalWidth and originalHeight are readonly getters that return the underlying texture.width / texture.height. Use them to reset a panel to its source size or to compute scaled sizes relative to the unstretched texture.
Global defaults
NineSliceSprite.defaultOptions.texture = Texture.from("defaultPanel.png");NineSliceSprite.defaultOptions is a mutable static object, but only its texture field is read as a fallback. Border defaults come from texture.defaultBorders (per-texture) or NineSliceGeometry.defaultOptions (global), and size defaults fall back to texture.width / texture.height or NineSliceGeometry.defaultOptions.width / .height.
Round pixels for crisp borders
const panel = new NineSliceSprite({
texture,
leftWidth: 10,
topHeight: 10,
rightWidth: 10,
bottomHeight: 10,
roundPixels: true,
});Use with pixel-art UI textures to avoid sub-pixel seams at the slice boundaries.
Common Mistakes
[HIGH] Using the old NineSlicePlane name
Wrong:
import { NineSlicePlane } from "pixi.js";
const panel = new NineSlicePlane(texture, 10, 10, 10, 10);Correct:
import { NineSliceSprite } from "pixi.js";
const panel = new NineSliceSprite({
texture,
leftWidth: 10,
topHeight: 10,
rightWidth: 10,
bottomHeight: 10,
});NineSlicePlane was renamed in v8 and switched to an options-object constructor. The old NineSlicePlane name is deprecated — use NineSliceSprite instead.
[HIGH] Setting texture.scale to resize the panel
Wrong:
panel.scale.set(2);Correct:
panel.width = 400;
panel.height = 200;scale stretches the entire geometry including corners, defeating the purpose of 9-slice. Always use width / height to resize a NineSliceSprite; this preserves corner art.
[MEDIUM] Borders larger than half the texture
If leftWidth + rightWidth > texture.width, the corners overlap and the center strip disappears. Keep the sum of opposing borders less than the corresponding texture dimension.
API Reference
Sprite
The core image-drawing leaf. Displays a single Texture at a transform. Use Sprite whenever you want to draw a static image that isn't animated (AnimatedSprite), repeating (TilingSprite), or resizable with borders (NineSliceSprite).
Quick Start
const texture = await Assets.load("bunny.png");
const sprite = new Sprite({
texture,
anchor: 0.5,
tint: 0xff8888,
});
sprite.x = app.screen.width / 2;
sprite.y = app.screen.height / 2;
app.stage.addChild(sprite);Sprite is a leaf; allowChildren is false. Wrap sprites in a Container if you need to group or nest them.
Position is set after construction because app.screen.width / 2 depends on the live renderer; literal positions can go directly in the options as x/y.
Core Patterns
Construction
const fromTexture = new Sprite(texture);
const fromCache = Sprite.from("bunny.png");
const fromCanvasNoCache = Sprite.from(canvas, true);
const withOptions = new Sprite({
texture,
anchor: 0.5,
x: 100,
y: 200,
tint: 0xffcc00,
alpha: 0.8,
roundPixels: true,
});SpriteOptions
| Option | Type | Default | Description |
|---|---|---|---|
texture | Texture | Texture.EMPTY | Texture to draw. |
anchor | `PointData \ | number` | 0 |
roundPixels | boolean | false | Snap rendering coordinates to integers for crisp pixel art. |
All Container options (position, scale, tint, label, filters, zIndex, etc.) are also valid here — see skills/pixijs-scene-core-concepts/references/constructor-options.md.
Sprite.from(source, skipCache?) accepts a Texture or a TextureSourceLike (canvas, video, URL). With a cached alias it only reads the cache and returns Texture.EMPTY if the texture was not loaded first; always await Assets.load(...) for images. The optional second skipCache argument forwards to Texture.from to avoid storing ephemeral textures in the global cache.
Video and canvas elements work as texture sources too. Load a video file via await Assets.load('clip.mp4') and pass the returned texture to new Sprite(texture); on mobile platforms, start playback from a user gesture to satisfy autoplay policies.
Sizing helpers
sprite.setSize(200); // square: both axes
sprite.setSize(200, 120); // width and height
sprite.setSize({ width: 200, height: 120 });
const size = sprite.getSize(); // { width, height }
const reused = { width: 0, height: 0 };
sprite.getSize(reused); // write into an existing objectsetSize avoids the double bounds recalculation of setting width and height separately. getSize(out?) returns the current drawn size and optionally writes into a passed object.
Visual vs source bounds
const drawn = sprite.visualBounds; // minX, maxX, minY, maxY of the drawn region (anchor-aware)sprite.visualBounds is the rectangle the sprite actually draws in local space, accounting for anchor and texture trim. It differs from getLocalBounds() when the texture has padding/trim or a non-zero anchor.
Anchor
sprite.anchor.set(0.5); // center both axes
sprite.anchor.set(0, 0); // top-left (default)
sprite.anchor.set(1, 0); // top-right
sprite.anchor = { x: 0.5, y: 1 }; // bottom-centeranchor is normalized [0, 1] relative to the texture dimensions. It shifts where the texture draws relative to the sprite's (x, y) without offsetting the sprite's position. If omitted, falls back to texture.defaultAnchor. Anchor is Sprite-only; it differs from pivot (inherited from Container, in pixel space); pivot shifts both transform origin and visual position.
Tint and alpha
sprite.tint = 0xff0000; // multiply against the texture colors
sprite.alpha = 0.5; // parent-combined transparencytint multiplies pixel values; white (0xffffff) is a no-op. alpha is combined with ancestor alpha up the tree.
Round pixels
const sprite = new Sprite({ texture, roundPixels: true });Snaps rendering coordinates to integers for crisp pixel-art. Apply per-sprite, or globally via TextureStyle.defaultOptions.scaleMode = 'nearest' + roundPixels: true on the renderer.
Dynamic textures
texture.dynamic = true;
texture.frame.width /= 2;
texture.update();v8 removed event-based change notification. Set texture.dynamic = true once, then normal texture.update() calls propagate to all sprites that reference it. Without dynamic, you must call sprite['onViewUpdate']() manually after mutating the texture.
Common Mistakes
[HIGH] Using Texture.from(url) to load
Wrong:
const texture = Texture.from("https://example.com/image.png");
const sprite = new Sprite(texture);Correct:
const texture = await Assets.load("https://example.com/image.png");
const sprite = new Sprite(texture);In v8, Texture.from() only retrieves from the cache. It does not fetch. Use Assets.load() first; its return value is the texture, so you don't need a separate Texture.from() call.
[HIGH] Confusing anchor with pivot
Wrong:
sprite.pivot.set(sprite.width / 2, sprite.height / 2);Correct:
sprite.anchor.set(0.5);anchor is normalized [0, 1] and shifts where the texture draws without offsetting position. pivot is in pixel space and offsets both the transform origin and the rendered position. For centering a sprite, always use anchor.
[MEDIUM] Adding children to a Sprite
Wrong:
sprite.addChild(childSprite);Correct:
const group = new Container();
group.addChild(sprite, childSprite);Sprite sets allowChildren = false. Adding children logs a deprecation warning and will become a hard error. Group leaves inside a Container.
API Reference
TilingSprite
A sprite variant that repeats a texture across a given area. The texture can be scrolled, scaled, and rotated independently of the sprite itself. Use for scrolling backgrounds, parallax layers, repeating ground patterns, and any surface that tiles a single texture.
Quick Start
const texture = await Assets.load("grass.png");
const bg = new TilingSprite({
texture,
width: app.screen.width,
height: app.screen.height,
});
app.stage.addChild(bg);
app.ticker.add((ticker) => {
bg.tilePosition.x -= 1 * ticker.deltaTime;
});width / height define the visible tiling region. tilePosition scrolls the pattern within that region.
Construction
const bg = new TilingSprite({
texture,
width: 800,
height: 600,
tilePosition: { x: 0, y: 0 },
tileScale: { x: 1.5, y: 1.5 },
anchor: 0.5,
roundPixels: true,
});
const fromTexture = TilingSprite.from(texture, { width: 800, height: 600 });
const fromCache = TilingSprite.from("pattern.png", { width: 800, height: 600 });TilingSprite.from(source, options?) accepts a Texture or a cached alias string. The alias form reads from the Assets cache only; await Assets.load('pattern.png') first or the returned sprite draws Texture.EMPTY.
TilingSpriteOptions
| Option | Type | Default | Description |
|---|---|---|---|
texture | Texture | Texture.EMPTY | Texture repeated across the tiling region. |
width | number | 256 | Width of the visible tiling region. |
height | number | 256 | Height of the visible tiling region. |
anchor | `PointData \ | number` | { x: 0, y: 0 } |
tilePosition | PointData | { x: 0, y: 0 } | Offset of the repeated pattern within the region; animate to scroll. |
tileScale | PointData | { x: 1, y: 1 } | Scale applied to the tile pattern only; sprite region stays the same size. |
tileRotation | number | 0 | Rotation in radians applied to the texture before tiling. |
applyAnchorToTexture | boolean | false | Shift the texture origin by the anchor instead of locking (0,0) to the top-left. |
roundPixels | boolean | false | Snap the sprite's position (not the tile pattern) to integer coordinates. |
All Container options (position, scale, tint, label, filters, zIndex, etc.) are also valid here — see skills/pixijs-scene-core-concepts/references/constructor-options.md.
Core Patterns
Scrolling pattern
app.ticker.add((ticker) => {
bg.tilePosition.x -= 2 * ticker.deltaTime;
bg.tilePosition.y -= 0.5 * ticker.deltaTime;
});tilePosition is an ObservablePoint. Shifting it moves the pattern without moving the sprite. This is the cheapest way to scroll a background.
Tile scale and rotation
bg.tileScale.set(2, 2);
bg.tileRotation = Math.PI / 4;tileScale: scales the pattern independently of the sprite. A value of{ x: 2, y: 2 }doubles each tile.tileRotation: rotates the tile pattern in radians. The rotation is applied to the texture before tiling, so the underlying sprite stays axis-aligned.
Anchor on the tiling region
const bg = new TilingSprite({
texture,
width: 800,
height: 600,
anchor: 0.5,
});
bg.x = app.screen.width / 2;
bg.y = app.screen.height / 2;anchor is the normalized origin of the tiling sprite itself (same semantics as Sprite), not of the repeated tile. The visible region is anchored, the tiles fill it.
applyAnchorToTexture
const bg = new TilingSprite({
texture,
width: 800,
height: 600,
anchor: 0.5,
applyAnchorToTexture: true,
});By default, the top-left corner of the tiling region always maps to the (0, 0) texture coordinate. Set applyAnchorToTexture: true to shift the texture origin based on the anchor; useful when you want the pattern to stay centered on the sprite's anchor point as it scales.
Parallax layers
const far = new TilingSprite({ texture: farTex, width: 800, height: 600 });
const near = new TilingSprite({ texture: nearTex, width: 800, height: 600 });
app.stage.addChild(far, near);
app.ticker.add((ticker) => {
far.tilePosition.x -= 0.5 * ticker.deltaTime;
near.tilePosition.x -= 2 * ticker.deltaTime;
});Give each layer a different tilePosition scroll rate for a parallax effect. Scroll speeds are independent per sprite.
Round pixels
const bg = new TilingSprite({
texture,
width: 800,
height: 600,
roundPixels: true,
});Snaps the sprite's position (not the tile pattern) to integer coordinates. Useful for pixel-art tilesets to avoid shimmer.
Hit testing
bg.eventMode = "static";
bg.on("pointertap", (e) => {
console.log("tile clicked", bg.toLocal(e.global));
});TilingSprite overrides containsPoint so hit testing respects the anchor-offset bounds of the tiling region (not the texture). Use it as a regular event target for clickable backgrounds.
Global defaults
TilingSprite.defaultOptions.texture = Texture.from("defaultPattern.png");
TilingSprite.defaultOptions.tileScale = { x: 2, y: 2 };TilingSprite.defaultOptions is a mutable static object merged with any options passed to the constructor. Override fields once at startup for project-wide defaults.
Resizing the tiling region
bg.setSize(app.screen.width, app.screen.height);
const size = bg.getSize();setSize(value, height?) accepts a square value, two numbers, or { width, height }. getSize(out?) returns the current region and optionally writes into an existing object. Both override the base Sprite behavior so a single call avoids recomputing bounds twice.
Common Mistakes
[HIGH] Forgetting to pass a texture
Wrong:
const bg = new TilingSprite({ width: 800, height: 600 });Correct:
const texture = await Assets.load("pattern.png");
const bg = new TilingSprite({ texture, width: 800, height: 600 });The runtime default is Texture.EMPTY (set in TilingSprite.defaultOptions), so omitting the texture produces an invisible sprite with nothing to tile. Always pass a real texture.
[HIGH] Scaling the sprite instead of the tile
Wrong:
bg.scale.set(2);Correct:
bg.tileScale.set(2);Scaling the sprite stretches everything; including the visible area. Use tileScale to make each tile larger while keeping the sprite's region the same size.
[MEDIUM] Non-power-of-two textures with tileScale
Some WebGL implementations cannot repeat non-power-of-two textures in hardware. If you see the pattern clamp to the edge instead of wrapping, resize the source texture to power-of-two dimensions (128, 256, 512, etc.) or pre-bake the tile pattern into a larger texture.
API Reference
Related skills
How it compares
Use pixijs-scene-sprite for spritesheet frame playback; pair with pixijs-assets when animations must preload in the background across level transitions.
FAQ
When should I use NineSliceSprite?
For resizable UI panels and buttons that must stretch centers without distorting corner art.
How do I center a sprite correctly?
Use anchor.set(0.5) rather than pivot pixel offsets that also shift visual position unexpectedly.
Can sprites have child nodes?
No. Sprite leaf classes disallow children; wrap multiple sprites in a Container.
Is Pixijs Scene Sprite safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.