I'm working on my 2d game engine using HTML5 and Canvas. I have a sprite sheet, and each frame of this sprite sheet has its own size.

Considering that the Viewport is following this sprite sheet (in the sense that it is translated relative to the position and dimension of this spritesheet), the centering process of the object undergoes some changes due to the recalculation that takes into account the size of the aforementioned sprite sheet, which in some frames is larger, and in other frames smaller.

For instance, this is an excerpt of the code that manages part of the translation of the viewport based on the position of the target sprite sheet

this._Edge = this.mLocation.X + this.Target.Width - this.Deadzone.Location.X - this.Deadzone.Width;

    if (this.View.Location.X < this._Edge)
        this.View.Location.X = this._Edge;

The problem is that "Target.Width" is nothing more than the width of the current frame, so if the frame is much larger than the previous ones the viewport has a "jump", because it tries to reposition itself based on the current frame size.

enter image description here

From the gif you can see that when I activate the sword sequence, the spritesheet is wider, and consequently the viewport is forced to reposition itself.

To avoid these problems, should I give the sprite sheet a fixed size? Or, for example, would it be more appropriate to consider a fictitious dimension that is an average of the dimensions of the individual frames? As a solution I thought to consider only the center of the sprite sheet, which is always 1x1 pixel. What do you think?

I am ready to consider all suggested solutions.

  • \$\begingroup\$ "Viewport is following this sprite sheet" - sorry, what? Could you please elaborate on that? :-) \$\endgroup\$
    – Kromster
    Nov 9, 2021 at 6:53
  • \$\begingroup\$ Sorry just edited with more details, thanks \$\endgroup\$
    – cs.edoardo
    Nov 9, 2021 at 7:02
  • \$\begingroup\$ Still vague. You might want to take a look at this explosion spritesheet (pngkey.com/png/detail/…) to better grasp the idea of "each frame of this sprite sheet has its own size" and that in such case every sprite has it's own offset relative to the "sprite animation pivot". \$\endgroup\$
    – Kromster
    Nov 9, 2021 at 7:16
  • \$\begingroup\$ Sure, each frame has its own specific size, if that's what you intend to show me, but in this case that's my problem, because I match the size of the sprite sheet to the size of the current frame (which can always vary). Anyway, I added more details to the question, hoping I could be clearer \$\endgroup\$
    – cs.edoardo
    Nov 9, 2021 at 10:52
  • 2
    \$\begingroup\$ Well, you should center your viewport on the sprites pivot, not on it's "center". \$\endgroup\$
    – Kromster
    Nov 9, 2021 at 10:55

1 Answer 1


When you want to use a spritesheet with non-uniform frame size, then you need to introduce the concept of a separate "pivot point" for each animation frame. The pivot point is the "zero-point" of the frame. When you draw a frame at coordinates x:y, then the pivot is the pixel coordinate within that frame where that x:y point is supposed to be on that frame.

Where to place the pivot is a matter of taste. But for a platformer it's a good choice IMO to place the pivot at the bottom of the sprite between the feet.

For example, let's say that your sprite above is 32x64 in the idle pose and 64x64 in the attack poses. In that case, the pivot of both the right-facing idle and attack frames would be 16:64 - the center of the idle and the left quarter of the attack pose. However, for the left-facing attack pose, you would want to draw the whole frame further left. So the pivot of that frame would be 48:64 - three-quarters to the right.

When you draw a frame, you would calculate the coordinates somehow like this:

function drawFrameAtScreenPosition(pos, frame) {
    x = pos.x - frame.pivot.x;
    y = pos.y - frame.pivot.y;
    YourFavoriteGraphicsApi.drawImage(frame.image, x, y, frame.width, frame.height);
  • 4
    \$\begingroup\$ To add, usually pivots are specified in the spritesheet metadata for each sprite (as pivots, or as offsets), since they can "move" by a lot if the sprite is anything more complex than an idle character. \$\endgroup\$
    – Kromster
    Nov 9, 2021 at 11:04

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .