Appearance
Display Animations
This guide explains how to display animations in RPG-JS. There are two main types of animations you can create and display:
- Spritesheet Animations - Using image spritesheets with the built-in animation system
- Custom Component Animations - Creating your own Canvas Engine components for complex effects
Spritesheet Animations
See also: Spritesheets Guide for comprehensive information about spritesheets, including dynamic spritesheet resolution.
1. Creating the Animation Spritesheet
First, you need to create an animation spritesheet and add it to your module's spritesheets configuration.
Using AnimationSpritesheetPreset
The easiest way is to use the built-in AnimationSpritesheetPreset helper:
ts
import { Presets } from "@rpgjs/client";
// In your client module configuration
spritesheets: [
{
id: "explosion",
width: 1024,
height: 1024,
image: "explosion.png",
...Presets.AnimationSpritesheetPreset(4, 4), // 4x4 grid = 16 frames
}
]The AnimationSpritesheetPreset(framesWidth, framesHeight) automatically generates frame coordinates for a grid-based spritesheet. For example, AnimationSpritesheetPreset(4, 4) creates 16 frames arranged in a 4x4 grid.
Manual Spritesheet Configuration
You can also manually configure your spritesheet:
ts
spritesheets: [
{
id: "custom-animation",
image: "my-animation.png",
width: 512,
height: 512,
framesWidth: 8,
framesHeight: 2,
textures: {
default: {
animations: () => [
[
{ time: 0, frameX: 0, frameY: 0 },
{ time: 100, frameX: 1, frameY: 0 },
{ time: 200, frameX: 2, frameY: 0 },
// ... more frames
]
],
}
}
}
]2. Displaying Spritesheet Animations
On a Player
Use the showAnimation method on a player instance:
ts
/**
* Display an animation on a player
* @param graphic - The spritesheet ID
* @param animationName - Animation name (default: 'default')
* @param replaceGraphic - Whether to replace the player's graphic (default: false)
*/
player.showAnimation(graphic: string, animationName: string = 'default', replaceGraphic: boolean = false)Examples:
ts
// Show explosion animation on player
player.showAnimation("explosion");
// Show specific animation from spritesheet
player.showAnimation("spell-effects", "fireball");
// Replace player graphic with animation
player.showAnimation("transformation", "default", true);On a Map
Use the showAnimation method on a map instance:
ts
/**
* Display an animation at a specific position on the map
* @param position - The x, y coordinates where to display the animation
* @param graphic - The spritesheet ID
* @param animationName - Animation name (default: 'default')
*/
map.showAnimation(position: { x: number, y: number }, graphic: string, animationName: string = 'default')Examples:
ts
// Show explosion at specific coordinates
map.showAnimation({ x: 100, y: 200 }, "explosion");
// Show spell effect at player position
const playerPos = { x: player.x, y: player.y };
map.showAnimation(playerPos, "spell-effects", "lightning");Custom Component Animations
For more complex animations with custom logic, you can create Canvas Engine components.
1. Creating a Custom Animation Component
Create a Canvas Engine component file (e.g., ExplosionComponent.ce):
ts
<Sprite sheet x y anchor={0.5} scale alpha={opacity} />
<script>
import { animatedSignal, mount, tick } from "canvasengine";
import { inject, RpgClientEngine } from "@rpgjs/client";
// Get props passed from server
const {
x,
y,
onFinish, // Required: callback to remove animation when done
intensity, // Custom parameter
color, // Custom parameter
duration // Custom parameter with default value
} = defineProps({
duration: {
default: 1000
},
intensity: {
default: 1
},
color: {
default: 'white'
}
});
const client = inject(RpgClientEngine);
// Animation properties
const scale = animatedSignal(0.1, { duration: duration() });
const opacity = animatedSignal(1, { duration: duration() });
// Setup spritesheet
const sheet = {
definition: client.getSpriteSheet('explosion'),
playing: 'default'
};
// Start animation on mount
mount(() => {
scale.set(intensity() * 2);
opacity.set(0);
});
// Handle animation completion
let elapsedTime = 0;
tick(({ deltaTime }) => {
elapsedTime += deltaTime;
if (elapsedTime >= duration()) {
if (onFinish) {
onFinish(); // This removes the animation
}
}
});
</script>2. Registering the Component Animation
Add your component to the module configuration:
ts
import ExplosionComponent from "./components/ExplosionComponent.ce";
import { RpgClient, defineModule } from "@rpgjs/client";
export default defineModule<RpgClient>({
componentAnimations: [
{
id: "explosion",
component: ExplosionComponent
}
]
});3. Displaying Custom Component Animations
On a Player
Use the showComponentAnimation method:
ts
/**
* Display a component animation on a player
* @param id - The component animation ID
* @param params - Parameters to pass to the component
*/
player.showComponentAnimation(id: string, params: any)Examples:
ts
// Basic explosion on player
player.showComponentAnimation("explosion", {});
// Explosion with custom parameters
player.showComponentAnimation("explosion", {
intensity: 2.5,
color: "red",
duration: 1500
});
// Hit indicator with damage text
player.showComponentAnimation("hit", {
text: "150",
color: "red"
});
// Heal animation
player.showComponentAnimation("heal", {
amount: 50,
color: "green"
});On a Map
Use the showComponentAnimation method on the map:
ts
/**
* Display a component animation at a specific position
* @param id - The component animation ID
* @param position - The x, y coordinates
* @param params - Parameters to pass to the component
*/
map.showComponentAnimation(id: string, position: { x: number, y: number }, params: any)Examples:
ts
// Explosion at specific location
map.showComponentAnimation("explosion", { x: 300, y: 400 }, {
intensity: 3,
duration: 2000
});
// Area effect at multiple positions
const positions = [
{ x: 100, y: 100 },
{ x: 150, y: 120 },
{ x: 200, y: 140 }
];
positions.forEach(pos => {
map.showComponentAnimation("sparkle", pos, {
color: "gold",
size: 0.8
});
});Best Practices
1. Animation Performance
- Keep spritesheet sizes reasonable (max 2048x2048)
- Limit the number of simultaneous animations
- Use
onFinishcallback to properly clean up component animations
2. Parameter Validation
Always provide default values for component parameters:
ts
const {
duration,
intensity
} = defineProps({
duration: { default: 1000 },
intensity: { default: 1 }
});3. Memory Management
Component animations are automatically cleaned up when onFinish is called. Always call this callback when your animation completes:
ts
// In your component animation
tick(({ deltaTime }) => {
elapsedTime += deltaTime;
if (elapsedTime >= duration()) {
if (onFinish) {
onFinish(); // Essential for cleanup
}
}
});