Skip to content

Customization

Learn how to customize the appearance and behavior of your virtual joystick.

We recommend use the Tailwind pallete to get beautiful colors. You can use the lib PhaserWind.

const joystick = new VirtualJoystick({
scene: this,
deadZone: {
fillColor: 0xFF6B6B, // Red
alpha: 0.3,
strokeColor: 0xFF5252,
strokeWidth: 3
},
baseArea: {
fillColor: 0x4ECDC4, // Teal
alpha: 0.1,
strokeColor: 0x26A69A,
strokeWidth: 4
},
stick: {
fillColor: 0xFFE66D, // Yellow
alpha: 0.9,
strokeColor: 0xFFD54F,
strokeWidth: 2
}
});

Each visual component (deadZone, baseArea, stick) can be customized:

interface StyleConfig {
alpha: number; // Transparency (0-1)
strokeColor: number; // Stroke color (hex)
strokeAlpha: number; // Stroke transparency (0-1)
strokeWidth: number; // Stroke width in pixels
radius: number; // Circle radius in pixels
fillColor: number; // Fill color (hex)
}
const darkJoystick = new VirtualJoystick({
scene: this,
deadZone: {
fillColor: 0x1a1a1a,
strokeColor: 0x333333,
alpha: 0.2
},
baseArea: {
fillColor: 0x1a1a1a,
strokeColor: 0x333333,
alpha: 0.1
},
stick: {
fillColor: 0x333333,
strokeColor: 0x666666,
alpha: 0.9
}
});
const lightJoystick = new VirtualJoystick({
scene: this,
deadZone: {
fillColor: 0xffffff,
strokeColor: 0xcccccc,
alpha: 0.3
},
baseArea: {
fillColor: 0xffffff,
strokeColor: 0xcccccc,
alpha: 0.1
},
stick: {
fillColor: 0xcccccc,
strokeColor: 0x999999,
alpha: 0.8
}
});
const neonJoystick = new VirtualJoystick({
scene: this,
deadZone: {
fillColor: 0x00ffff,
strokeColor: 0x00cccc,
alpha: 0.3
},
baseArea: {
fillColor: 0x00ffff,
strokeColor: 0x00cccc,
alpha: 0.1
},
stick: {
fillColor: 0xff00ff,
strokeColor: 0xcc00cc,
alpha: 0.9
}
});
// Racing game theme
const racingJoystick = new VirtualJoystick({
scene: this,
deadZone: {
fillColor: 0x2d5016, // Dark green
strokeColor: 0x4a7c59,
alpha: 0.3
},
baseArea: {
fillColor: 0x2d5016,
strokeColor: 0x4a7c59,
alpha: 0.1
},
stick: {
fillColor: 0x4a7c59, // Light green
strokeColor: 0x2d5016,
alpha: 0.9
}
});
// Space game theme
const spaceJoystick = new VirtualJoystick({
scene: this,
deadZone: {
fillColor: 0x000033, // Dark blue
strokeColor: 0x0066cc,
alpha: 0.3
},
baseArea: {
fillColor: 0x000033,
strokeColor: 0x0066cc,
alpha: 0.1
},
stick: {
fillColor: 0x0066cc, // Bright blue
strokeColor: 0x000033,
alpha: 0.9
}
});

Define custom bounds for joystick activation:

const joystick = new VirtualJoystick({
scene: this,
bounds: {
topLeft: { x: 0, y: 100 },
bottomRight: { x: 400, y: 600 }
}
});
// Left side for movement
const moveJoystick = new VirtualJoystick({
scene: this,
bounds: {
topLeft: { x: 0, y: 0 },
bottomRight: { x: this.cameras.main.width / 2, y: this.cameras.main.height }
}
});
// Right side for aiming
const aimJoystick = new VirtualJoystick({
scene: this,
bounds: {
topLeft: { x: this.cameras.main.width / 2, y: 0 },
bottomRight: { x: this.cameras.main.width, y: this.cameras.main.height }
}
});

Add custom icons to your joystick:

