Body Rendering

The 2D body render assembles a full player model from six body parts extracted
from the skin texture: head, torso, left arm, right arm, left leg, and right
leg. Each part is cropped, resized, and composited onto a single output canvas.
The entire pipeline uses Jimp.


Body Part Regions

Each body part occupies a specific rectangle on the Minecraft skin texture. The
coordinates below are in the format (x, y, width, height) relative to the
top-left corner of the skin PNG.

Base Layer Parts

Part Position Size Notes
Head front (8, 8) 8x8 Same as head render
Torso front (20, 20) 8x12
Left arm front (44, 20) 4x12
Right arm front (36, 52) 4x12 New format only
Left leg front (4, 20) 4x12
Right leg front (20, 52) 4x12 New format only

Overlay Layer Parts

Part Position Size Notes
Head overlay (40, 8) 8x8 Hat layer
Torso overlay (20, 36) 8x12
Left arm overlay (44, 36) 4x12
Right arm overlay (52, 52) 4x12 New format only
Left leg overlay (4, 36) 4x12
Right leg overlay (4, 52) 4x12 New format only

Skin Layout Diagram

64x64 Modern Skin Texture Map:

         0    4    8   16   20   28   32   36   40   44   48   52   56
     0   +----+----+----+----+----+----+----+----+----+----+----+----+
         |         |Head     |         |         |Hat      |         |
     8   |         |Top      |         |         |Top      |         |
         +---------+---------+---------+---------+---------+---------+
         |Head|Head|Head|Head|Hat |Hat  |Hat |Hat |         |         |
    16   |Rgt |Frnt|Left|Back|Rgt |Front|Left|Back|         |         |
         +----+----+----+----+----+-----+----+----+---------+---------+
         |    |Leg |    |    |    |Torso|    |    |    |Arm |    |    |
    20   |    |Frnt|    |    |    |Front|    |    |    |Frnt|    |    |
         |    |4x12|    |    |    |8x12 |    |    |    |4x12|    |    |
    32   +----+----+----+----+----+-----+----+----+----+----+----+----+
         |    |Leg |    |    |    |Torso|    |    |    |Arm |    |    |
    36   |    |Ovly|    |    |    |Ovly |    |    |    |Ovly|    |    |
         |    |4x12|    |    |    |8x12 |    |    |    |4x12|    |    |
    48   +----+----+----+----+----+-----+----+----+----+----+----+----+
         |    |RLeg|    |    |    |RArm |    |    |    |    |    |    |
    52   |    |Frnt|    |    |    |Front|    |    |    |    |    |    |
         |    |4x12|    |    |    |4x12 |    |    |    |    |    |    |
    64   +----+----+----+----+----+-----+----+----+----+----+----+----+

   "R" prefix = right side (new format only, rows 48-63)
   Overlay rows (32-47) mirror base rows (16-31) for each part.

Legacy vs Modern Skin Format

Minecraft skins come in two sizes:

  • Legacy format: 64x32 pixels. Only the left arm and left leg are defined.
    The right arm and right leg are created by mirroring (horizontally flipping)
    the left side.
  • Modern format: 64x64 pixels. Both left and right limbs have independent
    textures, plus overlay layers for every body part.

The API detects the format by checking the image height:

const isNewFormat = skin.bitmap.height >= 64;

For legacy skins, the right arm and right leg are generated by cloning and
flipping:

if (isNewFormat) {
    rightArm = skin.clone().crop(36, 52, 4, 12)
        .resize(size/4, size*3/4, Jimp.RESIZE_NEAREST_NEIGHBOR);
} else {
    rightArm = leftArm.clone().flip(true, false);
}

The flip(true, false) call mirrors horizontally (left-right) without vertical
flipping.


Composite Layout

The output canvas is size pixels wide and size * 2 pixels tall (portrait
orientation). Body parts are positioned relative to the size parameter:

Output canvas (size x size*2):

     0         size/4      size/2      3*size/4      size
     +----------+----------+----------+----------+
  0  |          |          |          |          |
     |          | HEAD     | HEAD     |          |
     |          | (size/2 x size/2)   |          |
     |          |          |          |          |
size/2+---------+----------+----------+----------+
     | LEFT ARM | TORSO               | RIGHT ARM|
     | (size/4  | (size/2 x size*3/4) | (size/4  |
     |  x       |                     |  x       |
     | size*3/4)|                     | size*3/4)|
5s/4 +----------+----------+----------+----------+
     |          | LEFT LEG | RIGHT LEG|          |
     |          | (size/4  | (size/4  |          |
     |          |  x       |  x       |          |
     |          | size*3/4)| size*3/4)|          |
 2s  +----------+----------+----------+----------+

Part Positions (in pixels)

Part X offset Y offset Render size
Head size/4 0 size/2 x size/2
Torso size/4 size/2 size/2 x size*3/4
Left arm 0 size/2 size/4 x size*3/4
Right arm size*3/4 size/2 size/4 x size*3/4
Left leg size/4 size*5/4 size/4 x size*3/4
Right leg size/2 size*5/4 size/4 x size*3/4

Overlay Compositing

When the hat option is enabled, overlay layers are drawn on top of each base
part. The overlay regions are located 16 rows below their corresponding base
regions on the skin texture (e.g., torso base at row 20, torso overlay at
row 36).

The compositing order is bottom-to-top for each part:

  1. Draw base part.
  2. Draw overlay part at the same position (alpha-blended on top).

For legacy skins, right-side overlays are not available, so only the left arm
and left leg overlays are drawn. The right arm/leg overlay compositing is
skipped with an isNewFormat guard:

if (hat && isNewFormat) {
    const rightArmOverlay = skin.clone()
        .crop(52, 52, 4, 12)
        .resize(size/4, size*3/4, Jimp.RESIZE_NEAREST_NEIGHBOR);
    body.composite(rightArmOverlay, size*3/4, size/2);
}

Rendering Order

Parts are composited in this sequence:

  1. Head (base)
  2. Head overlay (if hat)
  3. Torso (base)
  4. Torso overlay (if hat)
  5. Left arm (base)
  6. Left arm overlay (if hat)
  7. Right arm (base, from new format or flipped)
  8. Right arm overlay (if hat and new format)
  9. Left leg (base)
  10. Left leg overlay (if hat)
  11. Right leg (base, from new format or flipped)
  12. Right leg overlay (if hat and new format)

The order matters because later composites draw over earlier ones. Arms and legs
are drawn after the torso so their edges overlap the torso boundary correctly.


Output

The function returns a PNG buffer via body.getBufferAsync(Jimp.MIME_PNG). The
output dimensions are always size x (size * 2) pixels. For the default size
of 128, that produces a 128x256 pixel image.


Endpoint

GET /player/:input/:size?/:option?
  • input -- username, UUID, or Bedrock identifier.
  • size -- width in pixels (default 128). Height is always 2x the width.
  • option -- pass hat to include overlay layers.

Route defined in routes/player.js, calls createBodyRender in
utils/imageProcessor.js.