Classroom Public page

Lab 4.3: Replace a Sprite Tile

1,018 words

~120 minutes. Modify one 8x8 sprite tile by changing its raw bytes in CHR-ROM. Use what you learned in lab 2.2 about the 2-bitplane encoding.


Goal: redesign one specific 8x8 tile (the player character's head, an enemy face, a fruit pickup, anything visible) by editing the 16 bytes that encode it.

Estimated time: 120 minutes (the most ambitious lab of week 4)

Prerequisites: lab 2.2 complete (you understand the 2-bitplane tile encoding); lab 4.1 and 4.2 complete

Steps

Step 1: Pick a tile (15 minutes)

Run your ROM in Mesen. Find a clearly identifiable tile you want to redesign. Strong candidates:

  • The player character's face / head
  • An enemy face
  • An item / pickup sprite (coin, key, fruit)
  • A letter from the title screen
  • A particular environment tile (a brick; a tree)

Open Mesen's PPU Viewer → Pattern Tables. Find the tile and note its tile index. Confirm by hovering, Mesen should highlight the corresponding location.

Write down: "I want to change tile index ___ in pattern table ___. It currently looks like ___. I will redraw it as ___."

Step 2: Plan your redesign on graph paper (or digitally) (20 minutes)

Sketch the new 8×8 design. You have 4 color slots (palette indices 0, 1, 2, 3), that is, each pixel can be one of 4 values. Plan which pixels are each color.

A typical 8x8 sketch on graph paper:

. . X X X X . .
. X X X X X X .
X X 1 1 1 1 X X
X X 1 2 2 1 X X
X X 1 2 2 1 X X
X X 1 1 1 1 X X
. X X X X X X .
. . X X X X . .

(Where . = palette index 0 (transparent/background), X = palette index 3 (outline), 1 = palette index 1 (fill), 2 = palette index 2 (detail).)

Step 3: Convert your sketch to bytes (30 minutes)

You have an 8×8 grid where each cell is one of {0, 1, 2, 3}. You need to convert this to 16 bytes (8 low-bitplane bytes + 8 high-bitplane bytes).

For each row r (0 to 7):

  • low_byte[r] = the 8 LOW bits of the pixels in row r, packed MSB-first
  • high_byte[r] = the 8 HIGH bits of the pixels in row r, packed MSB-first

For pixel value v, the low bit is v & 1 and the high bit is (v >> 1) & 1. (So palette 0 → low=0, high=0; palette 1 → low=1, high=0; palette 2 → low=0, high=1; palette 3 → low=1, high=1.)

Example for the row . X 1 2 2 1 X .:

Palette indices:    0 3 1 2 2 1 3 0
Low bits:           0 1 1 0 0 1 1 0  → binary 01100110 → 0x66
High bits:          0 1 0 1 1 0 1 0  → binary 01011010 → 0x5A

Do this for all 8 rows. Write down all 16 bytes.

Step 4: Find the tile's bytes in your ROM (15 minutes)

Use the offset math from lab 2.2:

  • CHR-ROM start = 16 (header) + PRG-ROM size in bytes
  • Tile offset within CHR-ROM = tile index × 16 + (4096 if pattern table 1)
  • File offset = CHR-ROM start + tile offset

Open your hex editor at that file offset. The 16 bytes you see are the original tile encoding.

Step 5: Write the new bytes (10 minutes)

Overwrite the 16 bytes at the tile's file offset with your new 16 bytes. The first 8 bytes are the low bitplane; the next 8 are the high bitplane.

Save the file.

Step 6: Verify in Mesen (15 minutes)

Reload your hack in Mesen. Open Tools → PPU Viewer → Pattern Tables. Find your tile (same index). Does it match your sketch?

  • Yes, exactly: great. Now run the game and find where the tile appears. Confirm it shows up in context (the player's face IS now your new design; the enemy IS now your modified version)
  • The tile is there but the colors are weird: the palette assigned to this tile in the game is different from what you assumed. Your shape is correct; the colors are determined elsewhere
  • The tile is garbled: your byte conversion was wrong. Re-check step 3. Most likely: you swapped low and high bitplane bytes, or you reversed the column ordering (column 0 is bit 7, not bit 0)

Step 7: Take screenshots (10 minutes)

Save:

  • ~/spk-101/working/lab-4-3-before-tileview.png (PPU viewer of the original tile)
  • ~/spk-101/working/lab-4-3-after-tileview.png (PPU viewer of your modified tile)
  • ~/spk-101/working/lab-4-3-before-ingame.png (the game showing the original tile in context)
  • ~/spk-101/working/lab-4-3-after-ingame.png (the game showing your modified tile in context)

Step 8: Journal (15 minutes)

In ~/spk-101/journal/lab-4-3-notes.md:

  • The tile you picked and your sketch
  • Your row-by-row byte conversion (at least the first two rows in full detail)
  • Where the tile lived in the ROM (file offset)
  • What you tried that did not work first
  • A reflection: this lab packed an 8×8 image (64 pixels, 4 colors per pixel) into 16 bytes. A 1989 PNG with the same data would be ~80 bytes (header + chunks + compressed pixel data); a 2025 PNG could be much smaller because of better compression. What is the tradeoff the NES designers made by choosing this very-compact custom encoding?

Expected output

  • One redesigned 8x8 sprite tile, visible in your hacked ROM
  • 4 screenshots (2 tile-viewer, 2 in-game)
  • A detailed journal entry showing your byte-conversion work

Common pitfalls

  • Confusing low and high bitplane bytes: the FIRST 8 bytes of a tile are the LOW bitplane; the NEXT 8 are the HIGH bitplane. Swapping them shows the right shape with the wrong colors
  • Reversing column order: column 0 is the LEFTMOST pixel and corresponds to BIT 7 (MSB) of each row byte. Bit 0 is the rightmost
  • Off-by-one tile index: tile index 0 starts at offset CHR-ROM-start; tile index 1 starts at CHR-ROM-start + 16. Confirm before editing
  • Editing a tile that does not appear during normal gameplay: some tiles are used only in specific contexts. You may have edited a tile that never shows during the part of the game you tested. Check Mesen's PPU Viewer to confirm your edit took effect; then play more of the game to find it

Stretch (optional)

  • Redesign a second tile that combines with the first (e.g., the player's face AND the player's body, so the full character is yours)
  • Use a free pixel-art editor (Aseprite trial; GIMP; even MS Paint at 8x zoom) to design your tile, then export the bytes by hand. Some PPU viewers can import pixel-art directly
  • Find one tile that is repeated in multiple places (e.g., the same brick used 50 times in a level). Modifying it changes ALL those places at once. Use this for stylistic effect

Lab 4.3 v0.1. The most ambitious week-4 lab. Genuine pixel art on real hardware emulation.