// Create custom icon
const stickIcon = this.add.text(0, 0, '🎮', {
fontSize: '24px',
color: '#ffffff'
});
const joystick = new VirtualJoystick({
scene: this,
stickIcon: stickIcon
});
// Movement joystick with arrow icon
const moveIcon = this.add.text(0, 0, '↔️', {
fontSize: '20px',
color: '#ffffff'
});
const moveJoystick = new VirtualJoystick({
scene: this,
stickIcon: moveIcon,
bounds: {
topLeft: { x: 0, y: 0 },
bottomRight: { x: this.cameras.main.width / 2, y: this.cameras.main.height }
}
});
// Aim joystick with crosshair icon
const aimIcon = this.add.text(0, 0, '🎯', {
fontSize: '20px',
color: '#ffffff'
});
const aimJoystick = new VirtualJoystick({
scene: this,
stickIcon: aimIcon,
bounds: {
topLeft: { x: this.cameras.main.width / 2, y: 0 },
bottomRight: { x: this.cameras.main.width, y: this.cameras.main.height }
}
});
// Large joystick for movement
const movementJoystick = new VirtualJoystick({
scene: this,
deadZone: { radius: 20 },
baseArea: { radius: 80 },
stick: { radius: 35 }
});
// Small joystick for aiming
const aimJoystick = new VirtualJoystick({
scene: this,
deadZone: { radius: 15 },
baseArea: { radius: 60 },
stick: { radius: 25 }
});
const highContrastJoystick = new VirtualJoystick({
scene: this,
deadZone: {
fillColor: 0x000000, // Black
strokeColor: 0xffffff, // White
alpha: 1.0,
strokeWidth: 3
},
baseArea: {
fillColor: 0x000000,
strokeColor: 0xffffff,
alpha: 0.8,
strokeWidth: 3
},
stick: {
fillColor: 0xffffff, // White
strokeColor: 0x000000, // Black
alpha: 1.0,
strokeWidth: 3
}
});
const accessibleJoystick = new VirtualJoystick({
scene: this,
deadZone: { radius: 25 },
baseArea: { radius: 100 }, // Larger radius for easier targeting
stick: { radius: 45 },
bounds: {
topLeft: { x: 0, y: 0 },
bottomRight: { x: this.cameras.main.width, y: this.cameras.main.height }
}
});

Enable joystick on desktop for testing:

const joystick = new VirtualJoystick({
scene: this,
enableWithoutTouch: true // Allows mouse interaction on desktop
});
export class GameScene extends Phaser.Scene {
private joystick!: VirtualJoystick;
create() {
// Adjust settings based on device capabilities
const isLowEndDevice = this.sys.game.device.input.touch &&
this.sys.game.device.os.android;
this.joystick = new VirtualJoystick({
scene: this,
deadZone: {
radius: isLowEndDevice ? 20 : 16,
alpha: isLowEndDevice ? 0.9 : 0.8
},
baseArea: {
radius: isLowEndDevice ? 80 : 64,
alpha: isLowEndDevice ? 0.9 : 0.8
},
stick: {
radius: isLowEndDevice ? 40 : 35,
alpha: isLowEndDevice ? 0.9 : 0.8
}
});
this.add.existing(this.joystick);
}
}
export class GameScene extends Phaser.Scene {
private joystick!: VirtualJoystick;
create() {
this.joystick = new VirtualJoystick({
scene: this
});
this.add.existing(this.joystick);
}
destroy() {
// Always clean up when scene is destroyed
if (this.joystick) {
this.joystick.destroy();
}
}
}
  1. Consistent theming: Match joystick appearance to your game’s art style
  2. Accessibility: Consider high contrast and large size options
  3. Performance: Optimize for different device capabilities
  4. User preferences: Allow players to customize joystick settings
  5. Visual feedback: Use animations and color changes to show state
  6. Memory management: Always clean up joysticks when destroying scenes
  7. Testing: Test on various devices and screen sizes
  8. Custom icons: Use meaningful icons that match your game’s theme
  9. Bounds: Define clear activation areas to avoid conflicts with UI
  10. Desktop testing: Enable enableWithoutTouch for development and testing