Skip to main content

Jumping Bunnies Performance Stress Test

Performance stress test with bouncing bunnies

This demo showcases the performance of moving many Konva.Image objects at the same time. It's adapted from the Bunnymark demo of the PixiJS framework.

Note: You may notice that the Konva version is slower than the original PixiJS version. This is because PixiJS is highly optimized for WebGL rendering and this specific type of animation. While Konva continues to optimize its internals, remember that this demo doesn't represent the performance of typical applications made with Konva.

For applications with a very large number of animated objects, you might consider using Native Canvas Access or even a different framework. Choose the right tool for your specific application needs.

Instructions: Click or touch the canvas to add more bunnies. The counter will show how many bunnies are currently animating.

import Konva from 'konva';

// Set up stage and layer
const width = window.innerWidth;
const height = window.innerHeight;

const stage = new Konva.Stage({
  container: 'container',
  width: width,
  height: height,
});

const layer = new Konva.FastLayer();
stage.add(layer);

// Create stats and counter display
const counterDiv = document.createElement('div');
counterDiv.style.position = 'absolute';
counterDiv.style.top = '50px';
counterDiv.style.backgroundColor = 'white';
counterDiv.style.fontSize = '12px';
counterDiv.style.padding = '5px';
counterDiv.innerHTML = '0 BUNNIES';
document.getElementById('container').appendChild(counterDiv);

// Define variables
const bunnys = [];
const GRAVITY = 0.75;
const maxX = width;
const minX = 0;
const maxY = height;
const minY = 0;
const startBunnyCount = 100; // Starting with fewer bunnies for better initial performance
const amount = 10; // Add this many bunnies at a time
let isAdding = false;
let count = 0;
let wabbitTexture;

// Load the bunny image
wabbitTexture = new Image();
wabbitTexture.onload = function() {
  addBunnies(startBunnyCount);
  counterDiv.innerHTML = startBunnyCount + ' BUNNIES';
  count = startBunnyCount;
  
  // Start animation loop
  requestAnimationFrame(update);
};
wabbitTexture.src = 'https://konvajs.org/assets/bunny.png';

// Add event listeners
stage.on('mousedown touchstart', function() {
  isAdding = true;
});

stage.on('mouseup touchend', function() {
  isAdding = false;
});

// Function to add bunnies
function addBunnies(num) {
  for (let i = 0; i < num; i++) {
    const bunny = new Konva.Image({
      image: wabbitTexture,
      transformsEnabled: 'position',
      perfectDrawEnabled: false,
      x: Math.random() * width,
      y: Math.random() * height,
    });

    bunny.speedX = Math.random() * 10;
    bunny.speedY = Math.random() * 10 - 5;

    bunnys.push(bunny);
    layer.add(bunny);
  }
}

// Animation update function
function update() {
  // Add more bunnies if mouse is down
  if (isAdding) {
    addBunnies(amount);
    count += amount;
    counterDiv.innerHTML = count + ' BUNNIES';
  }

  // Update all bunnies
  for (let i = 0; i < bunnys.length; i++) {
    const bunny = bunnys[i];
    let x = bunny.x();
    let y = bunny.y();

    x += bunny.speedX;
    y += bunny.speedY;
    bunny.speedY += GRAVITY;

    // Bounce off the edges
    if (x > maxX - wabbitTexture.width) {
      bunny.speedX *= -1;
      x = maxX - wabbitTexture.width;
    } else if (x < minX) {
      bunny.speedX *= -1;
      x = minX;
    }

    if (y > maxY - wabbitTexture.height) {
      bunny.speedY *= -0.85;
      y = maxY - wabbitTexture.height;
      if (Math.random() > 0.5) {
        bunny.speedY -= Math.random() * 6;
      }
    } else if (y < minY) {
      bunny.speedY = 0;
      y = minY;
    }

    bunny.position({ x, y });
  }

  layer.batchDraw();
  requestAnimationFrame(update);
}